diff --git a/pom.xml b/pom.xml
index cf6a8f7..70038f1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -163,6 +163,11 @@
core
3.3.3
+
+ cn.hutool
+ hutool-http
+ 5.8.31
+
diff --git a/src/main/kotlin/info/alinadace/sakuramiki/service/jm/util/DownloadUtil.kt b/src/main/kotlin/info/alinadace/sakuramiki/service/jm/util/DownloadUtil.kt
index 1801157..5be375a 100644
--- a/src/main/kotlin/info/alinadace/sakuramiki/service/jm/util/DownloadUtil.kt
+++ b/src/main/kotlin/info/alinadace/sakuramiki/service/jm/util/DownloadUtil.kt
@@ -47,12 +47,6 @@ class DownloadUtil {
return this.newCall(Request.Builder()
.url(url)
.method(method, body)
-//// .addHeader("Content-Type", "application/json")
-//// .addHeader("Authorization", "Bearer $APIKEY")
-// .addHeader("User-Agent", "Apifox/1.0.0 (https://apifox.com)")
-// .addHeader("Accept", "*/*")
-// .addHeader("Host", "api.github.com")
-// .addHeader("Connection", "keep-alive")
.build()).execute()
}
}
diff --git a/src/main/kotlin/info/alinadace/sakuramiki/service/mfa/MFAGenerateService.kt b/src/main/kotlin/info/alinadace/sakuramiki/service/mfa/MFAGenerateService.kt
index 3bff029..3b90462 100644
--- a/src/main/kotlin/info/alinadace/sakuramiki/service/mfa/MFAGenerateService.kt
+++ b/src/main/kotlin/info/alinadace/sakuramiki/service/mfa/MFAGenerateService.kt
@@ -57,7 +57,7 @@ class MFAGenerateService : Service {
event.send("您还没有绑定默认MFA,使用 #mfa bind default 绑定默认MFA")
return
}
- event.send(MFAUtil.generate(mfa.secret, 30))
+ event.send(MFAUtil.generate(mfa.secret))
return
}
if (command.size == 2){
@@ -70,7 +70,7 @@ class MFAGenerateService : Service {
event.send("您还没有绑定${command[1]} MFA,使用 #mfa bind ${command[1]} 绑定${command[1]} MFA")
return
}
- event.send(MFAUtil.generate(mfa.secret, 30))
+ event.send(MFAUtil.generate(mfa.secret))
return
}
}
diff --git a/src/main/kotlin/info/alinadace/sakuramiki/util/JsonUtil.kt b/src/main/kotlin/info/alinadace/sakuramiki/util/JsonUtil.kt
index a3b3f66..9f6bffe 100644
--- a/src/main/kotlin/info/alinadace/sakuramiki/util/JsonUtil.kt
+++ b/src/main/kotlin/info/alinadace/sakuramiki/util/JsonUtil.kt
@@ -7,7 +7,15 @@ import com.fasterxml.jackson.databind.ObjectMapper
* @author Kane
* @since 2025/3/24 16:10
*/
-private val OBJECT_MAPPER = ObjectMapper()
+val OBJECT_MAPPER = ObjectMapper()
fun parse(json: String): Dict {
return OBJECT_MAPPER.readValue(json, OBJECT_MAPPER.typeFactory.constructType(Dict::class.java))
}
+
+inline fun T.toJson(): String {
+ return OBJECT_MAPPER.writeValueAsString(this)
+}
+
+inline fun T.ofJson(json: String): T{
+ return OBJECT_MAPPER.readValue(json, T::class.java)
+}
diff --git a/src/main/kotlin/info/alinadace/sakuramiki/util/MFAUtil.kt b/src/main/kotlin/info/alinadace/sakuramiki/util/MFAUtil.kt
index 1987872..64d62fd 100644
--- a/src/main/kotlin/info/alinadace/sakuramiki/util/MFAUtil.kt
+++ b/src/main/kotlin/info/alinadace/sakuramiki/util/MFAUtil.kt
@@ -11,41 +11,53 @@ import kotlin.math.pow
* @since 2025/3/18 16:01
*/
class MFAUtil {
- companion object{
+ companion object {
private const val ALGORITHM = "HmacSHA1"
private val mac = Mac.getInstance(ALGORITHM)
+ private const val CODE_DIGITS = 6
+ private const val CODE_MODULUS = 10.0
+
/**
* 生成 MFA 验证码
*/
fun generate(key: String, step: Int): String {
- val data = ByteArray(8)
- var value = System.currentTimeMillis() / 1000 / step
- run {
- var i = 8
- while (i-- > 0) {
+ return try {
+ val data = ByteArray(8)
+ var value = System.currentTimeMillis() / 1000 / step
+
+ for (i in 7 downTo 0) {
data[i] = value.toByte()
value = value ushr 8
}
+
+ val decodedKey = Base32.decode(key)
+ val signKey = SecretKeySpec(decodedKey, ALGORITHM)
+ mac.init(signKey)
+ val hash = mac.doFinal(data)
+ val offset = hash[hash.size - 1].toInt() and 0xF
+
+ var truncatedHash: Long = 0
+
+ for (i in 0..3) {
+ truncatedHash = truncatedHash shl 8
+ truncatedHash = truncatedHash or (hash[offset + i].toInt() and 0xFF).toLong()
+ }
+
+ truncatedHash = truncatedHash and 0x7FFFFFFFL
+ truncatedHash %= CODE_MODULUS.pow(CODE_DIGITS).toLong()
+
+ "%0${CODE_DIGITS}d".format(truncatedHash)
+ } catch (e: Exception) {
+ throw RuntimeException("Failed to generate MFA code", e)
}
-
- val decodedKey = Base32.decode(key)
- val signKey = SecretKeySpec(decodedKey, ALGORITHM)
- mac.init(signKey)
- val hash = mac.doFinal(data)
- println(hash.contentToString())
- val offset = hash[hash.size - 1].toInt() and 0xF
-
- var truncatedHash: Long = 0
-
- for (i in 0..3) {
- truncatedHash = truncatedHash shl 8
- truncatedHash = truncatedHash or (hash[offset + i].toInt() and 0xFF).toLong()
- }
-
- truncatedHash = truncatedHash and 0x7FFFFFFFL
- truncatedHash %= 10.0.pow(6.0).toLong()
-
- return String.format("%0" + 6 + "d", truncatedHash)
}
+
+ /**
+ * 生成默认步长(30秒)的 MFA 验证码
+ *
+ * @param key Base32编码的密钥
+ * @return 6位数字验证码
+ */
+ fun generate(key: String): String = generate(key, 30)
}
}