Updated on 2026-08-14

This commit is contained in:
Tangem 2024-12-11 23:52:53 +04:00
parent 1524ae4ce4
commit ff0dffd2dc
5 changed files with 55 additions and 84 deletions

View file

@ -223,7 +223,6 @@ dependencies {
implementation(deps.lottie)
implementation(deps.compose.accompanist.appCompatTheme)
implementation(deps.compose.accompanist.systemUiController)
implementation(deps.compose.accompanist.webView)
implementation(deps.xmlShimmer)
implementation(deps.viewBindingDelegate)
implementation(deps.armadillo)

View file

@ -0,0 +1,30 @@
package com.tangem.core.ui.webview
import android.webkit.WebSettings
import android.webkit.WebView
/**
* Applies set of settings to prevent base security issues
*
[REDACTED_AUTHOR]
*/
fun WebView.applySafeSettings() {
settings.apply {
// disable to use scripts
javaScriptEnabled = false
// disable access to files
allowFileAccess = false
// disable access to content by system content provider
allowContentAccess = false
// disable to use cached data (scripts, files, etc)
cacheMode = WebSettings.LOAD_NO_CACHE
// disable to use local storage
domStorageEnabled = false
}
setDownloadListener(null)
}

View file

@ -1,7 +1,7 @@
package com.tangem.features.disclaimer.impl.ui
import android.annotation.SuppressLint
import android.content.res.Configuration
import android.webkit.WebView
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
@ -14,7 +14,6 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
@ -37,29 +36,22 @@ import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.TestTags.DISCLAIMER_SCREEN_ACCEPT_BUTTON
import com.tangem.core.ui.test.TestTags.DISCLAIMER_SCREEN_CONTAINER
import com.tangem.core.ui.webview.applySafeSettings
import com.tangem.features.disclaimer.impl.R
import com.tangem.features.disclaimer.impl.entity.DisclaimerUM
import com.tangem.features.disclaimer.impl.entity.DummyDisclaimer
import com.tangem.features.disclaimer.impl.local.localTermsOfServices
import com.tangem.features.pushnotifications.api.utils.getPushPermissionOrNull
import java.nio.charset.StandardCharsets
@Composable
internal fun DisclaimerScreen(state: DisclaimerUM) {
val bottomBarHeight = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() }
val bottomPadding = if (state.isTosAccepted) {
bottomBarHeight + TangemTheme.dimens.size16
} else {
bottomBarHeight + TangemTheme.dimens.size64
}
val backgroundColor = if (state.isTosAccepted) TangemTheme.colors.background.primary else TangemColorPalette.Dark6
val (textColor, iconColor) = if (state.isTosAccepted) {
TangemTheme.colors.text.primary1 to TangemTheme.colors.icon.primary1
} else {
TangemColorPalette.Light4 to TangemColorPalette.Light4
}
val bottomPadding = bottomBarHeight + TangemTheme.dimens.size16
Box(
modifier = Modifier
.background(backgroundColor)
.background(TangemTheme.colors.background.primary)
.statusBarsPadding()
.testTag(DISCLAIMER_SCREEN_CONTAINER),
) {
@ -75,14 +67,15 @@ internal fun DisclaimerScreen(state: DisclaimerUM) {
onIconClicked = state.popBack,
).takeIf { state.isTosAccepted },
titleAlignment = Alignment.CenterHorizontally,
textColor = textColor,
iconTint = iconColor,
)
DisclaimerContent(state.url, state.isTosAccepted)
DisclaimerContent(state.url)
}
if (!state.isTosAccepted) {
BottomFade(Modifier.align(Alignment.BottomCenter), backgroundColor = backgroundColor)
BottomFade(
modifier = Modifier.align(Alignment.BottomCenter),
backgroundColor = TangemTheme.colors.background.primary,
)
DisclaimerButton(state.onAccept)
} else {
NavigationBar3ButtonsScrim()
@ -90,14 +83,14 @@ internal fun DisclaimerScreen(state: DisclaimerUM) {
}
}
@SuppressLint("SetJavaScriptEnabled")
@Composable
private fun DisclaimerContent(url: String, isTosAccepted: Boolean) {
val backgroundColor = if (isTosAccepted) TangemTheme.colors.background.primary else TangemColorPalette.Dark6
private fun DisclaimerContent(url: String) {
val webViewStateUrl = rememberWebViewState(url)
val webViewStateData =
rememberWebViewStateWithHTMLData(data = localTermsOfServices, mimeType = "text/html", encoding = "UTF-8")
val webViewStateData = rememberWebViewStateWithHTMLData(
data = localTermsOfServices,
mimeType = "text/html",
encoding = StandardCharsets.UTF_8.name(),
)
val webViewState by remember {
derivedStateOf {
@ -113,12 +106,10 @@ private fun DisclaimerContent(url: String, isTosAccepted: Boolean) {
WebView(
state = webViewState,
captureBackPresses = false,
onCreated = {
it.settings.javaScriptEnabled = !isTosAccepted
it.setBackgroundColor(backgroundColor.toArgb())
},
client = remember { DisclaimerWebViewClient() },
modifier = Modifier.fillMaxSize(),
onCreated = WebView::applySafeSettings,
modifier = Modifier
.fillMaxSize()
.background(TangemTheme.colors.background.primary),
)
AnimatedVisibility(
@ -128,12 +119,12 @@ private fun DisclaimerContent(url: String, isTosAccepted: Boolean) {
exit = fadeOut(),
modifier = Modifier
.fillMaxSize()
.background(backgroundColor),
.background(TangemTheme.colors.background.primary),
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(backgroundColor),
.background(TangemTheme.colors.background.primary),
) {
CircularProgressIndicator(
color = TangemTheme.colors.icon.informative,

View file

@ -1,45 +0,0 @@
package com.tangem.features.disclaimer.impl.ui
import android.graphics.Bitmap
import android.webkit.WebView
import com.google.accompanist.web.AccompanistWebViewClient
internal enum class ProgressState {
Loading,
Done,
Error,
}
/**
* Workaround to display web view with ToS only in dark theme
*/
private fun WebView.injectCSS() {
val code = "javascript:(function() {" +
"var node = document.createElement('style');" +
"node.type = 'text/css';" +
" node.innerHTML = 'body, label,th,p,a, td, tr,li,ul,span,table,h1,h2,h3,h4,h5,h6,h7,div,small {" +
" color: #C9C9C9;" +
"background-color: #1E1E1E;" +
" } ';" +
" document.head.appendChild(node);})();"
evaluateJavascript(code, null)
}
internal class DisclaimerWebViewClient : AccompanistWebViewClient() {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
view?.injectCSS()
super.onPageStarted(view, url, favicon)
}
override fun onPageCommitVisible(view: WebView?, url: String?) {
view?.injectCSS()
super.onPageCommitVisible(view, url)
}
override fun onPageFinished(view: WebView?, url: String?) {
view?.injectCSS()
super.onPageFinished(view, url)
}
}

View file

@ -20,6 +20,7 @@ import com.google.accompanist.web.rememberWebViewState
import com.tangem.core.ui.components.appbar.TangemTopAppBar
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.webview.applySafeSettings
import com.tangem.feature.referral.presentation.R
/**
@ -50,12 +51,7 @@ private fun AgreementHtmlView(url: String) {
modifier = Modifier.background(TangemTheme.colors.background.primary),
captureBackPresses = false,
onCreated = {
if (!isInPreviewMode) {
it.settings.apply {
javaScriptEnabled = false
allowFileAccess = false
}
}
if (!isInPreviewMode) it.applySafeSettings()
},
)
}