@@ -470,58 +470,82 @@ class MainActivity : BaseAppCompatActivity() {
470470 key : String ,
471471 data : String?
472472 ) {
473- when (key) {
474- // 浏览器内打开指定链接
475- " url" -> {
476- if (data != null ) {
477- withContext(Dispatchers .Main ) {
478- this @MainActivity.openLink(data)
473+ runCatching {
474+ when (key) {
475+ // 浏览器内打开指定链接
476+ " url" -> {
477+ data?.let { url ->
478+ val trimmed = url.trim()
479+ // 防止 file://、intent:// 等危险 scheme
480+ if (trimmed.startsWith(" http://" , ignoreCase = true ) ||
481+ trimmed.startsWith(" https://" , ignoreCase = true )
482+ ) {
483+ withContext(Dispatchers .Main ) {
484+ this @MainActivity.openLink(trimmed)
485+ }
486+ } else {
487+ lWarning(" Blocked unsafe URL from homepage event: $trimmed " )
488+ }
479489 }
480490 }
481- }
482- // 检查启动器更新
483- " check_update" -> checkUpdate()
484- // 启动当前选中的游戏版本
485- " launch_game" -> {
486- if (data != null ) {
487- runCatching {
488- val parms = data.split(" =" )
489- if (parms.size == 2 && parms[0 ] == " server" ) {
490- // 指定快速启动的服务器ip
491- val serverIp = parms[1 ].trim()
491+ // 检查启动器更新
492+ " check_update" -> checkUpdate()
493+ // 启动当前选中的游戏版本
494+ " launch_game" -> {
495+ val serverIp = data?.let { raw ->
496+ runCatching {
497+ val parms = raw.split(" =" , limit = 2 )
498+ if (parms.size == 2 && parms[0 ] == " server" ) {
499+ parms[1 ].trim()
500+ } else null
501+ }.onFailure { e ->
502+ lWarning(" Failed to parse quick join server parameters: $raw " , e)
503+ }.getOrNull()
504+ }
505+ if (! serverIp.isNullOrEmpty()) {
506+ // 禁止控制字符与换行,防止注入命令行参数或配置文件
507+ if (serverIp.none { it.code < 32 }) {
492508 launchGameViewModel.tryPlayServer(serverIp)
493- return
509+ } else {
510+ lWarning(" Invalid server address from homepage event: $serverIp " )
494511 }
495- }.onFailure { e ->
496- lWarning( " Failed to parse quick join server parameters: $data " , e )
512+ } else {
513+ launchGameViewModel.tryLaunch( )
497514 }
498515 }
499- launchGameViewModel.tryLaunch()
500- }
501- // 复制指定文本
502- " copy " -> {
503- if (data != null ) {
504- withContext( Dispatchers . Main ) {
505- copyText(
506- null ,
507- data ,
508- this @MainActivity,
509- showToast = true
510- )
516+ // 复制指定文本
517+ " copy " -> {
518+ data?. let { text ->
519+ val trimmed = text.trim()
520+ withContext( Dispatchers . Main ) {
521+ copyText(
522+ null ,
523+ trimmed.take( 10_000 ), // 限制复制内容长度
524+ this @MainActivity ,
525+ showToast = true
526+ )
527+ }
511528 }
512529 }
513- }
514- // 刷新主页
515- " refresh_page" -> homePageViewModel.reloadPage(true )
516- // 分享游戏日志
517- " share_game_log" -> {
518- VersionsManager .currentVersion.value?.let { version ->
519- VersionsManager .getLatestLog(version).takeIf { it.exists() }
520- }?.let { logFile ->
521- logsUploadViewModel.check(logFile)
522- logShareViewModel.openMenu(logFile)
530+ // 刷新主页
531+ " refresh_page" -> homePageViewModel.reloadPage(true )
532+ // 分享游戏日志
533+ " share_game_log" -> {
534+ VersionsManager .currentVersion.value?.let { version ->
535+ VersionsManager .getLatestLog(version).takeIf { it.exists() }
536+ }?.let { logFile ->
537+ withContext(Dispatchers .Main ) {
538+ logsUploadViewModel.check(logFile)
539+ logShareViewModel.openMenu(logFile)
540+ }
541+ }
542+ }
543+ else -> {
544+ lWarning(" Unknown homepage event: key=$key , data=$data " )
523545 }
524546 }
547+ }.onFailure { e ->
548+ lWarning(" Failed to handle homepage event: key=$key , data=$data " , e)
525549 }
526550 }
527551
0 commit comments