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.ConsoleDataScope
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.ExperimentalPermission
import net.mamoe.mirai.console.permission.PermissionService
@ -172,14 +173,19 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI
phase `auto-login bots`@{
runBlocking {
for ((id, password) in AutoLoginConfig.plainPasswords) {
for ((id, password) in AutoLoginConfig.plainPasswords.filterNot { it.key == 123456654321L }) {
mainLogger.info { "Auto-login $id" }
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" }
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.ValueDescription
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() {
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(
@ -21,5 +23,9 @@ internal object AutoLoginConfig : AutoSavePluginConfig() {
账号和 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 {
@JvmStatic
public fun parseFromString(string: String): AbstractPermissibleIdentifier {
val str = string.trim()
objects.find { it.toString() == str }?.let { return it as AbstractPermissibleIdentifier }
for ((regex, block) in regexes) {
val result = regex.find(str) ?: continue
if (result.range.last != str.lastIndex) continue
if (result.range.first != 0) continue
return result.destructured.run(block)
val str = string.trim { it.isWhitespace() }.toLowerCase()
if (str == "console") return Console
if (str.isNotEmpty()) {
when (str[0]) {
'g' -> {
val arg = str.substring(1)
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")
}
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
@ -86,54 +117,70 @@ public sealed class AbstractPermissibleIdentifier(
)
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) {
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 val groupId: 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) {
override fun toString(): String = "AnyFriend"
override fun toString(): String = "f*"
}
public data class ExactFriend(
public val id: Long
) : AbstractPermissibleIdentifier(ExactUser(id)) {
override fun toString(): String = "ExactFriend"
override fun toString(): String = "f$id"
}
public object AnyTemp : AbstractPermissibleIdentifier(AnyUser) {
override fun toString(): String = "AnyTemp"
public data class AnyTemp(
public val groupId: Long,
) : AbstractPermissibleIdentifier(AnyUser, AnyMember(groupId)) {
override fun toString(): String = "t$groupId.*"
}
public data class ExactTemp(
public val groupId: Long,
public val id: Long
) : AbstractPermissibleIdentifier(ExactUser(groupId)) // TODO: 2020/9/8 ExactMember ?
public val memberId: Long
) : AbstractPermissibleIdentifier(ExactUser(groupId), ExactMember(groupId, memberId)) {
override fun toString(): String = "t$groupId.$memberId"
}
public object AnyUser : AbstractPermissibleIdentifier(AnyContact) {
override fun toString(): String = "AnyUser"
override fun toString(): String = "u*"
}
public data class ExactUser(
public val id: Long
) : AbstractPermissibleIdentifier(AnyUser)
) : AbstractPermissibleIdentifier(AnyUser) {
override fun toString(): String = "u$id"
}
public object AnyContact : AbstractPermissibleIdentifier() {
override fun toString(): String = "AnyContact"
override fun toString(): String = "*"
}
public object Console : AbstractPermissibleIdentifier() {
override fun toString(): String = "Console"
override fun toString(): String = "console"
}
}