From d8819bd615fdc711fdd746ca60a8f164f7168a33 Mon Sep 17 00:00:00 2001 From: Him188 Date: Mon, 2 Aug 2021 14:46:55 +0800 Subject: [PATCH] Add tests for AccountSecrets --- .../components/AccountSecretsManager.kt | 59 +++++++++++++++---- .../kotlin/utils/BotConfigurationExt.kt | 1 + .../network/impl/netty/AccountSecretsTest.kt | 50 ++++++++++++++++ 3 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 mirai-core/src/commonTest/kotlin/network/impl/netty/AccountSecretsTest.kt diff --git a/mirai-core/src/commonMain/kotlin/network/components/AccountSecretsManager.kt b/mirai-core/src/commonMain/kotlin/network/components/AccountSecretsManager.kt index 0fa093424..731a55b91 100644 --- a/mirai-core/src/commonMain/kotlin/network/components/AccountSecretsManager.kt +++ b/mirai-core/src/commonMain/kotlin/network/components/AccountSecretsManager.kt @@ -18,7 +18,7 @@ import net.mamoe.mirai.internal.network.WLoginSigInfo import net.mamoe.mirai.internal.network.component.ComponentKey import net.mamoe.mirai.internal.network.getRandomByteArray import net.mamoe.mirai.internal.network.protocol.packet.login.wtlogin.get_mpasswd -import net.mamoe.mirai.internal.utils.actualCacheDir +import net.mamoe.mirai.internal.utils.accountSecretsFile import net.mamoe.mirai.internal.utils.crypto.ECDHInitialPublicKey import net.mamoe.mirai.internal.utils.crypto.TEA import net.mamoe.mirai.internal.utils.crypto.defaultInitialPublicKey @@ -77,7 +77,6 @@ internal interface AccountSecrets { } -@Suppress("ArrayInDataClass") // for `copy` @Serializable internal data class AccountSecretsImpl( override var loginExtraData: MutableSet, @@ -89,7 +88,39 @@ internal data class AccountSecretsImpl( override var tgtgtKey: ByteArray, override val randomKey: ByteArray, override var ecdhInitialPublicKey: ECDHInitialPublicKey, -) : AccountSecrets, ProtoBuf +) : AccountSecrets, ProtoBuf { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as AccountSecretsImpl + + if (loginExtraData != other.loginExtraData) return false + if (wLoginSigInfoField != other.wLoginSigInfoField) return false + if (!G.contentEquals(other.G)) return false + if (!dpwd.contentEquals(other.dpwd)) return false + if (!randSeed.contentEquals(other.randSeed)) return false + if (!ksid.contentEquals(other.ksid)) return false + if (!tgtgtKey.contentEquals(other.tgtgtKey)) return false + if (!randomKey.contentEquals(other.randomKey)) return false + if (ecdhInitialPublicKey != other.ecdhInitialPublicKey) return false + + return true + } + + override fun hashCode(): Int { + var result = loginExtraData.hashCode() + result = 31 * result + (wLoginSigInfoField?.hashCode() ?: 0) + result = 31 * result + G.contentHashCode() + result = 31 * result + dpwd.contentHashCode() + result = 31 * result + randSeed.contentHashCode() + result = 31 * result + ksid.contentHashCode() + result = 31 * result + tgtgtKey.contentHashCode() + result = 31 * result + randomKey.contentHashCode() + result = 31 * result + ecdhInitialPublicKey.hashCode() + return result + } +} internal fun AccountSecretsImpl( other: AccountSecrets, @@ -152,14 +183,7 @@ internal class FileCacheAccountSecretsManager( @Synchronized override fun saveSecrets(account: BotAccount, secrets: AccountSecrets) { if (secrets.wLoginSigInfoField == null) return - - file.writeBytes( - TEA.encrypt( - AccountSecretsImpl(secrets).toByteArray(AccountSecretsImpl.serializer()), - account.passwordMd5 - ) - ) - + saveSecretsToFile(file, account, secrets) logger.info { "Saved account secrets to local cache for fast login." } } @@ -190,6 +214,17 @@ internal class FileCacheAccountSecretsManager( override fun invalidate() { file.delete() } + + companion object { + fun saveSecretsToFile(file: File, account: BotAccount, secrets: AccountSecrets) { + file.writeBytes( + TEA.encrypt( + AccountSecretsImpl(secrets).toByteArray(AccountSecretsImpl.serializer()), + account.passwordMd5 + ) + ) + } + } } internal class CombinedAccountSecretsManager( @@ -218,7 +253,7 @@ internal fun BotConfiguration.createAccountsSecretsManager(logger: MiraiLogger): return CombinedAccountSecretsManager( MemoryAccountSecretsManager(), FileCacheAccountSecretsManager( - actualCacheDir().resolve("account.secrets"), + accountSecretsFile(), logger ) ) diff --git a/mirai-core/src/commonMain/kotlin/utils/BotConfigurationExt.kt b/mirai-core/src/commonMain/kotlin/utils/BotConfigurationExt.kt index db3ae2646..8e0dd9a20 100644 --- a/mirai-core/src/commonMain/kotlin/utils/BotConfigurationExt.kt +++ b/mirai-core/src/commonMain/kotlin/utils/BotConfigurationExt.kt @@ -20,3 +20,4 @@ internal fun BotConfiguration.contactCacheDir(): File = actualCacheDir().resolve internal fun BotConfiguration.friendCacheFile(): File = contactCacheDir().resolveCreateFile("friends.json") internal fun BotConfiguration.groupCacheDir(): File = contactCacheDir().resolveMkdir("groups") internal fun BotConfiguration.groupCacheFile(groupId: Long): File = groupCacheDir().resolveCreateFile("$groupId.json") +internal fun BotConfiguration.accountSecretsFile(): File = actualCacheDir().resolve("account.secrets") \ No newline at end of file diff --git a/mirai-core/src/commonTest/kotlin/network/impl/netty/AccountSecretsTest.kt b/mirai-core/src/commonTest/kotlin/network/impl/netty/AccountSecretsTest.kt new file mode 100644 index 000000000..5fd0022a8 --- /dev/null +++ b/mirai-core/src/commonTest/kotlin/network/impl/netty/AccountSecretsTest.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2019-2021 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/dev/LICENSE + */ + +package net.mamoe.mirai.internal.network.impl.netty + +import net.mamoe.mirai.internal.network.components.AccountSecretsImpl +import net.mamoe.mirai.internal.network.components.AccountSecretsManager +import net.mamoe.mirai.internal.network.components.FileCacheAccountSecretsManager +import net.mamoe.mirai.internal.network.framework.AbstractNettyNHTest +import net.mamoe.mirai.internal.network.handler.NetworkHandler +import net.mamoe.mirai.internal.test.runBlockingUnit +import net.mamoe.mirai.internal.utils.accountSecretsFile +import net.mamoe.mirai.utils.DeviceInfo +import net.mamoe.mirai.utils.getRandomByteArray +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + +internal class AccountSecretsTest : AbstractNettyNHTest() { + @Test + fun `can login with no secrets`() = runBlockingUnit { + val file = bot.configuration.accountSecretsFile() + file.delete() + bot.login() + bot.network.assertState(NetworkHandler.State.OK) + } + + @Test + fun `can login with good secrets`() = runBlockingUnit { + val file = bot.configuration.accountSecretsFile() + val s = AccountSecretsImpl(DeviceInfo.random(), bot.account) + FileCacheAccountSecretsManager.saveSecretsToFile(file, bot.account, s) + bot.login() + bot.network.assertState(NetworkHandler.State.OK) + assertEquals(s, bot.components[AccountSecretsManager].getSecrets(bot.account)) + } + + @Test + fun `can login with bad secrets`() = runBlockingUnit { + val file = bot.configuration.accountSecretsFile() + file.writeBytes(getRandomByteArray(16)) + bot.login() + bot.network.assertState(NetworkHandler.State.OK) + } +} \ No newline at end of file