Refactor load database

This commit is contained in:
J-Jamet
2019-09-26 20:29:33 +02:00
parent 75af97e0ae
commit 40b0982298
63 changed files with 315 additions and 562 deletions

View File

@@ -311,7 +311,7 @@ class FileDatabaseSelectActivity : StylishActivity(),
private val keyFileUri: Uri?) : ActionRunnable() {
override fun run() {
finishRun(true, null)
finishRun(true)
}
override fun onFinishRun(result: Result) {

View File

@@ -61,6 +61,7 @@ import com.kunzisoft.keepass.database.action.ProgressDialogThread
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.education.PasswordActivityEducation
import com.kunzisoft.keepass.biometric.AdvancedUnlockedManager
import com.kunzisoft.keepass.database.search.SearchDbHelper
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.utils.MenuUtil
@@ -69,7 +70,6 @@ import com.kunzisoft.keepass.view.AdvancedUnlockInfoView
import com.kunzisoft.keepass.view.asError
import kotlinx.android.synthetic.main.activity_password.*
import java.io.FileNotFoundException
import java.lang.ref.WeakReference
class PasswordActivity : StylishActivity() {
@@ -87,6 +87,8 @@ class PasswordActivity : StylishActivity() {
private var enableButtonOnCheckedChangeListener: CompoundButton.OnCheckedChangeListener? = null
private var mDatabaseFileUri: Uri? = null
private var mDatabaseKeyFileUri: Uri? = null
private var prefs: SharedPreferences? = null
private var mRememberKeyFile: Boolean = false
@@ -101,8 +103,7 @@ class PasswordActivity : StylishActivity() {
prefs = PreferenceManager.getDefaultSharedPreferences(this)
mRememberKeyFile = prefs!!.getBoolean(getString(R.string.keyfile_key),
resources.getBoolean(R.bool.keyfile_default))
mRememberKeyFile = PreferencesUtil.rememberKeyFiles(this)
setContentView(R.layout.activity_password)
@@ -222,6 +223,7 @@ class PasswordActivity : StylishActivity() {
private fun onPostInitUri(databaseFileUri: Uri?, keyFileUri: Uri?) {
mDatabaseFileUri = databaseFileUri
mDatabaseKeyFileUri = keyFileUri
// Define title
databaseFileUri?.let {
@@ -391,14 +393,18 @@ class PasswordActivity : StylishActivity() {
keyFile: Uri?,
cipherDatabaseEntity: CipherDatabaseEntity? = null) {
val keyPassword = if (checkboxPasswordView?.isChecked != true) null else password
val keyFileUri = if (checkboxKeyFileView?.isChecked != true) null else keyFile
loadDatabase(keyPassword, keyFileUri, cipherDatabaseEntity)
verifyKeyFileCheckbox(keyFile)
loadDatabase(keyPassword, mDatabaseKeyFileUri, cipherDatabaseEntity)
}
private fun verifyKeyFileCheckboxAndLoadDatabase(password: String?) {
val keyFile: Uri? = UriUtil.parse(keyFileView?.text?.toString())
val keyFileUri = if (checkboxKeyFileView?.isChecked != true) null else keyFile
loadDatabase(password, keyFileUri)
verifyKeyFileCheckbox(keyFile)
loadDatabase(password, mDatabaseKeyFileUri)
}
private fun verifyKeyFileCheckbox(keyFile: Uri?) {
mDatabaseKeyFileUri = if (checkboxKeyFileView?.isChecked != true) null else keyFile
}
private fun removePassword() {
@@ -423,11 +429,13 @@ class PasswordActivity : StylishActivity() {
ProgressDialogThread(this,
{ progressTaskUpdater ->
LoadDatabaseRunnable(
WeakReference(this@PasswordActivity),
database,
databaseUri,
password,
keyFile,
this@PasswordActivity.contentResolver,
this@PasswordActivity.filesDir,
SearchDbHelper(PreferencesUtil.omitBackup(this@PasswordActivity)),
progressTaskUpdater,
AfterLoadingDatabase(database, password, cipherDatabaseEntity))
},
@@ -453,6 +461,15 @@ class PasswordActivity : StylishActivity() {
}
if (result.isSuccess) {
// Save keyFile in app database
if (PreferencesUtil.rememberKeyFiles(this@PasswordActivity)) {
mDatabaseFileUri?.let { databaseUri ->
mDatabaseKeyFileUri?.let { keyFileUri ->
saveKeyFileData(databaseUri, keyFileUri)
}
}
}
// Remove the password in view in all cases
removePassword()
@@ -467,14 +484,29 @@ class PasswordActivity : StylishActivity() {
}
} else {
if (result.message != null && result.message!!.isNotEmpty()) {
Snackbar.make(activity_password_coordinator_layout, result.message!!, Snackbar.LENGTH_LONG).asError().show()
var errorMessage = result.message
val resultException = result.exception
Log.e(TAG, errorMessage)
if (errorMessage != null && errorMessage.isNotEmpty()) {
if (resultException != null)
errorMessage = "${resultException.getLocalizedMessage(resources)} $errorMessage"
Snackbar.make(activity_password_coordinator_layout, errorMessage, Snackbar.LENGTH_LONG).asError().show()
}
}
}
}
}
private fun saveKeyFileData(databaseUri: Uri, keyUri: Uri?) {
var keyFileUri = keyUri
if (!mRememberKeyFile) {
keyFileUri = null
}
FileDatabaseHistoryAction.getInstance(this).addOrUpdateDatabaseUri(databaseUri, keyFileUri)
}
private fun checkAndLaunchGroupActivity(database: Database, password: String?) {
if (database.validatePasswordEncoding(password)) {
launchGroupActivity()

View File

@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.database.action
import android.content.Context
import android.net.Uri
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.exception.InvalidKeyFileException
import com.kunzisoft.keepass.database.exception.LoadDatabaseInvalidKeyFileException
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.utils.UriUtil
import java.io.IOException
@@ -63,7 +63,7 @@ open class AssignPasswordInDatabaseRunnable @JvmOverloads constructor(
// To save the database
super.run()
finishRun(true)
} catch (e: InvalidKeyFileException) {
} catch (e: LoadDatabaseInvalidKeyFileException) {
erase(mBackupKey)
finishRun(false, e.message)
} catch (e: IOException) {

View File

@@ -19,118 +19,43 @@
*/
package com.kunzisoft.keepass.database.action
import android.content.Context
import android.content.ContentResolver
import android.net.Uri
import android.preference.PreferenceManager
import androidx.annotation.StringRes
import android.util.Log
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.exception.*
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.database.exception.LoadDatabaseException
import com.kunzisoft.keepass.database.search.SearchDbHelper
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import java.io.FileNotFoundException
import java.io.IOException
import java.lang.ref.WeakReference
import java.io.File
class LoadDatabaseRunnable(private val mWeakContext: WeakReference<Context>,
private val mDatabase: Database,
class LoadDatabaseRunnable(private val mDatabase: Database,
private val mUri: Uri,
private val mPass: String?,
private val mKey: Uri?,
private val contentResolver: ContentResolver,
private val cacheDirectory: File,
private val mSearchHelper: SearchDbHelper,
private val progressTaskUpdater: ProgressTaskUpdater?,
nestedAction: ActionRunnable)
: ActionRunnable(nestedAction, executeNestedActionIfResultFalse = true) {
private val mRememberKeyFile: Boolean
get() {
return mWeakContext.get()?.let {
PreferenceManager.getDefaultSharedPreferences(it)
.getBoolean(it.getString(R.string.keyfile_key),
it.resources.getBoolean(R.bool.keyfile_default))
} ?: true
}
override fun run() {
try {
mWeakContext.get()?.let {
mDatabase.loadData(it, mUri, mPass, mKey, progressTaskUpdater)
saveFileData(mUri, mKey)
finishRun(true)
} ?: finishRun(false, "Context null")
} catch (e: ArcFourException) {
catchError(e, R.string.error_arc4)
return
} catch (e: InvalidPasswordException) {
catchError(e, R.string.invalid_password)
return
} catch (e: ContentFileNotFoundException) {
catchError(e, R.string.file_not_found_content)
return
} catch (e: FileNotFoundException) {
catchError(e, R.string.file_not_found)
return
} catch (e: IOException) {
var messageId = R.string.error_load_database
e.message?.let {
if (it.contains("Hash failed with code"))
messageId = R.string.error_load_database_KDF_memory
}
catchError(e, messageId, true)
return
} catch (e: KeyFileEmptyException) {
catchError(e, R.string.keyfile_is_empty)
return
} catch (e: InvalidAlgorithmException) {
catchError(e, R.string.invalid_algorithm)
return
} catch (e: InvalidKeyFileException) {
catchError(e, R.string.keyfile_does_not_exist)
return
} catch (e: InvalidDBSignatureException) {
catchError(e, R.string.invalid_db_sig)
return
} catch (e: InvalidDBVersionException) {
catchError(e, R.string.unsupported_db_version)
return
} catch (e: InvalidDBException) {
catchError(e, R.string.error_invalid_db)
return
} catch (e: OutOfMemoryError) {
catchError(e, R.string.error_out_of_memory)
return
} catch (e: Exception) {
catchError(e, R.string.error_load_database, true)
return
mDatabase.loadData(mUri, mPass, mKey,
contentResolver,
cacheDirectory,
mSearchHelper,
progressTaskUpdater)
finishRun(true)
}
}
private fun catchError(e: Throwable, @StringRes messageId: Int, addThrowableMessage: Boolean = false) {
var errorMessage = mWeakContext.get()?.getString(messageId)
Log.e(TAG, errorMessage, e)
if (addThrowableMessage)
errorMessage = errorMessage + " " + e.localizedMessage
finishRun(false, errorMessage)
}
private fun saveFileData(uri: Uri, key: Uri?) {
var keyFileUri = key
if (!mRememberKeyFile) {
keyFileUri = null
}
mWeakContext.get()?.let {
FileDatabaseHistoryAction.getInstance(it).addOrUpdateDatabaseUri(uri, keyFileUri)
catch (e: LoadDatabaseException) {
finishRun(false, e)
}
}
override fun onFinishRun(result: Result) {
if (!result.isSuccess) {
mDatabase.closeAndClear(mWeakContext.get()?.filesDir)
mDatabase.closeAndClear(cacheDirectory)
}
}
companion object {
private val TAG = LoadDatabaseRunnable::class.java.name
}
}

View File

@@ -21,7 +21,7 @@ package com.kunzisoft.keepass.database.action
import android.content.Context
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.exception.PwDbOutputException
import com.kunzisoft.keepass.database.exception.DatabaseOutputException
import com.kunzisoft.keepass.tasks.ActionRunnable
import java.io.IOException
@@ -37,7 +37,7 @@ abstract class SaveDatabaseRunnable(protected var context: Context,
database.saveData(context.contentResolver)
} catch (e: IOException) {
finishRun(false, e.message)
} catch (e: PwDbOutputException) {
} catch (e: DatabaseOutputException) {
finishRun(false, e.message)
}
}

View File

@@ -20,7 +20,6 @@
package com.kunzisoft.keepass.database.element
import android.content.ContentResolver
import android.content.Context
import android.content.res.Resources
import android.database.Cursor
import android.net.Uri
@@ -39,7 +38,6 @@ import com.kunzisoft.keepass.database.file.save.PwDbV3Output
import com.kunzisoft.keepass.database.file.save.PwDbV4Output
import com.kunzisoft.keepass.database.search.SearchDbHelper
import com.kunzisoft.keepass.icons.IconDrawableFactory
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.stream.LEDataInputStream
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import com.kunzisoft.keepass.utils.SingletonHolder
@@ -56,7 +54,8 @@ class Database {
private var pwDatabaseV4: PwDatabaseV4? = null
private var mUri: Uri? = null
private var searchHelper: SearchDbHelper? = null
private var mSearchHelper: SearchDbHelper? = null
var isReadOnly = false
val drawFactory = IconDrawableFactory()
@@ -209,78 +208,92 @@ class Database {
this.mUri = databaseUri
}
@Throws(IOException::class, InvalidDBException::class)
fun loadData(ctx: Context, uri: Uri, password: String?, keyfile: Uri?, progressTaskUpdater: ProgressTaskUpdater?) {
@Throws(LoadDatabaseException::class)
fun loadData(uri: Uri, password: String?, keyfile: Uri?,
contentResolver: ContentResolver,
cacheDirectory: File,
searchHelper: SearchDbHelper,
progressTaskUpdater: ProgressTaskUpdater?) {
mUri = uri
isReadOnly = false
if (uri.scheme == "file") {
val file = File(uri.path!!)
isReadOnly = !file.canWrite()
}
// Pass Uris as InputStreams
val inputStream: InputStream?
try {
inputStream = UriUtil.getUriInputStream(ctx.contentResolver, uri)
} catch (e: Exception) {
Log.e("KPD", "Database::loadData", e)
throw ContentFileNotFoundException.getInstance(uri)
}
// Pass KeyFile Uri as InputStreams
var keyFileInputStream: InputStream? = null
keyfile?.let {
mUri = uri
isReadOnly = false
if (uri.scheme == "file") {
val file = File(uri.path!!)
isReadOnly = !file.canWrite()
}
// Pass Uris as InputStreams
val inputStream: InputStream?
try {
keyFileInputStream = UriUtil.getUriInputStream(ctx.contentResolver, keyfile)
inputStream = UriUtil.getUriInputStream(contentResolver, uri)
} catch (e: Exception) {
Log.e("KPD", "Database::loadData", e)
throw ContentFileNotFoundException.getInstance(keyfile)
throw LoadDatabaseFileNotFoundException()
}
}
// Load Data
// Pass KeyFile Uri as InputStreams
var keyFileInputStream: InputStream? = null
keyfile?.let {
try {
keyFileInputStream = UriUtil.getUriInputStream(contentResolver, keyfile)
} catch (e: Exception) {
Log.e("KPD", "Database::loadData", e)
throw LoadDatabaseFileNotFoundException()
}
}
val bufferedInputStream = BufferedInputStream(inputStream)
if (!bufferedInputStream.markSupported()) {
throw IOException("Input stream does not support mark.")
}
// Load Data
// We'll end up reading 8 bytes to identify the header. Might as well use two extra.
bufferedInputStream.mark(10)
val bufferedInputStream = BufferedInputStream(inputStream)
if (!bufferedInputStream.markSupported()) {
throw IOException("Input stream does not support mark.")
}
// Get the file directory to save the attachments
val sig1 = LEDataInputStream.readInt(bufferedInputStream)
val sig2 = LEDataInputStream.readInt(bufferedInputStream)
// We'll end up reading 8 bytes to identify the header. Might as well use two extra.
bufferedInputStream.mark(10)
// Return to the start
bufferedInputStream.reset()
// Get the file directory to save the attachments
val sig1 = LEDataInputStream.readInt(bufferedInputStream)
val sig2 = LEDataInputStream.readInt(bufferedInputStream)
when {
// Header of database V3
PwDbHeaderV3.matchesHeader(sig1, sig2) -> setDatabaseV3(ImporterV3()
.openDatabase(bufferedInputStream,
password,
keyFileInputStream,
progressTaskUpdater))
// Return to the start
bufferedInputStream.reset()
// Header of database V4
PwDbHeaderV4.matchesHeader(sig1, sig2) -> setDatabaseV4(ImporterV4(ctx.filesDir)
.openDatabase(bufferedInputStream,
password,
keyFileInputStream,
progressTaskUpdater))
when {
// Header of database V3
PwDbHeaderV3.matchesHeader(sig1, sig2) -> setDatabaseV3(ImporterV3()
.openDatabase(bufferedInputStream,
password,
keyFileInputStream,
progressTaskUpdater))
// Header not recognized
else -> throw InvalidDBSignatureException()
}
// Header of database V4
PwDbHeaderV4.matchesHeader(sig1, sig2) -> setDatabaseV4(ImporterV4(cacheDirectory)
.openDatabase(bufferedInputStream,
password,
keyFileInputStream,
progressTaskUpdater))
try {
searchHelper = SearchDbHelper(PreferencesUtil.omitBackup(ctx))
// Header not recognized
else -> throw LoadDatabaseSignatureException()
}
this.mSearchHelper = searchHelper
loaded = true
} catch (e: LoadDatabaseException) {
throw e
} catch (e: IOException) {
if (e.message?.contains("Hash failed with code") == true)
throw LoadDatabaseKDFMemoryException(e)
else
throw LoadDatabaseIOException(e)
} catch (e: OutOfMemoryError) {
throw LoadDatabaseNoMemoryException(e)
} catch (e: Exception) {
Log.e(TAG, "Load can't be performed with this Database version", e)
loaded = false
throw LoadDatabaseException(e)
}
}
@@ -292,7 +305,7 @@ class Database {
@JvmOverloads
fun search(str: String, max: Int = Integer.MAX_VALUE): GroupVersioned? {
return searchHelper?.search(this, str, max)
return mSearchHelper?.search(this, str, max)
}
fun searchEntries(query: String): Cursor? {
@@ -343,14 +356,14 @@ class Database {
return entry
}
@Throws(IOException::class, PwDbOutputException::class)
@Throws(IOException::class, DatabaseOutputException::class)
fun saveData(contentResolver: ContentResolver) {
mUri?.let {
saveData(contentResolver, it)
}
}
@Throws(IOException::class, PwDbOutputException::class)
@Throws(IOException::class, DatabaseOutputException::class)
private fun saveData(contentResolver: ContentResolver, uri: Uri) {
val errorMessage = "Failed to store database."
@@ -484,7 +497,7 @@ class Database {
?: false
}
@Throws(InvalidKeyFileException::class, IOException::class)
@Throws(LoadDatabaseInvalidKeyFileException::class, IOException::class)
fun retrieveMasterKey(key: String?, keyInputStream: InputStream?) {
pwDatabaseV3?.retrieveMasterKey(key, keyInputStream)
pwDatabaseV4?.retrieveMasterKey(key, keyInputStream)

View File

@@ -19,10 +19,10 @@
*/
package com.kunzisoft.keepass.database.element
import android.util.Log
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
import com.kunzisoft.keepass.database.exception.InvalidKeyFileException
import com.kunzisoft.keepass.database.exception.KeyFileEmptyException
import com.kunzisoft.keepass.database.exception.LoadDatabaseDuplicateUuidException
import com.kunzisoft.keepass.database.exception.LoadDatabaseInvalidKeyFileException
import com.kunzisoft.keepass.database.exception.LoadDatabaseKeyFileEmptyException
import com.kunzisoft.keepass.utils.MemoryUtil
import java.io.ByteArrayInputStream
@@ -72,15 +72,15 @@ abstract class PwDatabase<Group : PwGroup<*, Group, Entry>, Entry : PwEntry<Grou
var rootGroup: Group? = null
@Throws(InvalidKeyFileException::class, IOException::class)
@Throws(LoadDatabaseInvalidKeyFileException::class, IOException::class)
protected abstract fun getMasterKey(key: String?, keyInputStream: InputStream?): ByteArray
@Throws(InvalidKeyFileException::class, IOException::class)
@Throws(LoadDatabaseInvalidKeyFileException::class, IOException::class)
fun retrieveMasterKey(key: String?, keyInputStream: InputStream?) {
masterKey = getMasterKey(key, keyInputStream)
}
@Throws(InvalidKeyFileException::class, IOException::class)
@Throws(LoadDatabaseInvalidKeyFileException::class, IOException::class)
protected fun getCompositeKey(key: String, keyInputStream: InputStream): ByteArray {
val fileKey = getFileKey(keyInputStream)
val passwordKey = getPasswordKey(key)
@@ -120,7 +120,7 @@ abstract class PwDatabase<Group : PwGroup<*, Group, Entry>, Entry : PwEntry<Grou
return messageDigest.digest()
}
@Throws(InvalidKeyFileException::class, IOException::class)
@Throws(LoadDatabaseInvalidKeyFileException::class, IOException::class)
protected fun getFileKey(keyInputStream: InputStream): ByteArray {
val keyByteArrayOutputStream = ByteArrayOutputStream()
@@ -134,7 +134,7 @@ abstract class PwDatabase<Group : PwGroup<*, Group, Entry>, Entry : PwEntry<Grou
}
when (keyData.size.toLong()) {
0L -> throw KeyFileEmptyException()
0L -> throw LoadDatabaseKeyFileEmptyException()
32L -> return keyData
64L -> try {
return hexStringToByteArray(String(keyData))
@@ -238,7 +238,7 @@ abstract class PwDatabase<Group : PwGroup<*, Group, Entry>, Entry : PwEntry<Grou
fun addGroupIndex(group: Group) {
val groupId = group.nodeId
if (groupIndexes.containsKey(groupId)) {
Log.e(TAG, "Error, a group with the same UUID $groupId already exists")
throw LoadDatabaseDuplicateUuidException(Type.GROUP, groupId)
} else {
this.groupIndexes[groupId] = group
}
@@ -273,8 +273,7 @@ abstract class PwDatabase<Group : PwGroup<*, Group, Entry>, Entry : PwEntry<Grou
fun addEntryIndex(entry: Entry) {
val entryId = entry.nodeId
if (entryIndexes.containsKey(entryId)) {
// TODO History
Log.e(TAG, "Error, a group with the same UUID $entryId already exists, change the UUID")
throw LoadDatabaseDuplicateUuidException(Type.ENTRY, entryId)
} else {
this.entryIndexes[entryId] = entry
}

View File

@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.database.element
import com.kunzisoft.keepass.crypto.finalkey.FinalKeyFactory
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory
import com.kunzisoft.keepass.database.exception.InvalidKeyFileException
import com.kunzisoft.keepass.database.exception.LoadDatabaseInvalidKeyFileException
import com.kunzisoft.keepass.stream.NullOutputStream
import java.io.IOException
import java.io.InputStream
@@ -112,7 +112,7 @@ class PwDatabaseV3 : PwDatabase<PwGroupV3, PwEntryV3>() {
return newId
}
@Throws(InvalidKeyFileException::class, IOException::class)
@Throws(LoadDatabaseInvalidKeyFileException::class, IOException::class)
override fun getMasterKey(key: String?, keyInputStream: InputStream?): ByteArray {
return if (key != null && keyInputStream != null) {

View File

@@ -27,7 +27,7 @@ import com.kunzisoft.keepass.crypto.CryptoUtil
import com.kunzisoft.keepass.crypto.engine.AesEngine
import com.kunzisoft.keepass.crypto.engine.CipherEngine
import com.kunzisoft.keepass.crypto.keyDerivation.*
import com.kunzisoft.keepass.database.exception.InvalidKeyFileException
import com.kunzisoft.keepass.database.exception.LoadDatabaseInvalidKeyFileException
import com.kunzisoft.keepass.database.exception.UnknownKDF
import com.kunzisoft.keepass.utils.VariantDictionary
import org.w3c.dom.Node
@@ -236,7 +236,7 @@ class PwDatabaseV4 : PwDatabase<PwGroupV4, PwEntryV4> {
return getCustomData().isNotEmpty()
}
@Throws(InvalidKeyFileException::class, IOException::class)
@Throws(LoadDatabaseInvalidKeyFileException::class, IOException::class)
public override fun getMasterKey(key: String?, keyInputStream: InputStream?): ByteArray {
var masterKey = byteArrayOf()

View File

@@ -1,27 +0,0 @@
/*
* Copyright 2019 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.database.exception
class ArcFourException : InvalidDBException() {
companion object {
private const val serialVersionUID = 2103983626687861237L
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2019 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.database.exception
import android.net.Uri
import java.io.FileNotFoundException
class ContentFileNotFoundException : FileNotFoundException() {
companion object {
fun getInstance(uri: Uri?): FileNotFoundException {
if (uri == null) {
return FileNotFoundException()
}
val scheme = uri.scheme
return if (scheme != null
&& scheme.isNotEmpty()
&& scheme.equals("content", ignoreCase = true)) {
ContentFileNotFoundException()
} else FileNotFoundException()
}
}
}

View File

@@ -19,14 +19,10 @@
*/
package com.kunzisoft.keepass.database.exception
class PwDbOutputException : Exception {
class DatabaseOutputException : Exception {
constructor(string: String) : super(string)
constructor(string: String, e: Exception) : super(string, e)
constructor(e: Exception) : super(e)
companion object {
private const val serialVersionUID = 3321212743159473368L
}
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright 2019 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.database.exception
class InvalidAlgorithmException : InvalidDBException() {
companion object {
private const val serialVersionUID = 3062682891863487208L
}
}

View File

@@ -1,32 +0,0 @@
/*
* Copyright 2019 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.database.exception
open class InvalidDBException : Exception {
constructor(str: String) : super(str)
constructor() : super()
companion object {
private const val serialVersionUID = 5191964825154190923L
}
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright 2019 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.database.exception
class InvalidDBSignatureException : InvalidDBException() {
companion object {
private const val serialVersionUID = -5358923878743513758L
}
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright 2019 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.database.exception
class InvalidDBVersionException : InvalidDBException() {
companion object {
private const val serialVersionUID = -4260650987856400586L
}
}

View File

@@ -1,25 +0,0 @@
/*
* Copyright 2019 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/package com.kunzisoft.keepass.database.exception
open class InvalidKeyFileException : InvalidDBException() {
companion object {
private const val serialVersionUID = 5540694419562294464L
}
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright 2019 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.database.exception
class InvalidPasswordException : InvalidDBException() {
companion object {
private const val serialVersionUID = -8729476180242058319L
}
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright 2019 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
* KeePass DX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePass DX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.database.exception
class KeyFileEmptyException : InvalidKeyFileException() {
companion object {
private const val serialVersionUID = -1630780661204212325L
}
}

View File

@@ -0,0 +1,62 @@
package com.kunzisoft.keepass.database.exception
import android.content.res.Resources
import androidx.annotation.StringRes
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.database.element.PwNodeId
import com.kunzisoft.keepass.database.element.Type
import java.io.IOException
class LoadDatabaseArcFourException : LoadDatabaseException(R.string.error_arc4)
class LoadDatabaseFileNotFoundException : LoadDatabaseException(R.string.file_not_found_content)
class LoadDatabaseInvalidAlgorithmException : LoadDatabaseException(R.string.invalid_algorithm)
class LoadDatabaseDuplicateUuidException(type: Type, uuid: PwNodeId<*>):
LoadDatabaseException("Error, a $type with the same UUID $uuid already exists")
class LoadDatabaseIOException(exception: IOException) : LoadDatabaseException(exception, R.string.error_load_database)
class LoadDatabaseKDFMemoryException(exception: IOException) : LoadDatabaseException(exception, R.string.error_load_database_KDF_memory)
class LoadDatabaseSignatureException : LoadDatabaseException(R.string.invalid_db_sig)
class LoadDatabaseVersionException : LoadDatabaseException(R.string.unsupported_db_version)
open class LoadDatabaseInvalidKeyFileException : LoadDatabaseException(R.string.keyfile_does_not_exist)
class LoadDatabaseInvalidPasswordException : LoadDatabaseException(R.string.invalid_password)
class LoadDatabaseKeyFileEmptyException : LoadDatabaseException(R.string.keyfile_is_empty)
class LoadDatabaseNoMemoryException(exception: OutOfMemoryError) : LoadDatabaseException(exception, R.string.error_out_of_memory)
open class LoadDatabaseException : Exception {
@StringRes
var errorId: Int = R.string.error_load_database
constructor(errorMessage: String) : super(errorMessage)
constructor(errorMessageId: Int) : super() {
errorId = errorMessageId
}
constructor(throwable: Throwable, errorMessageId: Int? = null) : super(throwable) {
errorMessageId?.let {
errorId = it
}
}
constructor() : super()
companion object {
private const val serialVersionUID = 5191964825154190923L
}
fun getLocalizedMessage(resources: Resources): String {
return resources.getString(errorId)
}
}

View File

@@ -19,9 +19,4 @@
*/
package com.kunzisoft.keepass.database.exception
class SamsungClipboardException(e: Exception) : Exception(e) {
companion object {
private const val serialVersionUID = -3168837280393843509L
}
}
class SamsungClipboardException(e: Exception) : Exception(e)

View File

@@ -2,8 +2,4 @@ package com.kunzisoft.keepass.database.exception
import java.io.IOException
class UnknownKDF : IOException(message) {
companion object {
private const val message = "Unknown key derivation function"
}
}
class UnknownKDF : IOException("Unknown key derivation function")

View File

@@ -25,7 +25,7 @@ import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory
import com.kunzisoft.keepass.crypto.keyDerivation.KdfParameters
import com.kunzisoft.keepass.database.NodeHandler
import com.kunzisoft.keepass.database.element.*
import com.kunzisoft.keepass.database.exception.InvalidDBVersionException
import com.kunzisoft.keepass.database.exception.LoadDatabaseVersionException
import com.kunzisoft.keepass.stream.CopyInputStream
import com.kunzisoft.keepass.stream.HmacBlockStream
import com.kunzisoft.keepass.stream.LEDataInputStream
@@ -130,9 +130,9 @@ class PwDbHeaderV4(private val databaseV4: PwDatabaseV4) : PwDbHeader() {
/** Assumes the input stream is at the beginning of the .kdbx file
* @param inputStream
* @throws IOException
* @throws InvalidDBVersionException
* @throws LoadDatabaseVersionException
*/
@Throws(IOException::class, InvalidDBVersionException::class)
@Throws(IOException::class, LoadDatabaseVersionException::class)
fun loadFromFile(inputStream: InputStream): HeaderAndHash {
val messageDigest: MessageDigest
try {
@@ -150,12 +150,12 @@ class PwDbHeaderV4(private val databaseV4: PwDatabaseV4) : PwDbHeader() {
val sig2 = littleEndianDataInputStream.readInt()
if (!matchesHeader(sig1, sig2)) {
throw InvalidDBVersionException()
throw LoadDatabaseVersionException()
}
version = littleEndianDataInputStream.readUInt() // Erase previous value
if (!validVersion(version)) {
throw InvalidDBVersionException()
throw LoadDatabaseVersionException()
}
var done = false

View File

@@ -20,7 +20,7 @@
package com.kunzisoft.keepass.database.file.load
import com.kunzisoft.keepass.database.element.PwDatabase
import com.kunzisoft.keepass.database.exception.InvalidDBException
import com.kunzisoft.keepass.database.exception.LoadDatabaseException
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import java.io.IOException
@@ -36,9 +36,9 @@ abstract class Importer<PwDb : PwDatabase<*, *>> {
* @return new PwDatabase container.
*
* @throws IOException on any file error.
* @throws InvalidDBException on database error.
* @throws LoadDatabaseException on database error.
*/
@Throws(IOException::class, InvalidDBException::class)
@Throws(IOException::class, LoadDatabaseException::class)
abstract fun openDatabase(databaseInputStream: InputStream,
password: String?,
keyInputStream: InputStream?,

View File

@@ -73,7 +73,7 @@ class ImporterV3 : Importer<PwDatabaseV3>() {
private lateinit var mDatabaseToOpen: PwDatabaseV3
@Throws(IOException::class, InvalidDBException::class)
@Throws(IOException::class, LoadDatabaseException::class)
override fun openDatabase(databaseInputStream: InputStream,
password: String?,
keyInputStream: InputStream?,
@@ -92,11 +92,11 @@ class ImporterV3 : Importer<PwDatabaseV3>() {
hdr.loadFromFile(filebuf, 0)
if (hdr.signature1 != PwDbHeader.PWM_DBSIG_1 || hdr.signature2 != PwDbHeaderV3.DBSIG_2) {
throw InvalidDBSignatureException()
throw LoadDatabaseSignatureException()
}
if (!hdr.matchesVersion()) {
throw InvalidDBVersionException()
throw LoadDatabaseVersionException()
}
progressTaskUpdater?.updateMessage(R.string.retrieving_db_key)
@@ -109,7 +109,7 @@ class ImporterV3 : Importer<PwDatabaseV3>() {
} else if (hdr.flags and PwDbHeaderV3.FLAG_TWOFISH != 0) {
mDatabaseToOpen.encryptionAlgorithm = PwEncryptionAlgorithm.Twofish
} else {
throw InvalidAlgorithmException()
throw LoadDatabaseInvalidAlgorithmException()
}
mDatabaseToOpen.numberKeyEncryptionRounds = hdr.numKeyEncRounds.toLong()
@@ -152,7 +152,7 @@ class ImporterV3 : Importer<PwDatabaseV3>() {
} catch (e1: IllegalBlockSizeException) {
throw IOException("Invalid block size")
} catch (e1: BadPaddingException) {
throw InvalidPasswordException()
throw LoadDatabaseInvalidPasswordException()
}
val md: MessageDigest
@@ -171,7 +171,7 @@ class ImporterV3 : Importer<PwDatabaseV3>() {
if (!Arrays.equals(hash, hdr.contentsHash)) {
Log.w(TAG, "Database file did not decrypt correctly. (checksum code is broken)")
throw InvalidPasswordException()
throw LoadDatabaseInvalidPasswordException()
}
// New manual root because V3 contains multiple root groups (here available with getRootGroups())

View File

@@ -26,9 +26,9 @@ import com.kunzisoft.keepass.crypto.StreamCipherFactory
import com.kunzisoft.keepass.crypto.engine.CipherEngine
import com.kunzisoft.keepass.database.element.PwCompressionAlgorithm
import com.kunzisoft.keepass.database.element.*
import com.kunzisoft.keepass.database.exception.ArcFourException
import com.kunzisoft.keepass.database.exception.InvalidDBException
import com.kunzisoft.keepass.database.exception.InvalidPasswordException
import com.kunzisoft.keepass.database.exception.LoadDatabaseArcFourException
import com.kunzisoft.keepass.database.exception.LoadDatabaseException
import com.kunzisoft.keepass.database.exception.LoadDatabaseInvalidPasswordException
import com.kunzisoft.keepass.database.file.PwDbHeaderV4
import com.kunzisoft.keepass.database.element.security.ProtectedBinary
import com.kunzisoft.keepass.database.element.security.ProtectedString
@@ -89,7 +89,7 @@ class ImporterV4(private val streamDir: File) : Importer<PwDatabaseV4>() {
private var entryCustomDataKey: String? = null
private var entryCustomDataValue: String? = null
@Throws(IOException::class, InvalidDBException::class)
@Throws(IOException::class, LoadDatabaseException::class)
override fun openDatabase(databaseInputStream: InputStream,
password: String?,
keyInputStream: InputStream?,
@@ -138,14 +138,14 @@ class ImporterV4(private val streamDir: File) : Importer<PwDatabaseV4>() {
try {
storedStartBytes = dataDecrypted.readBytes(32)
if (storedStartBytes == null || storedStartBytes.size != 32) {
throw InvalidPasswordException()
throw LoadDatabaseInvalidPasswordException()
}
} catch (e: IOException) {
throw InvalidPasswordException()
throw LoadDatabaseInvalidPasswordException()
}
if (!Arrays.equals(storedStartBytes, header.streamStartBytes)) {
throw InvalidPasswordException()
throw LoadDatabaseInvalidPasswordException()
}
isPlain = HashedBlockInputStream(dataDecrypted)
@@ -153,18 +153,18 @@ class ImporterV4(private val streamDir: File) : Importer<PwDatabaseV4>() {
val isData = LEDataInputStream(databaseInputStream)
val storedHash = isData.readBytes(32)
if (!Arrays.equals(storedHash, hashOfHeader)) {
throw InvalidDBException()
throw LoadDatabaseException()
}
val hmacKey = mDatabase.hmacKey ?: throw InvalidDBException()
val hmacKey = mDatabase.hmacKey ?: throw LoadDatabaseException()
val headerHmac = PwDbHeaderV4.computeHeaderHmac(pbHeader, hmacKey)
val storedHmac = isData.readBytes(32)
if (storedHmac == null || storedHmac.size != 32) {
throw InvalidDBException()
throw LoadDatabaseException()
}
// Mac doesn't match
if (!Arrays.equals(headerHmac, storedHmac)) {
throw InvalidDBException()
throw LoadDatabaseException()
}
val hmIs = HmacBlockInputStream(isData, true, hmacKey)
@@ -185,7 +185,7 @@ class ImporterV4(private val streamDir: File) : Importer<PwDatabaseV4>() {
randomStream = StreamCipherFactory.getInstance(header.innerRandomStream, header.innerRandomStreamKey)
if (randomStream == null) {
throw ArcFourException()
throw LoadDatabaseArcFourException()
}
readXmlStreamed(isXml)
@@ -270,7 +270,7 @@ class ImporterV4(private val streamDir: File) : Importer<PwDatabaseV4>() {
Binaries
}
@Throws(IOException::class, InvalidDBException::class)
@Throws(IOException::class, LoadDatabaseException::class)
private fun readXmlStreamed(readerStream: InputStream) {
try {
readDocumentStreamed(createPullParser(readerStream))
@@ -281,7 +281,7 @@ class ImporterV4(private val streamDir: File) : Importer<PwDatabaseV4>() {
}
@Throws(XmlPullParserException::class, IOException::class, InvalidDBException::class)
@Throws(XmlPullParserException::class, IOException::class, LoadDatabaseException::class)
private fun readDocumentStreamed(xpp: XmlPullParser) {
ctxGroups.clear()
@@ -312,7 +312,7 @@ class ImporterV4(private val streamDir: File) : Importer<PwDatabaseV4>() {
if (ctxGroups.size != 0) throw IOException("Malformed")
}
@Throws(XmlPullParserException::class, IOException::class, InvalidDBException::class)
@Throws(XmlPullParserException::class, IOException::class, LoadDatabaseException::class)
private fun readXmlElement(ctx: KdbContext, xpp: XmlPullParser): KdbContext {
val name = xpp.name
when (ctx) {
@@ -336,7 +336,7 @@ class ImporterV4(private val streamDir: File) : Importer<PwDatabaseV4>() {
if (encodedHash.isNotEmpty() && hashOfHeader != null) {
val hash = Base64Coder.decode(encodedHash)
if (!Arrays.equals(hash, hashOfHeader)) {
throw InvalidDBException()
throw LoadDatabaseException()
}
}
} else if (name.equals(PwDatabaseV4XML.ElemSettingsChanged, ignoreCase = true)) {

View File

@@ -24,7 +24,7 @@ import com.kunzisoft.keepass.crypto.keyDerivation.KdfParameters
import com.kunzisoft.keepass.database.element.PwDatabaseV4
import com.kunzisoft.keepass.database.file.PwDbHeader
import com.kunzisoft.keepass.database.file.PwDbHeaderV4
import com.kunzisoft.keepass.database.exception.PwDbOutputException
import com.kunzisoft.keepass.database.exception.DatabaseOutputException
import com.kunzisoft.keepass.stream.HmacBlockStream
import com.kunzisoft.keepass.stream.LEDataOutputStream
import com.kunzisoft.keepass.stream.MacOutputStream
@@ -41,7 +41,7 @@ import java.security.NoSuchAlgorithmException
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
class PwDbHeaderOutputV4 @Throws(PwDbOutputException::class)
class PwDbHeaderOutputV4 @Throws(DatabaseOutputException::class)
constructor(private val db: PwDatabaseV4, private val header: PwDbHeaderV4, os: OutputStream) : PwDbHeaderOutput() {
private val los: LEDataOutputStream
private val mos: MacOutputStream
@@ -54,13 +54,13 @@ constructor(private val db: PwDatabaseV4, private val header: PwDbHeaderV4, os:
try {
md = MessageDigest.getInstance("SHA-256")
} catch (e: NoSuchAlgorithmException) {
throw PwDbOutputException("SHA-256 not implemented here.")
throw DatabaseOutputException("SHA-256 not implemented here.")
}
try {
db.makeFinalKey(header.masterSeed)
} catch (e: IOException) {
throw PwDbOutputException(e)
throw DatabaseOutputException(e)
}
val hmac: Mac
@@ -69,9 +69,9 @@ constructor(private val db: PwDatabaseV4, private val header: PwDbHeaderV4, os:
val signingKey = SecretKeySpec(HmacBlockStream.GetHmacKey64(db.hmacKey, Types.ULONG_MAX_VALUE), "HmacSHA256")
hmac.init(signingKey)
} catch (e: NoSuchAlgorithmException) {
throw PwDbOutputException(e)
throw DatabaseOutputException(e)
} catch (e: InvalidKeyException) {
throw PwDbOutputException(e)
throw DatabaseOutputException(e)
}
dos = DigestOutputStream(os, md)

View File

@@ -20,7 +20,7 @@
package com.kunzisoft.keepass.database.file.save
import com.kunzisoft.keepass.database.file.PwDbHeader
import com.kunzisoft.keepass.database.exception.PwDbOutputException
import com.kunzisoft.keepass.database.exception.DatabaseOutputException
import java.io.OutputStream
import java.security.NoSuchAlgorithmException
@@ -28,13 +28,13 @@ import java.security.SecureRandom
abstract class PwDbOutput<Header : PwDbHeader> protected constructor(protected var mOS: OutputStream) {
@Throws(PwDbOutputException::class)
@Throws(DatabaseOutputException::class)
protected open fun setIVs(header: Header): SecureRandom {
val random: SecureRandom
try {
random = SecureRandom.getInstance("SHA1PRNG")
} catch (e: NoSuchAlgorithmException) {
throw PwDbOutputException("Does not support secure random number generation.")
throw DatabaseOutputException("Does not support secure random number generation.")
}
random.nextBytes(header.encryptionIV)
@@ -43,10 +43,10 @@ abstract class PwDbOutput<Header : PwDbHeader> protected constructor(protected v
return random
}
@Throws(PwDbOutputException::class)
@Throws(DatabaseOutputException::class)
abstract fun output()
@Throws(PwDbOutputException::class)
@Throws(DatabaseOutputException::class)
abstract fun outputHeader(outputStream: OutputStream): Header
}

View File

@@ -21,7 +21,7 @@ package com.kunzisoft.keepass.database.file.save
import com.kunzisoft.keepass.crypto.CipherFactory
import com.kunzisoft.keepass.database.element.*
import com.kunzisoft.keepass.database.exception.PwDbOutputException
import com.kunzisoft.keepass.database.exception.DatabaseOutputException
import com.kunzisoft.keepass.database.file.PwDbHeader
import com.kunzisoft.keepass.database.file.PwDbHeaderV3
import com.kunzisoft.keepass.stream.LEDataOutputStream
@@ -42,18 +42,18 @@ class PwDbV3Output(private val mDatabaseV3: PwDatabaseV3, os: OutputStream) : Pw
private var headerHashBlock: ByteArray? = null
@Throws(PwDbOutputException::class)
@Throws(DatabaseOutputException::class)
fun getFinalKey(header: PwDbHeader): ByteArray? {
try {
val h3 = header as PwDbHeaderV3
mDatabaseV3.makeFinalKey(h3.masterSeed, h3.transformSeed, mDatabaseV3.numberKeyEncryptionRounds)
return mDatabaseV3.finalKey
} catch (e: IOException) {
throw PwDbOutputException("Key creation failed.", e)
throw DatabaseOutputException("Key creation failed.", e)
}
}
@Throws(PwDbOutputException::class)
@Throws(DatabaseOutputException::class)
override fun output() {
// Before we output the header, we should sort our list of groups
// and remove any orphaned nodes that are no longer part of the tree hierarchy
@@ -74,7 +74,7 @@ class PwDbV3Output(private val mDatabaseV3: PwDatabaseV3, os: OutputStream) : Pw
throw Exception()
}
} catch (e: Exception) {
throw PwDbOutputException("Algorithm not supported.", e)
throw DatabaseOutputException("Algorithm not supported.", e)
}
try {
@@ -86,23 +86,23 @@ class PwDbV3Output(private val mDatabaseV3: PwDatabaseV3, os: OutputStream) : Pw
bos.close()
} catch (e: InvalidKeyException) {
throw PwDbOutputException("Invalid key", e)
throw DatabaseOutputException("Invalid key", e)
} catch (e: InvalidAlgorithmParameterException) {
throw PwDbOutputException("Invalid algorithm parameter.", e)
throw DatabaseOutputException("Invalid algorithm parameter.", e)
} catch (e: IOException) {
throw PwDbOutputException("Failed to output final encrypted part.", e)
throw DatabaseOutputException("Failed to output final encrypted part.", e)
}
}
@Throws(PwDbOutputException::class)
@Throws(DatabaseOutputException::class)
override fun setIVs(header: PwDbHeaderV3): SecureRandom {
val random = super.setIVs(header)
random.nextBytes(header.transformSeed)
return random
}
@Throws(PwDbOutputException::class)
@Throws(DatabaseOutputException::class)
override fun outputHeader(outputStream: OutputStream): PwDbHeaderV3 {
// Build header
val header = PwDbHeaderV3()
@@ -115,7 +115,7 @@ class PwDbV3Output(private val mDatabaseV3: PwDatabaseV3, os: OutputStream) : Pw
} else if (mDatabaseV3.encryptionAlgorithm === PwEncryptionAlgorithm.Twofish) {
header.flags = header.flags or PwDbHeaderV3.FLAG_TWOFISH
} else {
throw PwDbOutputException("Unsupported algorithm.")
throw DatabaseOutputException("Unsupported algorithm.")
}
header.version = PwDbHeaderV3.DBVER_DW
@@ -130,7 +130,7 @@ class PwDbV3Output(private val mDatabaseV3: PwDatabaseV3, os: OutputStream) : Pw
try {
messageDigest = MessageDigest.getInstance("SHA-256")
} catch (e: NoSuchAlgorithmException) {
throw PwDbOutputException("SHA-256 not implemented here.", e)
throw DatabaseOutputException("SHA-256 not implemented here.", e)
}
// Header checksum
@@ -138,7 +138,7 @@ class PwDbV3Output(private val mDatabaseV3: PwDatabaseV3, os: OutputStream) : Pw
try {
headerDigest = MessageDigest.getInstance("SHA-256")
} catch (e: NoSuchAlgorithmException) {
throw PwDbOutputException("SHA-256 not implemented here.", e)
throw DatabaseOutputException("SHA-256 not implemented here.", e)
}
var nos = NullOutputStream()
@@ -151,7 +151,7 @@ class PwDbV3Output(private val mDatabaseV3: PwDatabaseV3, os: OutputStream) : Pw
pho.outputEnd()
headerDos.flush()
} catch (e: IOException) {
throw PwDbOutputException(e)
throw DatabaseOutputException(e)
}
val headerHash = headerDigest.digest()
@@ -166,7 +166,7 @@ class PwDbV3Output(private val mDatabaseV3: PwDatabaseV3, os: OutputStream) : Pw
bos.flush()
bos.close()
} catch (e: IOException) {
throw PwDbOutputException("Failed to generate checksum.", e)
throw DatabaseOutputException("Failed to generate checksum.", e)
}
header.contentsHash = messageDigest!!.digest()
@@ -181,14 +181,14 @@ class PwDbV3Output(private val mDatabaseV3: PwDatabaseV3, os: OutputStream) : Pw
pho.outputEnd()
dos.flush()
} catch (e: IOException) {
throw PwDbOutputException(e)
throw DatabaseOutputException(e)
}
return header
}
@Suppress("CAST_NEVER_SUCCEEDS")
@Throws(PwDbOutputException::class)
@Throws(DatabaseOutputException::class)
fun outputPlanGroupAndEntries(os: OutputStream) {
val los = LEDataOutputStream(os)
@@ -199,7 +199,7 @@ class PwDbV3Output(private val mDatabaseV3: PwDatabaseV3, os: OutputStream) : Pw
los.writeInt(headerHashBlock!!.size)
los.write(headerHashBlock!!)
} catch (e: IOException) {
throw PwDbOutputException("Failed to output header hash.", e)
throw DatabaseOutputException("Failed to output header hash.", e)
}
}
@@ -209,7 +209,7 @@ class PwDbV3Output(private val mDatabaseV3: PwDatabaseV3, os: OutputStream) : Pw
try {
pgo.output()
} catch (e: IOException) {
throw PwDbOutputException("Failed to output a tree", e)
throw DatabaseOutputException("Failed to output a tree", e)
}
}
mDatabaseV3.doForEachEntryInIndex { entry ->
@@ -217,7 +217,7 @@ class PwDbV3Output(private val mDatabaseV3: PwDatabaseV3, os: OutputStream) : Pw
try {
peo.output()
} catch (e: IOException) {
throw PwDbOutputException("Failed to output an entry.", e)
throw DatabaseOutputException("Failed to output an entry.", e)
}
}
}

View File

@@ -29,7 +29,7 @@ import com.kunzisoft.keepass.crypto.engine.CipherEngine
import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory
import com.kunzisoft.keepass.database.*
import com.kunzisoft.keepass.database.element.*
import com.kunzisoft.keepass.database.exception.PwDbOutputException
import com.kunzisoft.keepass.database.exception.DatabaseOutputException
import com.kunzisoft.keepass.database.exception.UnknownKDF
import com.kunzisoft.keepass.database.element.PwCompressionAlgorithm
import com.kunzisoft.keepass.database.file.PwDbHeaderV4
@@ -63,14 +63,14 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
private var headerHmac: ByteArray? = null
private var engine: CipherEngine? = null
@Throws(PwDbOutputException::class)
@Throws(DatabaseOutputException::class)
override fun output() {
try {
try {
engine = CipherFactory.getInstance(mDatabaseV4.dataCipher)
} catch (e: NoSuchAlgorithmException) {
throw PwDbOutputException("No such cipher", e)
throw DatabaseOutputException("No such cipher", e)
}
header = outputHeader(mOS)
@@ -104,13 +104,13 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
outputDatabase(osXml)
osXml.close()
} catch (e: IllegalArgumentException) {
throw PwDbOutputException(e)
throw DatabaseOutputException(e)
} catch (e: IllegalStateException) {
throw PwDbOutputException(e)
throw DatabaseOutputException(e)
}
} catch (e: IOException) {
throw PwDbOutputException(e)
throw DatabaseOutputException(e)
}
}
@@ -228,7 +228,7 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
xml.endTag(null, PwDatabaseV4XML.ElemMeta)
}
@Throws(PwDbOutputException::class)
@Throws(DatabaseOutputException::class)
private fun attachStreamEncryptor(header: PwDbHeaderV4, os: OutputStream): CipherOutputStream {
val cipher: Cipher
try {
@@ -236,13 +236,13 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
cipher = engine!!.getCipher(Cipher.ENCRYPT_MODE, mDatabaseV4.finalKey!!, header.encryptionIV)
} catch (e: Exception) {
throw PwDbOutputException("Invalid algorithm.", e)
throw DatabaseOutputException("Invalid algorithm.", e)
}
return CipherOutputStream(os, cipher)
}
@Throws(PwDbOutputException::class)
@Throws(DatabaseOutputException::class)
override fun setIVs(header: PwDbHeaderV4): SecureRandom {
val random = super.setIVs(header)
random.nextBytes(header.masterSeed)
@@ -275,7 +275,7 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
randomStream = StreamCipherFactory.getInstance(header.innerRandomStream, header.innerRandomStreamKey)
if (randomStream == null) {
throw PwDbOutputException("Invalid random cipher")
throw DatabaseOutputException("Invalid random cipher")
}
if (header.version < PwDbHeaderV4.FILE_VERSION_32_4) {
@@ -285,7 +285,7 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
return random
}
@Throws(PwDbOutputException::class)
@Throws(DatabaseOutputException::class)
override fun outputHeader(outputStream: OutputStream): PwDbHeaderV4 {
val header = PwDbHeaderV4(mDatabaseV4)
@@ -295,7 +295,7 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
try {
pho.output()
} catch (e: IOException) {
throw PwDbOutputException("Failed to output the header.", e)
throw DatabaseOutputException("Failed to output the header.", e)
}
hashOfHeader = pho.hashOfHeader

View File

@@ -33,6 +33,12 @@ object PreferencesUtil {
return prefs.getBoolean(context.getString(R.string.show_read_only_warning), true)
}
fun rememberKeyFiles(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.keyfile_key),
context.resources.getBoolean(R.bool.keyfile_default))
}
fun omitBackup(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
return prefs.getBoolean(context.getString(R.string.omitbackup_key),

View File

@@ -24,6 +24,7 @@ import android.content.Context
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import com.kunzisoft.keepass.database.exception.LoadDatabaseException
/**
* Callback after a task is completed.
@@ -52,8 +53,21 @@ abstract class ActionRunnable(private var nestedActionRunnable: ActionRunnable?
* launch the nested action runnable if exists and finish,
* else directly finish
*/
protected fun finishRun(isSuccess: Boolean, message: String? = null) {
protected fun finishRun(isSuccess: Boolean,
message: String? = null) {
finishRun(isSuccess, null, message)
}
/**
* If [success] or [executeNestedActionIfResultFalse] true,
* launch the nested action runnable if exists and finish,
* else directly finish
*/
protected fun finishRun(isSuccess: Boolean,
exception: LoadDatabaseException?,
message: String? = null) {
result.isSuccess = isSuccess
result.exception = exception
result.message = message
if (isSuccess || executeNestedActionIfResultFalse) {
execute()
@@ -89,5 +103,8 @@ abstract class ActionRunnable(private var nestedActionRunnable: ActionRunnable?
/**
* Class to manage result from ActionRunnable
*/
data class Result(var isSuccess: Boolean = true, var message: String? = null, var data: Bundle? = null)
data class Result(var isSuccess: Boolean = true,
var message: String? = null,
var exception: LoadDatabaseException? = null,
var data: Bundle? = null)
}

View File

@@ -54,7 +54,6 @@
<string name="error_title_required">اكتب عنوانًا.</string>
<string name="field_name">اسم الحقل</string>
<string name="field_value">قيمة الحقل</string>
<string name="file_not_found">تعذر إيجاد الملف.</string>
<string name="generate_password">توليد كلمة سر</string>
<string name="hint_conf_pass">تأكيد كلمة السر</string>
<string name="hint_group_name">اسم المجموعة</string>

View File

@@ -72,7 +72,6 @@
<string name="error_rounds_too_large">Massa passades. Establint a 2147483648.</string>
<string name="error_title_required">És necessari un títol.</string>
<string name="error_wrong_length">Insereix un enter positiu al camp longitud</string>
<string name="file_not_found">Arxiu no trobat.</string>
<string name="file_browser">Explorador d\'arxius</string>
<string name="generate_password">Generar contrasenya</string>
<string name="hint_conf_pass">confirma contrasenya</string>

View File

@@ -79,7 +79,6 @@
<string name="error_wrong_length">Do nastavení „Délka“ zadejte celé kladné číslo.</string>
<string name="field_name">Název pole</string>
<string name="field_value">Hodnota pole</string>
<string name="file_not_found">Soubor nenalezen.</string>
<string name="file_browser">Správce souborů</string>
<string name="generate_password">Vytvoř heslo</string>
<string name="hint_conf_pass">potvrď heslo</string>

View File

@@ -78,7 +78,6 @@
<string name="error_wrong_length">Angiv et positivt heltal i feltet \"Længde\".</string>
<string name="field_name">Feltnavn</string>
<string name="field_value">Feltværdi</string>
<string name="file_not_found">Kunne ikke finde filen.</string>
<string name="file_browser">Filhåndtering</string>
<string name="generate_password">Generer adgangskode</string>
<string name="hint_conf_pass">bekræft adgangskode</string>

View File

@@ -81,7 +81,6 @@
<string name="error_wrong_length">Eine positive ganze Zahl in das Feld „Länge“ eingeben.</string>
<string name="field_name">Feldname</string>
<string name="field_value">Feldwert</string>
<string name="file_not_found">Datei nicht gefunden.</string>
<string name="file_not_found_content">Datei nicht gefunden. Bitte versuchen, sie über den Dateimanager zu öffnen.</string>
<string name="file_browser">Dateimanager</string>
<string name="generate_password">Passwort generieren</string>

View File

@@ -77,7 +77,6 @@
<string name="error_wrong_length">Εισάγετε έναν θετικό ακέραιο αριθμό στο πεδίο μήκους</string>
<string name="field_name">Όνομα Πεδίου</string>
<string name="field_value">Τιμή πεδίου</string>
<string name="file_not_found">Το αρχείο δεν βρέθηκε.</string>
<string name="file_browser">Διαχείριση Αρχείων</string>
<string name="generate_password">Δημιουργία Κωδικού</string>
<string name="hint_conf_pass">επιβεβαίωση κωδικού</string>

View File

@@ -71,7 +71,6 @@
<string name="error_rounds_too_large">Pasadas demasiado grande. Establecido a 2147483648.</string>
<string name="error_title_required">Se necesita un título.</string>
<string name="error_wrong_length">Introduzca un entero positivo en el campo longitud</string>
<string name="file_not_found">Archivo no encontrado.</string>
<string name="file_browser">Explorador de Archivos</string>
<string name="generate_password">Generar Contraseña</string>
<string name="hint_conf_pass">confirmar contraseña</string>

View File

@@ -78,7 +78,6 @@
<string name="error_wrong_length">Eremuaren luzeran entero positibo bat sartu</string>
<string name="field_name">Eremuaren izena</string>
<string name="field_value">Eremuaren balorea</string>
<string name="file_not_found">Fitxategi ez aurkitua.</string>
<string name="file_browser">Fitxategien nabigatzailea</string>
<string name="generate_password">Pasahitza sortu</string>
<string name="hint_conf_pass">pasahitza berretsi</string>

View File

@@ -77,7 +77,6 @@
<string name="error_wrong_length">Syötä positiivinen kokonaisluku pituus-kenttään</string>
<string name="field_name">Kentän nimi</string>
<string name="field_value">Kentän arvo</string>
<string name="file_not_found">Tiedostoa ei löydetty.</string>
<string name="file_browser">Tiedostoselain</string>
<string name="generate_password">Generoi salasana</string>
<string name="hint_conf_pass">vahvista salasana</string>

View File

@@ -83,7 +83,6 @@
<string name="error_autofill_enable_service">Impossible dactiver le service de remplissage automatique.</string>
<string name="field_name">Nom du champ</string>
<string name="field_value">Valeur du champ</string>
<string name="file_not_found">Impossible de trouver le fichier.</string>
<string name="file_not_found_content">Impossible de trouver le fichier. Essayer de le rouvrir depuis votre gestionnaire de fichiers.</string>
<string name="file_browser">Gestionnaire de fichiers</string>
<string name="generate_password">Générer un mot de passe</string>

View File

@@ -76,7 +76,6 @@
<string name="error_wrong_length">Írjon be egy pozitív egész számot a „Hossz” mezőbe.</string>
<string name="field_name">Mezőnév</string>
<string name="field_value">Mezőérték</string>
<string name="file_not_found">A fájl nem található.</string>
<string name="file_not_found_content">A fájl nem található. Próbálja meg újra megnyitni a fájlkezelőben.</string>
<string name="file_browser">Fájlkezelő</string>
<string name="generate_password">Jelszó előállítása</string>

View File

@@ -77,7 +77,6 @@
<string name="error_wrong_length">Inserisci un numero naturale positivo nel campo \"lunghezza\".</string>
<string name="field_name">Nome campo</string>
<string name="field_value">Valore campo</string>
<string name="file_not_found">File non trovato.</string>
<string name="file_not_found_content">File non trovato. Prova a riaprirlo dal tuo gestore di file.</string>
<string name="file_browser">Gestore file</string>
<string name="generate_password">Genera password</string>

View File

@@ -74,7 +74,6 @@
<string name="error_wrong_length">הזן מספר חיובי בשדה האורך</string>
<string name="field_name">שם השדה</string>
<string name="field_value">ערך השדה</string>
<string name="file_not_found">קובץ לא נמצא.</string>
<string name="file_browser">סייר קבצים</string>
<string name="generate_password">צור סיסמה</string>
<string name="hint_conf_pass">אשר סיסמה</string>

View File

@@ -68,7 +68,6 @@
<string name="error_rounds_too_large">値が大きすぎます。 2147483648にセットしました。</string>
<string name="error_title_required">タイトルは必須入力です。</string>
<string name="error_wrong_length">\"長さ\"欄には正の整数を入力してください。</string>
<string name="file_not_found">ファイルが見つかりません。</string>
<string name="file_browser">ファイルブラウザ</string>
<string name="generate_password">パスワードを生成する</string>
<string name="hint_conf_pass">パスワードをもう一度入力</string>

View File

@@ -85,7 +85,6 @@
<string name="error_move_folder_in_itself">그룹을 자신에게 옮길 수 없습니다.</string>
<string name="field_name">필드 이름</string>
<string name="field_value">필드 값</string>
<string name="file_not_found">파일을 찾을 수 없습니다.</string>
<string name="file_not_found_content">파일을 찾을 수 없습니다. 파일 탐색기에서 열리는지 확인해 주세요.</string>
<string name="file_browser">파일 탐색기</string>
<string name="generate_password">비밀번호 생성</string>

View File

@@ -2,7 +2,6 @@
<resources>
<string name="about_description">KeePass DX yra KeePass slaptažodžių tvarkyklės realizacija Android platformai</string>
<string name="clipboard_cleared">Iškarpinė išvalyta.</string>
<string name="file_not_found">Failas nerastas.</string>
<string name="invalid_password">Neteisingas slaptažodis arba rakto failas.</string>
<string name="about_feedback">Atsiliepimai:</string>
<string name="about_homepage">Pagrindinis puslapis:</string>

View File

@@ -57,7 +57,6 @@
<string name="error_wrong_length">Norādiet garumu lielāku par nulli</string>
<string name="field_name">Lauka nosaukums</string>
<string name="field_value">Lauka vērtība</string>
<string name="file_not_found">Fails nav atrasts.</string>
<string name="file_browser">Failu pārlūks</string>
<string name="generate_password">Ģenerēt Paroli</string>
<string name="hint_conf_pass">apstipriniet paroli</string>

View File

@@ -85,7 +85,6 @@
<string name="error_move_folder_in_itself">Kan ikke flytte gruppe inn i seg selv.</string>
<string name="field_name">Feltnavn</string>
<string name="field_value">Feltverdi</string>
<string name="file_not_found">Fant ikke filen.</string>
<string name="file_not_found_content">Fant ikke filen. Prøv å åpne den fra din innholdsleverandør.</string>
<string name="file_browser">Filutforsker</string>
<string name="generate_password">Opprett passord</string>

View File

@@ -71,7 +71,6 @@
<string name="error_rounds_too_large">\"Cycli-waarde\" te groot. Wordt ingesteld op 2147483648.</string>
<string name="error_title_required">Voeg een titel toe.</string>
<string name="error_wrong_length">Voer een positief geheel getal in in het veld \"Lengte\".</string>
<string name="file_not_found">Bestand niet gevonden.</string>
<string name="file_browser">Bestandsverkenner</string>
<string name="generate_password">Wachtwoord genereren</string>
<string name="hint_conf_pass">wachtwoord bevestigen</string>

View File

@@ -69,7 +69,6 @@
<string name="error_rounds_too_large">For mange omgangar. Bruker 2147483648.</string>
<string name="error_title_required">Treng ein tittel.</string>
<string name="error_wrong_length">Bruk eit positivt heiltal i lengdfeltet</string>
<string name="file_not_found">Fann ikkje fila.</string>
<string name="file_browser">Filbehandlar</string>
<string name="generate_password">Lag passord</string>
<string name="hint_conf_pass">stadfest passordet</string>

View File

@@ -68,7 +68,6 @@
<string name="error_rounds_too_large">\"Rundy szyfrowania\" są zbyt wysokie. Ustaw na 2147483648.</string>
<string name="error_title_required">Dodaj tytuł.</string>
<string name="error_wrong_length">Wprowadź dodatnią liczbę całkowitą w polu \"Długość\".</string>
<string name="file_not_found">Nie znaleziono pliku.</string>
<string name="file_browser">Przeglądarka plików</string>
<string name="generate_password">Generuj hasło</string>
<string name="hint_conf_pass">potwierdź hasło</string>

View File

@@ -71,7 +71,6 @@
<string name="error_rounds_too_large">\"Número de rodadas\" é muito grande. Modificado para 2147483648.</string>
<string name="error_title_required">Insira um título.</string>
<string name="error_wrong_length">Digite um número inteiro positivo no campo \"Tamanho\".</string>
<string name="file_not_found">Não pôde encontrar o arquivo.</string>
<string name="file_browser">Localizador de arquivos</string>
<string name="generate_password">Gerar senha</string>
<string name="hint_conf_pass">confirmar senha</string>

View File

@@ -77,7 +77,6 @@
<string name="error_wrong_length">Digite um número inteiro positivo no campo \"Tamanho\".</string>
<string name="field_name">Nome do campo</string>
<string name="field_value">Valor do campo</string>
<string name="file_not_found">Não pôde encontrar o ficheiro.</string>
<string name="file_not_found_content">Arquivo não encontrado. Tente reabrí-lo de seu provedor de conteúdo.</string>
<string name="file_browser">Localizador de ficheiros</string>
<string name="generate_password">Gerar palavra-chave</string>

View File

@@ -77,7 +77,6 @@
<string name="error_wrong_length">Поле \"Длина\" должно быть положительным целым числом.</string>
<string name="field_name">Название поля</string>
<string name="field_value">Значение поля</string>
<string name="file_not_found">Файл не найден.</string>
<string name="file_not_found_content">Файл не найден. Попробуйте повторно открыть через встроенный поставщик содержимого.</string>
<string name="file_browser">Обзор файлов</string>
<string name="generate_password">Генерация пароля</string>

View File

@@ -68,7 +68,6 @@
<string name="error_rounds_too_large">Príliš veľa opakovaní. Nastavujem na 2147483648.</string>
<string name="error_title_required">Vyžaduje sa názov.</string>
<string name="error_wrong_length">Zadajte celé kladné číslo na dĺžku poľa</string>
<string name="file_not_found">Súbor nenájdený.</string>
<string name="file_browser">Správca Súborov</string>
<string name="generate_password">Generovať Heslo</string>
<string name="hint_conf_pass">potvrdiť heslo</string>

View File

@@ -77,7 +77,6 @@
<string name="error_wrong_length">Ange ett positivt heltal i fältet för längd</string>
<string name="field_name">Fältnamn</string>
<string name="field_value">Fältvärde</string>
<string name="file_not_found">Filen hittades inte.</string>
<string name="file_browser">Filhanterare</string>
<string name="generate_password">Generera lösenord</string>
<string name="hint_conf_pass">bekräfta lösenord</string>

View File

@@ -85,7 +85,6 @@
<string name="error_move_folder_in_itself">Bir grubu kendine taşıyamazsın.</string>
<string name="field_name">Alan adı</string>
<string name="field_value">Alan değeri</string>
<string name="file_not_found">Dosya bulunamadı.</string>
<string name="file_not_found_content">Dosya bulunamadı. Dosya tarayıcınızda yeniden açmayı deneyin.</string>
<string name="file_browser">Dosya tarayıcı</string>
<string name="generate_password">Parola üret</string>

View File

@@ -69,7 +69,6 @@
<string name="error_rounds_too_large">Надто багато циклів. Установлено 2147483648.</string>
<string name="error_title_required">Необхідно вказати заголовок.</string>
<string name="error_wrong_length">Введіть ціле число на усю довжину поля</string>
<string name="file_not_found">Файл не знайдено.</string>
<string name="file_browser">Перегляд файлів</string>
<string name="generate_password">Згенерувати пароль</string>
<string name="hint_conf_pass">підтвердження пароля</string>

View File

@@ -69,7 +69,6 @@
<string name="error_rounds_too_large">“变换次数”过多。已设置为 2147483648。</string>
<string name="error_title_required">请添加标题。</string>
<string name="error_wrong_length">请在“长度”字段输入一个正整数。</string>
<string name="file_not_found">找不到文件。</string>
<string name="file_browser">文件浏览器</string>
<string name="generate_password">生成密码</string>
<string name="hint_conf_pass">确认密码</string>

View File

@@ -68,7 +68,6 @@
<string name="error_rounds_too_large">次數太多。最大設置到2147483648。</string>
<string name="error_title_required">標題為必填。</string>
<string name="error_wrong_length">長度欄位輸入一個正整數</string>
<string name="file_not_found">文件未找到。</string>
<string name="file_browser">檔案管理器</string>
<string name="generate_password">生成密碼</string>
<string name="hint_conf_pass">確認密碼</string>

View File

@@ -113,7 +113,6 @@
<string name="error_create_database_file">Unable to create database with this password and key file.</string>
<string name="field_name">Field name</string>
<string name="field_value">Field value</string>
<string name="file_not_found">Could not find file.</string>
<string name="file_not_found_content">Could not find file. Try reopening it from your file browser.</string>
<string name="file_browser">File browser</string>
<string name="generate_password">Generate password</string>