Merge tag '2.5.0.0beta24' into develop

2.5.0.0beta24
This commit is contained in:
J-Jamet
2019-11-12 12:35:28 +01:00
10 changed files with 68 additions and 52 deletions

View File

@@ -55,7 +55,7 @@ You can contribute in different ways to help us on our work.
## F.A.Q. ## F.A.Q.
Other questions? You can read the [F.A.Q.](https://www.keepassdx.com/FAQ) Other questions? You can read the [F.A.Q.](https://github.com/Kunzisoft/KeePassDX/wiki/F.A.Q.)
## Other devices ## Other devices

1
_config.yml Normal file
View File

@@ -0,0 +1 @@
theme: jekyll-theme-cayman

View File

@@ -163,7 +163,7 @@ class FileDatabaseSelectActivity : StylishActivity(),
} }
// Attach the dialog thread to this activity // Attach the dialog thread to this activity
progressDialogThread = ProgressDialogThread(this) { actionTask, result -> progressDialogThread = ProgressDialogThread(this) { actionTask, _ ->
when (actionTask) { when (actionTask) {
ACTION_DATABASE_CREATE_TASK -> { ACTION_DATABASE_CREATE_TASK -> {
// TODO Check // TODO Check

View File

@@ -55,7 +55,11 @@ class SetOTPDialogFragment : DialogFragment() {
private var otpAlgorithmAdapter: ArrayAdapter<TokenCalculator.HashAlgorithm>? = null private var otpAlgorithmAdapter: ArrayAdapter<TokenCalculator.HashAlgorithm>? = null
private var mManualEvent = false private var mManualEvent = false
private var touchListener = View.OnTouchListener { _, event -> private var mOnFocusChangeListener = View.OnFocusChangeListener { _, isFocus ->
if (!isFocus)
mManualEvent = true
}
private var mOnTouchListener = View.OnTouchListener { _, event ->
when (event.action) { when (event.action) {
MotionEvent.ACTION_DOWN -> { MotionEvent.ACTION_DOWN -> {
mManualEvent = true mManualEvent = true
@@ -117,13 +121,17 @@ class SetOTPDialogFragment : DialogFragment() {
otpDigitsTextView = root?.findViewById(R.id.setup_otp_digits) otpDigitsTextView = root?.findViewById(R.id.setup_otp_digits)
// To fix init element // To fix init element
otpTypeSpinner?.setOnTouchListener(touchListener) // With tab keyboard selection
otpTokenTypeSpinner?.setOnTouchListener(touchListener) otpSecretTextView?.onFocusChangeListener = mOnFocusChangeListener
otpAlgorithmSpinner?.setOnTouchListener(touchListener) // With finger selection
otpSecretTextView?.setOnTouchListener(touchListener) otpTypeSpinner?.setOnTouchListener(mOnTouchListener)
otpPeriodTextView?.setOnTouchListener(touchListener) otpTokenTypeSpinner?.setOnTouchListener(mOnTouchListener)
otpCounterTextView?.setOnTouchListener(touchListener) otpSecretTextView?.setOnTouchListener(mOnTouchListener)
otpDigitsTextView?.setOnTouchListener(touchListener) otpAlgorithmSpinner?.setOnTouchListener(mOnTouchListener)
otpPeriodTextView?.setOnTouchListener(mOnTouchListener)
otpCounterTextView?.setOnTouchListener(mOnTouchListener)
otpDigitsTextView?.setOnTouchListener(mOnTouchListener)
// HOTP / TOTP Type selection // HOTP / TOTP Type selection
val otpTypeArray = OtpType.values() val otpTypeArray = OtpType.values()
@@ -178,8 +186,8 @@ class SetOTPDialogFragment : DialogFragment() {
return super.onCreateDialog(savedInstanceState) return super.onCreateDialog(savedInstanceState)
} }
override fun onStart() { override fun onResume() {
super.onStart() super.onResume()
(dialog as AlertDialog).getButton(Dialog.BUTTON_POSITIVE).setOnClickListener { (dialog as AlertDialog).getButton(Dialog.BUTTON_POSITIVE).setOnClickListener {
if (mSecretWellFormed if (mSecretWellFormed
&& mCounterWellFormed && mCounterWellFormed
@@ -236,16 +244,14 @@ class SetOTPDialogFragment : DialogFragment() {
// Set secret in OtpElement // Set secret in OtpElement
otpSecretTextView?.addTextChangedListener(object: TextWatcher { otpSecretTextView?.addTextChangedListener(object: TextWatcher {
override fun afterTextChanged(s: Editable?) { override fun afterTextChanged(s: Editable?) {
if (mManualEvent) { s?.toString()?.let { userString ->
s?.toString()?.let { userString -> try {
try { mOtpElement.setBase32Secret(userString)
mOtpElement.setBase32Secret(userString) otpSecretContainer?.error = null
otpSecretContainer?.error = null } catch (exception: Exception) {
} catch (exception: Exception) { otpSecretContainer?.error = getString(R.string.error_otp_secret_key)
otpSecretContainer?.error = getString(R.string.error_otp_secret_key)
}
mSecretWellFormed = otpSecretContainer?.error == null
} }
mSecretWellFormed = otpSecretContainer?.error == null
} }
} }
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
@@ -339,7 +345,11 @@ class SetOTPDialogFragment : DialogFragment() {
private fun upgradeParameters() { private fun upgradeParameters() {
otpAlgorithmSpinner?.setSelection(TokenCalculator.HashAlgorithm.values() otpAlgorithmSpinner?.setSelection(TokenCalculator.HashAlgorithm.values()
.indexOf(mOtpElement.algorithm)) .indexOf(mOtpElement.algorithm))
otpSecretTextView?.setText(mOtpElement.getBase32Secret()) otpSecretTextView?.apply {
setText(mOtpElement.getBase32Secret())
// Cursor at end
setSelection(this.text.length)
}
otpCounterTextView?.setText(mOtpElement.counter.toString()) otpCounterTextView?.setText(mOtpElement.counter.toString())
otpPeriodTextView?.setText(mOtpElement.period.toString()) otpPeriodTextView?.setText(mOtpElement.period.toString())
otpDigitsTextView?.setText(mOtpElement.digits.toString()) otpDigitsTextView?.setText(mOtpElement.digits.toString())

View File

@@ -75,9 +75,10 @@ class OpenFileHelper {
val intentOpenDocument = Intent(APP_ACTION_OPEN_DOCUMENT).apply { val intentOpenDocument = Intent(APP_ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE) addCategory(Intent.CATEGORY_OPENABLE)
type = "*/*" type = "*/*"
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or flags = Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_PREFIX_URI_PERMISSION or
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
} }
if (fragment != null) if (fragment != null)
fragment?.startActivityForResult(intentOpenDocument, OPEN_DOC) fragment?.startActivityForResult(intentOpenDocument, OPEN_DOC)
@@ -85,10 +86,15 @@ class OpenFileHelper {
activity?.startActivityForResult(intentOpenDocument, OPEN_DOC) activity?.startActivityForResult(intentOpenDocument, OPEN_DOC)
} }
@SuppressLint("InlinedApi")
private fun openActivityWithActionGetContent() { private fun openActivityWithActionGetContent() {
val intentGetContent = Intent(Intent.ACTION_GET_CONTENT).apply { val intentGetContent = Intent(Intent.ACTION_GET_CONTENT).apply {
addCategory(Intent.CATEGORY_OPENABLE) addCategory(Intent.CATEGORY_OPENABLE)
type = "*/*" type = "*/*"
flags = Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
Intent.FLAG_GRANT_PREFIX_URI_PERMISSION or
Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
} }
if (fragment != null) if (fragment != null)
fragment?.startActivityForResult(intentGetContent, GET_CONTENT) fragment?.startActivityForResult(intentGetContent, GET_CONTENT)

View File

@@ -62,16 +62,10 @@ class LoadDatabaseInvalidAlgorithmException : LoadDatabaseException {
class LoadDatabaseDuplicateUuidException: LoadDatabaseException { class LoadDatabaseDuplicateUuidException: LoadDatabaseException {
@StringRes @StringRes
override var errorId: Int = R.string.invalid_algorithm override var errorId: Int = R.string.invalid_db_same_uuid
constructor(type: Type, uuid: PwNodeId<*>) : super() { constructor(type: Type, uuid: PwNodeId<*>) : super() {
parameters = Array(2) { parameters = arrayOf(type.name, uuid.toString())
when(it) {
1 -> type.name
2 -> uuid.toString()
else -> {""}
}
}
} }
constructor(exception: Throwable) : super(exception) constructor(exception: Throwable) : super(exception)
} }

View File

@@ -1,7 +1,6 @@
package com.kunzisoft.keepass.otp package com.kunzisoft.keepass.otp
import com.kunzisoft.keepass.model.OtpModel import com.kunzisoft.keepass.model.OtpModel
import org.apache.commons.codec.DecoderException
import org.apache.commons.codec.binary.Base32 import org.apache.commons.codec.binary.Base32
import org.apache.commons.codec.binary.Base64 import org.apache.commons.codec.binary.Base64
import org.apache.commons.codec.binary.Hex import org.apache.commons.codec.binary.Hex
@@ -68,15 +67,17 @@ data class OtpElement(var otpModel: OtpModel = OtpModel()) {
var counter var counter
get() = otpModel.counter get() = otpModel.counter
@Throws(NumberFormatException::class)
set(value) { set(value) {
otpModel.counter = if (value < MIN_HOTP_COUNTER || value > MAX_HOTP_COUNTER) { otpModel.counter = if (value < MIN_HOTP_COUNTER || value > MAX_HOTP_COUNTER) {
TokenCalculator.HOTP_INITIAL_COUNTER TokenCalculator.HOTP_INITIAL_COUNTER
throw NumberFormatException() throw IllegalArgumentException()
} else value } else value
} }
var period var period
get() = otpModel.period get() = otpModel.period
@Throws(NumberFormatException::class)
set(value) { set(value) {
otpModel.period = if (value < MIN_TOTP_PERIOD || value > MAX_TOTP_PERIOD) { otpModel.period = if (value < MIN_TOTP_PERIOD || value > MAX_TOTP_PERIOD) {
TokenCalculator.TOTP_DEFAULT_PERIOD TokenCalculator.TOTP_DEFAULT_PERIOD
@@ -86,6 +87,7 @@ data class OtpElement(var otpModel: OtpModel = OtpModel()) {
var digits var digits
get() = otpModel.digits get() = otpModel.digits
@Throws(NumberFormatException::class)
set(value) { set(value) {
otpModel.digits = if (value < MIN_OTP_DIGITS|| value > MAX_OTP_DIGITS) { otpModel.digits = if (value < MIN_OTP_DIGITS|| value > MAX_OTP_DIGITS) {
TokenCalculator.OTP_DEFAULT_DIGITS TokenCalculator.OTP_DEFAULT_DIGITS
@@ -99,18 +101,20 @@ data class OtpElement(var otpModel: OtpModel = OtpModel()) {
otpModel.algorithm = value otpModel.algorithm = value
} }
@Throws(IllegalArgumentException::class)
fun setUTF8Secret(secret: String) { fun setUTF8Secret(secret: String) {
if (secret.isNotEmpty()) if (secret.isNotEmpty())
otpModel.secret = secret.toByteArray(Charset.forName("UTF-8")) otpModel.secret = secret.toByteArray(Charset.forName("UTF-8"))
else else
throw DecoderException() throw IllegalArgumentException()
} }
@Throws(IllegalArgumentException::class)
fun setHexSecret(secret: String) { fun setHexSecret(secret: String) {
if (secret.isNotEmpty()) if (secret.isNotEmpty())
otpModel.secret = Hex.decodeHex(secret) otpModel.secret = Hex.decodeHex(secret)
else else
throw DecoderException() throw IllegalArgumentException()
} }
fun getBase32Secret(): String { fun getBase32Secret(): String {
@@ -119,18 +123,20 @@ data class OtpElement(var otpModel: OtpModel = OtpModel()) {
} ?: "" } ?: ""
} }
@Throws(IllegalArgumentException::class)
fun setBase32Secret(secret: String) { fun setBase32Secret(secret: String) {
if (secret.isNotEmpty() && checkBase32Secret(secret)) if (secret.isNotEmpty() && checkBase32Secret(secret))
otpModel.secret = Base32().decode(secret.toByteArray()) otpModel.secret = Base32().decode(secret.toByteArray())
else else
throw DecoderException() throw IllegalArgumentException()
} }
@Throws(IllegalArgumentException::class)
fun setBase64Secret(secret: String) { fun setBase64Secret(secret: String) {
if (secret.isNotEmpty() && checkBase64Secret(secret)) if (secret.isNotEmpty() && checkBase64Secret(secret))
otpModel.secret = Base64().decode(secret.toByteArray()) otpModel.secret = Base64().decode(secret.toByteArray())
else else
throw DecoderException() throw IllegalArgumentException()
} }
val token: String val token: String

View File

@@ -158,29 +158,29 @@ object OtpEntryFields {
val digitsParam = uri.getQueryParameter(DIGITS_URL_PARAM) val digitsParam = uri.getQueryParameter(DIGITS_URL_PARAM)
if (digitsParam != null && digitsParam.isNotEmpty()) if (digitsParam != null && digitsParam.isNotEmpty())
otpElement.digits = try { try {
digitsParam.toIntOrNull() ?: OTP_DEFAULT_DIGITS otpElement.digits = digitsParam.toIntOrNull() ?: OTP_DEFAULT_DIGITS
} catch (exception: Exception) { } catch (exception: Exception) {
Log.e(TAG, "Unable to retrieve OTP digits.", exception) Log.e(TAG, "Unable to retrieve OTP digits.", exception)
OTP_DEFAULT_DIGITS otpElement.digits = OTP_DEFAULT_DIGITS
} }
val counterParam = uri.getQueryParameter(COUNTER_URL_PARAM) val counterParam = uri.getQueryParameter(COUNTER_URL_PARAM)
if (counterParam != null && counterParam.isNotEmpty()) if (counterParam != null && counterParam.isNotEmpty())
otpElement.counter = try { try {
counterParam.toLongOrNull() ?: HOTP_INITIAL_COUNTER otpElement.counter = counterParam.toLongOrNull() ?: HOTP_INITIAL_COUNTER
} catch (exception: Exception) { } catch (exception: Exception) {
Log.e(TAG, "Unable to retrieve HOTP counter.", exception) Log.e(TAG, "Unable to retrieve HOTP counter.", exception)
HOTP_INITIAL_COUNTER otpElement.counter = HOTP_INITIAL_COUNTER
} }
val stepParam = uri.getQueryParameter(PERIOD_URL_PARAM) val stepParam = uri.getQueryParameter(PERIOD_URL_PARAM)
if (stepParam != null && stepParam.isNotEmpty()) if (stepParam != null && stepParam.isNotEmpty())
otpElement.period = try { try {
stepParam.toIntOrNull() ?: TOTP_DEFAULT_PERIOD otpElement.period = stepParam.toIntOrNull() ?: TOTP_DEFAULT_PERIOD
} catch (exception: Exception) { } catch (exception: Exception) {
Log.e(TAG, "Unable to retrieve TOTP period.", exception) Log.e(TAG, "Unable to retrieve TOTP period.", exception)
TOTP_DEFAULT_PERIOD otpElement.period = TOTP_DEFAULT_PERIOD
} }
val algorithmParam = uri.getQueryParameter(ALGORITHM_URL_PARAM) val algorithmParam = uri.getQueryParameter(ALGORITHM_URL_PARAM)

View File

@@ -20,7 +20,8 @@
Translations from BoDEAN Translations from BoDEAN
Translations from Matthias Dill Translations from Matthias Dill
Translations from David Ramiro Translations from David Ramiro
--><resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> -->
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="about_feedback">Rückmeldung</string> <string name="about_feedback">Rückmeldung</string>
<string name="about_homepage">Webseite</string> <string name="about_homepage">Webseite</string>
<string name="about_description">Android-Implementierung des Passwortmanagers KeePass</string> <string name="about_description">Android-Implementierung des Passwortmanagers KeePass</string>
@@ -398,8 +399,6 @@
<string name="disable">Deaktivieren</string> <string name="disable">Deaktivieren</string>
<string name="biometric_prompt_store_credential_message">Datenbank-Anmeldeinformationen biometrisch speichern</string> <string name="biometric_prompt_store_credential_message">Datenbank-Anmeldeinformationen biometrisch speichern</string>
<string name="biometric_prompt_extract_credential_message">Datenbank-Anmeldeinformationen mit biometrischen Daten extrahieren</string> <string name="biometric_prompt_extract_credential_message">Datenbank-Anmeldeinformationen mit biometrischen Daten extrahieren</string>
<string name="fingerprint_open_biometric_prompt">Die Eingabeaufforderung für biometrische Daten mittels Klick auf den biometrischen Button öffnen</string>
<string name="biometric_auto_open_prompt_title">Biometrische Eingabeaufforderung automatisch öffnen</string> <string name="biometric_auto_open_prompt_title">Biometrische Eingabeaufforderung automatisch öffnen</string>
<string name="fingerprint_auto_open_biometric_prompt">Sie können die Einstellung ändern, um die biometrische Eingabeaufforderung schnell zu öffnen und Schritt 1 nicht wiederholen zu müssen.</string>
<string name="biometric_auto_open_prompt_summary">Biometrische Eingabeaufforderung automatisch öffnen, wenn ein biometrischer Schlüssel für eine Datenbank definiert ist</string> <string name="biometric_auto_open_prompt_summary">Biometrische Eingabeaufforderung automatisch öffnen, wenn ein biometrischer Schlüssel für eine Datenbank definiert ist</string>
</resources> </resources>

View File

@@ -10,7 +10,7 @@ buildscript {
google() google()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.5.1' classpath 'com.android.tools.build:gradle:3.5.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }