aboutsummaryrefslogtreecommitdiff
path: root/format-common
diff options
context:
space:
mode:
Diffstat (limited to 'format-common')
-rw-r--r--format-common/src/main/kotlin/app/passwordstore/data/passfile/PasswordEntry.kt14
-rw-r--r--format-common/src/main/kotlin/app/passwordstore/util/time/UserClock.kt (renamed from format-common/src/main/kotlin/app/passwordstore/util/time/Clocks.kt)0
-rw-r--r--format-common/src/main/kotlin/app/passwordstore/util/totp/Otp.kt33
-rw-r--r--format-common/src/test/kotlin/app/passwordstore/data/passfile/PasswordEntryTest.kt1
-rw-r--r--format-common/src/test/kotlin/app/passwordstore/util/time/TestUserClock.kt (renamed from format-common/src/test/kotlin/app/passwordstore/util/time/TestClocks.kt)0
5 files changed, 34 insertions, 14 deletions
diff --git a/format-common/src/main/kotlin/app/passwordstore/data/passfile/PasswordEntry.kt b/format-common/src/main/kotlin/app/passwordstore/data/passfile/PasswordEntry.kt
index 9543eb8c..38aa4a20 100644
--- a/format-common/src/main/kotlin/app/passwordstore/data/passfile/PasswordEntry.kt
+++ b/format-common/src/main/kotlin/app/passwordstore/data/passfile/PasswordEntry.kt
@@ -62,7 +62,7 @@ constructor(
do {
val otp = calculateTotp()
emit(otp)
- delay(1000L)
+ delay(ONE_SECOND.seconds)
} while (coroutineContext.isActive)
} else {
awaitCancellation()
@@ -90,6 +90,7 @@ constructor(
return totpSecret != null
}
+ @Suppress("ReturnCount")
private fun findAndStripPassword(passContent: List<String>): Pair<String?, List<String>> {
if (TotpFinder.TOTP_FIELDS.any { passContent[0].startsWith(it) }) return Pair(null, passContent)
for (line in passContent) {
@@ -180,8 +181,14 @@ constructor(
val totpAlgorithm = totpFinder.findAlgorithm(content)
val issuer = totpFinder.findIssuer(content)
val millis = clock.millis()
- val remainingTime = (totpPeriod - ((millis / 1000) % totpPeriod)).seconds
- Otp.calculateCode(totpSecret!!, millis / (1000 * totpPeriod), totpAlgorithm, digits, issuer)
+ val remainingTime = (totpPeriod - ((millis / ONE_SECOND) % totpPeriod)).seconds
+ Otp.calculateCode(
+ totpSecret!!,
+ millis / (ONE_SECOND * totpPeriod),
+ totpAlgorithm,
+ digits,
+ issuer
+ )
.mapBoth(
{ code ->
return Totp(code, remainingTime)
@@ -217,5 +224,6 @@ constructor(
"secret:",
"pass:",
)
+ private const val ONE_SECOND = 1000
}
}
diff --git a/format-common/src/main/kotlin/app/passwordstore/util/time/Clocks.kt b/format-common/src/main/kotlin/app/passwordstore/util/time/UserClock.kt
index 4ffeb6a6..4ffeb6a6 100644
--- a/format-common/src/main/kotlin/app/passwordstore/util/time/Clocks.kt
+++ b/format-common/src/main/kotlin/app/passwordstore/util/time/UserClock.kt
diff --git a/format-common/src/main/kotlin/app/passwordstore/util/totp/Otp.kt b/format-common/src/main/kotlin/app/passwordstore/util/totp/Otp.kt
index 72d5cffe..5abc0337 100644
--- a/format-common/src/main/kotlin/app/passwordstore/util/totp/Otp.kt
+++ b/format-common/src/main/kotlin/app/passwordstore/util/totp/Otp.kt
@@ -18,6 +18,13 @@ internal object Otp {
private val BASE_32 = Base32()
private val STEAM_ALPHABET = "23456789BCDFGHJKMNPQRTVWXY".toCharArray()
+ private const val BYTE_BUFFER_CAPACITY = 8
+ private const val END_INDEX_OFFSET = 4
+ private const val STEAM_GUARD_DIGITS = 5
+ private const val MINIMUM_DIGITS = 6
+ private const val MAXIMUM_DIGITS = 10
+ private const val ALPHABET_LENGTH = 26
+ private const val MOST_SIGNIFICANT_BYTE = 0x7f
fun calculateCode(
secret: String,
@@ -32,13 +39,13 @@ internal object Otp {
val digest =
Mac.getInstance(algo).run {
init(secretKey)
- doFinal(ByteBuffer.allocate(8).putLong(counter).array())
+ doFinal(ByteBuffer.allocate(BYTE_BUFFER_CAPACITY).putLong(counter).array())
}
// Least significant 4 bits are used as an offset into the digest.
val offset = (digest.last() and 0xf).toInt()
// Extract 32 bits at the offset and clear the most significant bit.
- val code = digest.copyOfRange(offset, offset + 4)
- code[0] = (0x7f and code[0].toInt()).toByte()
+ val code = digest.copyOfRange(offset, offset.plus(END_INDEX_OFFSET))
+ code[0] = (MOST_SIGNIFICANT_BYTE and code[0].toInt()).toByte()
val codeInt = ByteBuffer.wrap(code).int
check(codeInt > 0)
// SteamGuard is a horrible OTP implementation that generates non-standard 5 digit OTPs as
@@ -47,9 +54,9 @@ internal object Otp {
if (digits == "s" || issuer == "Steam") {
var remainingCodeInt = codeInt
buildString {
- repeat(5) {
+ repeat(STEAM_GUARD_DIGITS) {
append(STEAM_ALPHABET[remainingCodeInt % STEAM_ALPHABET.size])
- remainingCodeInt /= 26
+ remainingCodeInt /= ALPHABET_LENGTH
}
}
} else {
@@ -59,17 +66,21 @@ internal object Otp {
numDigits == null -> {
return Err(IllegalArgumentException("Digits specifier has to be either 's' or numeric"))
}
- numDigits < 6 -> {
- return Err(IllegalArgumentException("TOTP codes have to be at least 6 digits long"))
+ numDigits < MINIMUM_DIGITS -> {
+ return Err(
+ IllegalArgumentException("TOTP codes have to be at least $MINIMUM_DIGITS digits long")
+ )
}
- numDigits > 10 -> {
- return Err(IllegalArgumentException("TOTP codes can be at most 10 digits long"))
+ numDigits > MAXIMUM_DIGITS -> {
+ return Err(
+ IllegalArgumentException("TOTP codes can be at most $MAXIMUM_DIGITS digits long")
+ )
}
else -> {
// 2^31 = 2_147_483_648, so we can extract at most 10 digits with the first one
// always being 0, 1, or 2. Pad with leading zeroes.
- val codeStringBase10 = codeInt.toString(10).padStart(10, '0')
- check(codeStringBase10.length == 10)
+ val codeStringBase10 = codeInt.toString(MAXIMUM_DIGITS).padStart(MAXIMUM_DIGITS, '0')
+ check(codeStringBase10.length == MAXIMUM_DIGITS)
codeStringBase10.takeLast(numDigits)
}
}
diff --git a/format-common/src/test/kotlin/app/passwordstore/data/passfile/PasswordEntryTest.kt b/format-common/src/test/kotlin/app/passwordstore/data/passfile/PasswordEntryTest.kt
index f492604d..2022d968 100644
--- a/format-common/src/test/kotlin/app/passwordstore/data/passfile/PasswordEntryTest.kt
+++ b/format-common/src/test/kotlin/app/passwordstore/data/passfile/PasswordEntryTest.kt
@@ -194,6 +194,7 @@ class PasswordEntryTest {
companion object {
+ @Suppress("MaxLineLength")
const val TOTP_URI =
"otpauth://totp/ACME%20Co:john@example.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30"
diff --git a/format-common/src/test/kotlin/app/passwordstore/util/time/TestClocks.kt b/format-common/src/test/kotlin/app/passwordstore/util/time/TestUserClock.kt
index 8a860a39..8a860a39 100644
--- a/format-common/src/test/kotlin/app/passwordstore/util/time/TestClocks.kt
+++ b/format-common/src/test/kotlin/app/passwordstore/util/time/TestUserClock.kt