Skip to content

Commit

Permalink
Merge pull request #55 from aashishksahu/issue-47
Browse files Browse the repository at this point in the history
Issue 47
  • Loading branch information
aashishksahu committed Apr 20, 2024
2 parents 200a179 + 41f1b92 commit 1a2d5a7
Show file tree
Hide file tree
Showing 24 changed files with 373 additions and 65 deletions.
10 changes: 5 additions & 5 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ android {

minSdk 29
targetSdk 34
versionCode 20
versionName "1.4.6"
versionCode 22
versionName "1.4.8"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down Expand Up @@ -45,9 +45,9 @@ dependencies {
implementation "androidx.security:security-crypto:1.0.0"

// For Audio/Video
implementation 'androidx.media3:media3-exoplayer:1.3.0'
implementation 'androidx.media3:media3-ui:1.3.0'
implementation 'androidx.media3:media3-common:1.3.0'
implementation 'androidx.media3:media3-exoplayer:1.3.1'
implementation 'androidx.media3:media3-ui:1.3.1'
implementation 'androidx.media3:media3-common:1.3.1'

// For Pictures
implementation 'com.github.bumptech.glide:glide:4.15.1'
Expand Down
Binary file modified app/release/app-release.apk
Binary file not shown.
Binary file added app/release/baselineProfiles/0/app-release.dm
Binary file not shown.
Binary file added app/release/baselineProfiles/1/app-release.dm
Binary file not shown.
23 changes: 20 additions & 3 deletions app/release/output-metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,27 @@
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 20,
"versionName": "1.4.6",
"versionCode": 22,
"versionName": "1.4.8",
"outputFile": "app-release.apk"
}
],
"elementType": "File"
"elementType": "File",
"baselineProfiles": [
{
"minApi": 28,
"maxApi": 30,
"baselineProfiles": [
"baselineProfiles/1/app-release.dm"
]
},
{
"minApi": 31,
"maxApi": 2147483647,
"baselineProfiles": [
"baselineProfiles/0/app-release.dm"
]
}
],
"minSdkVersionForDexing": 29
}
11 changes: 11 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,17 @@
android:name=".main.MainActivity"
android:configChanges="keyboardHidden|screenSize"
android:exported="false" />

<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>

</application>

</manifest>
188 changes: 171 additions & 17 deletions app/src/main/java/org/privacymatters/safespace/AuthActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@ package org.privacymatters.safespace

import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.os.CountDownTimer
import android.view.KeyEvent
import android.widget.EditText
import android.widget.ImageButton
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat
import androidx.core.text.isDigitsOnly
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.privacymatters.safespace.lib.utils.Constants
import org.privacymatters.safespace.lib.utils.EncPref
Expand All @@ -19,6 +21,7 @@ import org.privacymatters.safespace.lib.utils.SetTheme
import org.privacymatters.safespace.main.MainActivity
import java.util.concurrent.Executor


/*
Possible authentication scenarios
Expand All @@ -38,14 +41,20 @@ class AuthActivity : AppCompatActivity() {
private lateinit var promptInfo: BiometricPrompt.PromptInfo
private lateinit var authTouch: ImageButton
private lateinit var pinField: EditText
private lateinit var sharedPref: SharedPreferences
private var confirmCounter = 0
private var confirmPIN = "-1"
private var isHardPinSet = false
private var attemptCount = 0
private lateinit var loginBlockMsg: TextView
private lateinit var loginBlockTimer: TextView
private var loginBlockedTime: Long = Constants.DEF_NUM_FLAG


override fun onCreate(savedInstanceState: Bundle?) {

// load theme from preferences
val sharedPref = getSharedPreferences(Constants.SHARED_PREF_FILE, Context.MODE_PRIVATE)
sharedPref = getSharedPreferences(Constants.SHARED_PREF_FILE, Context.MODE_PRIVATE)

if (!sharedPref.getBoolean(Constants.USE_BIOMETRIC, false)) {
biometricPossible = false
Expand All @@ -64,7 +73,21 @@ class AuthActivity : AppCompatActivity() {
setContentView(R.layout.activity_auth)

authTouch = findViewById(R.id.fingerprint)
pinField = findViewById(R.id.editTextNumberPassword)
pinField = findViewById(R.id.editTextPassword)

loginBlockMsg = findViewById(R.id.loginBlockMsg)
loginBlockTimer = findViewById(R.id.loginBlockTimer)
loginBlockedTime =
sharedPref.getLong(Constants.TIME_TO_UNLOCK_START, Constants.DEF_NUM_FLAG)

// check if user is blocked from login
val isLoginUnlocked = checkLoginUnlocked() // returns a pair(is blocked?, for how long)

// if user is blocked, start a countdown
if (!isLoginUnlocked.first) {
setLoginBlockMsg()
countDown(isLoginUnlocked.second).start()
}

// Root Check
if (!isPhoneRooted(pinField.context)) {
Expand All @@ -87,12 +110,14 @@ class AuthActivity : AppCompatActivity() {
}

BiometricManager.BIOMETRIC_SUCCESS -> {
if (isHardPinSet && biometricPossible) initiateBiometricAuthentication()
if (isHardPinSet && biometricPossible && isLoginUnlocked.first) initiateBiometricAuthentication()
}
}

authTouch.setOnClickListener {
if (biometricPossible && isHardPinSet) biometricPrompt.authenticate(promptInfo)
if (biometricPossible && isHardPinSet) biometricPrompt.authenticate(
promptInfo
)
}

}
Expand All @@ -116,23 +141,154 @@ class AuthActivity : AppCompatActivity() {
}

private fun authenticateUsingHardPin() {

if (pinField.text.toString().isDigitsOnly() &&
pinField.text.toString() == EncPref.getString(
if (pinField.text.toString() == EncPref.getString(
Constants.HARD_PIN,
applicationContext
)
) {
attemptCount = 0

blockBiometric(false, 0)

val intent = Intent(applicationContext, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
finish()
} else {
pinField.error = getString(R.string.pin_error5)
pinField.setText("")
attemptCount += 1
when (attemptCount) {
10 -> {
blockLogin(300000) // 5 minutes
countDown(300000).start()
}

12 -> {
blockLogin(600000) // 10 minutes
countDown(600000).start()
}

14 -> {
blockLogin(1800000) // 30 minutes
countDown(1800000).start()
}

16 -> {
blockLogin(3600000) // 1 Hour
countDown(3600000).start()
}

18 -> {
blockLogin(10800000) // 3 hours
countDown(10800000).start()
}

20 -> {
blockLogin(86400000) // 1 Day
countDown(86400000).start()
attemptCount = 0
}
}

}
}

private fun blockBiometric(flag: Boolean, blockDuration: Long) {
if(flag){

val biometricBackup = sharedPref.getBoolean(Constants.USE_BIOMETRIC, false)

sharedPref.edit()
.putLong(Constants.TIME_TO_UNLOCK_START, blockDuration + System.currentTimeMillis())
.putBoolean(
Constants.USE_BIOMETRIC_BCKP,
biometricBackup
)
.putBoolean(Constants.USE_BIOMETRIC, false)
.apply()
}else{
val biometricRestore = sharedPref.getBoolean(Constants.USE_BIOMETRIC_BCKP, false)

sharedPref.edit().putBoolean(
Constants.USE_BIOMETRIC,
biometricRestore
).apply()
}
}

private fun blockLogin(blockDuration: Long) {
setLoginBlockMsg()

biometricPossible = false

blockBiometric(true, blockDuration)
}

private fun unlockLogin() {
removeLoginBlockMsg()
sharedPref.edit()
.putLong(Constants.TIME_TO_UNLOCK_DURATION, Constants.DEF_NUM_FLAG)
.putLong(Constants.TIME_TO_UNLOCK_START, Constants.DEF_NUM_FLAG)
.apply()
}

private fun checkLoginUnlocked(): Pair<Boolean, Long> {

if (System.currentTimeMillis() > loginBlockedTime) {
return Pair(true, -1)
}

return Pair(false, loginBlockedTime - System.currentTimeMillis())
}

private fun countDown(millisRemaining: Long): CountDownTimer {

return object : CountDownTimer(millisRemaining, 1000) {

override fun onTick(millisUntilFinished: Long) {
val minutesUntilFinished = (millisUntilFinished / 60000)
val secondsUntilFinished = (millisUntilFinished % 60000) / 1000

var remainingTime = ""

remainingTime += if (minutesUntilFinished < 10) {
"0$minutesUntilFinished"
} else {
minutesUntilFinished.toString()
}

remainingTime += ":"

remainingTime += if (secondsUntilFinished < 10) {
"0$secondsUntilFinished"
} else {
secondsUntilFinished.toString()
}

loginBlockTimer.text = remainingTime
}

override fun onFinish() {
unlockLogin()
loginBlockTimer.text = ""
}
}

}

private fun setLoginBlockMsg() {
loginBlockMsg.text = getString(R.string.pin_error6)
pinField.isEnabled = false
authTouch.isEnabled = false
}

private fun removeLoginBlockMsg() {
loginBlockMsg.text = ""
pinField.isEnabled = true
authTouch.isEnabled = true
}

private fun setUpHardPin() {

pinField.hint = getString(R.string.set_pin_text)
Expand All @@ -144,15 +300,12 @@ class AuthActivity : AppCompatActivity() {
} else {

if (confirmCounter == 0) {
if (pinField.text.toString().isDigitsOnly()) {
confirmCounter += 1
pinField.hint = getString(R.string.confirm_pin_text)
confirmPIN = pinField.text.toString()
pinField.error = null
pinField.setText("")
} else {
pinField.error = getString(R.string.pin_error3)
}

confirmCounter += 1
pinField.hint = getString(R.string.confirm_pin_text)
confirmPIN = pinField.text.toString()
pinField.error = null
pinField.setText("")

} else if (confirmCounter == 1) {
if (confirmPIN != pinField.text.toString()) {
Expand Down Expand Up @@ -226,4 +379,5 @@ class AuthActivity : AppCompatActivity() {
}
return false
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ package org.privacymatters.safespace.lib.fileManager

import android.app.Application
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.FileUtils
import android.provider.OpenableColumns
import androidx.core.content.FileProvider
import androidx.documentfile.provider.DocumentFile
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.privacymatters.safespace.R
import org.privacymatters.safespace.lib.utils.Constants
import java.io.BufferedOutputStream
import java.io.File
Expand Down Expand Up @@ -343,6 +346,27 @@ class Operations(private val application: Application) {
return 1
}

fun shareFile(file: FileItem, internalPath: String) {
val fileToShare = File(joinPath(getFilesDir(), internalPath, file.name))
val fileUri = FileProvider.getUriForFile(
application,
application.applicationContext.packageName + ".provider",
fileToShare
)

val intent = Intent(Intent.ACTION_SEND)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.type = application.contentResolver.getType(fileUri)
intent.putExtra(Intent.EXTRA_STREAM, fileUri)

val chooser = Intent.createChooser(
intent,
application.getString(R.string.share_chooser_title)
)
chooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
application.startActivity(chooser)
}

fun createTextNote(noteName: String): String {

val filePath = joinPath(getFilesDir(), getInternalPath(), noteName)
Expand Down
Loading

0 comments on commit 1a2d5a7

Please sign in to comment.