refactor(util): 重构 MFAUtil 并优化相关服务
All checks were successful
Sakura-Miki-build / Automatic-Packaging (push) Successful in 4m48s
All checks were successful
Sakura-Miki-build / Automatic-Packaging (push) Successful in 4m48s
- 移除了 DownloadUtil 中的注释代码 - 修改了 MFAGenerateService 中的 MFA 验证码生成逻辑 - 重构了 MFAUtil 类,增加了默认步长的 generate 方法 - 更新了 JsonUtil,添加了对象与 JSON 字符串互转的扩展函数 - 在 pom.xml 中添加了 hutool-http 依赖
This commit is contained in:
parent
d3931b215c
commit
0374346f6a
5
pom.xml
5
pom.xml
@ -163,6 +163,11 @@
|
|||||||
<artifactId>core</artifactId>
|
<artifactId>core</artifactId>
|
||||||
<version>3.3.3</version>
|
<version>3.3.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.hutool</groupId>
|
||||||
|
<artifactId>hutool-http</artifactId>
|
||||||
|
<version>5.8.31</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -47,12 +47,6 @@ class DownloadUtil {
|
|||||||
return this.newCall(Request.Builder()
|
return this.newCall(Request.Builder()
|
||||||
.url(url)
|
.url(url)
|
||||||
.method(method, body)
|
.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()
|
.build()).execute()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ class MFAGenerateService : Service<FriendMessageEvent> {
|
|||||||
event.send("您还没有绑定默认MFA,使用 #mfa bind default <secret> 绑定默认MFA")
|
event.send("您还没有绑定默认MFA,使用 #mfa bind default <secret> 绑定默认MFA")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
event.send(MFAUtil.generate(mfa.secret, 30))
|
event.send(MFAUtil.generate(mfa.secret))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (command.size == 2){
|
if (command.size == 2){
|
||||||
@ -70,7 +70,7 @@ class MFAGenerateService : Service<FriendMessageEvent> {
|
|||||||
event.send("您还没有绑定${command[1]} MFA,使用 #mfa bind ${command[1]} <secret> 绑定${command[1]} MFA")
|
event.send("您还没有绑定${command[1]} MFA,使用 #mfa bind ${command[1]} <secret> 绑定${command[1]} MFA")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
event.send(MFAUtil.generate(mfa.secret, 30))
|
event.send(MFAUtil.generate(mfa.secret))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,15 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
|||||||
* @author Kane
|
* @author Kane
|
||||||
* @since 2025/3/24 16:10
|
* @since 2025/3/24 16:10
|
||||||
*/
|
*/
|
||||||
private val OBJECT_MAPPER = ObjectMapper()
|
val OBJECT_MAPPER = ObjectMapper()
|
||||||
fun parse(json: String): Dict {
|
fun parse(json: String): Dict {
|
||||||
return OBJECT_MAPPER.readValue(json, OBJECT_MAPPER.typeFactory.constructType(Dict::class.java))
|
return OBJECT_MAPPER.readValue(json, OBJECT_MAPPER.typeFactory.constructType(Dict::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Any> T.toJson(): String {
|
||||||
|
return OBJECT_MAPPER.writeValueAsString(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Any> T.ofJson(json: String): T{
|
||||||
|
return OBJECT_MAPPER.readValue(json, T::class.java)
|
||||||
|
}
|
||||||
|
@ -11,41 +11,53 @@ import kotlin.math.pow
|
|||||||
* @since 2025/3/18 16:01
|
* @since 2025/3/18 16:01
|
||||||
*/
|
*/
|
||||||
class MFAUtil {
|
class MFAUtil {
|
||||||
companion object{
|
companion object {
|
||||||
private const val ALGORITHM = "HmacSHA1"
|
private const val ALGORITHM = "HmacSHA1"
|
||||||
private val mac = Mac.getInstance(ALGORITHM)
|
private val mac = Mac.getInstance(ALGORITHM)
|
||||||
|
private const val CODE_DIGITS = 6
|
||||||
|
private const val CODE_MODULUS = 10.0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成 MFA 验证码
|
* 生成 MFA 验证码
|
||||||
*/
|
*/
|
||||||
fun generate(key: String, step: Int): String {
|
fun generate(key: String, step: Int): String {
|
||||||
val data = ByteArray(8)
|
return try {
|
||||||
var value = System.currentTimeMillis() / 1000 / step
|
val data = ByteArray(8)
|
||||||
run {
|
var value = System.currentTimeMillis() / 1000 / step
|
||||||
var i = 8
|
|
||||||
while (i-- > 0) {
|
for (i in 7 downTo 0) {
|
||||||
data[i] = value.toByte()
|
data[i] = value.toByte()
|
||||||
value = value ushr 8
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user