Fix detekt warnings in format-common (#2167)

* fix warning ktlint to format-common folder

* update to code review

* adjusted spotless
This commit is contained in:
Newton Cesar 2022-10-08 12:03:29 -03:00 committed by GitHub
parent 224d956e28
commit 6d73b63435
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 35 additions and 28 deletions

View file

@ -1,18 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<SmellBaseline> <SmellBaseline>
<ManuallySuppressedIssues/> <ManuallySuppressedIssues/>
<CurrentIssues> <CurrentIssues/>
<ID>MagicNumber:Otp.kt$Otp$0x7f</ID>
<ID>MagicNumber:Otp.kt$Otp$10</ID>
<ID>MagicNumber:Otp.kt$Otp$26</ID>
<ID>MagicNumber:Otp.kt$Otp$4</ID>
<ID>MagicNumber:Otp.kt$Otp$5</ID>
<ID>MagicNumber:Otp.kt$Otp$6</ID>
<ID>MagicNumber:Otp.kt$Otp$8</ID>
<ID>MagicNumber:PasswordEntry.kt$PasswordEntry$1000</ID>
<ID>MatchingDeclarationName:Clocks.kt$UserClock : Clock</ID>
<ID>MatchingDeclarationName:TestClocks.kt$TestUserClock : UserClock</ID>
<ID>MaxLineLength:PasswordEntryTest.kt$PasswordEntryTest.Companion$"otpauth://totp/ACME%20Co:john@example.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&amp;issuer=ACME%20Co&amp;algorithm=SHA1&amp;digits=6&amp;period=30"</ID>
<ID>ReturnCount:PasswordEntry.kt$PasswordEntry$private fun findAndStripPassword(passContent: List&lt;String>): Pair&lt;String?, List&lt;String>></ID>
</CurrentIssues>
</SmellBaseline> </SmellBaseline>

View file

@ -62,7 +62,7 @@ constructor(
do { do {
val otp = calculateTotp() val otp = calculateTotp()
emit(otp) emit(otp)
delay(1000L) delay(ONE_SECOND.seconds)
} while (coroutineContext.isActive) } while (coroutineContext.isActive)
} else { } else {
awaitCancellation() awaitCancellation()
@ -90,6 +90,7 @@ constructor(
return totpSecret != null return totpSecret != null
} }
@Suppress("ReturnCount")
private fun findAndStripPassword(passContent: List<String>): Pair<String?, List<String>> { private fun findAndStripPassword(passContent: List<String>): Pair<String?, List<String>> {
if (TotpFinder.TOTP_FIELDS.any { passContent[0].startsWith(it) }) return Pair(null, passContent) if (TotpFinder.TOTP_FIELDS.any { passContent[0].startsWith(it) }) return Pair(null, passContent)
for (line in passContent) { for (line in passContent) {
@ -180,8 +181,14 @@ constructor(
val totpAlgorithm = totpFinder.findAlgorithm(content) val totpAlgorithm = totpFinder.findAlgorithm(content)
val issuer = totpFinder.findIssuer(content) val issuer = totpFinder.findIssuer(content)
val millis = clock.millis() val millis = clock.millis()
val remainingTime = (totpPeriod - ((millis / 1000) % totpPeriod)).seconds val remainingTime = (totpPeriod - ((millis / ONE_SECOND) % totpPeriod)).seconds
Otp.calculateCode(totpSecret!!, millis / (1000 * totpPeriod), totpAlgorithm, digits, issuer) Otp.calculateCode(
totpSecret!!,
millis / (ONE_SECOND * totpPeriod),
totpAlgorithm,
digits,
issuer
)
.mapBoth( .mapBoth(
{ code -> { code ->
return Totp(code, remainingTime) return Totp(code, remainingTime)
@ -217,5 +224,6 @@ constructor(
"secret:", "secret:",
"pass:", "pass:",
) )
private const val ONE_SECOND = 1000
} }
} }

View file

@ -18,6 +18,13 @@ internal object Otp {
private val BASE_32 = Base32() private val BASE_32 = Base32()
private val STEAM_ALPHABET = "23456789BCDFGHJKMNPQRTVWXY".toCharArray() 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( fun calculateCode(
secret: String, secret: String,
@ -32,13 +39,13 @@ internal object Otp {
val digest = val digest =
Mac.getInstance(algo).run { Mac.getInstance(algo).run {
init(secretKey) 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. // Least significant 4 bits are used as an offset into the digest.
val offset = (digest.last() and 0xf).toInt() val offset = (digest.last() and 0xf).toInt()
// Extract 32 bits at the offset and clear the most significant bit. // Extract 32 bits at the offset and clear the most significant bit.
val code = digest.copyOfRange(offset, offset + 4) val code = digest.copyOfRange(offset, offset.plus(END_INDEX_OFFSET))
code[0] = (0x7f and code[0].toInt()).toByte() code[0] = (MOST_SIGNIFICANT_BYTE and code[0].toInt()).toByte()
val codeInt = ByteBuffer.wrap(code).int val codeInt = ByteBuffer.wrap(code).int
check(codeInt > 0) check(codeInt > 0)
// SteamGuard is a horrible OTP implementation that generates non-standard 5 digit OTPs as // 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") { if (digits == "s" || issuer == "Steam") {
var remainingCodeInt = codeInt var remainingCodeInt = codeInt
buildString { buildString {
repeat(5) { repeat(STEAM_GUARD_DIGITS) {
append(STEAM_ALPHABET[remainingCodeInt % STEAM_ALPHABET.size]) append(STEAM_ALPHABET[remainingCodeInt % STEAM_ALPHABET.size])
remainingCodeInt /= 26 remainingCodeInt /= ALPHABET_LENGTH
} }
} }
} else { } else {
@ -59,17 +66,21 @@ internal object Otp {
numDigits == null -> { numDigits == null -> {
return Err(IllegalArgumentException("Digits specifier has to be either 's' or numeric")) return Err(IllegalArgumentException("Digits specifier has to be either 's' or numeric"))
} }
numDigits < 6 -> { numDigits < MINIMUM_DIGITS -> {
return Err(IllegalArgumentException("TOTP codes have to be at least 6 digits long")) return Err(
IllegalArgumentException("TOTP codes have to be at least $MINIMUM_DIGITS digits long")
)
} }
numDigits > 10 -> { numDigits > MAXIMUM_DIGITS -> {
return Err(IllegalArgumentException("TOTP codes can be at most 10 digits long")) return Err(
IllegalArgumentException("TOTP codes can be at most $MAXIMUM_DIGITS digits long")
)
} }
else -> { else -> {
// 2^31 = 2_147_483_648, so we can extract at most 10 digits with the first one // 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. // always being 0, 1, or 2. Pad with leading zeroes.
val codeStringBase10 = codeInt.toString(10).padStart(10, '0') val codeStringBase10 = codeInt.toString(MAXIMUM_DIGITS).padStart(MAXIMUM_DIGITS, '0')
check(codeStringBase10.length == 10) check(codeStringBase10.length == MAXIMUM_DIGITS)
codeStringBase10.takeLast(numDigits) codeStringBase10.takeLast(numDigits)
} }
} }

View file

@ -194,6 +194,7 @@ class PasswordEntryTest {
companion object { companion object {
@Suppress("MaxLineLength")
const val TOTP_URI = const val TOTP_URI =
"otpauth://totp/ACME%20Co:john@example.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30" "otpauth://totp/ACME%20Co:john@example.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30"