aboutsummaryrefslogtreecommitdiff
path: root/format-common/src/main
diff options
context:
space:
mode:
authorHarsh Shandilya <me@msfjarvis.dev>2022-03-11 01:52:39 +0530
committerGitHub <noreply@github.com>2022-03-10 20:22:39 +0000
commit2f034bc2372d29b4ddebf74d532279073fb3d92b (patch)
treedc9197276622c56f32c9b395e9339a046f608103 /format-common/src/main
parent3e988b2a3428c3759535a2bd1f3e1ba0b5e411a3 (diff)
Show remaining time in TOTP field (#1766)
* Pass down remaining time for TOTPs to UI layer * format-common: switch TOTP flow to use co-operative cancelation * format-common: add a regression test for OTP duration calculation * Abstract out labels * Switch to launchIn
Diffstat (limited to 'format-common/src/main')
-rw-r--r--format-common/src/main/kotlin/dev/msfjarvis/aps/data/passfile/PasswordEntry.kt21
-rw-r--r--format-common/src/main/kotlin/dev/msfjarvis/aps/data/passfile/Totp.kt8
2 files changed, 21 insertions, 8 deletions
diff --git a/format-common/src/main/kotlin/dev/msfjarvis/aps/data/passfile/PasswordEntry.kt b/format-common/src/main/kotlin/dev/msfjarvis/aps/data/passfile/PasswordEntry.kt
index 94149477..a0a85f3e 100644
--- a/format-common/src/main/kotlin/dev/msfjarvis/aps/data/passfile/PasswordEntry.kt
+++ b/format-common/src/main/kotlin/dev/msfjarvis/aps/data/passfile/PasswordEntry.kt
@@ -13,12 +13,17 @@ import dev.msfjarvis.aps.util.time.UserClock
import dev.msfjarvis.aps.util.totp.Otp
import dev.msfjarvis.aps.util.totp.TotpFinder
import kotlin.collections.set
+import kotlin.coroutines.coroutineContext
+import kotlin.time.Duration.Companion.seconds
+import kotlin.time.ExperimentalTime
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.isActive
/** Represents a single entry in the password store. */
+@OptIn(ExperimentalTime::class)
public class PasswordEntry
@AssistedInject
constructor(
@@ -52,13 +57,13 @@ constructor(
* does not have a TOTP secret, the flow will never emit. Users should call [hasTotp] before
* collection to check if it is valid to collect this [Flow].
*/
- public val totp: Flow<String> = flow {
+ public val totp: Flow<Totp> = flow {
if (totpSecret != null) {
- repeat(Int.MAX_VALUE) {
- val (otp, remainingTime) = calculateTotp()
+ do {
+ val otp = calculateTotp()
emit(otp)
- delay(remainingTime)
- }
+ delay(1000L)
+ } while (coroutineContext.isActive)
} else {
awaitCancellation()
}
@@ -169,17 +174,17 @@ constructor(
return null
}
- private fun calculateTotp(): Pair<String, Long> {
+ private fun calculateTotp(): Totp {
val digits = totpFinder.findDigits(content)
val totpPeriod = totpFinder.findPeriod(content)
val totpAlgorithm = totpFinder.findAlgorithm(content)
val issuer = totpFinder.findIssuer(content)
val millis = clock.millis()
- val remainingTime = totpPeriod - (millis % totpPeriod)
+ val remainingTime = (totpPeriod - ((millis / 1000) % totpPeriod)).seconds
Otp.calculateCode(totpSecret!!, millis / (1000 * totpPeriod), totpAlgorithm, digits, issuer)
.mapBoth(
{ code ->
- return code to remainingTime
+ return Totp(code, remainingTime)
},
{ throwable -> throw throwable }
)
diff --git a/format-common/src/main/kotlin/dev/msfjarvis/aps/data/passfile/Totp.kt b/format-common/src/main/kotlin/dev/msfjarvis/aps/data/passfile/Totp.kt
new file mode 100644
index 00000000..a43cce6a
--- /dev/null
+++ b/format-common/src/main/kotlin/dev/msfjarvis/aps/data/passfile/Totp.kt
@@ -0,0 +1,8 @@
+package dev.msfjarvis.aps.data.passfile
+
+import kotlin.time.Duration
+import kotlin.time.ExperimentalTime
+
+/** Holder for a TOTP secret and the duration for which it is valid. */
+@OptIn(ExperimentalTime::class)
+public data class Totp(public val value: String, public val remainingTime: Duration)