Yet Another OTP generator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UriParser.kt 2.0KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. package com.chameth.yaotp.accounts
  2. import com.chameth.yaotp.algos.HotpParams
  3. import com.chameth.yaotp.algos.TotpParams
  4. import com.chameth.yaotp.algos.getHmacFunc
  5. import com.chameth.yaotp.util.base32Decode
  6. import java.net.URI
  7. fun parseUri(uri: String) : Account? {
  8. return try {
  9. toAccount(URI.create(uri))
  10. } catch (_ : Exception) {
  11. null
  12. }
  13. }
  14. @Throws(IllegalArgumentException::class)
  15. internal fun toAccount(uri: URI): Account? {
  16. require(uri.scheme == "otpauth") { "Scheme must be 'otpauth', got '${uri.scheme}'" }
  17. require(uri.path.length > 1) { "No label specified" }
  18. requireNotNull(uri.query) { "No query string supplied" }
  19. val label = uri.path.substring(1)
  20. val params = uri.queryParameters()
  21. require("secret" in params) { "No 'secret' parameter specified, got ${params.keys}"}
  22. return when(uri.host) {
  23. "hotp" -> getHotpAccount(label, params)
  24. "totp" -> getTotpAccount(label, params)
  25. else -> throw IllegalArgumentException("Unrecognised type: ${uri.host}")
  26. }
  27. }
  28. internal fun getHotpAccount(label: String, uriParams: Map<String, String>): HotpAccount {
  29. val counter = uriParams["counter"]?.toLongOrNull()
  30. requireNotNull(counter) { "No 'counter' parameter specified for HOTP" }
  31. return HotpAccount(label, uriParams["issuer"], counter!!, getHotpParameters(uriParams))
  32. }
  33. fun getTotpAccount(label: String, uriParams: Map<String, String>): TotpAccount {
  34. val step = uriParams["step"]?.toIntOrNull() ?: 30
  35. return TotpAccount(label, uriParams["issuer"], TotpParams(getHotpParameters(uriParams), step = step))
  36. }
  37. internal fun getHotpParameters(uriParams : Map<String, String>) : HotpParams {
  38. return HotpParams(
  39. base32Decode(uriParams["secret"] ?: ""),
  40. uriParams["digits"]?.toIntOrNull() ?: 6,
  41. getHmacFunc(uriParams["algorithm"])
  42. )
  43. }
  44. internal fun URI.queryParameters(): Map<String, String> {
  45. return query.split('&').map { with(it.split('=', limit = 2)) { this[0] to this[1] } }.toMap()
  46. }