Skip to content

Commit

Permalink
1.1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
lucky committed Aug 20, 2022
1 parent 00888e5 commit 3a83bc2
Show file tree
Hide file tree
Showing 21 changed files with 216 additions and 41 deletions.
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ Enforce security policies.
src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/me.lucky.sentry/)
[<img
src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png"
alt="Get it on Google Play"
height="80">](https://play.google.com/store/apps/details?id=me.lucky.sentry)

<img
src="fastlane/metadata/android/en-US/images/phoneScreenshots/1.png"
Expand Down
12 changes: 0 additions & 12 deletions SECURITY.md

This file was deleted.

15 changes: 10 additions & 5 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ android {
applicationId "me.lucky.sentry"
minSdk 23
targetSdk 32
versionCode 7
versionName "1.1.0"
versionCode 8
versionName "1.1.1"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

Expand Down Expand Up @@ -47,19 +47,24 @@ android {

dependencies {
implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'androidx.appcompat:appcompat:1.5.0'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

implementation 'androidx.security:security-crypto:1.0.0'
implementation 'androidx.preference:preference-ktx:1.2.0'
// https://issuetracker.google.com/issues/238425626
implementation('androidx.preference:preference-ktx:1.2.0') {
exclude group: 'androidx.lifecycle', module:'lifecycle-viewmodel'
exclude group: 'androidx.lifecycle', module:'lifecycle-viewmodel-ktx'
}
implementation 'androidx.biometric:biometric:1.1.0'
implementation 'androidx.drawerlayout:drawerlayout:1.1.1'
implementation 'info.guardianproject.panic:panic:1.0'

def room_version = "2.4.2"
def room_version = "2.4.3"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
}
22 changes: 22 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,27 @@
</meta-data>
</service>

<activity
android:name=".panic.PanicResponderActivity"
android:noHistory="true"
android:exported="true"
android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="info.guardianproject.panic.action.TRIGGER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

<activity
android:name=".panic.PanicConnectionActivity"
android:noHistory="true"
android:exported="true">
<intent-filter>
<action android:name="info.guardianproject.panic.action.CONNECT" />
<action android:name="info.guardianproject.panic.action.DISCONNECT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

</application>
</manifest>
2 changes: 1 addition & 1 deletion app/src/main/java/me/lucky/sentry/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import me.lucky.sentry.databinding.ActivityMainBinding
import me.lucky.sentry.fragment.MainFragment
import me.lucky.sentry.fragment.MonitorFragment

class MainActivity : AppCompatActivity() {
open class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
Expand Down
7 changes: 3 additions & 4 deletions app/src/main/java/me/lucky/sentry/NotificationManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package me.lucky.sentry

import android.content.Context
import android.content.pm.PackageManager
import android.os.SystemClock
import androidx.core.app.NotificationChannelCompat
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
Expand All @@ -11,8 +12,6 @@ class NotificationManager(private val ctx: Context) {
private const val CHANNEL_PASSWORD_ID = "monitor_password"
private const val CHANNEL_INTERNET_ID = "monitor_internet"
private const val GROUP_KEY = "alert"
private const val NOTIFICATION_PASSWORD_ID = 1000
private const val NOTIFICATION_INTERNET_ID = 1001
}

private val manager = NotificationManagerCompat.from(ctx)
Expand All @@ -32,7 +31,7 @@ class NotificationManager(private val ctx: Context) {

fun notifyInternet(packageName: String) =
manager.notify(
NOTIFICATION_INTERNET_ID,
SystemClock.uptimeMillis().toInt(),
buildNotification(NotificationCompat.Builder(ctx, CHANNEL_INTERNET_ID)
.setContentText(formatInternetText(packageName))),)

Expand All @@ -49,7 +48,7 @@ class NotificationManager(private val ctx: Context) {

fun notifyPassword() =
manager.notify(
NOTIFICATION_PASSWORD_ID,
SystemClock.uptimeMillis().toInt(),
buildNotification(NotificationCompat.Builder(ctx, CHANNEL_PASSWORD_ID)
.setContentText(ctx.getString(R.string.notification_password_text))
.setSilent(true)),)
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/java/me/lucky/sentry/Preferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class Preferences(ctx: Context, encrypted: Boolean = true) {
companion object {
private const val ENABLED = "enabled"
private const val MAX_FAILED_PASSWORD_ATTEMPTS = "max_failed_password_attempts"
private const val MAX_FAILED_PASSWORD_ATTEMPTS_WARNING =
"max_failed_password_attempts_warning"
private const val USB_DATA_SIGNALING_CTL_ENABLED = "usb_data_signaling_ctl_enabled"
private const val MONITOR = "monitor"

Expand Down Expand Up @@ -43,6 +45,10 @@ class Preferences(ctx: Context, encrypted: Boolean = true) {
get() = prefs.getInt(MAX_FAILED_PASSWORD_ATTEMPTS, 0)
set(value) = prefs.edit { putInt(MAX_FAILED_PASSWORD_ATTEMPTS, value) }

var isMaxFailedPasswordAttemptsWarningChecked: Boolean
get() = prefs.getBoolean(MAX_FAILED_PASSWORD_ATTEMPTS_WARNING, false)
set(value) = prefs.edit { putBoolean(MAX_FAILED_PASSWORD_ATTEMPTS_WARNING, value) }

var isUsbDataSignalingCtlEnabled: Boolean
get() = prefs.getBoolean(USB_DATA_SIGNALING_CTL_ENABLED, false)
set(value) = prefs.edit { putBoolean(USB_DATA_SIGNALING_CTL_ENABLED, value) }
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/me/lucky/sentry/admin/DeviceAdminManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ class DeviceAdminManager(private val ctx: Context) {
fun getCurrentFailedPasswordAttempts() = dpm?.currentFailedPasswordAttempts ?: 0
fun isDeviceOwner() = dpm?.isDeviceOwnerApp(ctx.packageName) ?: false

fun setMaximumFailedPasswordsForWipe(num: Int) =
dpm?.setMaximumFailedPasswordsForWipe(deviceAdmin, num)

@RequiresApi(Build.VERSION_CODES.S)
fun canUsbDataSignalingBeDisabled() = dpm?.canUsbDataSignalingBeDisabled() ?: false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class DeviceAdminReceiver : DeviceAdminReceiver() {
|| context.getSystemService(UserManager::class.java)?.isUserUnlocked == true)
if (prefs.monitor.and(Monitor.PASSWORD.value) != 0)
NotificationManager(context).notifyPassword()
if (prefs.isMaxFailedPasswordAttemptsWarningChecked) return
val maxFailedPasswordAttempts = prefs.maxFailedPasswordAttempts
if (!prefs.isEnabled || maxFailedPasswordAttempts <= 0) return
val admin = DeviceAdminManager(context)
Expand Down
25 changes: 22 additions & 3 deletions app/src/main/java/me/lucky/sentry/fragment/MainFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.widget.doAfterTextChanged
import androidx.fragment.app.Fragment
import com.google.android.material.snackbar.Snackbar

Expand Down Expand Up @@ -52,7 +53,9 @@ class MainFragment : Fragment() {
prefsdb = Preferences(ctx, encrypted = false)
prefs.copyTo(prefsdb)
binding.apply {
maxFailedPasswordAttempts.value = prefs.maxFailedPasswordAttempts.toFloat()
maxFailedPasswordAttempts.editText?.setText(prefs.maxFailedPasswordAttempts.toString())
maxFailedPasswordAttemptsWarning.isChecked =
prefs.isMaxFailedPasswordAttemptsWarningChecked
val canChangeUsbDataSignaling = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
admin.canUsbDataSignalingBeDisabled() &&
admin.isDeviceOwner()
Expand All @@ -65,8 +68,18 @@ class MainFragment : Fragment() {
}

private fun setup() = binding.apply {
maxFailedPasswordAttempts.addOnChangeListener { _, value, _ ->
prefs.maxFailedPasswordAttempts = value.toInt()
maxFailedPasswordAttempts.editText?.doAfterTextChanged {
val i = it?.toString()?.toIntOrNull() ?: return@doAfterTextChanged
prefs.maxFailedPasswordAttempts = i
if (prefs.isMaxFailedPasswordAttemptsWarningChecked)
try { admin.setMaximumFailedPasswordsForWipe(i) } catch (exc: SecurityException) {}
}
maxFailedPasswordAttemptsWarning.setOnCheckedChangeListener { _, isChecked ->
prefs.isMaxFailedPasswordAttemptsWarningChecked = isChecked
try {
admin.setMaximumFailedPasswordsForWipe(
if (isChecked) prefs.maxFailedPasswordAttempts else 0)
} catch (exc: SecurityException) {}
}
usbDataSignaling.setOnCheckedChangeListener { _, isChecked ->
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return@setOnCheckedChangeListener
Expand All @@ -88,6 +101,12 @@ class MainFragment : Fragment() {
}

private fun setOn() {
try {
admin.setMaximumFailedPasswordsForWipe(
if (prefs.isMaxFailedPasswordAttemptsWarningChecked) prefs.maxFailedPasswordAttempts
else 0
)
} catch (exc: SecurityException) {}
prefs.isEnabled = true
binding.toggle.isChecked = true
}
Expand Down
46 changes: 46 additions & 0 deletions app/src/main/java/me/lucky/sentry/panic/PanicConnectionActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package me.lucky.sentry.panic

import android.content.pm.PackageManager
import android.os.Bundle
import com.google.android.material.dialog.MaterialAlertDialogBuilder

import info.guardianproject.panic.PanicResponder
import me.lucky.sentry.MainActivity
import me.lucky.sentry.R

class PanicConnectionActivity : MainActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (PanicResponder.checkForDisconnectIntent(this)) {
finish()
return
}
val sender = PanicResponder.getConnectIntentSender(this)
val packageName = PanicResponder.getTriggerPackageName(this)
if (sender != "" && sender != packageName) showOptInDialog() else finish()
}

private fun showOptInDialog() {
var app: CharSequence = getString(R.string.panic_app_unknown_app)
val packageName = callingActivity?.packageName
if (packageName != null) {
try {
app = packageManager
.getApplicationLabel(packageManager.getApplicationInfo(packageName, 0))
} catch (exc: PackageManager.NameNotFoundException) {}
}
MaterialAlertDialogBuilder(this)
.setTitle(R.string.panic_app_dialog_title)
.setMessage(getString(R.string.panic_app_dialog_message, app))
.setNegativeButton(R.string.allow) { _, _ ->
PanicResponder.setTriggerPackageName(this)
setResult(RESULT_OK)
finish()
}
.setPositiveButton(android.R.string.cancel) { _, _ ->
setResult(RESULT_CANCELED)
finish()
}
.show()
}
}
21 changes: 21 additions & 0 deletions app/src/main/java/me/lucky/sentry/panic/PanicResponderActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package me.lucky.sentry.panic

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

import info.guardianproject.panic.Panic
import info.guardianproject.panic.PanicResponder
import me.lucky.sentry.AppDatabase

class PanicResponderActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (!Panic.isTriggerIntent(intent)) {
finishAndRemoveTask()
return
}
if (PanicResponder.receivedTriggerFromConnectedApp(this))
AppDatabase.getInstance(this).packageDao().deleteAll()
finishAndRemoveTask()
}
}
32 changes: 26 additions & 6 deletions app/src/main/res/layout/fragment_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,39 @@
android:layout_height="wrap_content"
android:orientation="vertical">

<com.google.android.material.slider.Slider
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/maxFailedPasswordAttempts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:valueFrom="0"
android:valueTo="10"
android:stepSize="1.0" />
app:helperTextEnabled="true"
app:helperText="@string/max_failed_password_attempts_helper_text"
android:hint="@string/max_failed_password_attempts_hint">

<com.google.android.material.textfield.TextInputEditText
android:inputType="number"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

</com.google.android.material.textfield.TextInputLayout>

<Space
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="5dp" />

<CheckBox
android:id="@+id/maxFailedPasswordAttemptsWarning"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutDirection="rtl"
android:textAppearance="?attr/textAppearanceBodyLarge"
android:text="@string/max_failed_password_attempts_warning" />

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceBodySmall"
android:text="@string/max_failed_password_attempts_description" />
android:text="@string/max_failed_password_attempts_warning_description"
android:textAppearance="?attr/textAppearanceBodySmall" />

<Space
android:layout_width="match_parent"
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<string name="monitor">Überwachung</string>
<string name="main">Start</string>
<string name="authentication">Authentifizierung</string>
<string name="max_failed_password_attempts_description">Maximale Anzahl von fehlgeschlagenen Passwortversuchen.</string>
<string name="max_failed_password_attempts_helper_text">Maximale Anzahl von fehlgeschlagenen Passwortversuchen.</string>
<string name="usb_data_signaling_change_failed_popup">USB-Datensignalisierungsrichtlinie konnte nicht geändert werden</string>
<string name="usb_data_signaling_ctl_description">Schalten Sie die USB-Datensignalisierung bei ausgeschaltetem Bildschirm AUS und bei entsperrtem Bildschirm EIN.</string>
<string name="usb_data_signaling_description">Wenn diese Funktion deaktiviert ist, sind USB-Datenverbindungen (mit Ausnahme von Ladefunktionen) verboten.</string>
Expand Down
18 changes: 16 additions & 2 deletions app/src/main/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@
<string name="app_name">Sentry</string>
<string name="usb_data_signaling">Передача данных по USB</string>
<string name="usb_data_signaling_description">Когда отключено, соединения по USB (кроме зарядки) запрещены.</string>
<string name="usb_data_signaling_ctl">Контроллер</string>
<string name="usb_data_signaling_ctl_description">Выключите сигнализацию данных USB на выключенном экране и включите ее при разблокировке.</string>
<string name="usb_data_signaling_change_failed_popup">Не удалось изменить политику передачи данных по USB</string>
<string name="max_failed_password_attempts_description">Максимальное количество неудачных попыток ввода пароля.</string>
</resources>
<string name="max_failed_password_attempts_helper_text">Максимальное количество неудачных попыток ввода пароля.</string>
<string name="authentication">Аутентификация</string>
<string name="main">Главная</string>
<string name="monitor">Экран</string>
<string name="monitor_password">Пароль</string>
<string name="monitor_password_description">При неудачной попытке ввода пароля вы получите уведомление.</string>
<string name="monitor_internet">Интернет</string>
<string name="monitor_internet_description">Если какое-либо приложение получит ИНТЕРНЕТ разрешение после обновления, вы получите уведомление.</string>
<string name="notification_title">ВНИМАНИЕ</string>
<string name="notification_password_text">Обнаружена неудачная попытка вввода пароля!</string>
<string name="notification_internet_text">%1$s (%2$s) получил ИНТЕРНЕТ разрешение!</string>
<string name="unknown_app">Неизвестное приложение</string>
<string name="goto_button">НАЙТИ</string>
</resources>
Loading

0 comments on commit 3a83bc2

Please sign in to comment.