Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:56:56 +01:00
parent 75dc487a7a
commit 39c29d175b
6317 changed files with 388324 additions and 2 deletions

View file

@ -0,0 +1,19 @@
plugins {
id(ThunderbirdPlugins.Library.androidCompose)
}
android {
namespace = "app.k9mail.feature.account.server.certificate"
resourcePrefix = "account_server_certificate_"
}
dependencies {
implementation(projects.core.ui.compose.designsystem)
implementation(projects.core.common)
implementation(projects.feature.account.common)
implementation(projects.mail.common)
implementation(libs.okio)
testImplementation(projects.core.ui.compose.testing)
}

View file

@ -0,0 +1,49 @@
package app.k9mail.feature.account.server.certificate.ui
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.rememberScrollState
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import app.k9mail.core.ui.compose.common.koin.koinPreview
import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme
import app.k9mail.feature.account.server.certificate.domain.entity.FormattedServerCertificateError
import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertificateProperties
import okio.ByteString.Companion.decodeHex
@Composable
@Preview(showBackground = true)
internal fun ServerCertificateErrorContentPreview() {
val state = ServerCertificateErrorContract.State(
isShowServerCertificate = true,
certificateError = FormattedServerCertificateError(
hostname = "mail.domain.example",
serverCertificateProperties = ServerCertificateProperties(
subjectAlternativeNames = listOf("*.domain.example", "domain.example"),
notValidBefore = "January 1, 2023, 12:00 AM",
notValidAfter = "December 31, 2023, 11:59 PM",
subject = "CN=*.domain.example",
issuer = "CN=test, O=MZLA",
fingerprintSha1 = "33ab5639bfd8e7b95eb1d8d0b87781d4ffea4d5d".decodeHex(),
fingerprintSha256 = "1894a19c85ba153acbf743ac4e43fc004c891604b26f8c69e1e83ea2afc7c48f".decodeHex(),
fingerprintSha512 = (
"81381f1dacd4824a6c503fd07057763099c12b8309d0abcec4000c9060cbbfa6" +
"7988b2ada669ab4837fcd3d4ea6e2b8db2b9da9197d5112fb369fd006da545de"
).decodeHex(),
),
),
)
koinPreview {
factory<ServerNameFormatter> { DefaultServerNameFormatter() }
factory<FingerprintFormatter> { DefaultFingerprintFormatter() }
} WithContent {
PreviewWithTheme {
ServerCertificateErrorContent(
innerPadding = PaddingValues(all = 0.dp),
state = state,
scrollState = rememberScrollState(),
)
}
}
}

View file

@ -0,0 +1,74 @@
package app.k9mail.feature.account.server.certificate.ui
import androidx.compose.runtime.Composable
import app.k9mail.core.ui.compose.common.annotation.PreviewDevices
import app.k9mail.core.ui.compose.common.koin.koinPreview
import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme
import app.k9mail.feature.account.server.certificate.data.InMemoryServerCertificateErrorRepository
import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertificateError
import app.k9mail.feature.account.server.certificate.domain.usecase.FormatServerCertificateError
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
@Composable
@PreviewDevices
internal fun ServerCertificateErrorScreenPreview() {
val inputStream = """
-----BEGIN CERTIFICATE-----
MIIE8jCCA9qgAwIBAgISA3bsPKY1eoe/RiBO2t8fUvh1MA0GCSqGSIb3DQEBCwUA
MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
EwJSMzAeFw0yMzA3MjEyMDU1MTJaFw0yMzEwMTkyMDU1MTFaMBcxFTATBgNVBAMM
DCouYmFkc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJgw
o/dYmPaujmm7sqIuZCe5/kyMwDYKo/pWeeXSvQxRXhxiVvd2Xu9PG0ZXW2R0xOSr
BpaRWm6MXxEnNqNr+n22j9US6M62zJpcuU4tQ0J8xRyIGL6rM53z59rEnCdkF9HQ
+7y7PBlVXCm0jrw51h3Bg5qryvTFyimIbqGw0UJhM7m/NaVJWZyBRwHp7emXxRJC
kC7pdX462c+m/7rQ06iohqUt6mf0DkUH1QjpaVbZm8CBs/GSiLB3LdMHj1uvrXgH
z8dp0nQ3eVRCjuD1xVcZnFoeEa/W3a9ZdcBj1phr9XOwaqYMeAv64g2w40G6fXMH
9DpHuFarRtleQusiPAMCAwEAAaOCAhswggIXMA4GA1UdDwEB/wQEAwIFoDAdBgNV
HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4E
FgQU1M4J2vX/9DWJnsAtofmT+94js/YwHwYDVR0jBBgwFoAUFC6zF7dYVsuuUAlA
5h+vnYsUwsYwVQYIKwYBBQUHAQEESTBHMCEGCCsGAQUFBzABhhVodHRwOi8vcjMu
by5sZW5jci5vcmcwIgYIKwYBBQUHMAKGFmh0dHA6Ly9yMy5pLmxlbmNyLm9yZy8w
IwYDVR0RBBwwGoIMKi5iYWRzc2wuY29tggpiYWRzc2wuY29tMBMGA1UdIAQMMAow
CAYGZ4EMAQIBMIIBBQYKKwYBBAHWeQIEAgSB9gSB8wDxAHYAtz77JN+cTbp18jnF
ulj0bF38Qs96nzXEnh0JgSXttJkAAAGJenMebAAABAMARzBFAiAH7A3OWC1AKOcO
jsOP39nzkyoIdrwYFHOOW1qKkLrk9gIhAJD0xFn5FwJvag3K6mTXAlW1EvIy9joA
okiPniKVBIztAHcAejKMVNi3LbYg6jjgUh7phBZwMhOFTTvSK8E6V6NS61IAAAGJ
enMehwAABAMASDBGAiEAvRyLnINSJQ0WyfcU8L0PY5z7//Gq8P9i2HJvZJvnfBkC
IQCHslQMJaOg+rn9+2WW4KKgYW/yDrvBbiVABW5CcYWR0DANBgkqhkiG9w0BAQsF
AAOCAQEAB/JpXHqRnGmCFz3f0hx7mJYY/auSNWnOgpdRpc3JXzcOHHUd+569UGtu
TSMAFEGNXYTbXrG52iGBCrdfe1kkRokg7/KtUvFRelkoNt4FN/4/zVjBxINXVIMb
/7toq4OxBF/sz4SU+eXanmwJyOMmNQzM94zqDwrEmMNuNLYshdWn7XyJCXIM4X+6
8M/anh/pi2AviLHH9pszkeuH3AjGJR68cPf+QKC4XcFloR08fhx0jKl8LBa4A6Nm
o7IlPgdD9rzZCsbYe+VNBQWY3358u7ifOJG8r2jXzyHKgUC+OBXgz3kjrClzJfl1
pjcJhNU1UQtIVERwmxI9F5oQqUyxvA==
-----END CERTIFICATE-----
""".trimIndent().byteInputStream()
val certificateFactory = CertificateFactory.getInstance("X.509")
val certificate = certificateFactory.generateCertificate(inputStream) as X509Certificate
val serverCertificateError = ServerCertificateError(
hostname = "mail.domain.example",
port = 143,
certificateChain = listOf(certificate),
)
koinPreview {
factory<ServerNameFormatter> { DefaultServerNameFormatter() }
factory<FingerprintFormatter> { DefaultFingerprintFormatter() }
} WithContent {
PreviewWithTheme {
ServerCertificateErrorScreen(
onCertificateAccepted = {},
onBack = {},
viewModel = ServerCertificateErrorViewModel(
addServerCertificateException = { _, _, _ -> },
certificateErrorRepository = InMemoryServerCertificateErrorRepository(serverCertificateError),
formatServerCertificateError = FormatServerCertificateError(),
initialState = ServerCertificateErrorContract.State(isShowServerCertificate = false),
),
)
}
}
}

View file

@ -0,0 +1,41 @@
package app.k9mail.feature.account.server.certificate.ui
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import app.k9mail.core.ui.compose.common.koin.koinPreview
import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme
import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertificateProperties
import okio.ByteString.Companion.decodeHex
@Composable
@Preview(showBackground = true)
internal fun ServerCertificateViewPreview() {
val serverCertificateProperties = ServerCertificateProperties(
subjectAlternativeNames = listOf(
"*.domain.example",
"domain.example",
"quite.the.long.domain.name.that.hopefully.exceeds.the.available.width.example",
),
notValidBefore = "January 1, 2023, 12:00 AM",
notValidAfter = "December 31, 2023, 11:59 PM",
subject = "CN=*.domain.example",
issuer = "CN=test, O=MZLA",
fingerprintSha1 = "33ab5639bfd8e7b95eb1d8d0b87781d4ffea4d5d".decodeHex(),
fingerprintSha256 = "1894a19c85ba153acbf743ac4e43fc004c891604b26f8c69e1e83ea2afc7c48f".decodeHex(),
fingerprintSha512 = (
"81381f1dacd4824a6c503fd07057763099c12b8309d0abcec4000c9060cbbfa6" +
"7988b2ada669ab4837fcd3d4ea6e2b8db2b9da9197d5112fb369fd006da545de"
).decodeHex(),
)
koinPreview {
factory<ServerNameFormatter> { DefaultServerNameFormatter() }
factory<FingerprintFormatter> { DefaultFingerprintFormatter() }
} WithContent {
PreviewWithTheme {
ServerCertificateView(
serverCertificateProperties = serverCertificateProperties,
)
}
}
}

View file

@ -0,0 +1,43 @@
package app.k9mail.feature.account.server.certificate
import app.k9mail.feature.account.server.certificate.data.InMemoryServerCertificateErrorRepository
import app.k9mail.feature.account.server.certificate.domain.ServerCertificateDomainContract
import app.k9mail.feature.account.server.certificate.domain.usecase.AddServerCertificateException
import app.k9mail.feature.account.server.certificate.domain.usecase.FormatServerCertificateError
import app.k9mail.feature.account.server.certificate.ui.DefaultFingerprintFormatter
import app.k9mail.feature.account.server.certificate.ui.DefaultServerNameFormatter
import app.k9mail.feature.account.server.certificate.ui.FingerprintFormatter
import app.k9mail.feature.account.server.certificate.ui.ServerCertificateErrorViewModel
import app.k9mail.feature.account.server.certificate.ui.ServerNameFormatter
import org.koin.core.module.Module
import org.koin.core.module.dsl.viewModel
import org.koin.dsl.module
val featureAccountServerCertificateModule: Module = module {
single<ServerCertificateDomainContract.ServerCertificateErrorRepository> {
InMemoryServerCertificateErrorRepository()
}
factory<ServerCertificateDomainContract.UseCase.AddServerCertificateException> {
AddServerCertificateException(
localKeyStore = get(),
)
}
factory<ServerCertificateDomainContract.UseCase.FormatServerCertificateError> {
FormatServerCertificateError()
}
factory<ServerNameFormatter> { DefaultServerNameFormatter() }
factory<FingerprintFormatter> { DefaultFingerprintFormatter() }
viewModel {
ServerCertificateErrorViewModel(
certificateErrorRepository = get(),
addServerCertificateException = get(),
formatServerCertificateError = get(),
)
}
}

View file

@ -0,0 +1,21 @@
package app.k9mail.feature.account.server.certificate.data
import app.k9mail.feature.account.server.certificate.domain.ServerCertificateDomainContract
import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertificateError
class InMemoryServerCertificateErrorRepository(
private var serverCertificateError: ServerCertificateError? = null,
) : ServerCertificateDomainContract.ServerCertificateErrorRepository {
override fun getCertificateError(): ServerCertificateError? {
return serverCertificateError
}
override fun setCertificateError(serverCertificateError: ServerCertificateError) {
this.serverCertificateError = serverCertificateError
}
override fun clearCertificateError() {
serverCertificateError = null
}
}

View file

@ -0,0 +1,26 @@
package app.k9mail.feature.account.server.certificate.domain
import app.k9mail.feature.account.server.certificate.domain.entity.FormattedServerCertificateError
import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertificateError
import java.security.cert.X509Certificate
interface ServerCertificateDomainContract {
interface ServerCertificateErrorRepository {
fun getCertificateError(): ServerCertificateError?
fun setCertificateError(serverCertificateError: ServerCertificateError)
fun clearCertificateError()
}
interface UseCase {
fun interface AddServerCertificateException {
suspend fun addCertificate(hostname: String, port: Int, certificate: X509Certificate?)
}
fun interface FormatServerCertificateError {
operator fun invoke(serverCertificateError: ServerCertificateError): FormattedServerCertificateError
}
}
}

View file

@ -0,0 +1,6 @@
package app.k9mail.feature.account.server.certificate.domain.entity
data class FormattedServerCertificateError(
val hostname: String,
val serverCertificateProperties: ServerCertificateProperties,
)

View file

@ -0,0 +1,9 @@
package app.k9mail.feature.account.server.certificate.domain.entity
import java.security.cert.X509Certificate
data class ServerCertificateError(
val hostname: String,
val port: Int,
val certificateChain: List<X509Certificate>,
)

View file

@ -0,0 +1,14 @@
package app.k9mail.feature.account.server.certificate.domain.entity
import okio.ByteString
data class ServerCertificateProperties(
val subjectAlternativeNames: List<String>,
val notValidBefore: String,
val notValidAfter: String,
val subject: String,
val issuer: String,
val fingerprintSha1: ByteString,
val fingerprintSha256: ByteString,
val fingerprintSha512: ByteString,
)

View file

@ -0,0 +1,19 @@
package app.k9mail.feature.account.server.certificate.domain.usecase
import app.k9mail.feature.account.server.certificate.domain.ServerCertificateDomainContract.UseCase
import com.fsck.k9.mail.ssl.LocalKeyStore
import java.security.cert.X509Certificate
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
internal class AddServerCertificateException(
private val localKeyStore: LocalKeyStore,
private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO,
) : UseCase.AddServerCertificateException {
override suspend fun addCertificate(hostname: String, port: Int, certificate: X509Certificate?) {
withContext(coroutineDispatcher) {
localKeyStore.addCertificate(hostname, port, certificate)
}
}
}

View file

@ -0,0 +1,75 @@
package app.k9mail.feature.account.server.certificate.domain.usecase
import app.k9mail.feature.account.server.certificate.domain.ServerCertificateDomainContract.UseCase
import app.k9mail.feature.account.server.certificate.domain.entity.FormattedServerCertificateError
import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertificateError
import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertificateProperties
import java.security.cert.X509Certificate
import java.text.DateFormat
import java.util.Date
import kotlin.time.ExperimentalTime
import kotlin.time.Instant
import okio.ByteString
import okio.HashingSink
import okio.blackholeSink
import okio.buffer
@OptIn(ExperimentalTime::class)
class FormatServerCertificateError(
private val dateFormat: DateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT),
) : UseCase.FormatServerCertificateError {
override operator fun invoke(serverCertificateError: ServerCertificateError): FormattedServerCertificateError {
val certificate = serverCertificateError.certificateChain.firstOrNull()
?: error("Certificate chain must not be empty")
val notValidBeforeInstant = Instant.fromEpochMilliseconds(certificate.notBefore.time)
val notValidAfterInstant = Instant.fromEpochMilliseconds(certificate.notAfter.time)
val subjectAlternativeNames = certificate.subjectAlternativeNames.orEmpty().map { it[1].toString() }
val notValidBefore = dateFormat.format(Date(notValidBeforeInstant.toEpochMilliseconds()))
val notValidAfter = dateFormat.format(Date(notValidAfterInstant.toEpochMilliseconds()))
// TODO: Parse the name to be able to display the components in a more structured way.
val subject = certificate.subjectX500Principal.toString()
val issuer = certificate.issuerX500Principal.toString()
val fingerprintSha1 = computeFingerprint(certificate, HashAlgorithm.SHA_1)
val fingerprintSha256 = computeFingerprint(certificate, HashAlgorithm.SHA_256)
val fingerprintSha512 = computeFingerprint(certificate, HashAlgorithm.SHA_512)
return FormattedServerCertificateError(
hostname = serverCertificateError.hostname,
serverCertificateProperties = ServerCertificateProperties(
subjectAlternativeNames,
notValidBefore,
notValidAfter,
subject,
issuer,
fingerprintSha1,
fingerprintSha256,
fingerprintSha512,
),
)
}
private fun computeFingerprint(certificate: X509Certificate, algorithm: HashAlgorithm): ByteString {
val sink = when (algorithm) {
HashAlgorithm.SHA_1 -> HashingSink.sha1(blackholeSink())
HashAlgorithm.SHA_256 -> HashingSink.sha256(blackholeSink())
HashAlgorithm.SHA_512 -> HashingSink.sha512(blackholeSink())
}
sink.buffer()
.write(certificate.encoded)
.flush()
return sink.hash
}
}
private enum class HashAlgorithm {
SHA_1,
SHA_256,
SHA_512,
}

View file

@ -0,0 +1,50 @@
package app.k9mail.feature.account.server.certificate.ui
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.withStyle
import okio.ByteString
/**
* Format a certificate fingerprint.
*
* Outputs bytes as hexadecimal number, separated by `:`. Includes zero width space (U+200B) after colons to decrease
* the chance of long lines being displayed with a line break in the middle of a byte.
*/
internal fun interface FingerprintFormatter {
fun format(fingerprint: ByteString, separatorColor: Color): AnnotatedString
}
internal class DefaultFingerprintFormatter : FingerprintFormatter {
override fun format(fingerprint: ByteString, separatorColor: Color): AnnotatedString {
require(fingerprint.size > 0)
return buildAnnotatedString {
appendByteAsHexNumber(fingerprint[0])
for (i in 1 until fingerprint.size) {
appendSeparator(separatorColor)
appendByteAsHexNumber(fingerprint[i])
}
}
}
@OptIn(ExperimentalStdlibApi::class)
private fun AnnotatedString.Builder.appendByteAsHexNumber(byte: Byte) {
withStyle(SpanStyle(fontFamily = FontFamily.Monospace)) {
append(byte.toHexString(format = HexFormat.UpperCase))
}
}
private fun AnnotatedString.Builder.appendSeparator(separatorColor: Color) {
withStyle(style = SpanStyle(color = separatorColor)) {
append(":")
}
// Zero width space so long lines will be broken here and not in the middle of a byte value
append('\u200B')
}
}

View file

@ -0,0 +1,108 @@
package app.k9mail.feature.account.server.certificate.ui
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import app.k9mail.core.ui.compose.common.baseline.withBaseline
import app.k9mail.core.ui.compose.common.resources.annotatedStringResource
import app.k9mail.core.ui.compose.common.text.bold
import app.k9mail.core.ui.compose.designsystem.atom.icon.Icon
import app.k9mail.core.ui.compose.designsystem.atom.icon.IconsWithBaseline
import app.k9mail.core.ui.compose.designsystem.atom.text.TextBodyLarge
import app.k9mail.core.ui.compose.designsystem.atom.text.TextHeadlineMedium
import app.k9mail.core.ui.compose.designsystem.atom.text.TextTitleMedium
import app.k9mail.core.ui.compose.designsystem.template.ResponsiveWidthContainer
import app.k9mail.core.ui.compose.theme2.MainTheme
import app.k9mail.feature.account.server.certificate.R
import app.k9mail.feature.account.server.certificate.domain.entity.FormattedServerCertificateError
import app.k9mail.feature.account.server.certificate.ui.ServerCertificateErrorContract.State
import org.koin.compose.koinInject
@Composable
internal fun ServerCertificateErrorContent(
innerPadding: PaddingValues,
state: State,
scrollState: ScrollState,
) {
ResponsiveWidthContainer(modifier = Modifier.padding(innerPadding)) { contentPadding ->
Column(
modifier = Modifier.verticalScroll(scrollState).padding(contentPadding),
) {
CertificateErrorOverview(state)
AnimatedContent(
targetState = state.isShowServerCertificate,
label = "ServerCertificateViewVisibility",
) { isShowServerCertificate ->
if (isShowServerCertificate) {
ServerCertificateView(
serverCertificateProperties = state.certificateError!!.serverCertificateProperties,
)
}
}
}
}
}
@Composable
private fun CertificateErrorOverview(state: State) {
Column(
modifier = Modifier.padding(all = MainTheme.spacings.double),
) {
WarningTitle()
TextTitleMedium(stringResource(R.string.account_server_certificate_unknown_error_subtitle))
Spacer(modifier = Modifier.height(MainTheme.spacings.quadruple))
state.certificateError?.let { certificateError ->
CertificateErrorDescription(certificateError)
}
}
}
@Composable
private fun WarningTitle() {
Row {
val warningIcon = IconsWithBaseline.Filled.warning
val iconSize = MainTheme.sizes.medium
val iconScalingFactor = iconSize / warningIcon.image.defaultHeight
val iconBaseline = warningIcon.baseline * iconScalingFactor
Icon(
imageVector = warningIcon.image,
tint = MainTheme.colors.warning,
modifier = Modifier
.padding(end = MainTheme.spacings.default)
.requiredSize(iconSize)
.withBaseline(iconBaseline)
.alignByBaseline(),
)
TextHeadlineMedium(
text = stringResource(R.string.account_server_certificate_warning_title),
modifier = Modifier.alignByBaseline(),
)
}
}
@Composable
private fun CertificateErrorDescription(
certificateError: FormattedServerCertificateError,
serverNameFormatter: ServerNameFormatter = koinInject(),
) {
TextBodyLarge(
text = annotatedStringResource(
id = R.string.account_server_certificate_unknown_error_description_format,
serverNameFormatter.format(certificateError.hostname).bold(),
),
)
}

View file

@ -0,0 +1,25 @@
package app.k9mail.feature.account.server.certificate.ui
import app.k9mail.core.ui.compose.common.mvi.UnidirectionalViewModel
import app.k9mail.feature.account.server.certificate.domain.entity.FormattedServerCertificateError
interface ServerCertificateErrorContract {
interface ViewModel : UnidirectionalViewModel<State, Event, Effect>
data class State(
val isShowServerCertificate: Boolean = false,
val certificateError: FormattedServerCertificateError? = null,
)
sealed interface Event {
data object OnShowAdvancedClicked : Event
data object OnCertificateAcceptedClicked : Event
data object OnBackClicked : Event
}
sealed interface Effect {
data object NavigateCertificateAccepted : Effect
data object NavigateBack : Effect
}
}

View file

@ -0,0 +1,120 @@
package app.k9mail.feature.account.server.certificate.ui
import androidx.activity.compose.BackHandler
import androidx.compose.animation.Crossfade
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import app.k9mail.core.ui.compose.common.mvi.observe
import app.k9mail.core.ui.compose.designsystem.atom.Surface
import app.k9mail.core.ui.compose.designsystem.atom.button.ButtonFilled
import app.k9mail.core.ui.compose.designsystem.atom.button.ButtonOutlined
import app.k9mail.core.ui.compose.designsystem.template.ResponsiveWidthContainer
import app.k9mail.core.ui.compose.designsystem.template.Scaffold
import app.k9mail.core.ui.compose.theme2.MainTheme
import app.k9mail.feature.account.server.certificate.R
import app.k9mail.feature.account.server.certificate.ui.ServerCertificateErrorContract.Effect
import app.k9mail.feature.account.server.certificate.ui.ServerCertificateErrorContract.Event
import app.k9mail.feature.account.server.certificate.ui.ServerCertificateErrorContract.State
import app.k9mail.feature.account.server.certificate.ui.ServerCertificateErrorContract.ViewModel
import org.koin.androidx.compose.koinViewModel
@Composable
fun ServerCertificateErrorScreen(
onCertificateAccepted: () -> Unit,
onBack: () -> Unit,
modifier: Modifier = Modifier,
viewModel: ViewModel = koinViewModel<ServerCertificateErrorViewModel>(),
) {
val scrollState = rememberScrollState()
val (state, dispatch) = viewModel.observe { effect ->
when (effect) {
is Effect.NavigateCertificateAccepted -> onCertificateAccepted()
is Effect.NavigateBack -> onBack()
}
}
BackHandler {
dispatch(Event.OnBackClicked)
}
Scaffold(
bottomBar = {
ButtonBar(
state = state.value,
dispatch = dispatch,
scrollState = scrollState,
)
},
modifier = modifier,
) { innerPadding ->
ServerCertificateErrorContent(
innerPadding = innerPadding,
state = state.value,
scrollState = scrollState,
)
}
}
@Composable
private fun ButtonBar(
state: State,
dispatch: (Event) -> Unit,
scrollState: ScrollState,
) {
val elevation by animateDpAsState(
targetValue = if (scrollState.canScrollForward) 8.dp else 0.dp,
label = "BottomBarElevation",
)
Surface(
tonalElevation = elevation,
) {
ResponsiveWidthContainer(
modifier = Modifier
.padding(
start = MainTheme.spacings.double,
end = MainTheme.spacings.double,
top = MainTheme.spacings.half,
bottom = MainTheme.spacings.half,
),
) { contentPadding ->
Column(modifier = Modifier.animateContentSize().padding(contentPadding)) {
ButtonFilled(
text = stringResource(R.string.account_server_certificate_button_back),
onClick = { dispatch(Event.OnBackClicked) },
modifier = Modifier.fillMaxWidth(),
)
Crossfade(
targetState = state.isShowServerCertificate,
label = "ContinueButton",
) { isShowServerCertificate ->
if (isShowServerCertificate) {
ButtonOutlined(
text = stringResource(R.string.account_server_certificate_button_continue),
onClick = { dispatch(Event.OnCertificateAcceptedClicked) },
modifier = Modifier.fillMaxWidth(),
)
} else {
ButtonOutlined(
text = stringResource(R.string.account_server_certificate_button_advanced),
onClick = { dispatch(Event.OnShowAdvancedClicked) },
modifier = Modifier.fillMaxWidth(),
)
}
}
}
}
}
}

View file

@ -0,0 +1,67 @@
package app.k9mail.feature.account.server.certificate.ui
import androidx.lifecycle.viewModelScope
import app.k9mail.core.ui.compose.common.mvi.BaseViewModel
import app.k9mail.feature.account.server.certificate.domain.ServerCertificateDomainContract
import app.k9mail.feature.account.server.certificate.domain.ServerCertificateDomainContract.UseCase
import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertificateError
import app.k9mail.feature.account.server.certificate.ui.ServerCertificateErrorContract.Effect
import app.k9mail.feature.account.server.certificate.ui.ServerCertificateErrorContract.Event
import app.k9mail.feature.account.server.certificate.ui.ServerCertificateErrorContract.State
import kotlinx.coroutines.launch
class ServerCertificateErrorViewModel(
private val certificateErrorRepository: ServerCertificateDomainContract.ServerCertificateErrorRepository,
private val addServerCertificateException: UseCase.AddServerCertificateException,
private val formatServerCertificateError: UseCase.FormatServerCertificateError,
initialState: State = State(),
) : BaseViewModel<State, Event, Effect>(initialState), ServerCertificateErrorContract.ViewModel {
private val serverCertificateError: ServerCertificateError? = certificateErrorRepository.getCertificateError()
init {
serverCertificateError?.let { serverCertificateError ->
updateState {
it.copy(
certificateError = formatServerCertificateError(serverCertificateError),
)
}
}
}
override fun event(event: Event) {
when (event) {
Event.OnShowAdvancedClicked -> showAdvanced()
Event.OnCertificateAcceptedClicked -> acceptCertificate()
Event.OnBackClicked -> navigateBack()
}
}
private fun showAdvanced() {
updateState {
it.copy(isShowServerCertificate = true)
}
}
private fun acceptCertificate() {
val certificateError = requireNotNull(serverCertificateError)
viewModelScope.launch {
addServerCertificateException.addCertificate(
hostname = certificateError.hostname,
port = certificateError.port,
certificate = certificateError.certificateChain.first(),
)
certificateErrorRepository.clearCertificateError()
navigateCertificateAccepted()
}
}
private fun navigateBack() {
emitEffect(Effect.NavigateBack)
}
private fun navigateCertificateAccepted() {
emitEffect(Effect.NavigateCertificateAccepted)
}
}

View file

@ -0,0 +1,103 @@
package app.k9mail.feature.account.server.certificate.ui
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import app.k9mail.core.ui.compose.designsystem.atom.text.TextBodyLarge
import app.k9mail.core.ui.compose.designsystem.atom.text.TextLabelSmall
import app.k9mail.core.ui.compose.designsystem.atom.text.TextTitleLarge
import app.k9mail.core.ui.compose.designsystem.atom.text.TextTitleSmall
import app.k9mail.core.ui.compose.theme2.MainTheme
import app.k9mail.feature.account.server.certificate.R
import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertificateProperties
import okio.ByteString
import org.koin.compose.koinInject
@Composable
internal fun ServerCertificateView(
serverCertificateProperties: ServerCertificateProperties,
modifier: Modifier = Modifier,
serverNameFormatter: ServerNameFormatter = koinInject(),
fingerprintFormatter: FingerprintFormatter = koinInject(),
) {
Column(
modifier = modifier.padding(
start = MainTheme.spacings.double,
end = MainTheme.spacings.double,
top = MainTheme.spacings.double,
),
) {
TextTitleLarge(stringResource(R.string.account_server_certificate_section_title))
Spacer(modifier = Modifier.height(MainTheme.spacings.double))
if (serverCertificateProperties.subjectAlternativeNames.isNotEmpty()) {
TextTitleSmall(stringResource(R.string.account_server_certificate_subject_alternative_names))
for (subjectAlternativeName in serverCertificateProperties.subjectAlternativeNames) {
BulletedListItem(serverNameFormatter.format(subjectAlternativeName))
}
Spacer(modifier = Modifier.height(MainTheme.spacings.double))
}
TextTitleSmall(stringResource(R.string.account_server_certificate_not_valid_before))
TextBodyLarge(text = serverCertificateProperties.notValidBefore)
Spacer(modifier = Modifier.height(MainTheme.spacings.default))
TextTitleSmall(stringResource(R.string.account_server_certificate_not_valid_after))
TextBodyLarge(text = serverCertificateProperties.notValidAfter)
Spacer(modifier = Modifier.height(MainTheme.spacings.double))
TextTitleSmall(stringResource(R.string.account_server_certificate_subject))
TextBodyLarge(text = serverCertificateProperties.subject)
Spacer(modifier = Modifier.height(MainTheme.spacings.double))
TextTitleSmall(stringResource(R.string.account_server_certificate_issuer))
TextBodyLarge(text = serverCertificateProperties.issuer)
Spacer(modifier = Modifier.height(MainTheme.spacings.double))
TextLabelSmall(text = stringResource(R.string.account_server_certificate_fingerprints_section))
Spacer(modifier = Modifier.height(MainTheme.spacings.default))
Fingerprint("SHA-1", serverCertificateProperties.fingerprintSha1, fingerprintFormatter)
Fingerprint("SHA-256", serverCertificateProperties.fingerprintSha256, fingerprintFormatter)
Fingerprint("SHA-512", serverCertificateProperties.fingerprintSha512, fingerprintFormatter)
}
}
@Composable
private fun Fingerprint(
title: String,
fingerprint: ByteString,
fingerprintFormatter: FingerprintFormatter,
) {
val formattedFingerprint = fingerprintFormatter.format(
fingerprint,
separatorColor = MainTheme.colors.onSurfaceVariant,
)
Column {
TextTitleSmall(text = title)
TextBodyLarge(text = formattedFingerprint)
Spacer(modifier = Modifier.height(MainTheme.spacings.double))
}
}
@Composable
private fun BulletedListItem(text: String) {
Row {
TextBodyLarge(
text = "\u2022",
modifier = Modifier.padding(horizontal = MainTheme.spacings.half),
)
TextBodyLarge(text = text)
}
}

View file

@ -0,0 +1,32 @@
package app.k9mail.feature.account.server.certificate.ui
import net.thunderbird.core.common.net.HostNameUtils
/**
* Format a hostname or IP address for display.
*
* Inserts zero width space (U+200B) after components separators to decrease the chance of long lines being displayed
* with a line break in the middle of a component (DNS label or number component of an IP address).
*/
internal fun interface ServerNameFormatter {
fun format(hostname: String): String
}
internal class DefaultServerNameFormatter : ServerNameFormatter {
override fun format(hostname: String): String {
val address = HostNameUtils.isLegalIPv6Address(hostname)
return if (address != null) {
formatIPv6Address(address)
} else {
formatDotName(hostname)
}
}
private fun formatIPv6Address(address: String): String {
return address.replace(":", ":\u200B")
}
private fun formatDotName(hostname: String): String {
return hostname.replace(".", ".\u200B")
}
}

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">تحذير</string>
<string name="account_server_certificate_unknown_error_subtitle">خطأ في الشهادة</string>
<string name="account_server_certificate_button_back">العودة إلى الوراء (يستحسن)</string>
<string name="account_server_certificate_button_advanced">متقدم</string>
<string name="account_server_certificate_button_continue">قبول المخاطرة والمتابعة</string>
<string name="account_server_certificate_section_title">شهادة الخادم</string>
<string name="account_server_certificate_not_valid_before">ليست صالحة قبل</string>
<string name="account_server_certificate_not_valid_after">ليست صالحة بعد</string>
<string name="account_server_certificate_subject">اسم الموضوع</string>
<string name="account_server_certificate_issuer">اسم المُصدر</string>
<string name="account_server_certificate_subject_alternative_names">الأسماء البديلة للموضوع (Subject Alternative Names)</string>
<string name="account_server_certificate_unknown_error_description_format">اكتشف التطبيق تهديدًا أمنيًا محتملاً وأوقف الاتصال بـ <xliff:g id="serverName">1%s</xliff:g>.\nإذا قمت بمتابعة الاتصال، فقد يحاول المهاجمون سرقة معلومات مثل كلمة المرور أو رسائل البريد الإلكتروني الخاصة بك.</string>
<string name="account_server_certificate_fingerprints_section">بصمات رقمية</string>
</resources>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="account_server_certificate_warning_title">Папярэджанне</string>
<string name="account_server_certificate_unknown_error_subtitle">Памылка сертыфіката</string>
</resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Внимание</string>
<string name="account_server_certificate_unknown_error_subtitle">Грешка със сертификатите</string>
<string name="account_server_certificate_unknown_error_description_format">Приложението откри потенциална заплаха за сигурността и не продължи свързването с <xliff:g id="serverName">%s</xliff:g>f:g&gt;.\nАко продължите, хакерите могат да се опитат да откраднат информация като паролата ви или пощата ви.</string>
<string name="account_server_certificate_button_back">Назад (препоръчително)</string>
<string name="account_server_certificate_button_advanced">Разширени</string>
<string name="account_server_certificate_button_continue">Приемане на риска и продължаване</string>
<string name="account_server_certificate_section_title">Сертификат на сървъра</string>
<string name="account_server_certificate_subject_alternative_names">Subject alternative names</string>
<string name="account_server_certificate_not_valid_before">Невалиден преди</string>
<string name="account_server_certificate_not_valid_after">невалиден след</string>
<string name="account_server_certificate_subject">Тема</string>
<string name="account_server_certificate_issuer">Издател</string>
<string name="account_server_certificate_fingerprints_section">отпечатък</string>
</resources>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="account_server_certificate_warning_title">Diwallit</string>
<string name="account_server_certificate_unknown_error_subtitle">Fazi testeni</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Upozorenje</string>
<string name="account_server_certificate_unknown_error_subtitle">Greška sertifikata</string>
<string name="account_server_certificate_button_back">Idite nazad (preporučeno)</string>
<string name="account_server_certificate_button_advanced">Napredna podešavanja</string>
<string name="account_server_certificate_button_continue">Prihvatite rizik i nastavite</string>
<string name="account_server_certificate_section_title">Sertifikat servera</string>
<string name="account_server_certificate_subject_alternative_names">Alternativna imena subjekta (SAN - Subject alternative names)</string>
<string name="account_server_certificate_not_valid_after">Nevažeći poslije</string>
<string name="account_server_certificate_subject">Subjekat iz sertifikata servera</string>
<string name="account_server_certificate_issuer">Sertifikaciono tijelo</string>
<string name="account_server_certificate_fingerprints_section">Fingerprint-i</string>
<string name="account_server_certificate_unknown_error_description_format">Aplikacija je detektovala potencijalnu sigurnosnu prijetnju i neće se povezati sa <xliff:g id="serverName">%s</xliff:g>.
\nAko nastavite, hakeri bi mogli ukrasti vaše informacije kao što su lozinka ili mejlovi.</string>
<string name="account_server_certificate_not_valid_before">Nevažeći prije</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_subject">Subjecte</string>
<string name="account_server_certificate_unknown_error_subtitle">Error de certificat</string>
<string name="account_server_certificate_unknown_error_description_format">L\'aplicació ha detectat una possible amenaça de seguretat i no ha continuat amb la connexió a <xliff:g id="serverName">%s</xliff:g>.
\nSi continues, els atacants podrien intentar robar-te informació com ara la contrasenya o els teus correus.</string>
<string name="account_server_certificate_section_title">Certificat del servidor</string>
<string name="account_server_certificate_warning_title">Avís</string>
<string name="account_server_certificate_not_valid_after">No vàlid després</string>
<string name="account_server_certificate_issuer">Emissor</string>
<string name="account_server_certificate_fingerprints_section">Empremtes</string>
<string name="account_server_certificate_button_back">Torna enrere (recomanat)</string>
<string name="account_server_certificate_button_advanced">Avançat</string>
<string name="account_server_certificate_button_continue">Accepta el risc i continua</string>
<string name="account_server_certificate_subject_alternative_names">Noms alternatius del subjecte</string>
<string name="account_server_certificate_not_valid_before">Abans no era vàlid</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Avertimentu</string>
<string name="account_server_certificate_unknown_error_subtitle">Sbagliu di certificatu</string>
<string name="account_server_certificate_button_back">Ritornu (ricumandatu)</string>
<string name="account_server_certificate_button_continue">Accettà u risicu è cuntinuà</string>
<string name="account_server_certificate_button_advanced">Espertu</string>
<string name="account_server_certificate_section_title">Certificatu di u servitore</string>
<string name="account_server_certificate_not_valid_before">Inaccettevule nanzu à</string>
<string name="account_server_certificate_not_valid_after">Inaccettevule dopu à</string>
<string name="account_server_certificate_subject">Sughjettu</string>
<string name="account_server_certificate_issuer">Emettore</string>
<string name="account_server_certificate_fingerprints_section">Impronte</string>
<string name="account_server_certificate_unknown_error_description_format">Lappiecazione hà scupertu una minaccia pussibule di sicurità è ùn hà micca cuntinuatu à cunnettesi à <xliff:g id="serverName">%s</xliff:g>.
\nSè vo cuntinuate, assaltadori puderianu pruvà darrubavvi infurmazioni cumè parolla dintesa o messaghji elettronichi.</string>
<string name="account_server_certificate_subject_alternative_names">Nomi alternativi di u sughjettu</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Varování</string>
<string name="account_server_certificate_button_back">Jít zpět (doporučeno)</string>
<string name="account_server_certificate_button_advanced">Pokročilé</string>
<string name="account_server_certificate_button_continue">Přijmout riziko a pokračovat</string>
<string name="account_server_certificate_not_valid_after">Platné do</string>
<string name="account_server_certificate_issuer">Vydavatel</string>
<string name="account_server_certificate_fingerprints_section">Otisky certifikátu</string>
<string name="account_server_certificate_unknown_error_subtitle">Chyba certifikátu</string>
<string name="account_server_certificate_unknown_error_description_format">Aplikace zjistila potenciální bezpečnostní hrozbu a přerušila připojování k <xliff:g id="serverName">%s</xliff:g>.
\nPokud budete pokračovat, útočníci by se mohli pokusit získat informace jako hesla a e-maily.</string>
<string name="account_server_certificate_section_title">Certifikát serveru</string>
<string name="account_server_certificate_subject_alternative_names">Alternativní názvy</string>
<string name="account_server_certificate_not_valid_before">Platné od</string>
<string name="account_server_certificate_subject">Předmět</string>
</resources>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Warnung</string>
<string name="account_server_certificate_button_back">Zurück (empfohlen)</string>
<string name="account_server_certificate_button_continue">Risiko akzeptieren und fortfahren</string>
<string name="account_server_certificate_section_title">Serverzertifikat</string>
<string name="account_server_certificate_subject_alternative_names">Alternative Namen</string>
<string name="account_server_certificate_not_valid_before">Gültig ab</string>
<string name="account_server_certificate_not_valid_after">Gültig bis</string>
<string name="account_server_certificate_subject">Gegenstand</string>
<string name="account_server_certificate_issuer">Aussteller</string>
<string name="account_server_certificate_fingerprints_section">Fingerabdrücke</string>
<string name="account_server_certificate_unknown_error_subtitle">Zertifikatsfehler</string>
<string name="account_server_certificate_unknown_error_description_format">Die App hat eine potenzielle Sicherheitsbedrohung erkannt und hat daher keine Verbindung zu <xliff:g id="serverName">%s</xliff:g> hergestellt.
\nWenn du fortfahren möchtest, könnten Angreifer versuchen, Informationen wie dein Passwort oder E-Mails zu stehlen.</string>
<string name="account_server_certificate_button_advanced">Erweitert</string>
</resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Προειδοποίηση</string>
<string name="account_server_certificate_unknown_error_subtitle">Σφάλμα πιστοποιητικού</string>
<string name="account_server_certificate_button_back">Επιστροφή (προτείνεται)</string>
<string name="account_server_certificate_button_advanced">Σύνθετα</string>
<string name="account_server_certificate_button_continue">Αποδοχή κινδύνου και συνέχεια</string>
<string name="account_server_certificate_section_title">Πιστοποιητικό διακομιστή</string>
<string name="account_server_certificate_issuer">Εκδότης</string>
<string name="account_server_certificate_fingerprints_section">Αποτυπώματα</string>
<string name="account_server_certificate_unknown_error_description_format">Η εφαρμογή εντόπισε μια πιθανή απειλή ασφαλείας και δεν προχώρησε στη σύνδεση με το <xliff:g id="serverName">%s</xliff:g>.\nΕάν συνεχίσετε, οι επιτιθέμενοι ενδέχεται να αποπειραθούν να υποκλέψουν πληροφορίες, όπως τον κωδικό πρόσβασης ή τα email σας.</string>
<string name="account_server_certificate_not_valid_before">Μη έγκυρο πριν από</string>
<string name="account_server_certificate_not_valid_after">Μη έγκυρο μετά από</string>
<string name="account_server_certificate_subject">Θέμα</string>
<string name="account_server_certificate_subject_alternative_names">Subject alternative names (SAN)</string>
</resources>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Warning</string>
<string name="account_server_certificate_unknown_error_subtitle">Certificate error</string>
<string name="account_server_certificate_unknown_error_description_format">The app detected a potential security threat and did not continue to connect to <xliff:g id="serverName">%s</xliff:g>.\nIf you continue, attackers could try to steal information like your password or emails.</string>
</resources>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Averto</string>
<string name="account_server_certificate_unknown_error_subtitle">Atestila eraro</string>
<string name="account_server_certificate_fingerprints_section">Fingrospuroj</string>
<string name="account_server_certificate_section_title">Servila atestilo</string>
<string name="account_server_certificate_button_back">Reen (rekomendate)</string>
<string name="account_server_certificate_button_advanced">Spertula</string>
<string name="account_server_certificate_button_continue">Akcepti la riskon kaj daŭrigi</string>
<string name="account_server_certificate_not_valid_before">Ne valida antaŭ</string>
<string name="account_server_certificate_not_valid_after">Ne valida post</string>
<string name="account_server_certificate_unknown_error_description_format">La apo detektis eblan sekurecan minacon kaj ne daŭrigis kontekti al <xliff:g id="serverName">%s</xliff:g>.\nSe vi daŭrigas, atakantoj eble provos ŝteli informojn, interalie pasvortojn aŭ retpoŝtmesaĝojn.</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_unknown_error_subtitle">Error en el certificado</string>
<string name="account_server_certificate_button_back">Retroceder (recomendado)</string>
<string name="account_server_certificate_not_valid_before">No válido antes de</string>
<string name="account_server_certificate_not_valid_after">No es válido después de</string>
<string name="account_server_certificate_subject">Asunto</string>
<string name="account_server_certificate_issuer">Emisor</string>
<string name="account_server_certificate_fingerprints_section">Huella digital</string>
<string name="account_server_certificate_warning_title">Advertencia</string>
<string name="account_server_certificate_unknown_error_description_format">La aplicación ha detectado un posible problema de seguridad y ha cortado la conexión con <xliff:g id="serverName">%s</xliff:g>.
\nSi ignoras este aviso y sigues adelante los atacantes podrían conseguir robar información privada como tu contraseña o tus correos electrónicos.</string>
<string name="account_server_certificate_button_advanced">Avanzado</string>
<string name="account_server_certificate_button_continue">Aceptar el riesgo y continuar</string>
<string name="account_server_certificate_section_title">Certificado del servidor</string>
<string name="account_server_certificate_subject_alternative_names">Nombres alternativos del sujeto</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Hoiatus</string>
<string name="account_server_certificate_unknown_error_subtitle">Sertifikaadiviga</string>
<string name="account_server_certificate_subject">Sisu</string>
<string name="account_server_certificate_unknown_error_description_format">Rakendus tuvastas võimaliku turvariski ning loobus ühendusest serveriga <xliff:g id="serverName">%s</xliff:g>.
\nKui sa jätkad, siis võimalikud ründajad võivad varastada sinu andmeid, sh. kasutajanime ja salasõna.</string>
<string name="account_server_certificate_button_back">Mine tagasi (soovitatav)</string>
<string name="account_server_certificate_button_advanced">Lisateave</string>
<string name="account_server_certificate_button_continue">Nõustu riskiga ja jätka</string>
<string name="account_server_certificate_section_title">Serveri sertifikaat</string>
<string name="account_server_certificate_subject_alternative_names">Serveri SANs nimed</string>
<string name="account_server_certificate_not_valid_before">Pole kehtiv varem kui</string>
<string name="account_server_certificate_not_valid_after">Pole kehtiv hiljem kui</string>
<string name="account_server_certificate_issuer">Väljaandja</string>
<string name="account_server_certificate_fingerprints_section">Sõrmejäljed</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Abisua</string>
<string name="account_server_certificate_unknown_error_subtitle">Ziurtagiriaren errorea</string>
<string name="account_server_certificate_unknown_error_description_format">Aplikazioak balizko segurtasun-mehatxu bat detektatu du eta ez du <xliff:g id="serverName">%s</xliff:g>-ra konektatzen jarraitu.
\nJarraitzen baduzu, erasotzaileak zure pasahitza edo mezu elektronikoak bezalako informazioa lapurtzen saia litezke.</string>
<string name="account_server_certificate_button_back">Atzera itzuli (gomendatua)</string>
<string name="account_server_certificate_button_advanced">Aurreratua</string>
<string name="account_server_certificate_button_continue">Arriskua onartu eta jarraitu</string>
<string name="account_server_certificate_section_title">Zerbitzariaren ziurtagiria</string>
<string name="account_server_certificate_subject_alternative_names">Subjektuaren ordezko izenak</string>
<string name="account_server_certificate_not_valid_before">Data hau baino lehen ez du balio</string>
<string name="account_server_certificate_not_valid_after">Data honen ondoren ez du balio</string>
<string name="account_server_certificate_subject">Subjektua</string>
<string name="account_server_certificate_issuer">Jaulkitzailea</string>
<string name="account_server_certificate_fingerprints_section">Hatz-markak</string>
</resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_button_back">بازگشت (توصیه می‌شود)</string>
<string name="account_server_certificate_button_advanced">پیشرفته</string>
<string name="account_server_certificate_button_continue">پذیرفتن ریسک و ادامه دادن</string>
<string name="account_server_certificate_not_valid_before">معتبر نیست تا قبل از</string>
<string name="account_server_certificate_not_valid_after">معتبر نیست تا بعد از</string>
<string name="account_server_certificate_subject">موضوع</string>
<string name="account_server_certificate_issuer">ایجاد کننده</string>
<string name="account_server_certificate_fingerprints_section">اثرانگشت‌ها</string>
<string name="account_server_certificate_warning_title">اخطار</string>
<string name="account_server_certificate_unknown_error_subtitle">خطای گواهی</string>
<string name="account_server_certificate_unknown_error_description_format">برنامه مشکل امنیتی بالقوه‌ای تشخیص داد و به <xliff:g id="serverName">%s</xliff:g> وصل نشد. \nدر صورت ادامه خطر سرقت اطلاعاتی چون گذرواژه یا رایانامه‌ها وجود دارد.</string>
<string name="account_server_certificate_section_title">گواهی کارساز</string>
<string name="account_server_certificate_subject_alternative_names">نام‌های حایگزین موضوع</string>
</resources>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="account_server_certificate_button_advanced">Lisäasetukset</string>
<string name="account_server_certificate_warning_title">Varoitus</string>
<string name="account_server_certificate_unknown_error_subtitle">Varmennevirhe</string>
<string name="account_server_certificate_button_back">Palaa takaisin (suositeltu)</string>
<string name="account_server_certificate_button_continue">Hyväksy riski ja jatka</string>
<string name="account_server_certificate_section_title">Palvelimen varmenne</string>
<string name="account_server_certificate_subject_alternative_names">Vaihtoehtoiset nimet</string>
<string name="account_server_certificate_not_valid_before">Ei kelvollinen ennen</string>
<string name="account_server_certificate_not_valid_after">Ei kelvollinen jälkeen</string>
<string name="account_server_certificate_issuer">Myöntäjä</string>
<string name="account_server_certificate_fingerprints_section">Sormenjäljet</string>
</resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Avertissement</string>
<string name="account_server_certificate_unknown_error_subtitle">Erreur de certificat</string>
<string name="account_server_certificate_button_back">Revenir en arrière (recommandé)</string>
<string name="account_server_certificate_button_advanced">Avancé</string>
<string name="account_server_certificate_button_continue">Accepter le risque et poursuivre</string>
<string name="account_server_certificate_section_title">Certificat du serveur</string>
<string name="account_server_certificate_subject_alternative_names">Autres noms du sujet</string>
<string name="account_server_certificate_not_valid_before">Non valide avant le</string>
<string name="account_server_certificate_not_valid_after">Non valide après le</string>
<string name="account_server_certificate_subject">Sujet</string>
<string name="account_server_certificate_issuer">Émetteur</string>
<string name="account_server_certificate_fingerprints_section">Empreintes</string>
<string name="account_server_certificate_unknown_error_description_format">Lappli a détecté une menace de sécurité potentielle et a cessé de se connecter à <xliff:g id="serverName">%s</xliff:g>.\nSi vous poursuivez, des assaillants pourraient tenter de voler des renseignements tels que votre mot de passe ou vos courriels.</string>
</resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Warskôging</string>
<string name="account_server_certificate_unknown_error_subtitle">Sertifikaatflater</string>
<string name="account_server_certificate_unknown_error_description_format">De app hat in potinsjeel befeiligingsrisiko detektearre en is net troch gien mei ferbinen nei <xliff:g id="serverName">%s</xliff:g>.\nAs jo trochgean kinne oanfallers probearje ynformaasje lykas jo wachtwurd of e-mailberjochten te stellen.</string>
<string name="account_server_certificate_button_back">Tebek (oanrekommandearre)</string>
<string name="account_server_certificate_button_advanced">Avansearre</string>
<string name="account_server_certificate_button_continue">Risiko akseptearje en trochgean</string>
<string name="account_server_certificate_section_title">Serversertifikaat</string>
<string name="account_server_certificate_subject_alternative_names">Multi-domeinsertifikaten</string>
<string name="account_server_certificate_not_valid_before">Pas jildich mei yngong fan</string>
<string name="account_server_certificate_not_valid_after">Unjildich nei</string>
<string name="account_server_certificate_subject">Eigener</string>
<string name="account_server_certificate_issuer">Utjouwer</string>
<string name="account_server_certificate_fingerprints_section">Fingerôfdrukken</string>
</resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Rabhadh</string>
<string name="account_server_certificate_button_back">Téigh ar ais (molta)</string>
<string name="account_server_certificate_unknown_error_subtitle">Earráid deimhnithe</string>
<string name="account_server_certificate_unknown_error_description_format">Bhraith an aip go bhféadfadh bagairt shlándála a bheith ann agus níor leanadh de nascadh le <xliff:g id="serverName">%s</xliff:g>.\nMá leanann tú ar aghaidh, dfhéadfadh ionsaitheoirí iarracht faisnéis a ghoid amhail do phasfhocal nó ríomhphoist.</string>
<string name="account_server_certificate_button_advanced">Roghanna Ard</string>
<string name="account_server_certificate_button_continue">Glac le riosca agus lean ar aghaidh</string>
<string name="account_server_certificate_fingerprints_section">Méarloirg</string>
<string name="account_server_certificate_section_title">Deimhniú freastalaí</string>
<string name="account_server_certificate_subject_alternative_names">Ainmneacha malartacha ábhair</string>
<string name="account_server_certificate_not_valid_before">Gan bailí roimhe seo</string>
<string name="account_server_certificate_not_valid_after">Gan bailí tar éis</string>
<string name="account_server_certificate_subject">Ábhar</string>
<string name="account_server_certificate_issuer">Eisitheoir</string>
</resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_button_advanced">Adhartach</string>
<string name="account_server_certificate_unknown_error_description_format">Mhothaich an aplacaid do rud a dhfhaodadh a bhith na cunnart tèarainteachd is cha do choilean e an ceangal ri <xliff:g id="serverName">%s</xliff:g>.\nMa leanas tu air adhart, dhfhaoidte gum b urrainn do luchd-ionnsaigh fiosrachadh a ghoid ort, mar fhaclan-faire no post-d.</string>
<string name="account_server_certificate_warning_title">Rabhadh</string>
<string name="account_server_certificate_unknown_error_subtitle">Mearachd an teisteanais</string>
<string name="account_server_certificate_button_back">Air ais (mholamaid seo)</string>
<string name="account_server_certificate_button_continue">Tha mi a tuigsinn a chunnairt ach air adhart leam</string>
<string name="account_server_certificate_section_title">Teisteanas an fhrithealaiche</string>
<string name="account_server_certificate_subject_alternative_names">Subject Alternative Names</string>
<string name="account_server_certificate_not_valid_before">Cha bhi seo dligheach ron</string>
<string name="account_server_certificate_not_valid_after">Cha bhi seo dligheach an dèidh</string>
<string name="account_server_certificate_subject">An cuspair</string>
<string name="account_server_certificate_fingerprints_section">Lorgan-meòir</string>
<string name="account_server_certificate_issuer">Am foillsichear</string>
</resources>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="account_server_certificate_warning_title">सूचना</string>
<string name="account_server_certificate_unknown_error_subtitle">प्रमाणपत्र की त्रुटि</string>
</resources>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Upozorenje</string>
<string name="account_server_certificate_unknown_error_subtitle">Greška certifikata</string>
<string name="account_server_certificate_unknown_error_description_format">Aplikacija je otkrila potencijalnu sigurnosnu prijetnju i nije nastavila s povezivanjem na <xliff:g id="serverName">%s</xliff:g>.\nAko nastavite, napadači bi mogli ukrasti vaše osobne podatke poput lozinke ili e-mailove.</string>
<string name="account_server_certificate_button_back">Vrati se (preporučeno)</string>
<string name="account_server_certificate_button_continue">Potvrdi rizik i nastavi</string>
<string name="account_server_certificate_section_title">Certifikat servera</string>
<string name="account_server_certificate_not_valid_before">Nije valjano prije</string>
<string name="account_server_certificate_not_valid_after">Nije valjano nakon</string>
<string name="account_server_certificate_button_advanced">Napredno</string>
<string name="account_server_certificate_issuer">Izdavatelj</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_unknown_error_description_format">Az alkalmazás lehetséges biztonsági fenyegetést észlelt, és nem folytatta a kapcsolódást a(z) <xliff:g id="serverName">%s</xliff:g> felé.
\nHa folytatja, akkor támadók olyan információkat próbálhatnak ellopni, mint a jelszava vagy az e-mailjei.</string>
<string name="account_server_certificate_fingerprints_section">Ujjlenyomatok</string>
<string name="account_server_certificate_warning_title">Figyelmeztetés</string>
<string name="account_server_certificate_unknown_error_subtitle">Tanúsítványhiba</string>
<string name="account_server_certificate_button_back">Ugrás vissza (ajánlott)</string>
<string name="account_server_certificate_button_advanced">Speciális</string>
<string name="account_server_certificate_button_continue">Kockázat elfogadása és folytatás</string>
<string name="account_server_certificate_section_title">Kiszolgálótanúsítvány</string>
<string name="account_server_certificate_subject_alternative_names">Tárgy alternatív nevei</string>
<string name="account_server_certificate_not_valid_before">Eddig nem érvényes</string>
<string name="account_server_certificate_not_valid_after">Ezután nem érvényes</string>
<string name="account_server_certificate_subject">Tárgy</string>
<string name="account_server_certificate_issuer">Kibocsátó</string>
</resources>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_unknown_error_description_format">Aplikasi ini mendeteksi adanya potensi ancaman keamanan dan tidak melanjutkan koneksi ke <xliff:g id="serverName">%s</xliff:g>. \nJika tetap Anda lanjutkan, informasi diri Anda seperti kata sandi dan surel dapat dicuri oleh penyerang.</string>
<string name="account_server_certificate_subject">Subjek</string>
<string name="account_server_certificate_issuer">Penerbit</string>
<string name="account_server_certificate_warning_title">Peringatan</string>
<string name="account_server_certificate_unknown_error_subtitle">Galat sertifikat</string>
<string name="account_server_certificate_button_back">Kembali (disarankan)</string>
<string name="account_server_certificate_button_advanced">Lanjutan</string>
<string name="account_server_certificate_button_continue">Terima risikonya dan lanjutkan</string>
<string name="account_server_certificate_section_title">Sertifikat peladen</string>
<string name="account_server_certificate_subject_alternative_names">Nama alternatif subjek</string>
<string name="account_server_certificate_not_valid_before">Tidak valid sebelum</string>
<string name="account_server_certificate_not_valid_after">Tidak valid sesudah</string>
<string name="account_server_certificate_fingerprints_section">Sidik jari</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_issuer">Útgefandi</string>
<string name="account_server_certificate_fingerprints_section">Fingraför</string>
<string name="account_server_certificate_warning_title">Aðvörun</string>
<string name="account_server_certificate_unknown_error_subtitle">Villa í skilríki</string>
<string name="account_server_certificate_unknown_error_description_format">Forritið rakst á mögulega öryggisógn og hélt ekki áfram að tengjast við <xliff:g id="serverName">%s</xliff:g>.
\nEf þú heldur áfram, gætu óprúttnir aðilar reynt að stela upplýsingum á borð við lykilorðin þín eða tölvupósta.</string>
<string name="account_server_certificate_button_back">Fara til baka (ráðlagt)</string>
<string name="account_server_certificate_button_advanced">Ítarlegt</string>
<string name="account_server_certificate_button_continue">Taka áhættu og halda áfram</string>
<string name="account_server_certificate_section_title">Skilríki þjóns</string>
<string name="account_server_certificate_subject_alternative_names">Önnur heiti viðfangs</string>
<string name="account_server_certificate_not_valid_before">Ekki gilt fyrir</string>
<string name="account_server_certificate_not_valid_after">Ekki gilt eftir</string>
<string name="account_server_certificate_subject">Viðfang</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_button_continue">Accetta il rischio e continua</string>
<string name="account_server_certificate_section_title">Certificato del server</string>
<string name="account_server_certificate_warning_title">Avviso</string>
<string name="account_server_certificate_unknown_error_subtitle">Errore di certificato</string>
<string name="account_server_certificate_unknown_error_description_format">L\'applicazione ha rilevato una potenziale minaccia alla sicurezza ed ha impedito la connessione a <xliff:g id="Nome del server">%s</xliff:g>.
\nSe prosegui, gli aggressori potrebbero tentare di rubare informazioni come la password o i tuoi indirizzi email.</string>
<string name="account_server_certificate_button_back">Torna indietro (raccomandato)</string>
<string name="account_server_certificate_button_advanced">Avanzato</string>
<string name="account_server_certificate_subject">Soggetto</string>
<string name="account_server_certificate_subject_alternative_names">Subject alternative names (SAN)</string>
<string name="account_server_certificate_not_valid_before">Non valido prima del</string>
<string name="account_server_certificate_not_valid_after">Non valido dopo il</string>
<string name="account_server_certificate_issuer">Emittente</string>
<string name="account_server_certificate_fingerprints_section">Impronta</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_unknown_error_subtitle">שגיאת תעודה</string>
<string name="account_server_certificate_button_back">לחזור אחורה (מומלץ)</string>
<string name="account_server_certificate_button_advanced">מתקדם</string>
<string name="account_server_certificate_button_continue">לקבל את הסיכון ולהמשיך</string>
<string name="account_server_certificate_section_title">תעודת שרת</string>
<string name="account_server_certificate_subject_alternative_names">Subject alternative names</string>
<string name="account_server_certificate_not_valid_before">לא תקף לפני</string>
<string name="account_server_certificate_not_valid_after">לא תקף אחרי</string>
<string name="account_server_certificate_subject">Subject</string>
<string name="account_server_certificate_issuer">מנפיק</string>
<string name="account_server_certificate_warning_title">אזהרה</string>
<string name="account_server_certificate_unknown_error_description_format">היישומון הבחין באיום אבטחה אפשרי ולא המשיך להתחבר אל <xliff:g id="serverName">%s</xliff:g>.
\nאם תמשיך, תוקפים יוכלו לנסות לגנוב מידע כגון הסיסמה שלך או הודעות דוא\"ל.</string>
<string name="account_server_certificate_fingerprints_section">טביעות אצבע</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_subject_alternative_names">サブジェクトの代替名</string>
<string name="account_server_certificate_warning_title">警告</string>
<string name="account_server_certificate_unknown_error_subtitle">証明書エラー</string>
<string name="account_server_certificate_unknown_error_description_format">潜在的なセキュリティ上の脅威がアプリによって検出されたため、<xliff:g id="serverName">%s</xliff:g> への接続しませんでした。
\n続行すると、パスワードやメールなどを攻撃者が奪取できるようになります。</string>
<string name="account_server_certificate_button_back">戻る (推奨)</string>
<string name="account_server_certificate_button_advanced">詳細</string>
<string name="account_server_certificate_button_continue">リスクを承知した上で続行</string>
<string name="account_server_certificate_section_title">サーバー証明書</string>
<string name="account_server_certificate_not_valid_before">効力の開始</string>
<string name="account_server_certificate_not_valid_after">有効期限</string>
<string name="account_server_certificate_subject">サブジェクト</string>
<string name="account_server_certificate_issuer">発行元</string>
<string name="account_server_certificate_fingerprints_section">フィンガープリント</string>
</resources>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="account_server_certificate_warning_title">Ескерту</string>
<string name="account_server_certificate_button_back">Артқа (ұсынылады)</string>
<string name="account_server_certificate_unknown_error_subtitle">Сертификат қатесі</string>
<string name="account_server_certificate_button_continue">Тәуекелді қабылдап, жалғастыру</string>
<string name="account_server_certificate_section_title">Сервер сертификаты</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_button_back">뒤로 가기 (권장)</string>
<string name="account_server_certificate_button_advanced">고급</string>
<string name="account_server_certificate_section_title">서버 인증서</string>
<string name="account_server_certificate_subject_alternative_names">SAN</string>
<string name="account_server_certificate_not_valid_before">시작 날짜</string>
<string name="account_server_certificate_not_valid_after">만료 날짜</string>
<string name="account_server_certificate_subject">서버</string>
<string name="account_server_certificate_issuer">발급자</string>
<string name="account_server_certificate_warning_title">경고</string>
<string name="account_server_certificate_unknown_error_description_format">잠재적인 보안 위협을 감지하여 <xliff:g id="serverName">%s</xliff:g>에 연결하지 않았습니다.
\n계속 진행할 경우, 공격자가 비밀번호나 이메일과 같은 정보를 탈취하려 할 수 있습니다.</string>
<string name="account_server_certificate_button_continue">위험을 감수하고 계속 진행</string>
<string name="account_server_certificate_unknown_error_subtitle">인증서 오류</string>
<string name="account_server_certificate_fingerprints_section">지문</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_unknown_error_description_format">Programa aptiko galima saugos grėsmę, todėl nutraukė bandymą jungtis prie <xliff:g id="serverName">%s</xliff:g>.
\nJei tęsite, piktavaliai gali kėsintis pavogti jūsų duomenis, pavyzdžiui slaptažodį ar el. laiškus.</string>
<string name="account_server_certificate_warning_title">Įspėjimas</string>
<string name="account_server_certificate_unknown_error_subtitle">Liudijimo klaida</string>
<string name="account_server_certificate_button_advanced">Išsamiau</string>
<string name="account_server_certificate_button_back">Grįžti (rekomenduotina)</string>
<string name="account_server_certificate_button_continue">Priimti riziką ir tęsti</string>
<string name="account_server_certificate_section_title">Serverio liudijimas</string>
<string name="account_server_certificate_subject_alternative_names">Subjekto alternatyvieji vardai</string>
<string name="account_server_certificate_not_valid_before">Negalioja iki</string>
<string name="account_server_certificate_not_valid_after">Negalioja po</string>
<string name="account_server_certificate_subject">Subjektas</string>
<string name="account_server_certificate_issuer">Išdavėjas</string>
<string name="account_server_certificate_fingerprints_section">Kontroliniai kodai</string>
</resources>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_button_continue">Godta risiko og fortsett</string>
<string name="account_server_certificate_section_title">Tjenersertifikat</string>
<string name="account_server_certificate_not_valid_before">Ikke gyldig før</string>
<string name="account_server_certificate_not_valid_after">Ikke gyldig etter</string>
<string name="account_server_certificate_fingerprints_section">Fingeravtrykk</string>
<string name="account_server_certificate_button_back">Gå tilbake (anbefalt)</string>
<string name="account_server_certificate_subject_alternative_names">Alternative emnenavn</string>
<string name="account_server_certificate_warning_title">Advarsel</string>
<string name="account_server_certificate_unknown_error_subtitle">Sertifikatfeil</string>
<string name="account_server_certificate_button_advanced">Avansert</string>
<string name="account_server_certificate_subject">Emne</string>
<string name="account_server_certificate_issuer">Utsteder</string>
<string name="account_server_certificate_unknown_error_description_format">Appen oppdaget en potensiell sikkerhetsrisiko og gikk ikke viderer til å koble til <xliff:g id="serverName">%s</xliff:g>. \nHvis du fortsetter kan angripere prøve å stjele info som f.eks. dine passord eller e-poster.</string>
</resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Waarschuwing</string>
<string name="account_server_certificate_unknown_error_subtitle">Certificaatfout</string>
<string name="account_server_certificate_unknown_error_description_format">De app heeft een potentieel beveiligingsrisico gedetecteerd en is niet verder gegaan met verbinden naar <xliff:g id="serverName">%s</xliff:g>.\nAls u doorgaat kunnen aanvallers proberen informatie zoals uw wachtwoord of e-mailberichten te stelen.</string>
<string name="account_server_certificate_button_back">Terug (aanbevolen)</string>
<string name="account_server_certificate_button_advanced">Geavanceerd</string>
<string name="account_server_certificate_section_title">Servercertificaat</string>
<string name="account_server_certificate_not_valid_before">Pas geldig vanaf</string>
<string name="account_server_certificate_not_valid_after">Ongeldig na</string>
<string name="account_server_certificate_subject">Eigenaar</string>
<string name="account_server_certificate_issuer">Uitgever</string>
<string name="account_server_certificate_fingerprints_section">Vingerafdrukken</string>
<string name="account_server_certificate_button_continue">Risico accepteren en doorgaan</string>
<string name="account_server_certificate_subject_alternative_names">Multi-domeincertificaten</string>
</resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Åtvaring</string>
<string name="account_server_certificate_unknown_error_subtitle">Sertifikatsfeil</string>
<string name="account_server_certificate_button_back">Gå tilbake (tilrådd)</string>
<string name="account_server_certificate_section_title">Tenersertifikat</string>
<string name="account_server_certificate_subject_alternative_names">Alternative emnenamn</string>
<string name="account_server_certificate_issuer">utferdar</string>
<string name="account_server_certificate_fingerprints_section">Fingeravtrykk</string>
<string name="account_server_certificate_subject">Emne</string>
<string name="account_server_certificate_unknown_error_description_format">Appen oppdaga ein potensiell sikkerheitsrisiko og gjekk ikkje vidare til å kople til <xliff:g id="serverName">%s</xliff:g>. \nViss du held fram kan angriparar prøve å stele info som t.d. passord eller e-postar.</string>
<string name="account_server_certificate_button_advanced">Avansert</string>
<string name="account_server_certificate_button_continue">Godta risiko og hald fram</string>
<string name="account_server_certificate_not_valid_after">Ikkje gyldig etter</string>
<string name="account_server_certificate_not_valid_before">Ikkje gyldig før</string>
</resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_button_back">Wróć (zalecane)</string>
<string name="account_server_certificate_button_advanced">Zaawansowane</string>
<string name="account_server_certificate_button_continue">Zaakceptuj ryzyko i kontynuuj</string>
<string name="account_server_certificate_section_title">Certyfikat serwera</string>
<string name="account_server_certificate_subject_alternative_names">Alternatywne nazwy podmiotu</string>
<string name="account_server_certificate_not_valid_before">Nieważny przed</string>
<string name="account_server_certificate_not_valid_after">Nieważny po</string>
<string name="account_server_certificate_issuer">Wystawca</string>
<string name="account_server_certificate_fingerprints_section">Odciski palców</string>
<string name="account_server_certificate_warning_title">Ostrzeżenie</string>
<string name="account_server_certificate_unknown_error_subtitle">Błąd certyfikatu</string>
<string name="account_server_certificate_subject">Podmiot</string>
<string name="account_server_certificate_unknown_error_description_format">Aplikacja wykryła potencjalne zagrożenie bezpieczeństwa i nie nawiązała dalszego połączenia z <xliff:g id="serverName">%s</xliff:g>. \nJeśli będziesz kontynuować, osoby atakujące mogą spróbować ukraść informacje, takie jak hasło lub adresy e-mail.</string>
</resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Aviso</string>
<string name="account_server_certificate_unknown_error_subtitle">Erro de certificado</string>
<string name="account_server_certificate_unknown_error_description_format">O aplicativo detectou um potencial risco de segurança e não conectou com <xliff:g id="serverName">%s</xliff:g>. \nSe você continuar, invasores podem tentar roubar informações como sua senha ou emails.</string>
<string name="account_server_certificate_button_back">Voltar (recomendado)</string>
<string name="account_server_certificate_button_advanced">Avançado</string>
<string name="account_server_certificate_button_continue">Aceitar o risco e continuar</string>
<string name="account_server_certificate_section_title">Certificado do servidor</string>
<string name="account_server_certificate_subject_alternative_names">Nomes alternativos do sujeito</string>
<string name="account_server_certificate_not_valid_before">Inválido antes de</string>
<string name="account_server_certificate_not_valid_after">Inválido após</string>
<string name="account_server_certificate_subject">Sujeito</string>
<string name="account_server_certificate_issuer">Emissor</string>
<string name="account_server_certificate_fingerprints_section">Impressão digital</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Aviso</string>
<string name="account_server_certificate_unknown_error_subtitle">Erro de certificado</string>
<string name="account_server_certificate_button_back">Regressar (recomendado)</string>
<string name="account_server_certificate_button_advanced">Avançado</string>
<string name="account_server_certificate_button_continue">Aceitar risco e continuar</string>
<string name="account_server_certificate_section_title">Certificado do servidor</string>
<string name="account_server_certificate_subject_alternative_names">Nomes alternativos</string>
<string name="account_server_certificate_not_valid_before">Não válido antes de</string>
<string name="account_server_certificate_not_valid_after">Não válido depois de</string>
<string name="account_server_certificate_issuer">Emissor</string>
<string name="account_server_certificate_subject">Sujeito</string>
<string name="account_server_certificate_fingerprints_section">Impressão digital</string>
<string name="account_server_certificate_unknown_error_description_format">A aplicação detetou um potencial risco de segurança e não continuou a ligar-se a <xliff:g id="serverName">%s</xliff:g>.
\nSe continuar, os atacantes podem tentar roubar informações como a sua palavra-passe ou e-mails.</string>
</resources>

View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_unknown_error_subtitle">Eroare de certificare</string>
<string name="account_server_certificate_warning_title">Avertisment</string>
<string name="account_server_certificate_button_back">Întoarcere (recomandat)</string>
<string name="account_server_certificate_button_advanced">Avansat</string>
<string name="account_server_certificate_button_continue">Acceptă riscurile și continuă</string>
<string name="account_server_certificate_section_title">Certificatul serverului</string>
<string name="account_server_certificate_subject_alternative_names">Nume alternative ale subiectului</string>
<string name="account_server_certificate_not_valid_before">Nu este valabil înainte de</string>
<string name="account_server_certificate_not_valid_after">Nu este valabil după data de</string>
<string name="account_server_certificate_subject">Subiect</string>
<string name="account_server_certificate_issuer">Emitent</string>
<string name="account_server_certificate_fingerprints_section">Amprente digitale</string>
<string name="account_server_certificate_unknown_error_description_format">Aplicația a detectat o potențială amenințare la adresa securității și nu a continuat să se conecteze la <xliff:g id="serverName">%s</xliff:g>.
\nDacă continui, atacatorii ar putea încerca să fure informații precum parola sau corespondența electronică.</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Внимание</string>
<string name="account_server_certificate_unknown_error_subtitle">Ошибка сертификата</string>
<string name="account_server_certificate_button_back">Вернуться (рекомендуется)</string>
<string name="account_server_certificate_button_advanced">Дополнительно</string>
<string name="account_server_certificate_button_continue">Принять риск и продолжить</string>
<string name="account_server_certificate_section_title">Сертификат сервера</string>
<string name="account_server_certificate_subject_alternative_names">Альтернативные названия субъектов</string>
<string name="account_server_certificate_not_valid_before">Не действителен до</string>
<string name="account_server_certificate_not_valid_after">Не действителен после</string>
<string name="account_server_certificate_subject">Субъект</string>
<string name="account_server_certificate_issuer">Эмитент</string>
<string name="account_server_certificate_unknown_error_description_format">Приложение обнаружило потенциальную угрозу безопасности и прекратило подключение к <xliff:g id="serverName">%s</xliff:g>.
\nЕсли вы продолжите подключение, злоумышленники могут попытаться украсть информацию, например ваш пароль или электронную почту.</string>
<string name="account_server_certificate_fingerprints_section">Цифровой отпечаток</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Varovanie</string>
<string name="account_server_certificate_unknown_error_subtitle">Chyba certifikátu</string>
<string name="account_server_certificate_unknown_error_description_format">Aplikácia zistila potenciálnu bezpečnostnú hrozbu a prerušila pripojovanie k <xliff:g id="serverName">%s</xliff:g>.
\nAk budete pokračovať, útočníci by sa mohli pokúsiť získať informácie ako heslá alebo emaily.</string>
<string name="account_server_certificate_not_valid_after">Platné do</string>
<string name="account_server_certificate_issuer">Vydavateľ</string>
<string name="account_server_certificate_button_back">Vrátiť sa späť (odporúčané)</string>
<string name="account_server_certificate_button_advanced">Pokročilé</string>
<string name="account_server_certificate_button_continue">Prijať riziko a pokračovať</string>
<string name="account_server_certificate_section_title">Certifikát servera</string>
<string name="account_server_certificate_subject_alternative_names">Alternatívne názvy</string>
<string name="account_server_certificate_not_valid_before">Platné od</string>
<string name="account_server_certificate_subject">Predmet</string>
<string name="account_server_certificate_fingerprints_section">Otlačky certifikátu</string>
</resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_button_back">Pojdi nazaj (priporočljivo)</string>
<string name="account_server_certificate_warning_title">Opozorilo</string>
<string name="account_server_certificate_unknown_error_subtitle">Napaka potrdila</string>
<string name="account_server_certificate_unknown_error_description_format">Program je zaznal morebitno varnostno grožnjo in se ni povezal na <xliff:g id="serverName">%s</xliff:g>.\nČe nadaljujete, bodo napadalci lahko poizkusili ukrasti podatke, kot je vaše geslo ali e-pošto.</string>
<string name="account_server_certificate_button_advanced">Napredno</string>
<string name="account_server_certificate_button_continue">Sprejmi tveganje in nadaljuj</string>
<string name="account_server_certificate_section_title">Potrdilo strežnika</string>
<string name="account_server_certificate_not_valid_before">Ni veljavno pred</string>
<string name="account_server_certificate_not_valid_after">Ni veljavno po</string>
<string name="account_server_certificate_issuer">Izdajatelj</string>
<string name="account_server_certificate_fingerprints_section">Prstni odtisi</string>
<string name="account_server_certificate_subject_alternative_names">Nadomestna imena subjekta</string>
<string name="account_server_certificate_subject">Subjekt</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_unknown_error_description_format">Aplikacioni pikasi një kërcënim potencial sigurie dhe svazhdoi të lidhet me <xliff:g id="serverName">%s</xliff:g>.
\nNëse vazhdoni, agresorë mund të përpiqen të vjedhin informacione, bie fjala, fjalëkalim, ose email-e.</string>
<string name="account_server_certificate_issuer">Lëshues</string>
<string name="account_server_certificate_fingerprints_section">Shenja gishtash</string>
<string name="account_server_certificate_warning_title">Kujdes</string>
<string name="account_server_certificate_unknown_error_subtitle">Gabim dëshmie</string>
<string name="account_server_certificate_button_back">Shko mbrapsht (e rekomanduar)</string>
<string name="account_server_certificate_button_advanced">Të mëtejshme</string>
<string name="account_server_certificate_button_continue">Pranojeni rrezikun dhe vazhdoni</string>
<string name="account_server_certificate_section_title">Dëshmi shërbyesi</string>
<string name="account_server_certificate_subject_alternative_names">Emra alternativë të subjektit</string>
<string name="account_server_certificate_not_valid_before">Jo e vlefshme para</string>
<string name="account_server_certificate_not_valid_after">Jo e vlefshme pas</string>
<string name="account_server_certificate_subject">Subjekt</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_button_advanced">Напредно</string>
<string name="account_server_certificate_not_valid_before">Није важеће пре</string>
<string name="account_server_certificate_button_continue">Прихвати ризик и настави</string>
<string name="account_server_certificate_section_title">Сертификат сервера</string>
<string name="account_server_certificate_subject_alternative_names">Алтернативни називи субјекта</string>
<string name="account_server_certificate_warning_title">Упозорење</string>
<string name="account_server_certificate_unknown_error_subtitle">Грешка сертификата</string>
<string name="account_server_certificate_unknown_error_description_format">Апликација је открила потенцијалну безбедносну претњу и није наставила са повезивањем на <xliff:g id="serverName">%s</xliff:g>.
\nАко наставите, нападачи би могли покушати да украду информације као што су ваша лозинка или имејлови.</string>
<string name="account_server_certificate_button_back">Врати се назад (препоручено)</string>
<string name="account_server_certificate_not_valid_after">Није важеће после</string>
<string name="account_server_certificate_subject">Субјект</string>
<string name="account_server_certificate_issuer">Издавалац</string>
<string name="account_server_certificate_fingerprints_section">Отисци прстију</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Varning</string>
<string name="account_server_certificate_unknown_error_subtitle">Certifikatfel</string>
<string name="account_server_certificate_button_back">Gå tillbaka (rekommenderas)</string>
<string name="account_server_certificate_button_advanced">Avancerat</string>
<string name="account_server_certificate_button_continue">Acceptera risken och fortsätt</string>
<string name="account_server_certificate_section_title">Servercertifikat</string>
<string name="account_server_certificate_subject_alternative_names">Ämnesalternativa namn</string>
<string name="account_server_certificate_not_valid_before">Inte giltigt före</string>
<string name="account_server_certificate_not_valid_after">Inte giltigt efter</string>
<string name="account_server_certificate_subject">Ämne</string>
<string name="account_server_certificate_unknown_error_description_format">Appen upptäckte ett potentiellt säkerhetshot och fortsatte inte att ansluta till <xliff:g id="serverName">%s</xliff:g>.
\nOm du fortsätter kan angripare försöka stjäla information som ditt lösenord eller e-postmeddelanden.</string>
<string name="account_server_certificate_issuer">Utfärdare</string>
<string name="account_server_certificate_fingerprints_section">Fingeravtryck</string>
</resources>

View file

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_unknown_error_subtitle">சான்றிதழ் பிழை</string>
<string name="account_server_certificate_unknown_error_description_format">பயன்பாடு சாத்தியமான பாதுகாப்பு அச்சுறுத்தலைக் கண்டறிந்தது மற்றும் <xliff:g id="serverName">%s</xliff:g> உடன் தொடர்ந்து இணைக்கப்படவில்லை.\n நீங்கள் தொடர்ந்தால், தாக்குதல் நடத்தியவர்கள் உங்கள் கடவுச்சொல் அல்லது மின்னஞ்சல்கள் போன்ற தகவல்களைத் திருட முயற்சி செய்யலாம்.</string>
<string name="account_server_certificate_button_back">திரும்பிச் செல்லுங்கள் (பரிந்துரைக்கப்படுகிறது)</string>
<string name="account_server_certificate_button_continue">ஆபத்தை ஏற்றுக்கொண்டு தொடரவும்</string>
<string name="account_server_certificate_section_title">சேவையக சான்றிதழ்</string>
<string name="account_server_certificate_not_valid_after">பிறகு செல்லுபடியாகாது</string>
<string name="account_server_certificate_subject">பொருள்</string>
<string name="account_server_certificate_button_advanced">மேம்பட்ட</string>
<string name="account_server_certificate_issuer">வழங்குபவர்</string>
<string name="account_server_certificate_fingerprints_section">கைரேகைகள்</string>
<string name="account_server_certificate_warning_title">எச்சரிக்கை</string>
<string name="account_server_certificate_subject_alternative_names">மாற்று பெயர்கள்</string>
<string name="account_server_certificate_not_valid_before">இதற்கு முன் செல்லுபடியாகாது</string>
</resources>

View file

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_unknown_error_subtitle">Sertifika hatası</string>
<string name="account_server_certificate_button_advanced">Gelişmiş</string>
<string name="account_server_certificate_button_continue">Riski kabul ederek devam et</string>
<string name="account_server_certificate_section_title">Sunucu sertifikası</string>
<string name="account_server_certificate_subject_alternative_names">Özne alternatif adları</string>
<string name="account_server_certificate_not_valid_before">Geçerlilik başlangıcı</string>
<string name="account_server_certificate_not_valid_after">Geçerlilik bitişi</string>
<string name="account_server_certificate_subject">Özne</string>
<string name="account_server_certificate_issuer">Düzenleyen</string>
<string name="account_server_certificate_fingerprints_section">Parmak izleri</string>
<string name="account_server_certificate_warning_title">Uyarı</string>
<string name="account_server_certificate_unknown_error_description_format">Uygulama olası bir güvenlik tehdidi algıladı ve <xliff:g id="serverName">%s</xliff:g> sunucusuna bağlanmaya devam etmedi.\nDevam ederseniz saldırganlar parolanız veya e-postalarınız gibi bilgileri çalmaya çalışabilir.</string>
<string name="account_server_certificate_button_back">Geri dön (önerilir)</string>
</resources>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">Попередження</string>
<string name="account_server_certificate_unknown_error_subtitle">Помилка сертифіката</string>
<string name="account_server_certificate_button_advanced">Додатково</string>
<string name="account_server_certificate_button_continue">Погодитися на ризик і продовжити</string>
<string name="account_server_certificate_subject_alternative_names">Альтернативні імена суб\'єктів</string>
<string name="account_server_certificate_not_valid_before">Недійсний до</string>
<string name="account_server_certificate_not_valid_after">Недійсний після</string>
<string name="account_server_certificate_subject">Суб\'єкт</string>
<string name="account_server_certificate_fingerprints_section">Цифрові відбитки</string>
<string name="account_server_certificate_unknown_error_description_format">Застосунок виявив потенційну загрозу безпеці та припинив з\'єднання з <xliff:g id="serverName">%s</xliff:g>.\nЯкщо ви продовжите, зловмисники можуть спробувати викрасти вашу інформацію, наприклад, пароль або електронну пошту.</string>
<string name="account_server_certificate_button_back">Повернутися (рекомендовано)</string>
<string name="account_server_certificate_section_title">Сертифікат сервера</string>
<string name="account_server_certificate_issuer">Видавець</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_unknown_error_description_format">Ứng dụng phát hiện một lỗ hổng bảo mật tiềm năng và không kết nối đến <xliff:g id="serverName">%s</xliff:g>.
\nNếu bạn tiếp tục, kẻ xấu có thể lấy được thông tin cá nhân như mật khẩu và emails.</string>
<string name="account_server_certificate_warning_title">Cảnh báo</string>
<string name="account_server_certificate_unknown_error_subtitle">Lỗi chứng chỉ</string>
<string name="account_server_certificate_button_back">Quay lại (khuyến nghị)</string>
<string name="account_server_certificate_button_advanced">Nâng cao</string>
<string name="account_server_certificate_button_continue">Chấp nhận rủi ro và tiếp tục</string>
<string name="account_server_certificate_section_title">Chứng chỉ máy chủ</string>
<string name="account_server_certificate_subject_alternative_names">Tên miền phụ</string>
<string name="account_server_certificate_not_valid_before">Không hợp lệ trước</string>
<string name="account_server_certificate_not_valid_after">Không hợp lệ sau</string>
<string name="account_server_certificate_subject">Chủ đề</string>
<string name="account_server_certificate_issuer">Bên cấp</string>
<string name="account_server_certificate_fingerprints_section">Dấu vân tay</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">警告</string>
<string name="account_server_certificate_unknown_error_subtitle">证书错误</string>
<string name="account_server_certificate_unknown_error_description_format">此应用检测到潜在的安全威胁,没有继续连接到 <xliff:g id="serverName">%s</xliff:g>
\n如果您继续攻击者可能会试图窃取您的密码或电子邮件等信息。</string>
<string name="account_server_certificate_button_continue">接受风险并继续</string>
<string name="account_server_certificate_button_back">返回(推荐)</string>
<string name="account_server_certificate_button_advanced">高级</string>
<string name="account_server_certificate_section_title">服务器证书</string>
<string name="account_server_certificate_subject_alternative_names">主题备用名称</string>
<string name="account_server_certificate_not_valid_before">此前无效</string>
<string name="account_server_certificate_not_valid_after">此后无效</string>
<string name="account_server_certificate_subject">主题</string>
<string name="account_server_certificate_issuer">颁发者</string>
<string name="account_server_certificate_fingerprints_section">指纹</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="account_server_certificate_warning_title">警告</string>
<string name="account_server_certificate_unknown_error_subtitle">憑證錯誤</string>
<string name="account_server_certificate_button_advanced">進階</string>
<string name="account_server_certificate_unknown_error_description_format">應用程式偵測到潛在的安全威脅,並未繼續連接到 <xliff:g id="serverName">%s</xliff:g>
\n如果您繼續攻擊者可能會試圖竊取您的密碼或電子郵件等資訊。</string>
<string name="account_server_certificate_button_back">返回(推薦)</string>
<string name="account_server_certificate_button_continue">接受風險並繼續</string>
<string name="account_server_certificate_section_title">伺服器憑證</string>
<string name="account_server_certificate_not_valid_before">有效期開始時間</string>
<string name="account_server_certificate_not_valid_after">有效期結束時間</string>
<string name="account_server_certificate_fingerprints_section">指紋</string>
<string name="account_server_certificate_issuer">發行者</string>
<string name="account_server_certificate_subject_alternative_names">主體替代名稱</string>
<string name="account_server_certificate_subject">主體</string>
</resources>

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Title of the server certificate error screen -->
<string name="account_server_certificate_warning_title">Warning</string>
<!-- Subtitle of the server certificate error screen when we're not sure what the exact error is -->
<string name="account_server_certificate_unknown_error_subtitle">Certificate error</string>
<!-- Description text in the server certificate error screen when we're not sure what the exact error is -->
<string name="account_server_certificate_unknown_error_description_format">The app detected a potential security threat and did not continue to connect to <xliff:g id="serverName">%s</xliff:g>.\nIf you continue, attackers could try to steal information like your password or emails.</string>
<!-- Text of the back button in the server certificate error screen. Going back and not accepting the invalid certificate is the recommended action. -->
<string name="account_server_certificate_button_back">Go back (recommended)</string>
<!-- Text of the "more" button in the server certificate error screen. Pressing it will display details about the server certificate and only then allow the user to accept the certificate. -->
<string name="account_server_certificate_button_advanced">Advanced</string>
<!-- Text of the continue button in the server certificate error screen. Pressing it will accept the invalid certificate and continue to connect to the server. -->
<string name="account_server_certificate_button_continue">Accept risk and continue</string>
<!-- Title of the section displaying details of the server certificate -->
<string name="account_server_certificate_section_title">Server certificate</string>
<!-- Heading for the list of subject alternative names (SAN) from the server certificate. This is a technical term. If in doubt, do not translate. See https://en.wikipedia.org/wiki/Subject_Alternative_Name -->
<string name="account_server_certificate_subject_alternative_names">Subject alternative names</string>
<!-- Heading for the date/time when the certificate starts being valid -->
<string name="account_server_certificate_not_valid_before">Not valid before</string>
<!-- Heading for the date/time when the certificate stops being valid -->
<string name="account_server_certificate_not_valid_after">Not valid after</string>
<!-- Heading for the "subject" information from the server certificate. This is a technical term. If in doubt, do not translate. See https://en.wikipedia.org/wiki/Public_key_certificate -->
<string name="account_server_certificate_subject">Subject</string>
<!-- Heading for the "issuer" information from the server certificate. This is a technical term. If in doubt, do not translate. See https://en.wikipedia.org/wiki/Public_key_certificate -->
<string name="account_server_certificate_issuer">Issuer</string>
<!-- Heading for the "fingerprints" of the server certificate. This is a technical term. If in doubt, do not translate. See https://en.wikipedia.org/wiki/Fingerprint_(computing) -->
<string name="account_server_certificate_fingerprints_section">Fingerprints</string>
</resources>

View file

@ -0,0 +1,18 @@
package app.k9mail.feature.account.server.certificate
import app.k9mail.feature.account.server.certificate.ui.ServerCertificateErrorContract
import org.junit.Test
import org.koin.test.KoinTest
import org.koin.test.verify.verify
class ServerCertificateModuleKtTest : KoinTest {
@Test
fun `should have a valid di module`() {
featureAccountServerCertificateModule.verify(
extraTypes = listOf(
ServerCertificateErrorContract.State::class,
),
)
}
}

View file

@ -0,0 +1,137 @@
package app.k9mail.feature.account.server.certificate.domain.usecase
import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertificateError
import app.k9mail.feature.account.server.certificate.domain.entity.ServerCertificateProperties
import assertk.assertThat
import assertk.assertions.isEmpty
import assertk.assertions.isEqualTo
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.text.DateFormat
import java.util.Locale
import java.util.TimeZone
import kotlin.test.BeforeTest
import kotlin.test.Test
import okio.ByteString.Companion.decodeHex
class FormatServerCertificateErrorTest {
@BeforeTest
fun setTimeZone() {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"))
}
@Test
fun `format expired certificate`() {
val formatCertificateError = FormatServerCertificateError(
dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT, Locale.ROOT),
)
val serverCertificateError = ServerCertificateError(
hostname = "expired.badssl.com",
port = 443,
certificateChain = listOf(readCertificate(EXPIRED_CERTIFICATE)),
)
val result = formatCertificateError(serverCertificateError)
assertThat(result.hostname).isEqualTo("expired.badssl.com")
assertThat(result.serverCertificateProperties).isEqualTo(
ServerCertificateProperties(
subjectAlternativeNames = listOf("*.badssl.com", "badssl.com"),
notValidBefore = "2015 Apr 9 00:00",
notValidAfter = "2015 Apr 12 23:59",
subject = "CN=*.badssl.com, OU=PositiveSSL Wildcard, OU=Domain Control Validated",
issuer = "CN=COMODO RSA Domain Validation Secure Server CA, O=COMODO CA Limited, L=Salford, " +
"ST=Greater Manchester, C=GB",
fingerprintSha1 = "404bbd2f1f4cc2fdeef13aabdd523ef61f1c71f3".decodeHex(),
fingerprintSha256 = "ba105ce02bac76888ecee47cd4eb7941653e9ac993b61b2eb3dcc82014d21b4f".decodeHex(),
fingerprintSha512 = (
"851d7249d64f85d1242090b06224b6da67d442ae38cea5d8a78ae1d7d8c3e2f8" +
"f4ad44c7cf239ba5abb05170e0910fd72e6ea5e5c2604888f6c59e5f57c3db27"
).decodeHex(),
),
)
}
@Test
fun `format certificate without subject alternative names`() {
val formatCertificateError = FormatServerCertificateError(
dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT, Locale.ROOT),
)
val serverCertificateError = ServerCertificateError(
hostname = "10.0.0.1",
port = 993,
certificateChain = listOf(readCertificate(CERTIFICATE_WITHOUT_SAN)),
)
val result = formatCertificateError(serverCertificateError)
assertThat(result.serverCertificateProperties.subjectAlternativeNames).isEmpty()
}
private fun readCertificate(asciiArmoredCertificate: String): X509Certificate {
val inputStream = asciiArmoredCertificate.byteInputStream()
val certificateFactory = CertificateFactory.getInstance("X.509")
return certificateFactory.generateCertificate(inputStream) as X509Certificate
}
companion object {
val EXPIRED_CERTIFICATE = """
-----BEGIN CERTIFICATE-----
MIIFSzCCBDOgAwIBAgIQSueVSfqavj8QDxekeOFpCTANBgkqhkiG9w0BAQsFADCB
kDELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxNjA0BgNV
BAMTLUNPTU9ETyBSU0EgRG9tYWluIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBD
QTAeFw0xNTA0MDkwMDAwMDBaFw0xNTA0MTIyMzU5NTlaMFkxITAfBgNVBAsTGERv
bWFpbiBDb250cm9sIFZhbGlkYXRlZDEdMBsGA1UECxMUUG9zaXRpdmVTU0wgV2ls
ZGNhcmQxFTATBgNVBAMUDCouYmFkc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAMIE7PiM7gTCs9hQ1XBYzJMY61yoaEmwIrX5lZ6xKyx2PmzA
S2BMTOqytMAPgLaw+XLJhgL5XEFdEyt/ccRLvOmULlA3pmccYYz2QULFRtMWhyef
dOsKnRFSJiFzbIRMeVXk0WvoBj1IFVKtsyjbqv9u/2CVSndrOfEk0TG23U3AxPxT
uW1CrbV8/q71FdIzSOciccfCFHpsKOo3St/qbLVytH5aohbcabFXRNsKEqveww9H
dFxBIuGa+RuT5q0iBikusbpJHAwnnqP7i/dAcgCskgjZjFeEU4EFy+b+a1SYQCeF
xxC7c3DvaRhBB0VVfPlkPz0sw6l865MaTIbRyoUCAwEAAaOCAdUwggHRMB8GA1Ud
IwQYMBaAFJCvajqUWgvYkOoSVnPfQ7Q6KNrnMB0GA1UdDgQWBBSd7sF7gQs6R2lx
GH0RN5O8pRs/+zAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHSUE
FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwTwYDVR0gBEgwRjA6BgsrBgEEAbIxAQIC
BzArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8uY29tL0NQUzAI
BgZngQwBAgEwVAYDVR0fBE0wSzBJoEegRYZDaHR0cDovL2NybC5jb21vZG9jYS5j
b20vQ09NT0RPUlNBRG9tYWluVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNybDCB
hQYIKwYBBQUHAQEEeTB3ME8GCCsGAQUFBzAChkNodHRwOi8vY3J0LmNvbW9kb2Nh
LmNvbS9DT01PRE9SU0FEb21haW5WYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3J0
MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wIwYDVR0RBBww
GoIMKi5iYWRzc2wuY29tggpiYWRzc2wuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBq
evHa/wMHcnjFZqFPRkMOXxQhjHUa6zbgH6QQFezaMyV8O7UKxwE4PSf9WNnM6i1p
OXy+l+8L1gtY54x/v7NMHfO3kICmNnwUW+wHLQI+G1tjWxWrAPofOxkt3+IjEBEH
fnJ/4r+3ABuYLyw/zoWaJ4wQIghBK4o+gk783SHGVnRwpDTysUCeK1iiWQ8dSO/r
ET7BSp68ZVVtxqPv1dSWzfGuJ/ekVxQ8lEEFeouhN0fX9X3c+s5vMaKwjOrMEpsi
8TRwz311SotoKQwe6Zaoz7ASH1wq7mcvf71z81oBIgxw+s1F73hczg36TuHvzmWf
RwxPuzZEaFZcVlmtqoq8
-----END CERTIFICATE-----
""".trimIndent()
val CERTIFICATE_WITHOUT_SAN = """
-----BEGIN CERTIFICATE-----
MIIDfDCCAmSgAwIBAgIJAJB2iRjpM5OgMA0GCSqGSIb3DQEBCwUAME4xMTAvBgNV
BAsMKE5vIFNOSSBwcm92aWRlZDsgcGxlYXNlIGZpeCB5b3VyIGNsaWVudC4xGTAX
BgNVBAMTEGludmFsaWQyLmludmFsaWQwHhcNMTUwMTAxMDAwMDAwWhcNMzAwMTAx
MDAwMDAwWjBOMTEwLwYDVQQLDChObyBTTkkgcHJvdmlkZWQ7IHBsZWFzZSBmaXgg
eW91ciBjbGllbnQuMRkwFwYDVQQDExBpbnZhbGlkMi5pbnZhbGlkMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzWJP5cMThJgMBeTvRKKl7N6ZcZAbKDVA
tNBNnRhIgSitXxCzKtt9rp2RHkLn76oZjdNO25EPp+QgMiWU/rkkB00Y18Oahw5f
i8s+K9dRv6i+gSOiv2jlIeW/S0hOswUUDH0JXFkEPKILzpl5ML7wdp5kt93vHxa7
HswOtAxEz2WtxMdezm/3CgO3sls20wl3W03iI+kCt7HyvhGy2aRPLhJfeABpQr0U
ku3q6mtomy2cgFawekN/X/aH8KknX799MPcuWutM2q88mtUEBsuZmy2nsjK9J7/y
hhCRDzOV/yY8c5+l/u/rWuwwkZ2lgzGp4xBBfhXdr6+m9kmwWCUm9QIDAQABo10w
WzAOBgNVHQ8BAf8EBAMCAqQwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMC
MA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIEELsPOJZvPr5PK0bQQWrUrLUwDQYJ
KoZIhvcNAQELBQADggEBALnZ4lRc9WHtafO4Y+0DWp4qgSdaGygzS/wtcRP+S2V+
HFOCeYDmeZ9qs0WpNlrtyeBKzBH8hOt9y8aUbZBw2M1F2Mi23Q+dhAEUfQCOKbIT
tunBuVfDTTbAHUuNl/eyr78v8Egi133z7zVgydVG1KA0AOSCB+B65glbpx+xMCpg
ZLux9THydwg3tPo/LfYbRCof+Mb8I3ZCY9O6FfZGjuxJn+0ux3SDora3NX/FmJ+i
kTCTsMtIFWhH3hoyYAamOOuITpPZHD7yP0lfbuncGDEqAQu2YWbYxRixfq2VSxgv
gWbFcmkgBLYpE8iDWT3Kdluo1+6PHaDaLg2SacOY6Go=
-----END CERTIFICATE-----
""".trimIndent()
}
}

View file

@ -0,0 +1,47 @@
package app.k9mail.feature.account.server.certificate.ui
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.withStyle
import assertk.assertThat
import assertk.assertions.isEqualTo
import kotlin.test.Test
import okio.ByteString.Companion.decodeHex
class FingerprintFormatterTest {
private val formatter = DefaultFingerprintFormatter()
@Test
fun `simple fingerprint`() {
val fingerprint = "0088FF".decodeHex()
val separatorColor = Color.Cyan
val result = formatter.format(fingerprint, separatorColor)
assertThat(result).isEqualTo(
buildAnnotatedString {
withStyle(SpanStyle(fontFamily = FontFamily.Monospace)) {
append("00")
}
withStyle(SpanStyle(color = separatorColor)) {
append(":")
}
append('\u200B')
withStyle(SpanStyle(fontFamily = FontFamily.Monospace)) {
append("88")
}
withStyle(SpanStyle(color = separatorColor)) {
append(":")
}
append('\u200B')
withStyle(SpanStyle(fontFamily = FontFamily.Monospace)) {
append("FF")
}
},
)
}
}

View file

@ -0,0 +1,25 @@
package app.k9mail.feature.account.server.certificate.ui
import assertk.assertThat
import assertk.assertions.isEqualTo
import kotlin.test.Test
class ServerNameFormatterTest {
private val formatter = DefaultServerNameFormatter()
@Test
fun hostname() {
assertThat(formatter.format("domain.example")).isEqualTo("domain.\u200Bexample")
}
@Test
fun `IPv4 address`() {
assertThat(formatter.format("127.0.0.1")).isEqualTo("127.\u200B0.\u200B0.\u200B1")
}
@Test
fun `IPv6 address`() {
assertThat(formatter.format("2001:db8::1"))
.isEqualTo("2001:\u200B0db8:\u200B0000:\u200B0000:\u200B0000:\u200B0000:\u200B0000:\u200B0001")
}
}

View file

@ -0,0 +1,22 @@
plugins {
id(ThunderbirdPlugins.Library.androidCompose)
}
android {
namespace = "app.k9mail.feature.account.server.settings"
resourcePrefix = "account_server_settings_"
}
dependencies {
implementation(projects.core.ui.compose.designsystem)
implementation(projects.core.common)
implementation(projects.mail.common)
implementation(projects.mail.protocols.imap)
implementation(projects.feature.account.common)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.biometric)
testImplementation(projects.core.ui.compose.testing)
}

View file

@ -0,0 +1,28 @@
package app.k9mail.feature.account.server.settings.ui.common
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes
import app.k9mail.feature.account.common.domain.entity.InteractionMode
@Composable
@Preview(showBackground = true)
internal fun ServerSettingsPasswordInputCreatePreview() {
PreviewWithThemes {
ServerSettingsPasswordInput(
mode = InteractionMode.Create,
onPasswordChange = {},
)
}
}
@Composable
@Preview(showBackground = true)
internal fun ServerSettingsPasswordInputEditPreview() {
PreviewWithThemes {
ServerSettingsPasswordInput(
mode = InteractionMode.Edit,
onPasswordChange = {},
)
}
}

View file

@ -0,0 +1,20 @@
package app.k9mail.feature.account.server.settings.ui.incoming
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.runtime.Composable
import app.k9mail.core.ui.compose.common.annotation.PreviewDevices
import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme
import app.k9mail.feature.account.common.domain.entity.InteractionMode
@Composable
@PreviewDevices
internal fun IncomingServerSettingsContentPreview() {
PreviewWithTheme {
IncomingServerSettingsContent(
mode = InteractionMode.Create,
onEvent = { },
state = IncomingServerSettingsContract.State(),
contentPadding = PaddingValues(),
)
}
}

View file

@ -0,0 +1,23 @@
package app.k9mail.feature.account.server.settings.ui.incoming
import androidx.compose.runtime.Composable
import app.k9mail.core.ui.compose.common.annotation.PreviewDevices
import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme
import app.k9mail.feature.account.common.domain.entity.InteractionMode
import app.k9mail.feature.account.common.ui.fake.FakeAccountStateRepository
@Composable
@PreviewDevices
internal fun IncomingServerSettingsScreenPreview() {
PreviewWithTheme {
IncomingServerSettingsScreen(
onNext = {},
onBack = {},
viewModel = IncomingServerSettingsViewModel(
mode = InteractionMode.Create,
validator = IncomingServerSettingsValidator(),
accountStateRepository = FakeAccountStateRepository(),
),
)
}
}

View file

@ -0,0 +1,23 @@
package app.k9mail.feature.account.server.settings.ui.outgoing
import androidx.compose.runtime.Composable
import app.k9mail.core.ui.compose.common.annotation.PreviewDevices
import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme
import app.k9mail.feature.account.common.domain.entity.InteractionMode
import app.k9mail.feature.account.common.ui.fake.FakeAccountStateRepository
@Composable
@PreviewDevices
internal fun OutgoingServerSettingsScreenPreview() {
PreviewWithTheme {
OutgoingServerSettingsScreen(
onNext = {},
onBack = {},
viewModel = OutgoingServerSettingsViewModel(
mode = InteractionMode.Create,
validator = OutgoingServerSettingsValidator(),
accountStateRepository = FakeAccountStateRepository(),
),
)
}
}

View file

@ -0,0 +1,20 @@
package app.k9mail.feature.account.server.settings.ui.outgoing
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.runtime.Composable
import app.k9mail.core.ui.compose.common.annotation.PreviewDevices
import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme
import app.k9mail.feature.account.common.domain.entity.InteractionMode
@Composable
@PreviewDevices
internal fun OutgoingServerSettingsContentPreview() {
PreviewWithTheme {
OutgoingServerSettingsContent(
mode = InteractionMode.Create,
state = OutgoingServerSettingsContract.State(),
onEvent = { },
contentPadding = PaddingValues(),
)
}
}

View file

@ -0,0 +1,33 @@
package app.k9mail.feature.account.server.settings
import app.k9mail.feature.account.common.domain.entity.InteractionMode
import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract
import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsValidator
import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsViewModel
import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract
import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsValidator
import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsViewModel
import org.koin.core.module.Module
import org.koin.core.module.dsl.viewModel
import org.koin.dsl.module
val featureAccountServerSettingsModule: Module = module {
factory<IncomingServerSettingsContract.Validator> { IncomingServerSettingsValidator() }
factory<OutgoingServerSettingsContract.Validator> { OutgoingServerSettingsValidator() }
viewModel {
IncomingServerSettingsViewModel(
mode = InteractionMode.Create,
validator = get(),
accountStateRepository = get(),
)
}
viewModel {
OutgoingServerSettingsViewModel(
mode = InteractionMode.Create,
validator = get(),
accountStateRepository = get(),
)
}
}

View file

@ -0,0 +1,29 @@
package app.k9mail.feature.account.server.settings.domain
import net.thunderbird.core.common.domain.usecase.validation.ValidationResult
interface ServerSettingsDomainContract {
interface UseCase {
fun interface ValidatePassword {
fun execute(password: String): ValidationResult
}
fun interface ValidateServer {
fun execute(server: String): ValidationResult
}
fun interface ValidatePort {
fun execute(port: Long?): ValidationResult
}
fun interface ValidateUsername {
fun execute(username: String): ValidationResult
}
fun interface ValidateImapPrefix {
fun execute(imapPrefix: String): ValidationResult
}
}
}

Some files were not shown because too many files have changed in this diff Show more