Skip to content
This repository was archived by the owner on Jan 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
6216ac2
added 19 digit card support
Jan 12, 2023
74e92f4
improved payment gateway detection
Jan 12, 2023
1ff7b5d
fixed card pin bug in dashboard
Jan 12, 2023
8054450
defaulted to username on login item if available
Jan 12, 2023
720a373
added username clearing to AddLogin.kt
Jan 12, 2023
29f9503
added username clearing support logic to Dashboard
Jan 12, 2023
008b53a
added acra skeleton
Jan 16, 2023
6e75b2f
added totp size checker
Jan 16, 2023
1a940c5
implemented crash handler
Jan 17, 2023
4e4ece0
removed generic exception handlers
Jan 17, 2023
5bc31a5
removed generic exception handlers
Jan 17, 2023
6735af4
fixed more than 19 digits issue
Jan 18, 2023
a900727
fixed dashboard crash
Jan 18, 2023
f939bc2
Merge pull request #50 from Keyspace-cloud/totp_length_validation
nimish-ks Jan 19, 2023
9bb915f
removed email/username switch
Jan 19, 2023
bb6e078
added an email subject prefix
Jan 19, 2023
ff9a839
made settings UI match Android 13 spec even more
Jan 29, 2023
8dbc71e
adjusted margins and paddings
Jan 30, 2023
f0c3d8e
revamped developer options screen to Material 3.0 spec
Jan 30, 2023
b8ba703
renamed a setting category
Jan 30, 2023
a44ed77
Merge pull request #46 from Keyspace-cloud/usernames_on_dashboard
rohan-chaturvedi Feb 1, 2023
542786d
Merge pull request #45 from Keyspace-cloud/19_digit_cards
rohan-chaturvedi Feb 1, 2023
3c09799
chore: delete local.properties
rohan-chaturvedi Feb 1, 2023
afd644e
Update app/src/main/res/layout/settings.xml
0x4f53 Feb 1, 2023
40f730b
Merge pull request #53 from Keyspace-cloud/settings_ui_updates
0x4f53 Feb 1, 2023
d24ff2c
Update app/src/main/res/values/strings.xml
0x4f53 Feb 1, 2023
b358e3e
Merge pull request #49 from Keyspace-cloud/crash_logging
rohan-chaturvedi Feb 2, 2023
95a3624
chore: bump version
rohan-chaturvedi Feb 2, 2023
57ff73e
chore: bump versioncode
rohan-chaturvedi Feb 2, 2023
466f356
Merge pull request #56 from Keyspace-cloud/chore--bump-version
0x4f53 Feb 2, 2023
dad262b
Merge pull request #54 from Keyspace-cloud/chore--delete-local-proper…
0x4f53 Feb 2, 2023
ba47186
fixed nonfunctional back button in Developer Options
Feb 2, 2023
a855302
fixed a Volley network call memory leak
Feb 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ android {
applicationId "cloud.keyspace.android"
minSdkVersion 27
targetSdkVersion 33
versionCode 141
versionName "1.4.1"
versionCode 142
versionName "1.4.2"
multiDexEnabled true

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
Expand Down Expand Up @@ -51,7 +51,7 @@ android {
dependencies {
implementation 'com.android.support:multidex:2.0.1' // noinspection GradleDependency
implementation 'androidx.core:core-ktx:1.9.0' // Default Android stuff
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'androidx.appcompat:appcompat:1.6.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.gridlayout:gridlayout:1.0.0'
Expand All @@ -67,8 +67,8 @@ dependencies {
implementation 'androidx.core:core-ktx:1.9.0'
testImplementation 'junit:junit:4.13.2' // Testing
implementation 'androidx.biometric:biometric:1.2.0-alpha05' // Biometrics
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation 'com.google.android.material:material:1.7.0' // Material design
implementation 'androidx.fragment:fragment-ktx:1.5.5'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
Expand Down Expand Up @@ -99,4 +99,8 @@ dependencies {
implementation 'com.scottyab:rootbeer-lib:0.1.0' // To check if device is rooted
implementation "androidx.core:core-splashscreen:1.0.0" // Splash screen library
implementation 'com.nulab-inc:zxcvbn:1.7.0' // password strength
}

// ACRA for crash logging
implementation 'ch.acra:acra-mail:5.9.7' // mail component
implementation 'ch.acra:acra-dialog:5.9.7' // dialog component
}
19 changes: 18 additions & 1 deletion app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,21 @@

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile

#ACRA specifics
# Restore some Source file names and restore approximate line numbers in the stack traces,
# otherwise the stack traces are pretty useless
-keepattributes SourceFile, LineNumberTable

# ACRA needs "annotations" so add this...
# Note: This may already be defined in the default "proguard-android-optimize.txt"
# file in the SDK. If it is, then you don't need to duplicate it. See your
# "project.properties" file to get the path to the default "proguard-android-optimize.txt".
-keepattributes *Annotation*

# Keep all the ACRA classes
-keep class org.acra.** { *; }

# Don't warn about removed methods from AppCompat
-dontwarn android.support.v4.app.NotificationCompat*
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
android:fullBackupContent="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:name="cloud.keyspace.android.Keyspace"
android:largeHeap="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
Expand Down
29 changes: 23 additions & 6 deletions app/src/main/kotlin/cloud/keyspace/android/AddCard.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.text.Editable
import android.text.SpannableStringBuilder
import android.text.TextUtils
import android.text.TextWatcher
import android.text.method.PasswordTransformationMethod
Expand Down Expand Up @@ -266,12 +267,24 @@ class AddCard : AppCompatActivity() {
if (s.isNotEmpty() && s.length % 5 == 0) {
val c = s[s.length - 1]
if (space == c) s.delete(s.length - 1, s.length)
}

if (s.isNotEmpty() && s.length % 5 == 0) {
val c = s[s.length - 1]
if (Character.isDigit(c) && TextUtils.split(s.toString(), space.toString()).size <= 3) s.insert(s.length - 1, space.toString())
}
if (s.toString().replace(" ", "").length in 0..16) {
cardNumberInput.removeTextChangedListener(this)
cardNumberInput.setText(s.toString().replace(" ", "").replace("....".toRegex(), "$0 ")?.trim())
cardNumberInput.addTextChangedListener(this)
cardNumberInput.setSelection(cardNumberInput.text.toString().length)
}
if (s.toString().replace(" ", "").length in 17..18) {
for (c in s) {
if (c == ' ') {
s.delete(s.indexOf(c), s.indexOf(c)+1)
}
}
}
if (s.toString().replace(" ", "").length > 19) {
s.delete(s.length - 1, s.length)
}
}
override fun beforeTextChanged(cardNumber: CharSequence, start: Int, count: Int, after: Int) { }
override fun onTextChanged(cardNumber: CharSequence, start: Int, before: Int, count: Int) {
Expand Down Expand Up @@ -372,7 +385,9 @@ class AddCard : AppCompatActivity() {
vault.card?.remove(io.getCard(itemId!!, vault))
}

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

notesInput.setText(card.notes)

cardNumberInput.setText(card.cardNumber?.replace("....".toRegex(), "$0 "))
if (card.cardNumber?.length!! == 16) cardNumberInput.setText(card.cardNumber.replace("....".toRegex(), "$0 "))
else cardNumberInput.setText(card.cardNumber)

toDate.setText(card.expiry)
securityCode.setText(card.securityCode)
cardholderNameInput.setText(card.cardholderName)
Expand Down
21 changes: 6 additions & 15 deletions app/src/main/kotlin/cloud/keyspace/android/AddLogin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,6 @@ class AddLogin : AppCompatActivity() {
lateinit var emailInputLayout: TextInputLayout
lateinit var emailInput: TextInputEditText

lateinit var emailAsUsername: MaterialSwitch

lateinit var passwordInputLayout: TextInputLayout
lateinit var passwordInput: TextInputEditText
lateinit var clearButton: ImageView
Expand Down Expand Up @@ -195,6 +193,11 @@ class AddLogin : AppCompatActivity() {
}
}

if (secretInput.text.toString().isNotBlank() && secretInput.text.toString().length < 6) {
secretInput.error = "Please enter a valid TOTP secret"
return@setOnClickListener
}

saveItem()

}
Expand Down Expand Up @@ -290,14 +293,6 @@ class AddLogin : AppCompatActivity() {
userNameInput = findViewById (R.id.userNameInput)
userNameInput.imeOptions = IME_FLAG_NO_PERSONALIZED_LEARNING
userNameInputLayout = findViewById (R.id.userNameInputLayout)
userNameInputLayout.visibility = View.GONE

emailAsUsername = findViewById (R.id.emailAsUsername)
emailAsUsername.isChecked = true
emailAsUsername.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) userNameInputLayout.visibility = View.GONE
else userNameInputLayout.visibility = View.VISIBLE
}

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

if (!login.loginData!!.username.isNullOrBlank()) {
userNameInput.setText(login.loginData.username)
emailAsUsername.isChecked = false
} else {
userNameInputLayout.visibility = View.GONE
emailAsUsername.isChecked = true
}

if (!login.loginData.password.isNullOrEmpty()) {
Expand Down
15 changes: 12 additions & 3 deletions app/src/main/kotlin/cloud/keyspace/android/Dashboard.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1086,10 +1086,14 @@ class Dashboard : AppCompatActivity(), NavigationView.OnNavigationItemSelectedLi
if (!login.loginData?.email.isNullOrEmpty()) {
loginCard.usernameText.text = login.loginData!!.email
loginCard.usernameText.setCompoundDrawablesRelativeWithIntrinsicBounds (emailIcon, null, null, null)
} else if (!login.loginData?.username.isNullOrEmpty()) {
}

if (!login.loginData?.username.isNullOrEmpty()) {
loginCard.usernameText.text = login.loginData!!.username
loginCard.usernameText.setCompoundDrawablesRelativeWithIntrinsicBounds (loginIcon, null, null, null)
} else loginCard.usernameText.visibility = View.GONE
}

if (login.loginData?.username.isNullOrEmpty() && login.loginData?.email.isNullOrEmpty()) loginCard.usernameText.visibility = View.GONE

loginCard.miscText.visibility = View.GONE

Expand Down Expand Up @@ -1966,7 +1970,9 @@ class Dashboard : AppCompatActivity(), NavigationView.OnNavigationItemSelectedLi
}
}

cardCard.cardNumber.text = card.cardNumber?.replace("....".toRegex(), "$0 ")
if (card.cardNumber?.length == 16) cardCard.cardNumber.text = card.cardNumber.replace("....".toRegex(), "$0 ")
else cardCard.cardNumber.text = card.cardNumber

cardCard.toDate.text = card.expiry
cardCard.cardHolder.text = card.cardholderName

Expand Down Expand Up @@ -2128,6 +2134,8 @@ class Dashboard : AppCompatActivity(), NavigationView.OnNavigationItemSelectedLi
)
}

if (!card.pin.isNullOrBlank()) cardCard.pin.text = card.pin else cardCard.pinLayout.visibility = View.GONE

fun hideCodes () {
cardCard.pin.text = "●●●●"
cardCard.securityCode.text = "●●●"
Expand All @@ -2138,6 +2146,7 @@ class Dashboard : AppCompatActivity(), NavigationView.OnNavigationItemSelectedLi

var codesHidden = true
hideCodes()

cardCard.hideCodes.setOnClickListener {
codesHidden = !codesHidden
if (codesHidden) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ package cloud.keyspace.android

import android.os.Bundle
import android.util.Log
import android.widget.EditText
import android.widget.RadioGroup
import android.widget.TextView
import android.widget.Toast
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.button.MaterialButton
import com.goterl.lazysodium.LazySodiumAndroid
Expand Down Expand Up @@ -42,6 +39,9 @@ class DeveloperOptions : AppCompatActivity() {
val blake2bWordsInput = findViewById<EditText>(R.id.blake2bWordsInput)
val blake2bHashButton = findViewById<MaterialButton>(R.id.blake2bHashButton)

val backButton: ImageView = findViewById(R.id.backButton)
backButton.setOnClickListener { onBackPressed() }

blake2bHashButton.setOnClickListener {
val bip39Seed: ByteArray? = crypto.wordsToSeed(blake2bWordsInput.text.toString().toCharArray(), blake2bPassphraseInput.text.toString().toCharArray())

Expand Down
39 changes: 39 additions & 0 deletions app/src/main/kotlin/cloud/keyspace/android/Keyspace.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package cloud.keyspace.android

import android.app.Application
import android.content.Context
import org.acra.config.dialog
import org.acra.config.mailSender
import org.acra.data.StringFormat
import org.acra.ktx.initAcra
import java.time.Instant
import java.time.format.DateTimeFormatter

class Keyspace : Application() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
initAcra {
buildConfigClass = BuildConfig::class.java
reportFormat = StringFormat.KEY_VALUE_LIST

dialog {
text = getString(R.string.crash_send_logs_description)
title = " " + getString(R.string.app_name)
positiveButtonText = getString(R.string.crash_send_positive_button_text)
negativeButtonText = getString(R.string.exit)
resIcon = R.drawable.keyspace
resTheme = android.R.style.Theme_Material_Dialog
}

mailSender {
mailTo = getString(R.string.support_email)
reportAsFile = true
reportFileName = "android_bug_report_${DateTimeFormatter.ISO_INSTANT.format(Instant.now())}.txt"
subject = getString(R.string.crash_send_logs_email_subject)
body = getString(R.string.crash_send_logs_email_body)
}

}

}
}
27 changes: 17 additions & 10 deletions app/src/main/kotlin/cloud/keyspace/android/MiscUtilities.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,32 +36,39 @@ class MiscUtilities (applicationContext: Context) {
fun getPaymentGateway(cardNumber: String): String? {
try {
if (cardNumber.startsWith("4") ||
cardNumber.startsWith("4026") ||
cardNumber.startsWith("411750") ||
cardNumber.startsWith("4508") ||
cardNumber.startsWith("4913") ||
cardNumber.startsWith("4917") ||
cardNumber.startsWith("4844")) {
cardNumber.startsWith("40") ||
cardNumber.startsWith("411") ||
cardNumber.startsWith("45") ||
cardNumber.startsWith("49") ||
cardNumber.startsWith("49") ||
cardNumber.startsWith("48")
) {
return "visa"
} else if (
(cardNumber.take(4)).toInt() in 2221..2720 ||
(cardNumber.take(2)).toInt() in 51..55 ||
(cardNumber.take(4)).toInt() in 5100..5399) {
(cardNumber.take(4)).toInt() in 5100..5399 ||
cardNumber.startsWith("67")
) {
return "mastercard"
} else if (
(cardNumber.take(4)).toInt() in 622126..622925 ||
(cardNumber.take(3)).toInt() in 644..649 ||
cardNumber.startsWith("66")) {
cardNumber.startsWith("66") ||
cardNumber.startsWith("601")
) {
return "discover"
} else if (
cardNumber.startsWith("60") ||
cardNumber.startsWith("6521") ||
cardNumber.startsWith("6522") ||
cardNumber.startsWith("50")) {
cardNumber.startsWith("50")
) {
return "rupay"
} else if (
cardNumber.startsWith("34") ||
cardNumber.startsWith("37")) {
cardNumber.startsWith("37")
) {
return "americanExpress"
} else {
return null
Expand Down
Loading