diff options
| author | Harsh Shandilya <msfjarvis@gmail.com> | 2019-02-03 16:54:15 +0530 |
|---|---|---|
| committer | Mohamed Zenadi <zeapo@users.noreply.github.com> | 2019-02-03 12:24:15 +0100 |
| commit | 86696c668c08c8e283e840b6c54e40fa043c542a (patch) | |
| tree | f36139bed1a6ae1589570b7fcf8aff2ad4d3d4a9 /app/src/main/java/com/zeapo/pwdstore/PasswordEntry.kt | |
| parent | a819343c747b2ce022c5a5c7810979a62a213dc5 (diff) | |
| download | HardenedPass-86696c668c08c8e283e840b6c54e40fa043c542a.tar.gz HardenedPass-86696c668c08c8e283e840b6c54e40fa043c542a.zip | |
Convert PasswordEntry to Kotlin (#477)
Signed-off-by: Harsh Shandilya <msfjarvis@gmail.com>
Diffstat (limited to 'app/src/main/java/com/zeapo/pwdstore/PasswordEntry.kt')
| -rw-r--r-- | app/src/main/java/com/zeapo/pwdstore/PasswordEntry.kt | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordEntry.kt b/app/src/main/java/com/zeapo/pwdstore/PasswordEntry.kt new file mode 100644 index 00000000..757681c5 --- /dev/null +++ b/app/src/main/java/com/zeapo/pwdstore/PasswordEntry.kt @@ -0,0 +1,114 @@ +package com.zeapo.pwdstore + +import android.net.Uri + +import java.io.ByteArrayOutputStream +import java.io.UnsupportedEncodingException + +/** + * A single entry in password store. + */ +class PasswordEntry(private val content: String) { + val password: String + val username: String? + val totpSecret: String? + val hotpSecret: String? + val hotpCounter: Long? + var extraContent: String? = null + private set + private var isIncremented = false + + @Throws(UnsupportedEncodingException::class) + constructor(os: ByteArrayOutputStream) : this(os.toString("UTF-8")) + + init { + val passContent = content.split("\n".toRegex(), 2).toTypedArray() + password = passContent[0] + totpSecret = findTotpSecret(content) + hotpSecret = findHotpSecret(content) + hotpCounter = findHotpCounter(content) + extraContent = findExtraContent(passContent) + username = findUsername() + } + + fun hasExtraContent(): Boolean { + return !extraContent.isNullOrEmpty() + } + + fun hasUsername(): Boolean { + return username != null + } + + fun hasTotp(): Boolean { + return totpSecret != null + } + + fun hasHotp(): Boolean { + return hotpSecret != null && hotpCounter != null + } + + fun hotpIsIncremented(): Boolean { + return isIncremented + } + + fun incrementHotp() { + content.split("\n".toRegex()).forEach { line -> + if (line.startsWith("otpauth://hotp/")) { + extraContent = extraContent?.replaceFirst("counter=[0-9]+".toRegex(), "counter=${hotpCounter!! + 1}") + isIncremented = true + } + } + } + + private fun findUsername(): String? { + val extraLines = extraContent!!.split("\n".toRegex()) + for (line in extraLines) { + for (field in USERNAME_FIELDS) { + if (line.toLowerCase().startsWith("$field:")) { + return line.split(": *".toRegex(), 2).toTypedArray()[1] + } + } + } + return null + } + + private fun findTotpSecret(decryptedContent: String): String? { + decryptedContent.split("\n".toRegex()).forEach { line -> + if (line.startsWith("otpauth://totp/")) { + return Uri.parse(line).getQueryParameter("secret") + } + } + return null + } + + private fun findHotpSecret(decryptedContent: String): String? { + decryptedContent.split("\n".toRegex()).forEach { line -> + if (line.startsWith("otpauth://hotp/")) { + return Uri.parse(line).getQueryParameter("secret") + } + } + return null + } + + private fun findHotpCounter(decryptedContent: String): Long? { + decryptedContent.split("\n".toRegex()).forEach { line -> + if (line.startsWith("otpauth://hotp/")) { + return java.lang.Long.parseLong(Uri.parse(line).getQueryParameter("counter")!!) + } + } + return null + } + + private fun findExtraContent(passContent: Array<String>): String { + val extraContent = if (passContent.size > 1) passContent[1] else "" + // if there is a HOTP URI, we must return the extra content with the counter incremented + return if (hasHotp()) { + extraContent.replaceFirst("counter=[0-9]+".toRegex(), "counter=" + java.lang.Long.toString(hotpCounter!!)) + } else extraContent + } + + companion object { + + private val USERNAME_FIELDS = arrayOf("login", "username") + } +} |
