mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-09-19 16:24:41 +01:00
Use a default authenticator name until the user sets one.
This commit is contained in:
+9
-6
@@ -17,11 +17,13 @@ import org.signal.libsignal.net.TooManyMfaKeysException
|
||||
import org.signal.libsignal.net.TooManyTotpKeysException
|
||||
import org.signal.libsignal.net.TotpParameters
|
||||
import org.signal.network.api.AccountApiV2
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.net.SignalNetwork
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
import java.net.URLEncoder
|
||||
import java.time.Instant
|
||||
import org.signal.appsettings.R as AppSettingsR
|
||||
|
||||
/**
|
||||
* Everything the authenticator app screens need, sitting between them and the TOTP endpoints on [AccountApiV2].
|
||||
@@ -33,7 +35,8 @@ import java.time.Instant
|
||||
class TotpRepository(
|
||||
private val api: AccountApiV2 = SignalNetwork.accountApiV2,
|
||||
private val masterKeyProvider: () -> MasterKey = { SignalStore.svr.masterKey },
|
||||
private val clock: () -> Long = System::currentTimeMillis
|
||||
private val clock: () -> Long = System::currentTimeMillis,
|
||||
private val defaultAppName: () -> String = { AppDependencies.application.getString(AppSettingsR.string.TotpRepository__authenticator) }
|
||||
) {
|
||||
|
||||
companion object {
|
||||
@@ -111,14 +114,14 @@ class TotpRepository(
|
||||
/**
|
||||
* Confirms the pending key with a code from the user's authenticator app.
|
||||
*
|
||||
* The key is confirmed without a name, because the service wants metadata at confirmation time and the user doesn't
|
||||
* name their app until the screen after this one. Naming it later means a brief window where a key has no name, which
|
||||
* is a better failure than a window where the second factor isn't active yet.
|
||||
* The key is confirmed with a default name, because the service wants metadata at confirmation time and the user
|
||||
* doesn't name their app until the screen after this one. Anything that lists keys in that window shows the default
|
||||
* rather than a nameless entry.
|
||||
*/
|
||||
suspend fun confirmPendingApp(code: String): ConfirmResult {
|
||||
val oneTimePassword = code.toIntOrNull() ?: return ConfirmResult.IncorrectCode
|
||||
|
||||
val metadata = MfaMetadata(name = "", createdAt = Instant.ofEpochMilli(clock()))
|
||||
val metadata = MfaMetadata(name = defaultAppName(), createdAt = Instant.ofEpochMilli(clock()))
|
||||
|
||||
return when (val result = api.confirmTotpKey(oneTimePassword = oneTimePassword, metadata = metadata, masterKey = masterKeyProvider())) {
|
||||
is RequestResult.Success -> {
|
||||
@@ -179,7 +182,7 @@ class TotpRepository(
|
||||
return setMetadata(app.id, MfaMetadata(name = name, createdAt = Instant.ofEpochMilli(app.createdAt)))
|
||||
}
|
||||
|
||||
/** Names a newly confirmed app, which was confirmed without one moments ago. */
|
||||
/** Names a newly confirmed app, replacing the default name it was confirmed with moments ago. */
|
||||
suspend fun nameNewTotpApp(appId: Long, name: String): UpdateResult {
|
||||
return setMetadata(appId, MfaMetadata(name = name, createdAt = Instant.ofEpochMilli(clock())))
|
||||
}
|
||||
|
||||
+4
-3
@@ -46,6 +46,7 @@ class TotpRepositoryTest {
|
||||
private const val NOW = 1_700_000_000_000L
|
||||
private const val ACCOUNT_NAME = "8B4A1F0C"
|
||||
private const val CODE = "123456"
|
||||
private const val DEFAULT_NAME = "Authenticator"
|
||||
private const val KEY_ID = 1
|
||||
|
||||
private val KEY = ByteArray(32) { it.toByte() }
|
||||
@@ -58,7 +59,7 @@ class TotpRepositoryTest {
|
||||
|
||||
private var now = NOW
|
||||
private val api = mockk<AccountApiV2>()
|
||||
private val repository = TotpRepository(api = api, masterKeyProvider = { MASTER_KEY }, clock = { now })
|
||||
private val repository = TotpRepository(api = api, masterKeyProvider = { MASTER_KEY }, clock = { now }, defaultAppName = { DEFAULT_NAME })
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
@@ -181,13 +182,13 @@ class TotpRepositoryTest {
|
||||
|
||||
/** The service wants metadata at confirmation time, and the user hasn't been asked for a name yet. */
|
||||
@Test
|
||||
fun `a key is confirmed without a name, stamped with the time it was confirmed`() = runTest {
|
||||
fun `a key is confirmed with a default name, stamped with the time it was confirmed`() = runTest {
|
||||
val metadata = slot<MfaMetadata>()
|
||||
coEvery { api.confirmTotpKey(any(), capture(metadata), any()) } returns RequestResult.Success(KEY_ID)
|
||||
|
||||
repository.confirmPendingApp(CODE)
|
||||
|
||||
assertThat(metadata.captured.name).isEqualTo("")
|
||||
assertThat(metadata.captured.name).isEqualTo(DEFAULT_NAME)
|
||||
assertThat(metadata.captured.createdAt).isEqualTo(Instant.ofEpochMilli(NOW))
|
||||
}
|
||||
|
||||
|
||||
@@ -146,6 +146,10 @@
|
||||
<string name="TotpCodeEntryScreen__incorrect_code">Incorrect code. Enter the code showing in your authenticator app now.</string>
|
||||
<!-- Error shown under the code field when we couldn\'t reach the service to check the code -->
|
||||
<string name="TotpCodeEntryScreen__couldnt_reach_signal">Couldn\'t reach Signal. Check your connection and try again.</string>
|
||||
|
||||
<!-- Default name given to an authenticator app the moment it\'s set up, before the user chooses their own name for it -->
|
||||
<string name="TotpRepository__authenticator">Authenticator</string>
|
||||
|
||||
<!-- TotpNameEntryScreen -->
|
||||
<!-- Title of the screen where the user names an authenticator app -->
|
||||
<string name="TotpNameEntryScreen__choose_a_name">Choose a name</string>
|
||||
|
||||
Reference in New Issue
Block a user