MainActivity is exported (launcher requirement) and consumed the session-id extra from any incoming intent without checking the action — a foreign app could launch it explicitly and force-navigate to a chat screen. Guard consumeNotificationIntent() on the app's own notification action and hoist the action string into a shared const so ChatNotificationService and MainActivity can never drift. Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
@@ -18,6 +18,18 @@ import com.m57.hermescontrol.theme.HermesControlTheme
|
|||||||
import com.m57.hermescontrol.util.LocaleContextWrapper
|
import com.m57.hermescontrol.util.LocaleContextWrapper
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* Action that identifies notification-driven "open this chat" intents.
|
||||||
|
* [ChatNotificationService] stamps it on the content intent; the
|
||||||
|
* consumer refuses anything else (issue #832 — MainActivity is
|
||||||
|
* exported as the launcher, so a foreign app could otherwise inject
|
||||||
|
* a session id via an explicit intent).
|
||||||
|
*/
|
||||||
|
const val ACTION_OPEN_CHAT_FROM_NOTIFICATION =
|
||||||
|
"com.m57.hermescontrol.ACTION_OPEN_CHAT_FROM_NOTIFICATION"
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply the user-selected display language before any view is inflated.
|
* Apply the user-selected display language before any view is inflated.
|
||||||
* Reads the persisted code from [AuthManager]; an uninitialized store
|
* Reads the persisted code from [AuthManager]; an uninitialized store
|
||||||
@@ -62,6 +74,9 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun consumeNotificationIntent(intent: Intent?) {
|
private fun consumeNotificationIntent(intent: Intent?) {
|
||||||
|
// Issue #832: MainActivity is exported (launcher requirement) — only
|
||||||
|
// honor intents stamped with our own notification action.
|
||||||
|
if (intent?.action != ACTION_OPEN_CHAT_FROM_NOTIFICATION) return
|
||||||
val sessionId = intent?.getStringExtra(NotificationReplyReceiver.EXTRA_SESSION_ID)
|
val sessionId = intent?.getStringExtra(NotificationReplyReceiver.EXTRA_SESSION_ID)
|
||||||
intent?.removeExtra(NotificationReplyReceiver.EXTRA_SESSION_ID)
|
intent?.removeExtra(NotificationReplyReceiver.EXTRA_SESSION_ID)
|
||||||
sessionId?.takeIf { it.isNotBlank() }?.let(NavigationController::openChatSession)
|
sessionId?.takeIf { it.isNotBlank() }?.let(NavigationController::openChatSession)
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ class ChatNotificationService : Service() {
|
|||||||
private fun buildContentIntent(sessionId: String?): PendingIntent {
|
private fun buildContentIntent(sessionId: String?): PendingIntent {
|
||||||
val intent =
|
val intent =
|
||||||
Intent(this, MainActivity::class.java).apply {
|
Intent(this, MainActivity::class.java).apply {
|
||||||
action = "$packageName.ACTION_OPEN_CHAT_FROM_NOTIFICATION"
|
action = MainActivity.ACTION_OPEN_CHAT_FROM_NOTIFICATION
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
}
|
}
|
||||||
if (!sessionId.isNullOrBlank()) {
|
if (!sessionId.isNullOrBlank()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user