Import from Authenticator Pro

This commit is contained in:
Rafał Kobyłko 2023-07-02 14:15:19 +02:00
parent a996a59707
commit 699c45a7e0
29 changed files with 339 additions and 26 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -70,11 +70,12 @@ class Strings(c: Context) {
val externalImportTitle = c.getString(R.string.settings__external_import)
val externalImportHeader = c.getString(R.string.externalimport_select_app)
val externalImportNotice = c.getString(R.string.externalimport_description)
val externalImportGoogleAuthenticator = c.getString(R.string.externalimport_google_authenticator)
val externalImportAegis = c.getString(R.string.externalimport_aegis)
val externalImportRaivo = c.getString(R.string.externalimport_raivo)
val externalImportLastPass = c.getString(R.string.externalimport_lastpass)
val externalImportNotice = c.getString(R.string.externalimport_description)
val externalImportAuthenticatorPro = c.getString(R.string.externalimport__authenticatorpro)
val trashTitle = c.getString(R.string.settings__trash)
val trashEmpty = c.getString(R.string.settings__trash_is_empty)

View File

@ -5,7 +5,7 @@
Release: Working copy
Locale: de-DE, German (Germany)
Exported by: rafakob
Exported at: Sun, 02 Jul 2023 00:37:49 -0700
Exported at: Sun, 02 Jul 2023 04:39:36 -0700
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
@ -776,4 +776,10 @@
<string name="settings__hide_tokens_description">Token werden nach dem antippen enthüllt</string>
<string name="browser__pair_manually_cta">Pair manually</string>
<string name="browser__pair_manually_hint">Pairing code</string>
<string name="externalimport__info_authenticatorpro_title">Import tokens from Authenticator Pro</string>
<string name="externalimport__authenticatorpro_success_msg">This text file allows importing tokens from Authenticator Pro.</string>
<string name="externalimport__authenticatorpro_title">Importing 2FA tokens from Authenticator Pro app</string>
<string name="externalimport__authenticatorpro_msg">Export your accounts from Authenticator Pro to an unencrypted text file and upload it using the \"Choose text file\" button. Remember to remove the file after a successful import.</string>
<string name="externalimport__authenticatorpro">Authenticator Pro</string>
<string name="externalimport__choose_txt_cta">Choose text file</string>
</resources>

View File

@ -5,7 +5,7 @@
Release: Working copy
Locale: es-ES, Spanish (Spain)
Exported by: rafakob
Exported at: Sun, 02 Jul 2023 00:37:49 -0700
Exported at: Sun, 02 Jul 2023 04:39:36 -0700
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
@ -776,4 +776,10 @@
<string name="settings__hide_tokens_description">Los tokens se revelarán al tacto</string>
<string name="browser__pair_manually_cta">Pair manually</string>
<string name="browser__pair_manually_hint">Pairing code</string>
<string name="externalimport__info_authenticatorpro_title">Import tokens from Authenticator Pro</string>
<string name="externalimport__authenticatorpro_success_msg">This text file allows importing tokens from Authenticator Pro.</string>
<string name="externalimport__authenticatorpro_title">Importing 2FA tokens from Authenticator Pro app</string>
<string name="externalimport__authenticatorpro_msg">Export your accounts from Authenticator Pro to an unencrypted text file and upload it using the \"Choose text file\" button. Remember to remove the file after a successful import.</string>
<string name="externalimport__authenticatorpro">Authenticator Pro</string>
<string name="externalimport__choose_txt_cta">Choose text file</string>
</resources>

View File

@ -5,7 +5,7 @@
Release: Working copy
Locale: fr-FR, French (France)
Exported by: rafakob
Exported at: Sun, 02 Jul 2023 00:37:49 -0700
Exported at: Sun, 02 Jul 2023 04:39:36 -0700
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
@ -776,4 +776,10 @@
<string name="settings__hide_tokens_description">Les jetons sont révélés lorsque vous appuyez sur l\'écran.</string>
<string name="browser__pair_manually_cta">Pair manually</string>
<string name="browser__pair_manually_hint">Pairing code</string>
<string name="externalimport__info_authenticatorpro_title">Import tokens from Authenticator Pro</string>
<string name="externalimport__authenticatorpro_success_msg">This text file allows importing tokens from Authenticator Pro.</string>
<string name="externalimport__authenticatorpro_title">Importing 2FA tokens from Authenticator Pro app</string>
<string name="externalimport__authenticatorpro_msg">Export your accounts from Authenticator Pro to an unencrypted text file and upload it using the \"Choose text file\" button. Remember to remove the file after a successful import.</string>
<string name="externalimport__authenticatorpro">Authenticator Pro</string>
<string name="externalimport__choose_txt_cta">Choose text file</string>
</resources>

View File

@ -5,7 +5,7 @@
Release: Working copy
Locale: it-IT, Italian (Italy)
Exported by: rafakob
Exported at: Sun, 02 Jul 2023 00:37:49 -0700
Exported at: Sun, 02 Jul 2023 04:39:36 -0700
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
@ -776,4 +776,10 @@
<string name="settings__hide_tokens_description">I token saranno rivelati al tocco</string>
<string name="browser__pair_manually_cta">Pair manually</string>
<string name="browser__pair_manually_hint">Pairing code</string>
<string name="externalimport__info_authenticatorpro_title">Import tokens from Authenticator Pro</string>
<string name="externalimport__authenticatorpro_success_msg">This text file allows importing tokens from Authenticator Pro.</string>
<string name="externalimport__authenticatorpro_title">Importing 2FA tokens from Authenticator Pro app</string>
<string name="externalimport__authenticatorpro_msg">Export your accounts from Authenticator Pro to an unencrypted text file and upload it using the \"Choose text file\" button. Remember to remove the file after a successful import.</string>
<string name="externalimport__authenticatorpro">Authenticator Pro</string>
<string name="externalimport__choose_txt_cta">Choose text file</string>
</resources>

View File

@ -5,7 +5,7 @@
Release: Working copy
Locale: pl-PL, Polish (Poland)
Exported by: rafakob
Exported at: Sun, 02 Jul 2023 00:37:49 -0700
Exported at: Sun, 02 Jul 2023 04:39:36 -0700
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
@ -782,4 +782,10 @@
<string name="settings__hide_tokens_description">Pokaż token po kliknięciu</string>
<string name="browser__pair_manually_cta">Pair manually</string>
<string name="browser__pair_manually_hint">Pairing code</string>
<string name="externalimport__info_authenticatorpro_title">Import tokens from Authenticator Pro</string>
<string name="externalimport__authenticatorpro_success_msg">This text file allows importing tokens from Authenticator Pro.</string>
<string name="externalimport__authenticatorpro_title">Importing 2FA tokens from Authenticator Pro app</string>
<string name="externalimport__authenticatorpro_msg">Export your accounts from Authenticator Pro to an unencrypted text file and upload it using the \"Choose text file\" button. Remember to remove the file after a successful import.</string>
<string name="externalimport__authenticatorpro">Authenticator Pro</string>
<string name="externalimport__choose_txt_cta">Choose text file</string>
</resources>

View File

@ -5,7 +5,7 @@
Release: Working copy
Locale: pt-PT, Portuguese (Portugal)
Exported by: rafakob
Exported at: Sun, 02 Jul 2023 00:37:49 -0700
Exported at: Sun, 02 Jul 2023 04:39:36 -0700
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
@ -776,4 +776,10 @@
<string name="settings__hide_tokens_description">Os tokens serão revelados ao tocar</string>
<string name="browser__pair_manually_cta">Pair manually</string>
<string name="browser__pair_manually_hint">Pairing code</string>
<string name="externalimport__info_authenticatorpro_title">Import tokens from Authenticator Pro</string>
<string name="externalimport__authenticatorpro_success_msg">This text file allows importing tokens from Authenticator Pro.</string>
<string name="externalimport__authenticatorpro_title">Importing 2FA tokens from Authenticator Pro app</string>
<string name="externalimport__authenticatorpro_msg">Export your accounts from Authenticator Pro to an unencrypted text file and upload it using the \"Choose text file\" button. Remember to remove the file after a successful import.</string>
<string name="externalimport__authenticatorpro">Authenticator Pro</string>
<string name="externalimport__choose_txt_cta">Choose text file</string>
</resources>

View File

@ -5,7 +5,7 @@
Release: Working copy
Locale: uk-UA, Ukrainian (Ukraine)
Exported by: rafakob
Exported at: Sun, 02 Jul 2023 00:37:49 -0700
Exported at: Sun, 02 Jul 2023 04:39:36 -0700
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
@ -780,6 +780,12 @@
<string name="social__facebook">Facebook</string>
<string name="settings__hide_tokens_title">Сховати токени</string>
<string name="settings__hide_tokens_description">Показати токени при натисканні</string>
<string name="browser__pair_manually_cta">Pair manually</string>
<string name="browser__pair_manually_hint">Pairing code</string>
<string name="browser__pair_manually_cta">Підключити вручну</string>
<string name="browser__pair_manually_hint">Код підключення</string>
<string name="externalimport__info_authenticatorpro_title">Імпорт токенів з Authenticator Pro</string>
<string name="externalimport__authenticatorpro_success_msg">Цей текстовий файл дозволяє імпорт токенів з Authenticator Pro.</string>
<string name="externalimport__authenticatorpro_title">Імпорт 2ФА токенів з додатку Authenticator Pro</string>
<string name="externalimport__authenticatorpro_msg">Експортуйте ваші акаунти з Authenticator Pro в незашифрований текстовий файл і завантажте його, використовуючи кнопку \"Обрати текстовий файл\". Не забудьте видалити файл після успішного імпорту.</string>
<string name="externalimport__authenticatorpro">Authenticator Pro</string>
<string name="externalimport__choose_txt_cta">Оберіть текстовий файл</string>
</resources>

View File

@ -5,7 +5,7 @@
Release: Working copy
Locale: en, English
Exported by: rafakob
Exported at: Sun, 02 Jul 2023 00:37:49 -0700
Exported at: Sun, 02 Jul 2023 04:39:36 -0700
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
@ -776,4 +776,10 @@
<string name="settings__hide_tokens_description">Tokens will be revealed on tap</string>
<string name="browser__pair_manually_cta">Pair manually</string>
<string name="browser__pair_manually_hint">Pairing code</string>
<string name="externalimport__info_authenticatorpro_title">Import tokens from Authenticator Pro</string>
<string name="externalimport__authenticatorpro_success_msg">This text file allows importing tokens from Authenticator Pro.</string>
<string name="externalimport__authenticatorpro_title">Importing 2FA tokens from Authenticator Pro app</string>
<string name="externalimport__authenticatorpro_msg">Export your accounts from Authenticator Pro to an unencrypted text file and upload it using the \"Choose text file\" button. Remember to remove the file after a successful import.</string>
<string name="externalimport__authenticatorpro">Authenticator Pro</string>
<string name="externalimport__choose_txt_cta">Choose text file</string>
</resources>

View File

@ -211,6 +211,9 @@ internal class ServicesRepositoryImpl(
override fun isServiceValid(link: OtpAuthLink): Boolean {
return try {
val otpAlgorithm = link.params[OtpAuthLink.ALGORITHM_PARAM]
val otpDigits = link.params[OtpAuthLink.DIGITS_PARAM]?.toIntOrNull()
val otpPeriod = link.params[OtpAuthLink.PERIOD_PARAM]?.toIntOrNull()
val algorithm = when {
otpAlgorithm == null -> Service.Algorithm.SHA1
otpAlgorithm.equals("SHA1", ignoreCase = true) -> Service.Algorithm.SHA1
@ -221,10 +224,26 @@ internal class ServicesRepositoryImpl(
else -> return false
}
val digits = when {
otpDigits == 6 -> 6
otpDigits == 7 -> 7
otpDigits == 8 -> 8
otpDigits == null -> 6
else -> return false
}
val period = when {
otpPeriod == 30 -> 30
otpPeriod == 60 -> 60
otpPeriod == 90 -> 90
otpPeriod == null -> 30
else -> return false
}
codeGenerator.check(
secret = link.secret,
digits = link.params[OtpAuthLink.DIGITS_PARAM]?.toIntOrNull() ?: 6,
period = link.params[OtpAuthLink.PERIOD_PARAM]?.toIntOrNull() ?: 30,
digits = digits,
period = period,
algorithm = algorithm
)
} catch (e: Exception) {

View File

@ -0,0 +1,73 @@
package com.twofasapp.data.services.otp
import android.net.Uri
import com.twofasapp.parsers.domain.OtpAuthLink
import timber.log.Timber
// TODO: This object should replace ParseOtpAuthLink
object OtpLinkParser {
private const val OTPAUTH = "otpauth"
private const val TOTP = "totp"
private const val HOTP = "hotp"
private const val SECRET = "secret"
private const val ISSUER = "issuer"
fun parseLegacy(link: String): OtpAuthLink? {
try {
Timber.d("Parse link: $link")
val decoded = Uri.decode(link).replace("#", "-") // remove hash, Uri.parse terminates on that
val uri = Uri.parse(decoded)
if (isUriValid(uri).not()) {
return null
// throw IllegalArgumentException("Link is not supported")
}
if (isAuthorityValid(uri).not()) {
return null
// throw IllegalArgumentException("Only TOTP and HOTP are supported")
}
val type = uri.authority!!
val label = getPath(uri)
val secret = uri.getQueryParameter(SECRET) ?: ""
val issuer = uri.getQueryParameter(ISSUER)
val queryParams = mapQueryParams(uri)
val otpAuthLink = OtpAuthLink(
type = type,
label = label,
secret = secret,
issuer = issuer,
params = queryParams,
link = link,
)
return otpAuthLink
} catch (e: Exception) {
Timber.e(e)
return null
}
}
private fun isUriValid(uri: Uri?) = uri?.scheme?.toLowerCase() == OTPAUTH
private fun isAuthorityValid(uri: Uri) =
uri.authority?.lowercase() == TOTP || uri.authority?.lowercase() == HOTP
private fun mapQueryParams(uri: Uri) = uri.queryParameterNames.map { it to uri.getQueryParameter(it)!! }.toMap()
private fun getPath(uri: Uri): String {
if (uri.path == null) return ""
return if (uri.path!!.startsWith("/")) uri.path!!.drop(1) else uri.path!!
}
data class Params(
val link: String
)
}

View File

@ -2,6 +2,7 @@ package com.twofasapp.feature.externalimport.di
import com.twofasapp.di.KoinModule
import com.twofasapp.feature.externalimport.domain.AegisImporter
import com.twofasapp.feature.externalimport.domain.AuthenticatorProImporter
import com.twofasapp.feature.externalimport.domain.GoogleAuthenticatorImporter
import com.twofasapp.feature.externalimport.domain.LastPassImporter
import com.twofasapp.feature.externalimport.domain.RaivoImporter
@ -21,5 +22,6 @@ class ExternalImportModule : KoinModule {
factoryOf(::AegisImporter)
factoryOf(::RaivoImporter)
factoryOf(::LastPassImporter)
factoryOf(::AuthenticatorProImporter)
}
}

View File

@ -0,0 +1,56 @@
package com.twofasapp.feature.externalimport.domain
import android.content.Context
import android.net.Uri
import com.twofasapp.data.services.ServicesRepository
import com.twofasapp.data.services.otp.OtpLinkParser
import com.twofasapp.prefs.model.ServiceDto
import com.twofasapp.services.domain.ConvertOtpLinkToService
import java.io.BufferedReader
internal class AuthenticatorProImporter(
private val context: Context,
private val convertOtpLinkToService: ConvertOtpLinkToService,
private val servicesRepository: ServicesRepository,
) : ExternalImporter {
override fun isSchemaSupported(content: String): Boolean {
return true
}
override fun read(content: String): ExternalImport {
try {
val fileUri = Uri.parse(content)
val fileDescriptor = context.contentResolver.openAssetFileDescriptor(fileUri, "r")
val size = fileDescriptor?.length ?: 0
if (size > 10 * 1024 * 1024) {
return ExternalImport.ParsingError(RuntimeException("File too big"))
}
val inputStream = context.contentResolver.openInputStream(fileUri)!!
val text = inputStream.bufferedReader(Charsets.UTF_8).use(BufferedReader::readText)
fileDescriptor?.close()
inputStream.close()
val totalServices = text.lines().filter { it.isNotBlank() }.size
val servicesToImport = mutableListOf<ServiceDto>()
text.lines()
.filter { it.isNotBlank() }
.mapNotNull { OtpLinkParser.parseLegacy(it) }
.filter { servicesRepository.isServiceValid(it) }
.forEach { entry -> servicesToImport.add(convertOtpLinkToService.execute(entry)) }
return ExternalImport.Success(
servicesToImport = servicesToImport,
totalServicesCount = totalServices,
)
} catch (e: Exception) {
e.printStackTrace()
return ExternalImport.ParsingError(e)
}
}
}

View File

@ -10,6 +10,7 @@ import com.twofasapp.android.navigation.NavGraph
import com.twofasapp.android.navigation.NavNode
import com.twofasapp.android.navigation.withArg
import com.twofasapp.feature.externalimport.navigation.ExternalImportNode.Aegis
import com.twofasapp.feature.externalimport.navigation.ExternalImportNode.AuthenticatorPro
import com.twofasapp.feature.externalimport.navigation.ExternalImportNode.GoogleAuthenticator
import com.twofasapp.feature.externalimport.navigation.ExternalImportNode.LastPass
import com.twofasapp.feature.externalimport.navigation.ExternalImportNode.Raivo
@ -17,6 +18,7 @@ import com.twofasapp.feature.externalimport.navigation.ExternalImportNode.Result
import com.twofasapp.feature.externalimport.navigation.ExternalImportNode.Scan
import com.twofasapp.feature.externalimport.navigation.ExternalImportNode.Selector
import com.twofasapp.feature.externalimport.ui.aegis.AegisRoute
import com.twofasapp.feature.externalimport.ui.authenticatorpro.AuthenticatorProRoute
import com.twofasapp.feature.externalimport.ui.googleauthenticator.GoogleAuthenticatorRoute
import com.twofasapp.feature.externalimport.ui.lastpass.LastPassRoute
import com.twofasapp.feature.externalimport.ui.raivo.RaivoRoute
@ -28,7 +30,14 @@ object ExternalImportGraph : NavGraph {
override val route: String = "externalimport"
}
enum class ImportType { GoogleAuthenticator, Aegis, Raivo, LastPass }
enum class ImportType {
GoogleAuthenticator,
Aegis,
Raivo,
LastPass,
AuthenticatorPro,
;
}
private object NavArg {
val ImportType = navArgument("importType") { type = NavType.StringType; }
@ -44,6 +53,7 @@ private sealed class ExternalImportNode(override val path: String) : NavNode {
object Aegis : ExternalImportNode("aegis")
object Raivo : ExternalImportNode("raivo")
object LastPass : ExternalImportNode("lastpass")
object AuthenticatorPro : ExternalImportNode("authenticatorpro")
object Scan : ExternalImportNode("scan?startFromGallery={${NavArg.StartFromGallery.name}}")
object Result : ExternalImportNode("result/{${NavArg.ImportType.name}}/{${NavArg.ImportContent.name}}")
}
@ -63,6 +73,7 @@ fun NavGraphBuilder.externalImportNavigation(
onAegisClick = { navController.navigate(Aegis.route) },
onRaivoClick = { navController.navigate(Raivo.route) },
onLastPassClick = { navController.navigate(LastPass.route) },
onAuthenticatorProClick = { navController.navigate(AuthenticatorPro.route) },
)
}
@ -106,6 +117,16 @@ fun NavGraphBuilder.externalImportNavigation(
})
}
composable(route = AuthenticatorPro.route) {
AuthenticatorProRoute(onFilePicked = { content ->
navController.navigate(
Result.route
.withArg(NavArg.ImportType, ImportType.AuthenticatorPro.name)
.withArg(NavArg.ImportContent, content)
)
})
}
composable(
route = Scan.route,
arguments = listOf(NavArg.StartFromGallery)

View File

@ -0,0 +1,28 @@
package com.twofasapp.feature.externalimport.ui.authenticatorpro
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import com.twofasapp.core.encoding.encodeBase64ToString
import com.twofasapp.feature.externalimport.ui.common.ImportDescription
import com.twofasapp.feature.externalimport.ui.common.ImportFilePickerButton
import com.twofasapp.feature.externalimport.ui.common.ImportFileScaffold
import com.twofasapp.resources.R
@Composable
internal fun AuthenticatorProRoute(
onFilePicked: (String) -> Unit,
) {
ImportFileScaffold(
title = stringResource(id = R.string.externalimport__authenticatorpro),
image = painterResource(id = R.drawable.ic_import_authenticatorpro),
description = { ImportDescription(text = stringResource(id = R.string.externalimport__authenticatorpro_msg)) }
) {
ImportFilePickerButton(
text = stringResource(id = R.string.externalimport__choose_txt_cta),
fileType = "text/*",
onFilePicked = { onFilePicked(it.toString().encodeBase64ToString()) }
)
}
}

View File

@ -79,6 +79,7 @@ internal fun ImportResultRoute(
ImportType.Aegis -> R.drawable.ic_import_aegis
ImportType.Raivo -> R.drawable.ic_import_raivo
ImportType.LastPass -> R.drawable.ic_import_lastpass
ImportType.AuthenticatorPro -> R.drawable.ic_import_authenticatorpro
}
),
contentDescription = null,

View File

@ -7,6 +7,7 @@ import com.twofasapp.base.BaseViewModel
import com.twofasapp.base.dispatcher.Dispatchers
import com.twofasapp.core.encoding.decodeBase64
import com.twofasapp.feature.externalimport.domain.AegisImporter
import com.twofasapp.feature.externalimport.domain.AuthenticatorProImporter
import com.twofasapp.feature.externalimport.domain.ExternalImport
import com.twofasapp.feature.externalimport.domain.GoogleAuthenticatorImporter
import com.twofasapp.feature.externalimport.domain.LastPassImporter
@ -26,12 +27,13 @@ import kotlinx.coroutines.launch
internal class ImportResultViewModel(
private val dispatchers: Dispatchers,
private val addServiceCase: AddServiceCase,
private val syncBackupDispatcher: SyncBackupWorkDispatcher,
private val googleAuthenticatorImporter: GoogleAuthenticatorImporter,
private val aegisImporter: AegisImporter,
private val raivoImporter: RaivoImporter,
private val lastPassImporter: LastPassImporter,
private val addServiceCase: AddServiceCase,
private val syncBackupDispatcher: SyncBackupWorkDispatcher,
private val authenticatorProImporter: AuthenticatorProImporter,
) : BaseViewModel() {
private val _uiState = MutableStateFlow(ImportResultUiState())
@ -44,6 +46,7 @@ internal class ImportResultViewModel(
ImportType.Aegis -> aegisImporter.read(content.decodeBase64())
ImportType.Raivo -> raivoImporter.read(content.decodeBase64())
ImportType.LastPass -> lastPassImporter.read(content.decodeBase64())
ImportType.AuthenticatorPro -> authenticatorProImporter.read(content.decodeBase64())
}
when (result) {
@ -99,6 +102,7 @@ internal class ImportResultViewModel(
ImportType.Aegis -> R.string.externalimport__aegis_title
ImportType.Raivo -> R.string.externalimport__raivo_title
ImportType.LastPass -> R.string.externalimport__lastpass_title
ImportType.AuthenticatorPro -> R.string.externalimport__authenticatorpro_title
}
private fun getSuccessDescription(type: ImportType) = when (type) {
@ -106,5 +110,6 @@ internal class ImportResultViewModel(
ImportType.Aegis -> R.string.externalimport__aegis_success_msg
ImportType.Raivo -> R.string.externalimport__raivo_success_msg
ImportType.LastPass -> R.string.externalimport__lastpass_success_msg
ImportType.AuthenticatorPro -> R.string.externalimport__authenticatorpro_success_msg
}
}

View File

@ -19,12 +19,14 @@ internal fun SelectorRoute(
onAegisClick: () -> Unit,
onRaivoClick: () -> Unit,
onLastPassClick: () -> Unit,
onAuthenticatorProClick: () -> Unit,
) {
SelectorScreen(
onGoogleAuthenticatorClick = onGoogleAuthenticatorClick,
onAegisClick = onAegisClick,
onRaivoClick = onRaivoClick,
onLastPassClick = onLastPassClick,
onAuthenticatorProClick = onAuthenticatorProClick,
)
}
@ -34,6 +36,7 @@ private fun SelectorScreen(
onAegisClick: () -> Unit,
onRaivoClick: () -> Unit,
onLastPassClick: () -> Unit,
onAuthenticatorProClick: () -> Unit,
) {
Scaffold(
@ -77,6 +80,14 @@ private fun SelectorScreen(
)
}
item {
SettingsLink(
title = TwLocale.strings.externalImportAuthenticatorPro,
image = painterResource(id = R.drawable.logo_authenticatorpro),
onClick = onAuthenticatorProClick
)
}
item {
SettingsDescription(text = TwLocale.strings.externalImportNotice)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -5,7 +5,7 @@
Release: Working copy
Locale: de-DE, German (Germany)
Exported by: rafakob
Exported at: Sun, 02 Jul 2023 00:37:49 -0700
Exported at: Sun, 02 Jul 2023 04:39:36 -0700
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
@ -776,4 +776,10 @@
<string name="settings__hide_tokens_description">Token werden nach dem antippen enthüllt</string>
<string name="browser__pair_manually_cta">Pair manually</string>
<string name="browser__pair_manually_hint">Pairing code</string>
<string name="externalimport__info_authenticatorpro_title">Import tokens from Authenticator Pro</string>
<string name="externalimport__authenticatorpro_success_msg">This text file allows importing tokens from Authenticator Pro.</string>
<string name="externalimport__authenticatorpro_title">Importing 2FA tokens from Authenticator Pro app</string>
<string name="externalimport__authenticatorpro_msg">Export your accounts from Authenticator Pro to an unencrypted text file and upload it using the \"Choose text file\" button. Remember to remove the file after a successful import.</string>
<string name="externalimport__authenticatorpro">Authenticator Pro</string>
<string name="externalimport__choose_txt_cta">Choose text file</string>
</resources>

View File

@ -5,7 +5,7 @@
Release: Working copy
Locale: es-ES, Spanish (Spain)
Exported by: rafakob
Exported at: Sun, 02 Jul 2023 00:37:49 -0700
Exported at: Sun, 02 Jul 2023 04:39:36 -0700
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
@ -776,4 +776,10 @@
<string name="settings__hide_tokens_description">Los tokens se revelarán al tacto</string>
<string name="browser__pair_manually_cta">Pair manually</string>
<string name="browser__pair_manually_hint">Pairing code</string>
<string name="externalimport__info_authenticatorpro_title">Import tokens from Authenticator Pro</string>
<string name="externalimport__authenticatorpro_success_msg">This text file allows importing tokens from Authenticator Pro.</string>
<string name="externalimport__authenticatorpro_title">Importing 2FA tokens from Authenticator Pro app</string>
<string name="externalimport__authenticatorpro_msg">Export your accounts from Authenticator Pro to an unencrypted text file and upload it using the \"Choose text file\" button. Remember to remove the file after a successful import.</string>
<string name="externalimport__authenticatorpro">Authenticator Pro</string>
<string name="externalimport__choose_txt_cta">Choose text file</string>
</resources>

View File

@ -5,7 +5,7 @@
Release: Working copy
Locale: fr-FR, French (France)
Exported by: rafakob
Exported at: Sun, 02 Jul 2023 00:37:49 -0700
Exported at: Sun, 02 Jul 2023 04:39:36 -0700
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
@ -776,4 +776,10 @@
<string name="settings__hide_tokens_description">Les jetons sont révélés lorsque vous appuyez sur l\'écran.</string>
<string name="browser__pair_manually_cta">Pair manually</string>
<string name="browser__pair_manually_hint">Pairing code</string>
<string name="externalimport__info_authenticatorpro_title">Import tokens from Authenticator Pro</string>
<string name="externalimport__authenticatorpro_success_msg">This text file allows importing tokens from Authenticator Pro.</string>
<string name="externalimport__authenticatorpro_title">Importing 2FA tokens from Authenticator Pro app</string>
<string name="externalimport__authenticatorpro_msg">Export your accounts from Authenticator Pro to an unencrypted text file and upload it using the \"Choose text file\" button. Remember to remove the file after a successful import.</string>
<string name="externalimport__authenticatorpro">Authenticator Pro</string>
<string name="externalimport__choose_txt_cta">Choose text file</string>
</resources>

View File

@ -5,7 +5,7 @@
Release: Working copy
Locale: it-IT, Italian (Italy)
Exported by: rafakob
Exported at: Sun, 02 Jul 2023 00:37:49 -0700
Exported at: Sun, 02 Jul 2023 04:39:36 -0700
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
@ -776,4 +776,10 @@
<string name="settings__hide_tokens_description">I token saranno rivelati al tocco</string>
<string name="browser__pair_manually_cta">Pair manually</string>
<string name="browser__pair_manually_hint">Pairing code</string>
<string name="externalimport__info_authenticatorpro_title">Import tokens from Authenticator Pro</string>
<string name="externalimport__authenticatorpro_success_msg">This text file allows importing tokens from Authenticator Pro.</string>
<string name="externalimport__authenticatorpro_title">Importing 2FA tokens from Authenticator Pro app</string>
<string name="externalimport__authenticatorpro_msg">Export your accounts from Authenticator Pro to an unencrypted text file and upload it using the \"Choose text file\" button. Remember to remove the file after a successful import.</string>
<string name="externalimport__authenticatorpro">Authenticator Pro</string>
<string name="externalimport__choose_txt_cta">Choose text file</string>
</resources>

View File

@ -5,7 +5,7 @@
Release: Working copy
Locale: pl-PL, Polish (Poland)
Exported by: rafakob
Exported at: Sun, 02 Jul 2023 00:37:49 -0700
Exported at: Sun, 02 Jul 2023 04:39:36 -0700
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
@ -782,4 +782,10 @@
<string name="settings__hide_tokens_description">Pokaż token po kliknięciu</string>
<string name="browser__pair_manually_cta">Pair manually</string>
<string name="browser__pair_manually_hint">Pairing code</string>
<string name="externalimport__info_authenticatorpro_title">Import tokens from Authenticator Pro</string>
<string name="externalimport__authenticatorpro_success_msg">This text file allows importing tokens from Authenticator Pro.</string>
<string name="externalimport__authenticatorpro_title">Importing 2FA tokens from Authenticator Pro app</string>
<string name="externalimport__authenticatorpro_msg">Export your accounts from Authenticator Pro to an unencrypted text file and upload it using the \"Choose text file\" button. Remember to remove the file after a successful import.</string>
<string name="externalimport__authenticatorpro">Authenticator Pro</string>
<string name="externalimport__choose_txt_cta">Choose text file</string>
</resources>

View File

@ -5,7 +5,7 @@
Release: Working copy
Locale: pt-PT, Portuguese (Portugal)
Exported by: rafakob
Exported at: Sun, 02 Jul 2023 00:37:49 -0700
Exported at: Sun, 02 Jul 2023 04:39:36 -0700
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
@ -776,4 +776,10 @@
<string name="settings__hide_tokens_description">Os tokens serão revelados ao tocar</string>
<string name="browser__pair_manually_cta">Pair manually</string>
<string name="browser__pair_manually_hint">Pairing code</string>
<string name="externalimport__info_authenticatorpro_title">Import tokens from Authenticator Pro</string>
<string name="externalimport__authenticatorpro_success_msg">This text file allows importing tokens from Authenticator Pro.</string>
<string name="externalimport__authenticatorpro_title">Importing 2FA tokens from Authenticator Pro app</string>
<string name="externalimport__authenticatorpro_msg">Export your accounts from Authenticator Pro to an unencrypted text file and upload it using the \"Choose text file\" button. Remember to remove the file after a successful import.</string>
<string name="externalimport__authenticatorpro">Authenticator Pro</string>
<string name="externalimport__choose_txt_cta">Choose text file</string>
</resources>

View File

@ -5,7 +5,7 @@
Release: Working copy
Locale: uk-UA, Ukrainian (Ukraine)
Exported by: rafakob
Exported at: Sun, 02 Jul 2023 00:37:49 -0700
Exported at: Sun, 02 Jul 2023 04:39:36 -0700
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
@ -780,6 +780,12 @@
<string name="social__facebook">Facebook</string>
<string name="settings__hide_tokens_title">Сховати токени</string>
<string name="settings__hide_tokens_description">Показати токени при натисканні</string>
<string name="browser__pair_manually_cta">Pair manually</string>
<string name="browser__pair_manually_hint">Pairing code</string>
<string name="browser__pair_manually_cta">Підключити вручну</string>
<string name="browser__pair_manually_hint">Код підключення</string>
<string name="externalimport__info_authenticatorpro_title">Імпорт токенів з Authenticator Pro</string>
<string name="externalimport__authenticatorpro_success_msg">Цей текстовий файл дозволяє імпорт токенів з Authenticator Pro.</string>
<string name="externalimport__authenticatorpro_title">Імпорт 2ФА токенів з додатку Authenticator Pro</string>
<string name="externalimport__authenticatorpro_msg">Експортуйте ваші акаунти з Authenticator Pro в незашифрований текстовий файл і завантажте його, використовуючи кнопку \"Обрати текстовий файл\". Не забудьте видалити файл після успішного імпорту.</string>
<string name="externalimport__authenticatorpro">Authenticator Pro</string>
<string name="externalimport__choose_txt_cta">Оберіть текстовий файл</string>
</resources>

View File

@ -5,7 +5,7 @@
Release: Working copy
Locale: en, English
Exported by: rafakob
Exported at: Sun, 02 Jul 2023 00:37:49 -0700
Exported at: Sun, 02 Jul 2023 04:39:36 -0700
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
@ -776,4 +776,10 @@
<string name="settings__hide_tokens_description">Tokens will be revealed on tap</string>
<string name="browser__pair_manually_cta">Pair manually</string>
<string name="browser__pair_manually_hint">Pairing code</string>
<string name="externalimport__info_authenticatorpro_title">Import tokens from Authenticator Pro</string>
<string name="externalimport__authenticatorpro_success_msg">This text file allows importing tokens from Authenticator Pro.</string>
<string name="externalimport__authenticatorpro_title">Importing 2FA tokens from Authenticator Pro app</string>
<string name="externalimport__authenticatorpro_msg">Export your accounts from Authenticator Pro to an unencrypted text file and upload it using the \"Choose text file\" button. Remember to remove the file after a successful import.</string>
<string name="externalimport__authenticatorpro">Authenticator Pro</string>
<string name="externalimport__choose_txt_cta">Choose text file</string>
</resources>