Skip to content
This repository was archived by the owner on Jan 25, 2025. It is now read-only.

Commit 569bdee

Browse files
authored
Merge pull request #55 from Keyspace-cloud/v1.4.2
v1.4.2
2 parents 87bbee4 + a855302 commit 569bdee

19 files changed

+364
-272
lines changed

app/build.gradle

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ android {
1111
applicationId "cloud.keyspace.android"
1212
minSdkVersion 27
1313
targetSdkVersion 33
14-
versionCode 141
15-
versionName "1.4.1"
14+
versionCode 142
15+
versionName "1.4.2"
1616
multiDexEnabled true
1717

1818
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -51,7 +51,7 @@ android {
5151
dependencies {
5252
implementation 'com.android.support:multidex:2.0.1' // noinspection GradleDependency
5353
implementation 'androidx.core:core-ktx:1.9.0' // Default Android stuff
54-
implementation 'androidx.appcompat:appcompat:1.5.1'
54+
implementation 'androidx.appcompat:appcompat:1.6.0'
5555
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
5656
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
5757
implementation 'androidx.gridlayout:gridlayout:1.0.0'
@@ -67,8 +67,8 @@ dependencies {
6767
implementation 'androidx.core:core-ktx:1.9.0'
6868
testImplementation 'junit:junit:4.13.2' // Testing
6969
implementation 'androidx.biometric:biometric:1.2.0-alpha05' // Biometrics
70-
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
71-
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
70+
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
71+
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
7272
implementation 'com.google.android.material:material:1.7.0' // Material design
7373
implementation 'androidx.fragment:fragment-ktx:1.5.5'
7474
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
@@ -99,4 +99,8 @@ dependencies {
9999
implementation 'com.scottyab:rootbeer-lib:0.1.0' // To check if device is rooted
100100
implementation "androidx.core:core-splashscreen:1.0.0" // Splash screen library
101101
implementation 'com.nulab-inc:zxcvbn:1.7.0' // password strength
102-
}
102+
103+
// ACRA for crash logging
104+
implementation 'ch.acra:acra-mail:5.9.7' // mail component
105+
implementation 'ch.acra:acra-dialog:5.9.7' // dialog component
106+
}

app/proguard-rules.pro

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,21 @@
1818

1919
# If you keep the line number information, uncomment this to
2020
# hide the original source file name.
21-
#-renamesourcefileattribute SourceFile
21+
#-renamesourcefileattribute SourceFile
22+
23+
#ACRA specifics
24+
# Restore some Source file names and restore approximate line numbers in the stack traces,
25+
# otherwise the stack traces are pretty useless
26+
-keepattributes SourceFile, LineNumberTable
27+
28+
# ACRA needs "annotations" so add this...
29+
# Note: This may already be defined in the default "proguard-android-optimize.txt"
30+
# file in the SDK. If it is, then you don't need to duplicate it. See your
31+
# "project.properties" file to get the path to the default "proguard-android-optimize.txt".
32+
-keepattributes *Annotation*
33+
34+
# Keep all the ACRA classes
35+
-keep class org.acra.** { *; }
36+
37+
# Don't warn about removed methods from AppCompat
38+
-dontwarn android.support.v4.app.NotificationCompat*

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
android:fullBackupContent="false"
2121
android:icon="@mipmap/ic_launcher"
2222
android:label="@string/app_name"
23+
android:name="cloud.keyspace.android.Keyspace"
2324
android:largeHeap="true"
2425
android:roundIcon="@mipmap/ic_launcher_round"
2526
android:supportsRtl="true"

app/src/main/kotlin/cloud/keyspace/android/AddCard.kt

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import android.os.Bundle
99
import android.os.Handler
1010
import android.os.Looper
1111
import android.text.Editable
12+
import android.text.SpannableStringBuilder
1213
import android.text.TextUtils
1314
import android.text.TextWatcher
1415
import android.text.method.PasswordTransformationMethod
@@ -266,12 +267,24 @@ class AddCard : AppCompatActivity() {
266267
if (s.isNotEmpty() && s.length % 5 == 0) {
267268
val c = s[s.length - 1]
268269
if (space == c) s.delete(s.length - 1, s.length)
269-
}
270-
271-
if (s.isNotEmpty() && s.length % 5 == 0) {
272-
val c = s[s.length - 1]
273270
if (Character.isDigit(c) && TextUtils.split(s.toString(), space.toString()).size <= 3) s.insert(s.length - 1, space.toString())
274271
}
272+
if (s.toString().replace(" ", "").length in 0..16) {
273+
cardNumberInput.removeTextChangedListener(this)
274+
cardNumberInput.setText(s.toString().replace(" ", "").replace("....".toRegex(), "$0 ")?.trim())
275+
cardNumberInput.addTextChangedListener(this)
276+
cardNumberInput.setSelection(cardNumberInput.text.toString().length)
277+
}
278+
if (s.toString().replace(" ", "").length in 17..18) {
279+
for (c in s) {
280+
if (c == ' ') {
281+
s.delete(s.indexOf(c), s.indexOf(c)+1)
282+
}
283+
}
284+
}
285+
if (s.toString().replace(" ", "").length > 19) {
286+
s.delete(s.length - 1, s.length)
287+
}
275288
}
276289
override fun beforeTextChanged(cardNumber: CharSequence, start: Int, count: Int, after: Int) { }
277290
override fun onTextChanged(cardNumber: CharSequence, start: Int, before: Int, count: Int) {
@@ -372,7 +385,9 @@ class AddCard : AppCompatActivity() {
372385
vault.card?.remove(io.getCard(itemId!!, vault))
373386
}
374387

375-
if (cardNumberInput.text.toString().length < 16) cardNumberInput.error = "Enter a valid 16 digit card number"
388+
if (cardNumberInput.text.toString().replace(" ", "").length < 16) cardNumberInput.error = "Enter a valid 16 digit card number"
389+
else if (cardNumberInput.text.toString().replace(" ", "").length in 17..18
390+
|| cardNumberInput.text.toString().replace(" ", "").length > 19) cardNumberInput.error = "Enter a valid 19 digit card number"
376391
else if (securityCode.text.toString().length !in 3..4) securityCode.error = "Enter a valid security code"
377392
else if (toDate.text.toString().isEmpty()) toDate.error = "Enter an expiry date"
378393
else if (cardholderNameInput.text.toString().isEmpty()) cardholderNameInput.error = "Enter card holder's name"
@@ -438,7 +453,9 @@ class AddCard : AppCompatActivity() {
438453

439454
notesInput.setText(card.notes)
440455

441-
cardNumberInput.setText(card.cardNumber?.replace("....".toRegex(), "$0 "))
456+
if (card.cardNumber?.length!! == 16) cardNumberInput.setText(card.cardNumber.replace("....".toRegex(), "$0 "))
457+
else cardNumberInput.setText(card.cardNumber)
458+
442459
toDate.setText(card.expiry)
443460
securityCode.setText(card.securityCode)
444461
cardholderNameInput.setText(card.cardholderName)

app/src/main/kotlin/cloud/keyspace/android/AddLogin.kt

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,6 @@ class AddLogin : AppCompatActivity() {
7474
lateinit var emailInputLayout: TextInputLayout
7575
lateinit var emailInput: TextInputEditText
7676

77-
lateinit var emailAsUsername: MaterialSwitch
78-
7977
lateinit var passwordInputLayout: TextInputLayout
8078
lateinit var passwordInput: TextInputEditText
8179
lateinit var clearButton: ImageView
@@ -195,6 +193,11 @@ class AddLogin : AppCompatActivity() {
195193
}
196194
}
197195

196+
if (secretInput.text.toString().isNotBlank() && secretInput.text.toString().length < 6) {
197+
secretInput.error = "Please enter a valid TOTP secret"
198+
return@setOnClickListener
199+
}
200+
198201
saveItem()
199202

200203
}
@@ -290,14 +293,6 @@ class AddLogin : AppCompatActivity() {
290293
userNameInput = findViewById (R.id.userNameInput)
291294
userNameInput.imeOptions = IME_FLAG_NO_PERSONALIZED_LEARNING
292295
userNameInputLayout = findViewById (R.id.userNameInputLayout)
293-
userNameInputLayout.visibility = View.GONE
294-
295-
emailAsUsername = findViewById (R.id.emailAsUsername)
296-
emailAsUsername.isChecked = true
297-
emailAsUsername.setOnCheckedChangeListener { _, isChecked ->
298-
if (isChecked) userNameInputLayout.visibility = View.GONE
299-
else userNameInputLayout.visibility = View.VISIBLE
300-
}
301296

302297
emailInput = findViewById (R.id.emailInput)
303298
emailInput.imeOptions = IME_FLAG_NO_PERSONALIZED_LEARNING
@@ -629,7 +624,7 @@ class AddLogin : AppCompatActivity() {
629624
override fun afterTextChanged (s: Editable) { }
630625
override fun beforeTextChanged (s: CharSequence, start: Int, count: Int, after: Int) { }
631626
override fun onTextChanged (s: CharSequence, start: Int, before: Int, count: Int) {
632-
if (s.length >= 8) {
627+
if (s.length >= 6) {
633628
try {
634629
otpCode = GoogleAuthenticator(base32secret = secretInput.text.toString()).generate()
635630
runOnUiThread { tokenPreview.text = otpCode!!.replace("...".toRegex(), "$0 ") }
@@ -784,10 +779,6 @@ class AddLogin : AppCompatActivity() {
784779

785780
if (!login.loginData!!.username.isNullOrBlank()) {
786781
userNameInput.setText(login.loginData.username)
787-
emailAsUsername.isChecked = false
788-
} else {
789-
userNameInputLayout.visibility = View.GONE
790-
emailAsUsername.isChecked = true
791782
}
792783

793784
if (!login.loginData.password.isNullOrEmpty()) {

app/src/main/kotlin/cloud/keyspace/android/Dashboard.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,10 +1086,14 @@ class Dashboard : AppCompatActivity(), NavigationView.OnNavigationItemSelectedLi
10861086
if (!login.loginData?.email.isNullOrEmpty()) {
10871087
loginCard.usernameText.text = login.loginData!!.email
10881088
loginCard.usernameText.setCompoundDrawablesRelativeWithIntrinsicBounds (emailIcon, null, null, null)
1089-
} else if (!login.loginData?.username.isNullOrEmpty()) {
1089+
}
1090+
1091+
if (!login.loginData?.username.isNullOrEmpty()) {
10901092
loginCard.usernameText.text = login.loginData!!.username
10911093
loginCard.usernameText.setCompoundDrawablesRelativeWithIntrinsicBounds (loginIcon, null, null, null)
1092-
} else loginCard.usernameText.visibility = View.GONE
1094+
}
1095+
1096+
if (login.loginData?.username.isNullOrEmpty() && login.loginData?.email.isNullOrEmpty()) loginCard.usernameText.visibility = View.GONE
10931097

10941098
loginCard.miscText.visibility = View.GONE
10951099

@@ -1966,7 +1970,9 @@ class Dashboard : AppCompatActivity(), NavigationView.OnNavigationItemSelectedLi
19661970
}
19671971
}
19681972

1969-
cardCard.cardNumber.text = card.cardNumber?.replace("....".toRegex(), "$0 ")
1973+
if (card.cardNumber?.length == 16) cardCard.cardNumber.text = card.cardNumber.replace("....".toRegex(), "$0 ")
1974+
else cardCard.cardNumber.text = card.cardNumber
1975+
19701976
cardCard.toDate.text = card.expiry
19711977
cardCard.cardHolder.text = card.cardholderName
19721978

@@ -2128,6 +2134,8 @@ class Dashboard : AppCompatActivity(), NavigationView.OnNavigationItemSelectedLi
21282134
)
21292135
}
21302136

2137+
if (!card.pin.isNullOrBlank()) cardCard.pin.text = card.pin else cardCard.pinLayout.visibility = View.GONE
2138+
21312139
fun hideCodes () {
21322140
cardCard.pin.text = "●●●●"
21332141
cardCard.securityCode.text = "●●●"
@@ -2138,6 +2146,7 @@ class Dashboard : AppCompatActivity(), NavigationView.OnNavigationItemSelectedLi
21382146

21392147
var codesHidden = true
21402148
hideCodes()
2149+
21412150
cardCard.hideCodes.setOnClickListener {
21422151
codesHidden = !codesHidden
21432152
if (codesHidden) {

app/src/main/kotlin/cloud/keyspace/android/DeveloperOptions.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ package cloud.keyspace.android
22

33
import android.os.Bundle
44
import android.util.Log
5-
import android.widget.EditText
6-
import android.widget.RadioGroup
7-
import android.widget.TextView
8-
import android.widget.Toast
5+
import android.widget.*
96
import androidx.appcompat.app.AppCompatActivity
107
import com.google.android.material.button.MaterialButton
118
import com.goterl.lazysodium.LazySodiumAndroid
@@ -42,6 +39,9 @@ class DeveloperOptions : AppCompatActivity() {
4239
val blake2bWordsInput = findViewById<EditText>(R.id.blake2bWordsInput)
4340
val blake2bHashButton = findViewById<MaterialButton>(R.id.blake2bHashButton)
4441

42+
val backButton: ImageView = findViewById(R.id.backButton)
43+
backButton.setOnClickListener { onBackPressed() }
44+
4545
blake2bHashButton.setOnClickListener {
4646
val bip39Seed: ByteArray? = crypto.wordsToSeed(blake2bWordsInput.text.toString().toCharArray(), blake2bPassphraseInput.text.toString().toCharArray())
4747

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package cloud.keyspace.android
2+
3+
import android.app.Application
4+
import android.content.Context
5+
import org.acra.config.dialog
6+
import org.acra.config.mailSender
7+
import org.acra.data.StringFormat
8+
import org.acra.ktx.initAcra
9+
import java.time.Instant
10+
import java.time.format.DateTimeFormatter
11+
12+
class Keyspace : Application() {
13+
override fun attachBaseContext(base: Context) {
14+
super.attachBaseContext(base)
15+
initAcra {
16+
buildConfigClass = BuildConfig::class.java
17+
reportFormat = StringFormat.KEY_VALUE_LIST
18+
19+
dialog {
20+
text = getString(R.string.crash_send_logs_description)
21+
title = " " + getString(R.string.app_name)
22+
positiveButtonText = getString(R.string.crash_send_positive_button_text)
23+
negativeButtonText = getString(R.string.exit)
24+
resIcon = R.drawable.keyspace
25+
resTheme = android.R.style.Theme_Material_Dialog
26+
}
27+
28+
mailSender {
29+
mailTo = getString(R.string.support_email)
30+
reportAsFile = true
31+
reportFileName = "android_bug_report_${DateTimeFormatter.ISO_INSTANT.format(Instant.now())}.txt"
32+
subject = getString(R.string.crash_send_logs_email_subject)
33+
body = getString(R.string.crash_send_logs_email_body)
34+
}
35+
36+
}
37+
38+
}
39+
}

app/src/main/kotlin/cloud/keyspace/android/MiscUtilities.kt

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,32 +36,39 @@ class MiscUtilities (applicationContext: Context) {
3636
fun getPaymentGateway(cardNumber: String): String? {
3737
try {
3838
if (cardNumber.startsWith("4") ||
39-
cardNumber.startsWith("4026") ||
40-
cardNumber.startsWith("411750") ||
41-
cardNumber.startsWith("4508") ||
42-
cardNumber.startsWith("4913") ||
43-
cardNumber.startsWith("4917") ||
44-
cardNumber.startsWith("4844")) {
39+
cardNumber.startsWith("40") ||
40+
cardNumber.startsWith("411") ||
41+
cardNumber.startsWith("45") ||
42+
cardNumber.startsWith("49") ||
43+
cardNumber.startsWith("49") ||
44+
cardNumber.startsWith("48")
45+
) {
4546
return "visa"
4647
} else if (
4748
(cardNumber.take(4)).toInt() in 2221..2720 ||
4849
(cardNumber.take(2)).toInt() in 51..55 ||
49-
(cardNumber.take(4)).toInt() in 5100..5399) {
50+
(cardNumber.take(4)).toInt() in 5100..5399 ||
51+
cardNumber.startsWith("67")
52+
) {
5053
return "mastercard"
5154
} else if (
5255
(cardNumber.take(4)).toInt() in 622126..622925 ||
5356
(cardNumber.take(3)).toInt() in 644..649 ||
54-
cardNumber.startsWith("66")) {
57+
cardNumber.startsWith("66") ||
58+
cardNumber.startsWith("601")
59+
) {
5560
return "discover"
5661
} else if (
5762
cardNumber.startsWith("60") ||
5863
cardNumber.startsWith("6521") ||
5964
cardNumber.startsWith("6522") ||
60-
cardNumber.startsWith("50")) {
65+
cardNumber.startsWith("50")
66+
) {
6167
return "rupay"
6268
} else if (
6369
cardNumber.startsWith("34") ||
64-
cardNumber.startsWith("37")) {
70+
cardNumber.startsWith("37")
71+
) {
6572
return "americanExpress"
6673
} else {
6774
return null

0 commit comments

Comments
 (0)