Skip to content

Commit

Permalink
Merge branch 'release/5.1.0' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
rafakob committed Nov 17, 2023
2 parents a47a2fe + d6feb63 commit 3863bc6
Show file tree
Hide file tree
Showing 158 changed files with 355 additions and 216 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Please note that the graphics used in this app are not part of the open source p

We use GitHub for bug reports. Please visit the [2FAS for Android issues page](https://github.com/twofas/2fas-android/issues) to search for and report any bugs you may have found. Before adding a new issue, please search for existing issues to avoid duplicates.

For reporting security issues only, please send a detailed description of the vulnerability to [email protected]. Do not use this address for general inquiries or bug reports unrelated to security concerns.

## Getting Started

1. Download the app from the [releases page](https://2fas.com).
Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ android {

defaultConfig {
applicationId = "com.twofasapp"
versionName = "5.0.4"
versionCode = 5000008
versionName = "5.1.0"
versionCode = 5000009

val versionCodeOffset = 5000000

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package com.twofasapp.buildlogic.extension

import com.android.build.api.dsl.CommonExtension
import com.twofasapp.buildlogic.version.AppConfig
import com.twofasapp.buildlogic.version.AppConfig.compileSdk
import com.twofasapp.buildlogic.version.AppConfig.minSdk
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.plugins.ExtensionAware
Expand Down Expand Up @@ -55,15 +53,17 @@ internal fun Project.applyKotlinAndroid(
}

packaging {
resources.excludes.add("META-INF/DEPENDENCIES")
resources.excludes.add("META-INF/LICENSE")
resources.excludes.add("META-INF/LICENSE.txt")
resources.excludes.add("META-INF/license.txt")
resources.excludes.add("META-INF/NOTICE")
resources.excludes.add("META-INF/NOTICE.txt")
resources.excludes.add("META-INF/notice.txt")
resources.excludes.add("META-INF/ASL2.0")
resources.excludes.add("/META-INF/{AL2.0,LGPL2.1}")
resources {
excludes += "META-INF/DEPENDENCIES"
excludes += "META-INF/LICENSE"
excludes += "META-INF/LICENSE.txt"
excludes += "META-INF/license.txt"
excludes += "META-INF/NOTICE"
excludes += "META-INF/NOTICE.txt"
excludes += "META-INF/notice.txt"
excludes += "META-INF/ASL2.0"
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}

testOptions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ data class Service(
val progress: Float,
)

enum class AuthType { TOTP, HOTP }
enum class AuthType { TOTP, HOTP, STEAM }
enum class Algorithm { SHA1, SHA224, SHA256, SHA384, SHA512 }
enum class ImageType { IconCollection, Label }
enum class Source { Link, Manual }
Expand All @@ -58,6 +58,7 @@ data class Service(
}

companion object {
val DefaultAuthType = AuthType.TOTP
val DefaultAlgorithm = Algorithm.SHA1
const val DefaultPeriod = 30
const val DefaultDigits = 6
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import androidx.compose.ui.unit.dp
fun TwCircularProgressIndicator(
modifier: Modifier = Modifier,
color: Color = ProgressIndicatorDefaults.circularColor,

) {
) {
CircularProgressIndicator(modifier.size(32.dp), color, 4.dp)
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ fun TwOutlinedTextField(
var textValue by remember { mutableStateOf(TextFieldValue(value, selection = TextRange(value.length))) }

OutlinedTextField(
value = textValue,
value = textValue.copy(text = value),
onValueChange = {
if (it.text.length <= maxLength) {
textValue = it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ fun DsService(
ServiceStyle.Default -> NextCodeGravity.Below
ServiceStyle.Compact -> NextCodeGravity.End
},
animateColor = state.authType == ServiceAuthType.Totp,
animateColor = state.authType == ServiceAuthType.Totp || state.authType == ServiceAuthType.Steam,
textStyles = textStyles,
modifier = Modifier
.fillMaxWidth()
Expand All @@ -183,6 +183,7 @@ fun DsService(

if (state.revealed || hideCodes.not() || state.authType == ServiceAuthType.Hotp) {
when (state.authType) {
ServiceAuthType.Steam,
ServiceAuthType.Totp -> {
ServiceTimer(
timer = state.timer,
Expand All @@ -202,7 +203,7 @@ fun DsService(
}
}
} else {
if (state.authType == ServiceAuthType.Totp) {
if (state.authType == ServiceAuthType.Totp || state.authType == ServiceAuthType.Steam) {
Box(
Modifier
.padding(end = 7.dp)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ fun DsServiceModal(
nextCode = state.nextCode,
timer = state.timer,
nextCodeVisible = state.isNextCodeEnabled(showNextCode),
animateColor = state.authType == ServiceAuthType.Totp,
animateColor = state.authType == ServiceAuthType.Totp || state.authType == ServiceAuthType.Steam,
modifier = Modifier
.fillMaxWidth()
.alpha(if (state.revealed || hideCodes.not()) 1f else 0f),
Expand All @@ -115,6 +115,7 @@ fun DsServiceModal(

if (state.revealed || hideCodes.not() || state.authType == ServiceAuthType.Hotp) {
when (state.authType) {
ServiceAuthType.Steam,
ServiceAuthType.Totp -> {
ServiceTimer(
timer = state.timer,
Expand All @@ -132,7 +133,7 @@ fun DsServiceModal(
}
}
} else {
if (state.authType == ServiceAuthType.Totp) {
if (state.authType == ServiceAuthType.Totp || state.authType == ServiceAuthType.Steam) {
Box(
Modifier
.size(56.dp)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package com.twofasapp.designsystem.service

enum class ServiceAuthType { Totp, Hotp }
enum class ServiceAuthType { Totp, Hotp, Steam }
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ data class ServiceState(
}

fun isNextCodeEnabled(showNextCode: Boolean): Boolean {
return timer <= ServiceExpireTransitionThreshold && showNextCode && authType == ServiceAuthType.Totp
return timer <= ServiceExpireTransitionThreshold && showNextCode && (authType == ServiceAuthType.Totp || authType == ServiceAuthType.Steam)
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ fun Service.asState(): ServiceState {
authType = when (authType) {
Service.AuthType.TOTP -> ServiceAuthType.Totp
Service.AuthType.HOTP -> ServiceAuthType.Hotp
Service.AuthType.STEAM -> ServiceAuthType.Steam
},
iconLight = iconLight,
iconDark = iconDark,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ fun String.formatCode(): String {
if (isEmpty()) return ""

return when (this.length) {
5 -> if (this.toIntOrNull() == null) take(5) else "${take(3)} ${takeLast(2)}"
6 -> "${take(3)} ${takeLast(3)}"
7 -> "${take(4)} ${takeLast(3)}"
8 -> "${take(4)} ${takeLast(4)}"
Expand Down
2 changes: 1 addition & 1 deletion core/locale/src/main/res/values-de-rDE/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Release: Working copy
Locale: de-DE, German (Germany)
Exported by: rafakob
Exported at: Sat, 11 Nov 2023 08:12:03 -0800
Exported at: Thu, 16 Nov 2023 13:28:44 -0800
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
Expand Down
4 changes: 2 additions & 2 deletions core/locale/src/main/res/values-es-rES/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Release: Working copy
Locale: es-ES, Spanish (Spain)
Exported by: rafakob
Exported at: Sat, 11 Nov 2023 08:12:03 -0800
Exported at: Thu, 16 Nov 2023 13:28:44 -0800
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
Expand Down Expand Up @@ -811,5 +811,5 @@
<string name="introduction__backup_description">En el siguiente paso, tendrás que elegir tu cuenta de Google Drive, donde los tokens de 2FAS serán almacenados de forma segura.</string>
<string name="introduction__backup_take_risk_cta">Acepto el riesgo, sin copia de seguridad</string>
<string name="introduction__backup_success">¡Sincronización de Google Drive activada correctamente!</string>
<string name="backup__import_invalid_version">The backup file you\'re attempting to import is not supported in this application version. The application only supports backup format versions up to %d, while the file you\'re importing is version %d.</string>
<string name="backup__import_invalid_version">El archivo de copia de seguridad que estás intentando importar no es compatible con esta versión de la aplicación. La aplicación solo soporta formatos de copia de seguridad hasta la versión %d, mientras que el archivo que estás importando es de la versión %d.</string>
</resources>
4 changes: 2 additions & 2 deletions core/locale/src/main/res/values-fr-rFR/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Release: Working copy
Locale: fr-FR, French (France)
Exported by: rafakob
Exported at: Sat, 11 Nov 2023 08:12:03 -0800
Exported at: Thu, 16 Nov 2023 13:28:45 -0800
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
Expand Down Expand Up @@ -811,5 +811,5 @@
<string name="introduction__backup_description">Lors de la prochaine étape, il vous sera demandé de choisir votre compte Google Drive, où vos jetons 2FA seront stockées sécuritairement.</string>
<string name="introduction__backup_take_risk_cta">J\'accepte le risque, pas de sauvegarde</string>
<string name="introduction__backup_success">Synchronisation avec Google Drive activée avec succès!</string>
<string name="backup__import_invalid_version">The backup file you\'re attempting to import is not supported in this application version. The application only supports backup format versions up to %d, while the file you\'re importing is version %d.</string>
<string name="backup__import_invalid_version">Le fichier de sauvegarde que vous tentez d\'importer n\'est pas pris en charge par cette version de l\'application. L\'application ne prend en charge que les versions de format de sauvegarde jusqu\'à %d, alors que le fichier que vous importez est de la version %d.</string>
</resources>
2 changes: 1 addition & 1 deletion core/locale/src/main/res/values-in/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Release: Working copy
Locale: id-ID, Indonesian (Indonesia)
Exported by: rafakob
Exported at: Sat, 11 Nov 2023 08:12:03 -0800
Exported at: Thu, 16 Nov 2023 13:28:45 -0800
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
Expand Down
2 changes: 1 addition & 1 deletion core/locale/src/main/res/values-it-rIT/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Release: Working copy
Locale: it-IT, Italian (Italy)
Exported by: rafakob
Exported at: Sat, 11 Nov 2023 08:12:03 -0800
Exported at: Thu, 16 Nov 2023 13:28:45 -0800
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
Expand Down
2 changes: 1 addition & 1 deletion core/locale/src/main/res/values-nl-rNL/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Release: Working copy
Locale: nl-NL, Dutch (Netherlands)
Exported by: rafakob
Exported at: Sat, 11 Nov 2023 08:12:03 -0800
Exported at: Thu, 16 Nov 2023 13:28:45 -0800
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
Expand Down
2 changes: 1 addition & 1 deletion core/locale/src/main/res/values-pl-rPL/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Release: Working copy
Locale: pl-PL, Polish (Poland)
Exported by: rafakob
Exported at: Sat, 11 Nov 2023 08:12:03 -0800
Exported at: Thu, 16 Nov 2023 13:28:45 -0800
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
Expand Down
2 changes: 1 addition & 1 deletion core/locale/src/main/res/values-pt-rBR/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Release: Working copy
Locale: pt-BR, Brazilian Portuguese
Exported by: rafakob
Exported at: Sat, 11 Nov 2023 08:12:03 -0800
Exported at: Thu, 16 Nov 2023 13:28:45 -0800
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
Expand Down
2 changes: 1 addition & 1 deletion core/locale/src/main/res/values-pt-rPT/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Release: Working copy
Locale: pt-PT, Portuguese (Portugal)
Exported by: rafakob
Exported at: Sat, 11 Nov 2023 08:12:03 -0800
Exported at: Thu, 16 Nov 2023 13:28:45 -0800
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
Expand Down
4 changes: 2 additions & 2 deletions core/locale/src/main/res/values-uk-rUA/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Release: Working copy
Locale: uk-UA, Ukrainian (Ukraine)
Exported by: rafakob
Exported at: Sat, 11 Nov 2023 08:12:03 -0800
Exported at: Thu, 16 Nov 2023 13:28:45 -0800
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
Expand Down Expand Up @@ -817,5 +817,5 @@
<string name="introduction__backup_description">На наступному кроці вам буде запропоновано вибрати обліковий запис Google Drive, де безпечно зберігатимуться токени 2FA.</string>
<string name="introduction__backup_take_risk_cta">Не хочу вмикати резервне копіювання</string>
<string name="introduction__backup_success">Синхронізацію Google Drive ввімкнено успішно!</string>
<string name="backup__import_invalid_version">The backup file you\'re attempting to import is not supported in this application version. The application only supports backup format versions up to %d, while the file you\'re importing is version %d.</string>
<string name="backup__import_invalid_version">Файл резервної копії, який ви намагаєтеся імпортувати, не підтримується цією версією програми. Програма підтримує лише версії формату резервної копії до %d, тоді як файл, який ви імпортуєте, має версію %d.</string>
</resources>
2 changes: 1 addition & 1 deletion core/locale/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Release: Working copy
Locale: en, English
Exported by: rafakob
Exported at: Sat, 11 Nov 2023 08:12:03 -0800
Exported at: Thu, 16 Nov 2023 13:28:44 -0800
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- InfoPlist.strings
Expand Down
16 changes: 12 additions & 4 deletions core/otp/src/main/java/com/twofasapp/otp/OtpAuthenticator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class OtpAuthenticator {
private const val HmacSha384 = "HmacSHA384"
private const val HmacSha512 = "HmacSHA512"
private val keyModulus = mapOf(
5 to 10.0.pow(5.toDouble()).toLong(),
6 to 10.0.pow(6.toDouble()).toLong(),
7 to 10.0.pow(7.toDouble()).toLong(),
8 to 10.0.pow(8.toDouble()).toLong(),
Expand All @@ -50,7 +51,8 @@ class OtpAuthenticator {
OtpData.Algorithm.SHA256 -> HmacSha256
OtpData.Algorithm.SHA384 -> HmacSha384
OtpData.Algorithm.SHA512 -> HmacSha512
}
},
calculateModule = otpData.calculateModule,
)

return String.format("%0${otpData.digits}d", code)
Expand All @@ -69,6 +71,7 @@ class OtpAuthenticator {
counter: Long,
digits: Int,
algorithm: String,
calculateModule: Boolean,
): Int {
// Converting the instant of time from the long representation to a big-endian array of bytes (RFC4226, 5.2. Description).
val bigEndianTimestamp = ByteArray(8)
Expand Down Expand Up @@ -104,10 +107,15 @@ class OtpAuthenticator {
}

// Clean bits higher than the 32nd (inclusive) and calculate the module with the maximum validation code value.
truncatedHash = truncatedHash and 0x7FFFFFFF
truncatedHash %= keyModulus[digits]!!
return if (calculateModule) {
truncatedHash = truncatedHash and 0x7FFFFFFF
truncatedHash %= keyModulus[digits]!!
truncatedHash.toInt()
} else {
truncatedHash = truncatedHash and 0x7FFFFFFF
truncatedHash.toInt()
}

return truncatedHash.toInt()
} catch (e: NoSuchAlgorithmException) {
throw OtpException("The operation cannot be performed now.", e)
} catch (e: InvalidKeyException) {
Expand Down
1 change: 1 addition & 0 deletions core/otp/src/main/java/com/twofasapp/otp/OtpData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ data class OtpData(
val digits: Int,
val period: Int,
val algorithm: Algorithm,
val calculateModule: Boolean, // Do not calculate for Steam codes
) {
enum class Algorithm { SHA1, SHA224, SHA256, SHA384, SHA512 }
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,16 +104,22 @@ internal class BrowserExtRepositoryImpl(

override suspend fun fetchTokenRequests() {
return withContext(dispatchers.io) {
observeMobileDevice().firstOrNull()?.id?.let { deviceId ->
val deviceId = observeMobileDevice().firstOrNull()?.id

if (deviceId.isNullOrBlank().not()) {
localSource.updateTokenRequests(
remoteSource.fetchTokenRequests(deviceId).map { it.asDomain() }
remoteSource.fetchTokenRequests(deviceId!!).map { it.asDomain() }
)
}
}
}

override suspend fun getFcmToken(): String {
return FirebaseMessaging.getInstance().token.await()
return try {
FirebaseMessaging.getInstance().token.await().orEmpty()
} catch (e: Exception) {
""
}
}

override suspend fun deleteTokenRequest(requestId: String) {
Expand Down
Loading

0 comments on commit 3863bc6

Please sign in to comment.