Плавный прогрессбар 2fa
This commit is contained in:
@@ -11,9 +11,21 @@ data class TwoFaCodeState(
|
||||
val secondsUntilRefresh: Int,
|
||||
)
|
||||
|
||||
/** Доля прошедшего TOTP-периода [0f, 1f] для плавного progress bar. */
|
||||
fun totpPeriodProgress(nowMillis: Long, periodSeconds: Int): Float {
|
||||
val period = periodSeconds.coerceAtLeast(1)
|
||||
val elapsedSec = (nowMillis / 1000.0) % period
|
||||
return (elapsedSec / period).toFloat().coerceIn(0f, 1f)
|
||||
}
|
||||
|
||||
fun totpSecondsUntilRefresh(nowMillis: Long, periodSeconds: Int): Int {
|
||||
val period = periodSeconds.coerceAtLeast(1)
|
||||
return (period - ((nowMillis / 1000L) % period)).toInt().coerceAtLeast(0)
|
||||
}
|
||||
|
||||
fun buildTwoFaCodeState(token: TwoFaTokenRecord, nowMillis: Long): TwoFaCodeState? {
|
||||
val period = token.periodSeconds.coerceAtLeast(1)
|
||||
val remaining = (period - ((nowMillis / 1000L) % period)).toInt().coerceAtLeast(0)
|
||||
val remaining = totpSecondsUntilRefresh(nowMillis, period)
|
||||
val code = generateTotpCode(
|
||||
secret = token.secret,
|
||||
nowMillis = nowMillis,
|
||||
|
||||
@@ -33,6 +33,24 @@ class TwoFaTotpTest {
|
||||
assertTrue(state.secondsUntilRefresh in 1..30)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun totpPeriodProgressIsContinuousWithinPeriod() {
|
||||
val period = 30
|
||||
val periodStartMillis = 1_700_000_100_000L // epoch sec кратна period
|
||||
assertEquals(0f, totpPeriodProgress(periodStartMillis, period), 0.001f)
|
||||
assertEquals(0.5f, totpPeriodProgress(periodStartMillis + 15_000L, period), 0.001f)
|
||||
assertEquals(29f / 30f, totpPeriodProgress(periodStartMillis + 29_000L, period), 0.001f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun totpSecondsUntilRefreshCountsDownWithinPeriod() {
|
||||
val period = 30
|
||||
val t0 = 1_700_000_100_000L
|
||||
assertEquals(30, totpSecondsUntilRefresh(t0, period))
|
||||
assertEquals(15, totpSecondsUntilRefresh(t0 + 15_000L, period))
|
||||
assertEquals(1, totpSecondsUntilRefresh(t0 + 29_000L, period))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun buildTwoFaCodeStateReturnsNullForInvalidSecret() {
|
||||
val token = TwoFaTokenRecord(
|
||||
|
||||
Reference in New Issue
Block a user