diff options
Diffstat (limited to 'format-common/src/main')
-rw-r--r-- | format-common/src/main/kotlin/dev/msfjarvis/aps/data/passfile/PasswordEntry.kt | 21 | ||||
-rw-r--r-- | format-common/src/main/kotlin/dev/msfjarvis/aps/data/passfile/Totp.kt | 8 |
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) |