mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
First commit to allocate dynamic memory
This commit is contained in:
@@ -25,6 +25,7 @@ import com.kunzisoft.keepass.app.database.CipherDatabaseAction
|
|||||||
import com.kunzisoft.keepass.app.database.CipherDatabaseEntity
|
import com.kunzisoft.keepass.app.database.CipherDatabaseEntity
|
||||||
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
|
import com.kunzisoft.keepass.database.element.database.BinaryData
|
||||||
import com.kunzisoft.keepass.database.exception.LoadDatabaseException
|
import com.kunzisoft.keepass.database.exception.LoadDatabaseException
|
||||||
import com.kunzisoft.keepass.model.MainCredential
|
import com.kunzisoft.keepass.model.MainCredential
|
||||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
@@ -55,6 +56,9 @@ class LoadDatabaseRunnable(private val context: Context,
|
|||||||
mReadonly,
|
mReadonly,
|
||||||
context.contentResolver,
|
context.contentResolver,
|
||||||
UriUtil.getBinaryDir(context),
|
UriUtil.getBinaryDir(context),
|
||||||
|
{ memoryWanted ->
|
||||||
|
BinaryData.canMemoryBeAllocatedInRAM(context, memoryWanted)
|
||||||
|
},
|
||||||
Database.LoadedKey.generateNewCipherKey(),
|
Database.LoadedKey.generateNewCipherKey(),
|
||||||
mFixDuplicateUUID,
|
mFixDuplicateUUID,
|
||||||
progressTaskUpdater)
|
progressTaskUpdater)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package com.kunzisoft.keepass.database.action
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
|
import com.kunzisoft.keepass.database.element.database.BinaryData
|
||||||
import com.kunzisoft.keepass.database.exception.LoadDatabaseException
|
import com.kunzisoft.keepass.database.exception.LoadDatabaseException
|
||||||
import com.kunzisoft.keepass.settings.PreferencesUtil
|
import com.kunzisoft.keepass.settings.PreferencesUtil
|
||||||
import com.kunzisoft.keepass.tasks.ActionRunnable
|
import com.kunzisoft.keepass.tasks.ActionRunnable
|
||||||
@@ -46,6 +47,9 @@ class ReloadDatabaseRunnable(private val context: Context,
|
|||||||
try {
|
try {
|
||||||
mDatabase.reloadData(context.contentResolver,
|
mDatabase.reloadData(context.contentResolver,
|
||||||
UriUtil.getBinaryDir(context),
|
UriUtil.getBinaryDir(context),
|
||||||
|
{ memoryWanted ->
|
||||||
|
BinaryData.canMemoryBeAllocatedInRAM(context, memoryWanted)
|
||||||
|
},
|
||||||
tempCipherKey ?: Database.LoadedKey.generateNewCipherKey(),
|
tempCipherKey ?: Database.LoadedKey.generateNewCipherKey(),
|
||||||
progressTaskUpdater)
|
progressTaskUpdater)
|
||||||
} catch (e: LoadDatabaseException) {
|
} catch (e: LoadDatabaseException) {
|
||||||
|
|||||||
@@ -30,12 +30,15 @@ data class Attachment(var name: String,
|
|||||||
|
|
||||||
constructor(parcel: Parcel) : this(
|
constructor(parcel: Parcel) : this(
|
||||||
parcel.readString() ?: "",
|
parcel.readString() ?: "",
|
||||||
parcel.readParcelable(BinaryData::class.java.classLoader) ?: BinaryByte()
|
// TODO BinaryParcelable
|
||||||
|
//parcel.readParcelable(BinaryData::class.java.classLoader) ?:
|
||||||
|
BinaryByte()
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||||
parcel.writeString(name)
|
parcel.writeString(name)
|
||||||
parcel.writeParcelable(binaryData, flags)
|
// TODO BinaryParcelable
|
||||||
|
//parcel.writeParcelable(binaryData, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun describeContents(): Int {
|
override fun describeContents(): Int {
|
||||||
|
|||||||
@@ -453,6 +453,7 @@ class Database {
|
|||||||
readOnly: Boolean,
|
readOnly: Boolean,
|
||||||
contentResolver: ContentResolver,
|
contentResolver: ContentResolver,
|
||||||
cacheDirectory: File,
|
cacheDirectory: File,
|
||||||
|
isRAMSufficient: (memoryWanted: Long) -> Boolean,
|
||||||
tempCipherKey: LoadedKey,
|
tempCipherKey: LoadedKey,
|
||||||
fixDuplicateUUID: Boolean,
|
fixDuplicateUUID: Boolean,
|
||||||
progressTaskUpdater: ProgressTaskUpdater?) {
|
progressTaskUpdater: ProgressTaskUpdater?) {
|
||||||
@@ -474,7 +475,7 @@ class Database {
|
|||||||
// Read database stream for the first time
|
// Read database stream for the first time
|
||||||
readDatabaseStream(contentResolver, uri,
|
readDatabaseStream(contentResolver, uri,
|
||||||
{ databaseInputStream ->
|
{ databaseInputStream ->
|
||||||
DatabaseInputKDB(cacheDirectory)
|
DatabaseInputKDB(cacheDirectory, isRAMSufficient)
|
||||||
.openDatabase(databaseInputStream,
|
.openDatabase(databaseInputStream,
|
||||||
mainCredential.masterPassword,
|
mainCredential.masterPassword,
|
||||||
keyFileInputStream,
|
keyFileInputStream,
|
||||||
@@ -483,7 +484,7 @@ class Database {
|
|||||||
fixDuplicateUUID)
|
fixDuplicateUUID)
|
||||||
},
|
},
|
||||||
{ databaseInputStream ->
|
{ databaseInputStream ->
|
||||||
DatabaseInputKDBX(cacheDirectory)
|
DatabaseInputKDBX(cacheDirectory, isRAMSufficient)
|
||||||
.openDatabase(databaseInputStream,
|
.openDatabase(databaseInputStream,
|
||||||
mainCredential.masterPassword,
|
mainCredential.masterPassword,
|
||||||
keyFileInputStream,
|
keyFileInputStream,
|
||||||
@@ -507,6 +508,7 @@ class Database {
|
|||||||
@Throws(LoadDatabaseException::class)
|
@Throws(LoadDatabaseException::class)
|
||||||
fun reloadData(contentResolver: ContentResolver,
|
fun reloadData(contentResolver: ContentResolver,
|
||||||
cacheDirectory: File,
|
cacheDirectory: File,
|
||||||
|
isRAMSufficient: (memoryWanted: Long) -> Boolean,
|
||||||
tempCipherKey: LoadedKey,
|
tempCipherKey: LoadedKey,
|
||||||
progressTaskUpdater: ProgressTaskUpdater?) {
|
progressTaskUpdater: ProgressTaskUpdater?) {
|
||||||
|
|
||||||
@@ -515,14 +517,14 @@ class Database {
|
|||||||
fileUri?.let { oldDatabaseUri ->
|
fileUri?.let { oldDatabaseUri ->
|
||||||
readDatabaseStream(contentResolver, oldDatabaseUri,
|
readDatabaseStream(contentResolver, oldDatabaseUri,
|
||||||
{ databaseInputStream ->
|
{ databaseInputStream ->
|
||||||
DatabaseInputKDB(cacheDirectory)
|
DatabaseInputKDB(cacheDirectory, isRAMSufficient)
|
||||||
.openDatabase(databaseInputStream,
|
.openDatabase(databaseInputStream,
|
||||||
masterKey,
|
masterKey,
|
||||||
tempCipherKey,
|
tempCipherKey,
|
||||||
progressTaskUpdater)
|
progressTaskUpdater)
|
||||||
},
|
},
|
||||||
{ databaseInputStream ->
|
{ databaseInputStream ->
|
||||||
DatabaseInputKDBX(cacheDirectory)
|
DatabaseInputKDBX(cacheDirectory, isRAMSufficient)
|
||||||
.openDatabase(databaseInputStream,
|
.openDatabase(databaseInputStream,
|
||||||
masterKey,
|
masterKey,
|
||||||
tempCipherKey,
|
tempCipherKey,
|
||||||
@@ -576,8 +578,7 @@ class Database {
|
|||||||
|
|
||||||
val attachmentPool: AttachmentPool
|
val attachmentPool: AttachmentPool
|
||||||
get() {
|
get() {
|
||||||
// Binary pool is functionally only in KDBX
|
return mDatabaseKDB?.binaryPool ?: mDatabaseKDBX?.binaryPool ?: AttachmentPool()
|
||||||
return mDatabaseKDBX?.binaryPool ?: AttachmentPool()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val allowMultipleAttachments: Boolean
|
val allowMultipleAttachments: Boolean
|
||||||
@@ -593,7 +594,7 @@ class Database {
|
|||||||
compressed: Boolean = false,
|
compressed: Boolean = false,
|
||||||
protected: Boolean = false): BinaryData? {
|
protected: Boolean = false): BinaryData? {
|
||||||
return mDatabaseKDB?.buildNewAttachment(cacheDirectory)
|
return mDatabaseKDB?.buildNewAttachment(cacheDirectory)
|
||||||
?: mDatabaseKDBX?.buildNewAttachment(cacheDirectory, compressed, protected)
|
?: mDatabaseKDBX?.buildNewAttachment(cacheDirectory, false, compressed, protected)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeAttachmentIfNotUsed(attachment: Attachment) {
|
fun removeAttachmentIfNotUsed(attachment: Attachment) {
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ class Entry : Node, EntryVersionedInterface<Group> {
|
|||||||
|
|
||||||
fun getAttachments(attachmentPool: AttachmentPool, inHistory: Boolean = false): List<Attachment> {
|
fun getAttachments(attachmentPool: AttachmentPool, inHistory: Boolean = false): List<Attachment> {
|
||||||
val attachments = ArrayList<Attachment>()
|
val attachments = ArrayList<Attachment>()
|
||||||
entryKDB?.getAttachment()?.let {
|
entryKDB?.getAttachment(attachmentPool)?.let {
|
||||||
attachments.add(it)
|
attachments.add(it)
|
||||||
}
|
}
|
||||||
entryKDBX?.getAttachments(attachmentPool, inHistory)?.let {
|
entryKDBX?.getAttachments(attachmentPool, inHistory)?.let {
|
||||||
@@ -336,7 +336,7 @@ class Entry : Node, EntryVersionedInterface<Group> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun putAttachment(attachment: Attachment, attachmentPool: AttachmentPool) {
|
private fun putAttachment(attachment: Attachment, attachmentPool: AttachmentPool) {
|
||||||
entryKDB?.putAttachment(attachment)
|
entryKDB?.putAttachment(attachment, attachmentPool)
|
||||||
entryKDBX?.putAttachment(attachment, attachmentPool)
|
entryKDBX?.putAttachment(attachment, attachmentPool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.database.element.database
|
package com.kunzisoft.keepass.database.element.database
|
||||||
|
|
||||||
import android.os.Parcel
|
|
||||||
import android.os.Parcelable
|
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.stream.readAllBytes
|
import com.kunzisoft.keepass.stream.readAllBytes
|
||||||
import java.io.*
|
import java.io.*
|
||||||
@@ -35,18 +33,15 @@ class BinaryByte : BinaryData {
|
|||||||
*/
|
*/
|
||||||
constructor() : super()
|
constructor() : super()
|
||||||
|
|
||||||
|
constructor(compressed: Boolean = false,
|
||||||
|
protected: Boolean = false) : super(compressed, protected)
|
||||||
|
|
||||||
constructor(byteArray: ByteArray,
|
constructor(byteArray: ByteArray,
|
||||||
compressed: Boolean = false,
|
compressed: Boolean = false,
|
||||||
protected: Boolean = false) : super(compressed, protected) {
|
protected: Boolean = false) : super(compressed, protected) {
|
||||||
this.mDataByte = byteArray
|
this.mDataByte = byteArray
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(parcel: Parcel) : super(parcel) {
|
|
||||||
val byteArray = ByteArray(parcel.readInt())
|
|
||||||
parcel.readByteArray(byteArray)
|
|
||||||
mDataByte = byteArray
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun getInputDataStream(cipherKey: Database.LoadedKey): InputStream {
|
override fun getInputDataStream(cipherKey: Database.LoadedKey): InputStream {
|
||||||
return ByteArrayInputStream(mDataByte)
|
return ByteArrayInputStream(mDataByte)
|
||||||
@@ -112,12 +107,6 @@ class BinaryByte : BinaryData {
|
|||||||
return mDataByte.toString()
|
return mDataByte.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
|
||||||
super.writeToParcel(dest, flags)
|
|
||||||
dest.writeInt(mDataByte.size)
|
|
||||||
dest.writeByteArray(mDataByte)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other !is BinaryByte) return false
|
if (other !is BinaryByte) return false
|
||||||
@@ -145,21 +134,7 @@ class BinaryByte : BinaryData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private val TAG = BinaryByte::class.java.name
|
private val TAG = BinaryByte::class.java.name
|
||||||
// Max Parcelable / 2
|
|
||||||
const val MAX_BINARY_BYTES = 524288
|
|
||||||
|
|
||||||
@JvmField
|
|
||||||
val CREATOR: Parcelable.Creator<BinaryByte> = object : Parcelable.Creator<BinaryByte> {
|
|
||||||
override fun createFromParcel(parcel: Parcel): BinaryByte {
|
|
||||||
return BinaryByte(parcel)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun newArray(size: Int): Array<BinaryByte?> {
|
|
||||||
return arrayOfNulls(size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.database.element.database
|
package com.kunzisoft.keepass.database.element.database
|
||||||
|
|
||||||
import android.os.Parcel
|
import android.app.ActivityManager
|
||||||
import android.os.Parcelable
|
import android.content.Context
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@@ -28,7 +28,7 @@ import java.io.OutputStream
|
|||||||
import java.util.zip.GZIPInputStream
|
import java.util.zip.GZIPInputStream
|
||||||
import java.util.zip.GZIPOutputStream
|
import java.util.zip.GZIPOutputStream
|
||||||
|
|
||||||
abstract class BinaryData : Parcelable {
|
abstract class BinaryData {
|
||||||
|
|
||||||
var isCompressed: Boolean = false
|
var isCompressed: Boolean = false
|
||||||
protected set
|
protected set
|
||||||
@@ -46,12 +46,6 @@ abstract class BinaryData : Parcelable {
|
|||||||
this.isProtected = protected
|
this.isProtected = protected
|
||||||
}
|
}
|
||||||
|
|
||||||
protected constructor(parcel: Parcel) {
|
|
||||||
isCompressed = parcel.readByte().toInt() != 0
|
|
||||||
isProtected = parcel.readByte().toInt() != 0
|
|
||||||
isCorrupted = parcel.readByte().toInt() != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
abstract fun getInputDataStream(cipherKey: Database.LoadedKey): InputStream
|
abstract fun getInputDataStream(cipherKey: Database.LoadedKey): InputStream
|
||||||
|
|
||||||
@@ -91,16 +85,6 @@ abstract class BinaryData : Parcelable {
|
|||||||
|
|
||||||
abstract fun binaryHash(): Int
|
abstract fun binaryHash(): Int
|
||||||
|
|
||||||
override fun describeContents(): Int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
|
||||||
dest.writeByte((if (isCompressed) 1 else 0).toByte())
|
|
||||||
dest.writeByte((if (isProtected) 1 else 0).toByte())
|
|
||||||
dest.writeByte((if (isCorrupted) 1 else 0).toByte())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other !is BinaryData) return false
|
if (other !is BinaryData) return false
|
||||||
@@ -121,6 +105,13 @@ abstract class BinaryData : Parcelable {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val TAG = BinaryData::class.java.name
|
private val TAG = BinaryData::class.java.name
|
||||||
|
|
||||||
|
fun canMemoryBeAllocatedInRAM(context: Context, memoryWanted: Long): Boolean {
|
||||||
|
val memoryInfo = ActivityManager.MemoryInfo()
|
||||||
|
(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).getMemoryInfo(memoryInfo)
|
||||||
|
val availableMemory = memoryInfo.availMem
|
||||||
|
return availableMemory > memoryWanted * 3
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.database.element.database
|
package com.kunzisoft.keepass.database.element.database
|
||||||
|
|
||||||
import android.os.Parcel
|
|
||||||
import android.os.Parcelable
|
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import android.util.Base64InputStream
|
import android.util.Base64InputStream
|
||||||
import android.util.Base64OutputStream
|
import android.util.Base64OutputStream
|
||||||
@@ -57,14 +55,6 @@ class BinaryFile : BinaryData {
|
|||||||
this.mBinaryHash = 0
|
this.mBinaryHash = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(parcel: Parcel) : super(parcel) {
|
|
||||||
parcel.readString()?.let {
|
|
||||||
mDataFile = File(it)
|
|
||||||
}
|
|
||||||
mLength = parcel.readLong()
|
|
||||||
mBinaryHash = parcel.readInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun getInputDataStream(cipherKey: Database.LoadedKey): InputStream {
|
override fun getInputDataStream(cipherKey: Database.LoadedKey): InputStream {
|
||||||
return buildInputStream(mDataFile, cipherKey)
|
return buildInputStream(mDataFile, cipherKey)
|
||||||
@@ -172,13 +162,6 @@ class BinaryFile : BinaryData {
|
|||||||
return mDataFile.toString()
|
return mDataFile.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
|
||||||
super.writeToParcel(dest, flags)
|
|
||||||
dest.writeString(mDataFile?.absolutePath)
|
|
||||||
dest.writeLong(mLength)
|
|
||||||
dest.writeInt(mBinaryHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other !is BinaryFile) return false
|
if (other !is BinaryFile) return false
|
||||||
@@ -236,19 +219,7 @@ class BinaryFile : BinaryData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private val TAG = BinaryFile::class.java.name
|
private val TAG = BinaryFile::class.java.name
|
||||||
|
|
||||||
@JvmField
|
|
||||||
val CREATOR: Parcelable.Creator<BinaryFile> = object : Parcelable.Creator<BinaryFile> {
|
|
||||||
override fun createFromParcel(parcel: Parcel): BinaryFile {
|
|
||||||
return BinaryFile(parcel)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun newArray(size: Int): Array<BinaryFile?> {
|
|
||||||
return arrayOfNulls(size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class DatabaseKDB : DatabaseVersioned<Int, UUID, GroupKDB, EntryKDB>() {
|
|||||||
private var kdfListV3: MutableList<KdfEngine> = ArrayList()
|
private var kdfListV3: MutableList<KdfEngine> = ArrayList()
|
||||||
|
|
||||||
// Only to generate unique file name
|
// Only to generate unique file name
|
||||||
private var binaryPool = AttachmentPool()
|
var binaryPool = AttachmentPool()
|
||||||
|
|
||||||
override val version: String
|
override val version: String
|
||||||
get() = "KeePass 1"
|
get() = "KeePass 1"
|
||||||
|
|||||||
@@ -318,9 +318,9 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
|
|
||||||
fun addCustomIcon(cacheDirectory: File,
|
fun addCustomIcon(cacheDirectory: File,
|
||||||
customIconId: UUID? = null,
|
customIconId: UUID? = null,
|
||||||
dataSize: Int,
|
smallSize: Boolean,
|
||||||
result: (IconImageCustom, BinaryData?) -> Unit) {
|
result: (IconImageCustom, BinaryData?) -> Unit) {
|
||||||
iconsManager.addCustomIcon(cacheDirectory, customIconId, dataSize, result)
|
iconsManager.addCustomIcon(cacheDirectory, customIconId, smallSize, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isCustomIconBinaryDuplicate(binary: BinaryData): Boolean {
|
fun isCustomIconBinaryDuplicate(binary: BinaryData): Boolean {
|
||||||
@@ -642,12 +642,17 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun buildNewAttachment(cacheDirectory: File,
|
fun buildNewAttachment(cacheDirectory: File,
|
||||||
|
smallSize: Boolean,
|
||||||
compression: Boolean,
|
compression: Boolean,
|
||||||
protection: Boolean,
|
protection: Boolean,
|
||||||
binaryPoolId: Int? = null): BinaryData {
|
binaryPoolId: Int? = null): BinaryData {
|
||||||
return binaryPool.put(binaryPoolId) { uniqueBinaryId ->
|
return binaryPool.put(binaryPoolId) { uniqueBinaryId ->
|
||||||
val fileInCache = File(cacheDirectory, uniqueBinaryId)
|
if (smallSize) {
|
||||||
BinaryFile(fileInCache, compression, protection)
|
BinaryByte(compression, protection)
|
||||||
|
} else {
|
||||||
|
val fileInCache = File(cacheDirectory, uniqueBinaryId)
|
||||||
|
BinaryFile(fileInCache, compression, protection)
|
||||||
|
}
|
||||||
}.binary
|
}.binary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ package com.kunzisoft.keepass.database.element.entry
|
|||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import com.kunzisoft.keepass.database.element.Attachment
|
import com.kunzisoft.keepass.database.element.Attachment
|
||||||
|
import com.kunzisoft.keepass.database.element.database.AttachmentPool
|
||||||
import com.kunzisoft.keepass.database.element.database.BinaryData
|
import com.kunzisoft.keepass.database.element.database.BinaryData
|
||||||
import com.kunzisoft.keepass.database.element.group.GroupKDB
|
import com.kunzisoft.keepass.database.element.group.GroupKDB
|
||||||
import com.kunzisoft.keepass.database.element.icon.IconImageStandard.Companion.KEY_ID
|
import com.kunzisoft.keepass.database.element.icon.IconImageStandard.Companion.KEY_ID
|
||||||
@@ -56,7 +57,7 @@ class EntryKDB : EntryVersioned<Int, UUID, GroupKDB, EntryKDB>, NodeKDBInterface
|
|||||||
|
|
||||||
/** A string describing what is in binaryData */
|
/** A string describing what is in binaryData */
|
||||||
var binaryDescription = ""
|
var binaryDescription = ""
|
||||||
var binaryData: BinaryData? = null
|
private var binaryDataId: Int? = null
|
||||||
|
|
||||||
// Determine if this is a MetaStream entry
|
// Determine if this is a MetaStream entry
|
||||||
val isMetaStream: Boolean
|
val isMetaStream: Boolean
|
||||||
@@ -89,7 +90,7 @@ class EntryKDB : EntryVersioned<Int, UUID, GroupKDB, EntryKDB>, NodeKDBInterface
|
|||||||
url = parcel.readString() ?: url
|
url = parcel.readString() ?: url
|
||||||
notes = parcel.readString() ?: notes
|
notes = parcel.readString() ?: notes
|
||||||
binaryDescription = parcel.readString() ?: binaryDescription
|
binaryDescription = parcel.readString() ?: binaryDescription
|
||||||
binaryData = parcel.readParcelable(BinaryData::class.java.classLoader)
|
binaryDataId = parcel.readInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun readParentParcelable(parcel: Parcel): GroupKDB? {
|
override fun readParentParcelable(parcel: Parcel): GroupKDB? {
|
||||||
@@ -108,7 +109,9 @@ class EntryKDB : EntryVersioned<Int, UUID, GroupKDB, EntryKDB>, NodeKDBInterface
|
|||||||
dest.writeString(url)
|
dest.writeString(url)
|
||||||
dest.writeString(notes)
|
dest.writeString(notes)
|
||||||
dest.writeString(binaryDescription)
|
dest.writeString(binaryDescription)
|
||||||
dest.writeParcelable(binaryData, flags)
|
binaryDataId?.let {
|
||||||
|
dest.writeInt(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateWith(source: EntryKDB) {
|
fun updateWith(source: EntryKDB) {
|
||||||
@@ -119,7 +122,7 @@ class EntryKDB : EntryVersioned<Int, UUID, GroupKDB, EntryKDB>, NodeKDBInterface
|
|||||||
url = source.url
|
url = source.url
|
||||||
notes = source.notes
|
notes = source.notes
|
||||||
binaryDescription = source.binaryDescription
|
binaryDescription = source.binaryDescription
|
||||||
binaryData = source.binaryData
|
binaryDataId = source.binaryDataId
|
||||||
}
|
}
|
||||||
|
|
||||||
override var username = ""
|
override var username = ""
|
||||||
@@ -138,26 +141,39 @@ class EntryKDB : EntryVersioned<Int, UUID, GroupKDB, EntryKDB>, NodeKDBInterface
|
|||||||
override val type: Type
|
override val type: Type
|
||||||
get() = Type.ENTRY
|
get() = Type.ENTRY
|
||||||
|
|
||||||
fun getAttachment(): Attachment? {
|
fun getAttachment(attachmentPool: AttachmentPool): Attachment? {
|
||||||
val binary = binaryData
|
binaryDataId?.let { poolId ->
|
||||||
return if (binary != null)
|
attachmentPool[poolId]?.let { binary ->
|
||||||
Attachment(binaryDescription, binary)
|
return Attachment(binaryDescription, binary)
|
||||||
else null
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun containsAttachment(): Boolean {
|
fun containsAttachment(): Boolean {
|
||||||
return binaryData != null
|
return binaryDataId != null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun putAttachment(attachment: Attachment) {
|
fun getBinary(attachmentPool: AttachmentPool): BinaryData? {
|
||||||
|
this.binaryDataId?.let {
|
||||||
|
return attachmentPool[it]
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun putBinary(binaryData: BinaryData, attachmentPool: AttachmentPool) {
|
||||||
|
this.binaryDataId = attachmentPool.put(binaryData)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun putAttachment(attachment: Attachment, attachmentPool: AttachmentPool) {
|
||||||
this.binaryDescription = attachment.name
|
this.binaryDescription = attachment.name
|
||||||
this.binaryData = attachment.binaryData
|
this.binaryDataId = attachmentPool.put(attachment.binaryData)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeAttachment(attachment: Attachment? = null) {
|
fun removeAttachment(attachment: Attachment? = null) {
|
||||||
if (attachment == null || this.binaryDescription == attachment.name) {
|
if (attachment == null || this.binaryDescription == attachment.name) {
|
||||||
this.binaryDescription = ""
|
this.binaryDescription = ""
|
||||||
this.binaryData = null
|
this.binaryDataId = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ package com.kunzisoft.keepass.database.element.icon
|
|||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.kunzisoft.keepass.database.element.database.BinaryByte
|
import com.kunzisoft.keepass.database.element.database.BinaryByte
|
||||||
import com.kunzisoft.keepass.database.element.database.BinaryByte.Companion.MAX_BINARY_BYTES
|
|
||||||
import com.kunzisoft.keepass.database.element.database.BinaryData
|
import com.kunzisoft.keepass.database.element.database.BinaryData
|
||||||
import com.kunzisoft.keepass.database.element.database.BinaryFile
|
import com.kunzisoft.keepass.database.element.database.BinaryFile
|
||||||
import com.kunzisoft.keepass.database.element.database.CustomIconPool
|
import com.kunzisoft.keepass.database.element.database.CustomIconPool
|
||||||
@@ -56,16 +55,16 @@ class IconsManager {
|
|||||||
key: UUID? = null,
|
key: UUID? = null,
|
||||||
result: (IconImageCustom, BinaryData?) -> Unit) {
|
result: (IconImageCustom, BinaryData?) -> Unit) {
|
||||||
// Create a binary file for a brand new custom icon
|
// Create a binary file for a brand new custom icon
|
||||||
addCustomIcon(cacheDirectory, key, -1, result)
|
addCustomIcon(cacheDirectory, key, false, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addCustomIcon(cacheDirectory: File,
|
fun addCustomIcon(cacheDirectory: File,
|
||||||
key: UUID? = null,
|
key: UUID? = null,
|
||||||
dataSize: Int,
|
smallSize: Boolean,
|
||||||
result: (IconImageCustom, BinaryData?) -> Unit) {
|
result: (IconImageCustom, BinaryData?) -> Unit) {
|
||||||
val keyBinary = customCache.put(key) { uniqueBinaryId ->
|
val keyBinary = customCache.put(key) { uniqueBinaryId ->
|
||||||
// Create a byte array for better performance with small data
|
// Create a byte array for better performance with small data
|
||||||
if (dataSize in 1..MAX_BINARY_BYTES) {
|
if (smallSize) {
|
||||||
BinaryByte()
|
BinaryByte()
|
||||||
} else {
|
} else {
|
||||||
val fileInCache = File(cacheDirectory, uniqueBinaryId)
|
val fileInCache = File(cacheDirectory, uniqueBinaryId)
|
||||||
|
|||||||
@@ -26,8 +26,9 @@ import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
abstract class DatabaseInput<PwDb : DatabaseVersioned<*, *, *, *>>
|
abstract class DatabaseInput<D : DatabaseVersioned<*, *, *, *>>
|
||||||
(protected val cacheDirectory: File) {
|
(protected val cacheDirectory: File,
|
||||||
|
protected val isRAMSufficient: (memoryWanted: Long) -> Boolean) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a versioned database file, return contents in a new DatabaseVersioned.
|
* Load a versioned database file, return contents in a new DatabaseVersioned.
|
||||||
@@ -45,7 +46,7 @@ abstract class DatabaseInput<PwDb : DatabaseVersioned<*, *, *, *>>
|
|||||||
keyfileInputStream: InputStream?,
|
keyfileInputStream: InputStream?,
|
||||||
loadedCipherKey: Database.LoadedKey,
|
loadedCipherKey: Database.LoadedKey,
|
||||||
progressTaskUpdater: ProgressTaskUpdater?,
|
progressTaskUpdater: ProgressTaskUpdater?,
|
||||||
fixDuplicateUUID: Boolean = false): PwDb
|
fixDuplicateUUID: Boolean = false): D
|
||||||
|
|
||||||
|
|
||||||
@Throws(LoadDatabaseException::class)
|
@Throws(LoadDatabaseException::class)
|
||||||
@@ -53,5 +54,5 @@ abstract class DatabaseInput<PwDb : DatabaseVersioned<*, *, *, *>>
|
|||||||
masterKey: ByteArray,
|
masterKey: ByteArray,
|
||||||
loadedCipherKey: Database.LoadedKey,
|
loadedCipherKey: Database.LoadedKey,
|
||||||
progressTaskUpdater: ProgressTaskUpdater?,
|
progressTaskUpdater: ProgressTaskUpdater?,
|
||||||
fixDuplicateUUID: Boolean = false): PwDb
|
fixDuplicateUUID: Boolean = false): D
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,8 +46,9 @@ import javax.crypto.spec.SecretKeySpec
|
|||||||
/**
|
/**
|
||||||
* Load a KDB database file.
|
* Load a KDB database file.
|
||||||
*/
|
*/
|
||||||
class DatabaseInputKDB(cacheDirectory: File)
|
class DatabaseInputKDB(cacheDirectory: File,
|
||||||
: DatabaseInput<DatabaseKDB>(cacheDirectory) {
|
isRAMSufficient: (memoryWanted: Long) -> Boolean)
|
||||||
|
: DatabaseInput<DatabaseKDB>(cacheDirectory, isRAMSufficient) {
|
||||||
|
|
||||||
private lateinit var mDatabase: DatabaseKDB
|
private lateinit var mDatabase: DatabaseKDB
|
||||||
|
|
||||||
@@ -306,11 +307,11 @@ class DatabaseInputKDB(cacheDirectory: File)
|
|||||||
0x000E -> {
|
0x000E -> {
|
||||||
newEntry?.let { entry ->
|
newEntry?.let { entry ->
|
||||||
if (fieldSize > 0) {
|
if (fieldSize > 0) {
|
||||||
val binaryAttachment = mDatabase.buildNewAttachment(cacheDirectory)
|
val binaryData = mDatabase.buildNewAttachment(cacheDirectory)
|
||||||
entry.binaryData = binaryAttachment
|
entry.putBinary(binaryData, mDatabase.binaryPool)
|
||||||
val cipherKey = mDatabase.loadedCipherKey
|
val cipherKey = mDatabase.loadedCipherKey
|
||||||
?: throw IOException("Unable to retrieve cipher key to load binaries")
|
?: throw IOException("Unable to retrieve cipher key to load binaries")
|
||||||
BufferedOutputStream(binaryAttachment.getOutputDataStream(cipherKey)).use { outputStream ->
|
BufferedOutputStream(binaryData.getOutputDataStream(cipherKey)).use { outputStream ->
|
||||||
cipherInputStream.readBytes(fieldSize) { buffer ->
|
cipherInputStream.readBytes(fieldSize) { buffer ->
|
||||||
outputStream.write(buffer)
|
outputStream.write(buffer)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,8 +63,9 @@ import javax.crypto.Cipher
|
|||||||
import javax.crypto.CipherInputStream
|
import javax.crypto.CipherInputStream
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
class DatabaseInputKDBX(cacheDirectory: File)
|
class DatabaseInputKDBX(cacheDirectory: File,
|
||||||
: DatabaseInput<DatabaseKDBX>(cacheDirectory) {
|
isRAMSufficient: (memoryWanted: Long) -> Boolean)
|
||||||
|
: DatabaseInput<DatabaseKDBX>(cacheDirectory, isRAMSufficient) {
|
||||||
|
|
||||||
private var randomStream: StreamCipher? = null
|
private var randomStream: StreamCipher? = null
|
||||||
private lateinit var mDatabase: DatabaseKDBX
|
private lateinit var mDatabase: DatabaseKDBX
|
||||||
@@ -276,7 +277,8 @@ class DatabaseInputKDBX(cacheDirectory: File)
|
|||||||
val protectedFlag = dataInputStream.read().toByte() == DatabaseHeaderKDBX.KdbxBinaryFlags.Protected
|
val protectedFlag = dataInputStream.read().toByte() == DatabaseHeaderKDBX.KdbxBinaryFlags.Protected
|
||||||
val byteLength = size - 1
|
val byteLength = size - 1
|
||||||
// No compression at this level
|
// No compression at this level
|
||||||
val protectedBinary = mDatabase.buildNewAttachment(cacheDirectory, false, protectedFlag)
|
val protectedBinary = mDatabase.buildNewAttachment(cacheDirectory,
|
||||||
|
isRAMSufficient.invoke(byteLength.toLong()), false, protectedFlag)
|
||||||
val cipherKey = mDatabase.loadedCipherKey
|
val cipherKey = mDatabase.loadedCipherKey
|
||||||
?: throw IOException("Unable to retrieve cipher key to load binaries")
|
?: throw IOException("Unable to retrieve cipher key to load binaries")
|
||||||
protectedBinary.getOutputDataStream(cipherKey).use { outputStream ->
|
protectedBinary.getOutputDataStream(cipherKey).use { outputStream ->
|
||||||
@@ -703,11 +705,12 @@ class DatabaseInputKDBX(cacheDirectory: File)
|
|||||||
} else if (ctx == KdbContext.CustomIcons && name.equals(DatabaseKDBXXML.ElemCustomIcons, ignoreCase = true)) {
|
} else if (ctx == KdbContext.CustomIcons && name.equals(DatabaseKDBXXML.ElemCustomIcons, ignoreCase = true)) {
|
||||||
return KdbContext.Meta
|
return KdbContext.Meta
|
||||||
} else if (ctx == KdbContext.CustomIcon && name.equals(DatabaseKDBXXML.ElemCustomIconItem, ignoreCase = true)) {
|
} else if (ctx == KdbContext.CustomIcon && name.equals(DatabaseKDBXXML.ElemCustomIconItem, ignoreCase = true)) {
|
||||||
if (customIconID != DatabaseVersioned.UUID_ZERO && customIconData != null) {
|
val iconData = customIconData
|
||||||
mDatabase.addCustomIcon(cacheDirectory, customIconID, customIconData!!.size) { _, binary ->
|
if (customIconID != DatabaseVersioned.UUID_ZERO && iconData != null) {
|
||||||
|
mDatabase.addCustomIcon(cacheDirectory, customIconID, isRAMSufficient.invoke(iconData.size.toLong())) { _, binary ->
|
||||||
mDatabase.loadedCipherKey?.let { cipherKey ->
|
mDatabase.loadedCipherKey?.let { cipherKey ->
|
||||||
binary?.getOutputDataStream(cipherKey)?.use { outputStream ->
|
binary?.getOutputDataStream(cipherKey)?.use { outputStream ->
|
||||||
outputStream.write(customIconData)
|
outputStream.write(iconData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -981,7 +984,7 @@ class DatabaseInputKDBX(cacheDirectory: File)
|
|||||||
var binaryRetrieve = mDatabase.binaryPool[id]
|
var binaryRetrieve = mDatabase.binaryPool[id]
|
||||||
// Create empty binary if not retrieved in pool
|
// Create empty binary if not retrieved in pool
|
||||||
if (binaryRetrieve == null) {
|
if (binaryRetrieve == null) {
|
||||||
binaryRetrieve = mDatabase.buildNewAttachment(cacheDirectory,
|
binaryRetrieve = mDatabase.buildNewAttachment(cacheDirectory, false,
|
||||||
compression = false, protection = false, binaryPoolId = id)
|
compression = false, protection = false, binaryPoolId = id)
|
||||||
}
|
}
|
||||||
return binaryRetrieve
|
return binaryRetrieve
|
||||||
@@ -1018,7 +1021,8 @@ class DatabaseInputKDBX(cacheDirectory: File)
|
|||||||
return null
|
return null
|
||||||
|
|
||||||
// Build the new binary and compress
|
// Build the new binary and compress
|
||||||
val binaryAttachment = mDatabase.buildNewAttachment(cacheDirectory, compressed, protected, binaryId)
|
val binaryAttachment = mDatabase.buildNewAttachment(cacheDirectory,
|
||||||
|
isRAMSufficient.invoke(base64.length.toLong()), compressed, protected, binaryId)
|
||||||
val binaryCipherKey = mDatabase.loadedCipherKey
|
val binaryCipherKey = mDatabase.loadedCipherKey
|
||||||
?: throw IOException("Unable to retrieve cipher key to load binaries")
|
?: throw IOException("Unable to retrieve cipher key to load binaries")
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ class DatabaseOutputKDB(private val mDatabaseKDB: DatabaseKDB,
|
|||||||
}
|
}
|
||||||
// Entries
|
// Entries
|
||||||
mDatabaseKDB.doForEachEntryInIndex { entry ->
|
mDatabaseKDB.doForEachEntryInIndex { entry ->
|
||||||
EntryOutputKDB(entry, outputStream, mDatabaseKDB.loadedCipherKey).output()
|
EntryOutputKDB(entry, outputStream, mDatabaseKDB.loadedCipherKey).output(mDatabaseKDB)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package com.kunzisoft.keepass.database.file.output
|
|||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
|
import com.kunzisoft.keepass.database.element.database.DatabaseKDB
|
||||||
import com.kunzisoft.keepass.database.element.entry.EntryKDB
|
import com.kunzisoft.keepass.database.element.entry.EntryKDB
|
||||||
import com.kunzisoft.keepass.database.exception.DatabaseOutputException
|
import com.kunzisoft.keepass.database.exception.DatabaseOutputException
|
||||||
import com.kunzisoft.keepass.stream.*
|
import com.kunzisoft.keepass.stream.*
|
||||||
@@ -39,7 +40,7 @@ class EntryOutputKDB(private val mEntry: EntryKDB,
|
|||||||
|
|
||||||
//NOTE: Need be to careful about using ints. The actual type written to file is a unsigned int
|
//NOTE: Need be to careful about using ints. The actual type written to file is a unsigned int
|
||||||
@Throws(DatabaseOutputException::class)
|
@Throws(DatabaseOutputException::class)
|
||||||
fun output() {
|
fun output(database: DatabaseKDB) {
|
||||||
try {
|
try {
|
||||||
// UUID
|
// UUID
|
||||||
mOutputStream.write(UUID_FIELD_TYPE)
|
mOutputStream.write(UUID_FIELD_TYPE)
|
||||||
@@ -96,7 +97,7 @@ class EntryOutputKDB(private val mEntry: EntryKDB,
|
|||||||
// Binary
|
// Binary
|
||||||
mCipherKey?.let { cipherKey ->
|
mCipherKey?.let { cipherKey ->
|
||||||
mOutputStream.write(BINARY_DATA_FIELD_TYPE)
|
mOutputStream.write(BINARY_DATA_FIELD_TYPE)
|
||||||
val binaryData = mEntry.binaryData
|
val binaryData = mEntry.getBinary(database.binaryPool)
|
||||||
val binaryDataLength = binaryData?.getSize() ?: 0L
|
val binaryDataLength = binaryData?.getSize() ?: 0L
|
||||||
// Write data length
|
// Write data length
|
||||||
mOutputStream.write(uIntTo4Bytes(UnsignedInt.fromKotlinLong(binaryDataLength)))
|
mOutputStream.write(uIntTo4Bytes(UnsignedInt.fromKotlinLong(binaryDataLength)))
|
||||||
|
|||||||
Reference in New Issue
Block a user