Improve serialized configs

This commit is contained in:
Him188 2020-09-10 12:56:07 +08:00
parent 5cd35d7fbe
commit b242fc4eb8
4 changed files with 160 additions and 47 deletions

View File

@ -34,6 +34,7 @@ import net.mamoe.mirai.console.internal.command.CommandManagerImpl
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig
import net.mamoe.mirai.console.internal.data.builtins.ConsoleDataScope import net.mamoe.mirai.console.internal.data.builtins.ConsoleDataScope
import net.mamoe.mirai.console.internal.plugin.PluginManagerImpl import net.mamoe.mirai.console.internal.plugin.PluginManagerImpl
import net.mamoe.mirai.console.internal.util.autoHexToBytes
import net.mamoe.mirai.console.permission.BuiltInPermissionService import net.mamoe.mirai.console.permission.BuiltInPermissionService
import net.mamoe.mirai.console.permission.ExperimentalPermission import net.mamoe.mirai.console.permission.ExperimentalPermission
import net.mamoe.mirai.console.permission.PermissionService import net.mamoe.mirai.console.permission.PermissionService
@ -172,14 +173,19 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI
phase `auto-login bots`@{ phase `auto-login bots`@{
runBlocking { runBlocking {
for ((id, password) in AutoLoginConfig.plainPasswords) { for ((id, password) in AutoLoginConfig.plainPasswords.filterNot { it.key == 123456654321L }) {
mainLogger.info { "Auto-login $id" } mainLogger.info { "Auto-login $id" }
MiraiConsole.addBot(id, password).alsoLogin() MiraiConsole.addBot(id, password).alsoLogin()
} }
for ((id, password) in AutoLoginConfig.md5Passwords) { for ((id, password) in AutoLoginConfig.md5Passwords.filterNot { it.key == 123456654321L }) {
mainLogger.info { "Auto-login $id" } mainLogger.info { "Auto-login $id" }
MiraiConsole.addBot(id, password).alsoLogin() val x = runCatching {
password.autoHexToBytes()
}.getOrElse {
error("Bad auto-login md5: '$password'")
}
MiraiConsole.addBot(id, x).alsoLogin()
} }
} }
} }

View File

@ -3,6 +3,8 @@ package net.mamoe.mirai.console.internal.data.builtins
import net.mamoe.mirai.console.data.AutoSavePluginConfig import net.mamoe.mirai.console.data.AutoSavePluginConfig
import net.mamoe.mirai.console.data.ValueDescription import net.mamoe.mirai.console.data.ValueDescription
import net.mamoe.mirai.console.data.value import net.mamoe.mirai.console.data.value
import net.mamoe.mirai.console.internal.util.md5
import net.mamoe.mirai.console.internal.util.toUHexString
internal object AutoLoginConfig : AutoSavePluginConfig() { internal object AutoLoginConfig : AutoSavePluginConfig() {
override val saveName: String override val saveName: String
@ -13,7 +15,7 @@ internal object AutoLoginConfig : AutoSavePluginConfig() {
账号和明文密码列表 账号和明文密码列表
""" """
) )
val plainPasswords: MutableMap<Long, String> by value(mutableMapOf()) val plainPasswords: MutableMap<Long, String> by value(mutableMapOf(123456654321L to "example"))
@ValueDescription( @ValueDescription(
@ -21,5 +23,9 @@ internal object AutoLoginConfig : AutoSavePluginConfig() {
账号和 MD5 密码列表 账号和 MD5 密码列表
""" """
) )
val md5Passwords: MutableMap<Long, String> by value(mutableMapOf()) val md5Passwords: MutableMap<Long, String> by value(
mutableMapOf(
123456654321L to "example".toByteArray().md5().toUHexString()
)
)
} }

View File

@ -0,0 +1,54 @@
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.console.internal.util
import java.security.MessageDigest
@Suppress("DuplicatedCode") // false positive. `this` is not the same for `List<Byte>` and `ByteArray`
internal fun ByteArray.checkOffsetAndLength(offset: Int, length: Int) {
require(offset >= 0) { "offset shouldn't be negative: $offset" }
require(length >= 0) { "length shouldn't be negative: $length" }
require(offset + length <= this.size) { "offset ($offset) + length ($length) > array.size (${this.size})" }
}
internal fun String.autoHexToBytes(): ByteArray =
this.trim(Char::isWhitespace).asSequence().chunked(2).map {
(it[0].toString() + it[1]).toUByte(16).toByte()
}.toList().toByteArray()
internal fun ByteArray.md5(offset: Int = 0, length: Int = this.size - offset): ByteArray {
this.checkOffsetAndLength(offset, length)
return MessageDigest.getInstance("MD5").apply { update(this@md5, offset, length) }.digest()
}
@JvmOverloads
@Suppress("DuplicatedCode") // false positive. foreach is not common to UByteArray and ByteArray
internal fun ByteArray.toUHexString(
separator: String = " ",
offset: Int = 0,
length: Int = this.size - offset
): String {
this.checkOffsetAndLength(offset, length)
if (length == 0) {
return ""
}
val lastIndex = offset + length
return buildString(length * 2) {
this@toUHexString.forEachIndexed { index, it ->
if (index in offset until lastIndex) {
var ret = it.toUByte().toString(16).toUpperCase()
if (ret.length == 1) ret = "0$ret"
append(ret)
if (index < lastIndex - 1) append(separator)
}
}
}
}

View File

@ -46,36 +46,67 @@ public sealed class AbstractPermissibleIdentifier(
public companion object { public companion object {
@JvmStatic @JvmStatic
public fun parseFromString(string: String): AbstractPermissibleIdentifier { public fun parseFromString(string: String): AbstractPermissibleIdentifier {
val str = string.trim() val str = string.trim { it.isWhitespace() }.toLowerCase()
objects.find { it.toString() == str }?.let { return it as AbstractPermissibleIdentifier } if (str == "console") return Console
for ((regex, block) in regexes) { if (str.isNotEmpty()) {
val result = regex.find(str) ?: continue when (str[0]) {
if (result.range.last != str.lastIndex) continue 'g' -> {
if (result.range.first != 0) continue val arg = str.substring(1)
return result.destructured.run(block) if (arg == "*") return AnyGroup
else arg.toLongOrNull()?.let(::ExactGroup)?.let { return it }
}
'f' -> {
val arg = str.substring(1)
if (arg == "*") return AnyFriend
else arg.toLongOrNull()?.let(::ExactFriend)?.let { return it }
}
'u' -> {
val arg = str.substring(1)
if (arg == "*") return AnyUser
else arg.toLongOrNull()?.let(::ExactUser)?.let { return it }
}
'c' -> {
val arg = str.substring(1)
if (arg == "*") return AnyContact
}
'm' -> kotlin.run {
val arg = str.substring(1)
if (arg == "*") return AnyMemberFromAnyGroup
else {
val components = arg.split('.')
if (components.size == 2) {
val groupId = components[0].toLongOrNull() ?: return@run
if (components[1] == "*") return AnyMember(groupId)
else {
val memberId = components[1].toLongOrNull() ?: return@run
return ExactMember(groupId, memberId)
}
}
}
}
't' -> kotlin.run {
val arg = str.substring(1)
if (arg == "*") return AnyTempFromAnyGroup
else {
val components = arg.split('.')
if (components.size == 2) {
val groupId = components[0].toLongOrNull() ?: return@run
if (components[1] == "*") return AnyTemp(groupId)
else {
val memberId = components[1].toLongOrNull() ?: return@run
return ExactTemp(groupId, memberId)
}
}
}
}
}
} }
error("Cannot deserialize '$str' as AbstractPermissibleIdentifier") error("Cannot deserialize '$str' as AbstractPermissibleIdentifier")
} }
internal val objects by lazy {
// https://youtrack.jetbrains.com/issue/KT-41782
AbstractPermissibleIdentifier::class.nestedClasses.mapNotNull { it.objectInstance }
}
internal val regexes: List<Pair<Regex, (matchGroup: MatchResult.Destructured) -> AbstractPermissibleIdentifier>> =
listOf(
Regex("""ExactGroup\(\s*([0-9]+)\s*\)""") to { (id) -> ExactGroup(id.toLong()) },
Regex("""ExactFriend\(\s*([0-9]+)\s*\)""") to { (id) -> ExactFriend(id.toLong()) },
Regex("""ExactUser\(\s*([0-9]+)\s*\)""") to { (id) -> ExactUser(id.toLong()) },
Regex("""AnyMember\(\s*([0-9]+)\s*\)""") to { (id) -> AnyMember(id.toLong()) },
Regex("""ExactMember\(\s*([0-9]+)\s*([0-9]+)\s*\)""") to { (a, b) ->
ExactMember(
a.toLong(),
b.toLong()
)
},
Regex("""ExactTemp\(\s*([0-9]+)\s*([0-9]+)\s*\)""") to { (a, b) -> ExactTemp(a.toLong(), b.toLong()) },
)
} }
@ConsoleExperimentalAPI @ConsoleExperimentalAPI
@ -86,54 +117,70 @@ public sealed class AbstractPermissibleIdentifier(
) )
public object AnyGroup : AbstractPermissibleIdentifier(AnyContact) { public object AnyGroup : AbstractPermissibleIdentifier(AnyContact) {
override fun toString(): String = "AnyGroup" override fun toString(): String = "g*"
} }
public data class ExactGroup(public val groupId: Long) : AbstractPermissibleIdentifier(AnyGroup) public data class ExactGroup(public val groupId: Long) : AbstractPermissibleIdentifier(AnyGroup) {
override fun toString(): String = "g$groupId"
}
public data class AnyMember(public val groupId: Long) : AbstractPermissibleIdentifier(AnyMemberFromAnyGroup) public data class AnyMember(public val groupId: Long) : AbstractPermissibleIdentifier(AnyMemberFromAnyGroup) {
override fun toString(): String = "m$groupId.*"
}
public object AnyMemberFromAnyGroup : AbstractPermissibleIdentifier(AnyUser) { public object AnyMemberFromAnyGroup : AbstractPermissibleIdentifier(AnyUser) {
override fun toString(): String = "AnyMemberFromAnyGroup" override fun toString(): String = "m*"
}
public object AnyTempFromAnyGroup : AbstractPermissibleIdentifier(AnyUser) {
override fun toString(): String = "t*"
} }
public data class ExactMember( public data class ExactMember(
public val groupId: Long, public val groupId: Long,
public val memberId: Long public val memberId: Long
) : AbstractPermissibleIdentifier(AnyMember(groupId), ExactUser(memberId)) ) : AbstractPermissibleIdentifier(AnyMember(groupId), ExactUser(memberId)) {
override fun toString(): String = "m$groupId.$memberId"
}
public object AnyFriend : AbstractPermissibleIdentifier(AnyUser) { public object AnyFriend : AbstractPermissibleIdentifier(AnyUser) {
override fun toString(): String = "AnyFriend" override fun toString(): String = "f*"
} }
public data class ExactFriend( public data class ExactFriend(
public val id: Long public val id: Long
) : AbstractPermissibleIdentifier(ExactUser(id)) { ) : AbstractPermissibleIdentifier(ExactUser(id)) {
override fun toString(): String = "ExactFriend" override fun toString(): String = "f$id"
} }
public object AnyTemp : AbstractPermissibleIdentifier(AnyUser) { public data class AnyTemp(
override fun toString(): String = "AnyTemp" public val groupId: Long,
) : AbstractPermissibleIdentifier(AnyUser, AnyMember(groupId)) {
override fun toString(): String = "t$groupId.*"
} }
public data class ExactTemp( public data class ExactTemp(
public val groupId: Long, public val groupId: Long,
public val id: Long public val memberId: Long
) : AbstractPermissibleIdentifier(ExactUser(groupId)) // TODO: 2020/9/8 ExactMember ? ) : AbstractPermissibleIdentifier(ExactUser(groupId), ExactMember(groupId, memberId)) {
override fun toString(): String = "t$groupId.$memberId"
}
public object AnyUser : AbstractPermissibleIdentifier(AnyContact) { public object AnyUser : AbstractPermissibleIdentifier(AnyContact) {
override fun toString(): String = "AnyUser" override fun toString(): String = "u*"
} }
public data class ExactUser( public data class ExactUser(
public val id: Long public val id: Long
) : AbstractPermissibleIdentifier(AnyUser) ) : AbstractPermissibleIdentifier(AnyUser) {
override fun toString(): String = "u$id"
}
public object AnyContact : AbstractPermissibleIdentifier() { public object AnyContact : AbstractPermissibleIdentifier() {
override fun toString(): String = "AnyContact" override fun toString(): String = "*"
} }
public object Console : AbstractPermissibleIdentifier() { public object Console : AbstractPermissibleIdentifier() {
override fun toString(): String = "Console" override fun toString(): String = "console"
} }
} }