commit 0ac142f46c3260a148a8799aae63c5df37cafdfb
parent 43f1a305a2bcea6ff872b34438da778e5529f9c6
Author: rhunk <101876869+rhunk@users.noreply.github.com>
Date: Sun, 11 Aug 2024 17:42:42 +0200
feat(core): sif status
- add InAppOverlay custom composable
Diffstat:
5 files changed, 125 insertions(+), 67 deletions(-)
diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/FeatureManager.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/FeatureManager.kt
@@ -60,6 +60,7 @@ class FeatureManager(
fun init() {
register(
+ SecurityFeatures(),
EndToEndEncryption(),
ScopeSync(),
PreventMessageListAutoScroll(),
diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/SecurityFeatures.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/SecurityFeatures.kt
@@ -0,0 +1,74 @@
+package me.rhunk.snapenhance.core.features.impl
+
+import android.system.Os
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Text
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.withContext
+import me.rhunk.snapenhance.core.features.Feature
+
+class SecurityFeatures : Feature("Security Features") {
+ private fun transact(option: Int) = Os.prctl(option, 0, 0, 0, 0)
+
+ private val token by lazy {
+ runCatching { transact(0) }.getOrNull()
+ }
+
+ private fun getStatus() = token?.run {
+ transact(this).toString(2).padStart(32, '0').count { it == '1' }
+ }
+
+ override fun init() {
+ token // pre init token
+
+ context.inAppOverlay.addCustomComposable {
+ var statusText by remember {
+ mutableStateOf("")
+ }
+ var textColor by remember {
+ mutableStateOf(Color.Red)
+ }
+
+ LaunchedEffect(Unit) {
+ withContext(Dispatchers.IO) {
+ while (true) {
+ val status = getStatus()
+ withContext(Dispatchers.Main) {
+ if (status == null || status == 0) {
+ textColor = Color.Red
+ statusText = "sif not loaded. Can't get status"
+ } else {
+ textColor = Color.Green
+ statusText = "sif = $status"
+ }
+ }
+ delay(1000)
+ }
+ }
+ }
+
+ Text(
+ text = statusText,
+ modifier = Modifier
+ .align(Alignment.BottomCenter)
+ .background(Color.Black, shape = RoundedCornerShape(5.dp))
+ .padding(3.dp),
+ fontSize = 10.sp,
+ color = textColor
+ )
+ }
+ }
+}+
\ No newline at end of file
diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/experiments/AccountSwitcher.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/experiments/AccountSwitcher.kt
@@ -6,7 +6,6 @@ import android.content.Intent
import android.database.sqlite.SQLiteDatabase
import android.net.Uri
import android.os.ParcelFileDescriptor
-import android.widget.FrameLayout
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
@@ -26,12 +25,12 @@ import kotlinx.coroutines.withContext
import me.rhunk.snapenhance.common.data.FileType
import me.rhunk.snapenhance.common.ui.AppMaterialTheme
import me.rhunk.snapenhance.common.ui.createComposeAlertDialog
-import me.rhunk.snapenhance.common.ui.createComposeView
import me.rhunk.snapenhance.common.util.ktx.toParcelFileDescriptor
import me.rhunk.snapenhance.common.util.snap.MediaDownloaderHelper
import me.rhunk.snapenhance.core.event.events.impl.ActivityResultEvent
import me.rhunk.snapenhance.core.event.events.impl.AddViewEvent
import me.rhunk.snapenhance.core.features.Feature
+import me.rhunk.snapenhance.core.ui.CustomComposable
import me.rhunk.snapenhance.core.util.hook.HookStage
import me.rhunk.snapenhance.core.util.hook.hook
import me.rhunk.snapenhance.core.util.ktx.getId
@@ -507,24 +506,26 @@ class AccountSwitcher: Feature("Account Switcher") {
}
}
- findClass("com.snap.identity.loginsignup.ui.LoginSignupActivity").apply {
- hook("onPostCreate", HookStage.AFTER) {
- context.mainActivity!!.findViewById<FrameLayout>(android.R.id.content).addView(createComposeView(context.mainActivity!!) {
- Row(
- modifier = Modifier.fillMaxWidth(),
- ) {
- Button(
- onClick = { showManagementPopup() },
- modifier = Modifier.padding(16.dp)
- ) {
- Text("Switch Account")
- }
- }
- }.apply {
- layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT).apply {
- gravity = android.view.Gravity.TOP or android.view.Gravity.START
- }
- })
+ val switchButtonComposable: CustomComposable = {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .align(Alignment.TopStart),
+ ) {
+ Button(
+ onClick = { showManagementPopup() },
+ modifier = Modifier.padding(16.dp)
+ ) {
+ Text("Switch Account")
+ }
+ }
+ }
+
+ onNextActivityCreate { activity ->
+ if (!activity.componentName.className.endsWith("LoginSignupActivity")) return@onNextActivityCreate
+ context.inAppOverlay.addCustomComposable(switchButtonComposable)
+ onNextActivityCreate {
+ context.inAppOverlay.removeCustomComposable(switchButtonComposable)
}
}
}
diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/experiments/ComposerHooks.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/features/impl/experiments/ComposerHooks.kt
@@ -1,26 +1,16 @@
package me.rhunk.snapenhance.core.features.impl.experiments
-import android.app.Activity
-import android.view.View
-import android.widget.FrameLayout
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.BugReport
-import androidx.compose.material3.Button
-import androidx.compose.material3.FilledIconButton
-import androidx.compose.material3.Icon
-import androidx.compose.material3.Text
-import androidx.compose.material3.TextField
+import androidx.compose.material3.*
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
@@ -29,9 +19,7 @@ import androidx.compose.ui.unit.sp
import kotlinx.coroutines.launch
import me.rhunk.snapenhance.common.bridge.FileHandleScope
import me.rhunk.snapenhance.common.bridge.toWrapper
-import me.rhunk.snapenhance.common.ui.AppMaterialTheme
import me.rhunk.snapenhance.common.ui.createComposeAlertDialog
-import me.rhunk.snapenhance.common.ui.createComposeView
import me.rhunk.snapenhance.core.features.Feature
import me.rhunk.snapenhance.core.features.impl.downloader.MediaDownloader
import me.rhunk.snapenhance.core.util.hook.HookStage
@@ -101,35 +89,6 @@ class ComposerHooks: Feature("ComposerHooks") {
}
}
- private val composerConsoleTag = Random.nextLong().toString()
-
- private fun injectConsole(activity: Activity) {
- val root = activity.findViewById<FrameLayout>(android.R.id.content) ?: run {
- context.log.warn("Unable to find root view. Can't inject console.")
- return
- }
- root.post {
- if (root.findViewWithTag<View>(composerConsoleTag) != null) return@post
- root.addView(createComposeView(root.context) {
- AppMaterialTheme {
- FilledIconButton(
- onClick = {
- composerConsole.show()
- },
- modifier = Modifier.padding(top = 100.dp, end = 16.dp)
- ) {
- Icon(Icons.Default.BugReport, contentDescription = "Debug Console")
- }
- }
- }.apply {
- tag = composerConsoleTag
- layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT).apply {
- gravity = android.view.Gravity.TOP or android.view.Gravity.END
- }
- })
- }
- }
-
private fun newComposerFunction(block: ComposerMarshaller.() -> Boolean): Any? {
val composerFunctionClass = findClass("com.snap.composer.callable.ComposerFunction")
return Proxy.newProxyInstance(
@@ -223,9 +182,16 @@ class ComposerHooks: Feature("ComposerHooks") {
loadHooks()
- onNextActivityCreate { activity ->
- if (config.composerConsole.get()) {
- injectConsole(activity)
+ if (config.composerConsole.get()) {
+ context.inAppOverlay.addCustomComposable {
+ FilledIconButton(
+ onClick = {
+ composerConsole.show()
+ },
+ modifier = Modifier.align(Alignment.TopEnd).padding(top = 100.dp, end = 16.dp)
+ ) {
+ Icon(Icons.Default.BugReport, contentDescription = "Debug Console")
+ }
}
}
diff --git a/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/InAppOverlay.kt b/core/src/main/kotlin/me/rhunk/snapenhance/core/ui/InAppOverlay.kt
@@ -40,6 +40,8 @@ import me.rhunk.snapenhance.core.util.ktx.isDarkTheme
import kotlin.math.roundToInt
import kotlin.random.Random
+typealias CustomComposable = @Composable BoxScope.() -> Unit
+
class InAppOverlay(
private val context: ModContext
) {
@@ -113,6 +115,7 @@ class InAppOverlay(
}
private val toasts = mutableStateListOf<Toast>()
+ private val customComposables = mutableStateListOf<CustomComposable>()
@OptIn(ExperimentalFoundationApi::class)
@Composable
@@ -180,6 +183,10 @@ class InAppOverlay(
}
}
}
+
+ customComposables.forEach {
+ it()
+ }
}
}
@@ -204,6 +211,14 @@ class InAppOverlay(
injectOverlay(activity)
}
+ fun addCustomComposable(composable: CustomComposable) {
+ customComposables.add(composable)
+ }
+
+ fun removeCustomComposable(composable: CustomComposable) {
+ customComposables.remove(composable)
+ }
+
@Composable
private fun DurationProgress(
duration: Int,