feat: frontend support auto get key

This commit is contained in:
H3CoF6
2026-02-08 23:06:52 +08:00
parent d388224d3c
commit 40546f994f
3 changed files with 154 additions and 19 deletions

View File

@@ -26,24 +26,40 @@
<!-- 密钥输入 -->
<div>
<label for="key" class="block text-sm font-medium text-[#000000e6] mb-2">
<svg class="w-4 h-4 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"/>
</svg>
解密密钥 <span class="text-red-500">*</span>
</label>
<div class="relative">
<input
id="key"
v-model="formData.key"
type="text"
placeholder="请输入64位十六进制密钥"
class="w-full px-4 py-3 bg-white border border-[#EDEDED] rounded-lg font-mono text-sm focus:outline-none focus:ring-2 focus:ring-[#07C160] focus:border-transparent transition-all duration-200"
:class="{ 'border-red-500': formErrors.key }"
required
/>
<div v-if="formData.key" class="absolute right-3 top-1/2 transform -translate-y-1/2">
<span class="text-xs text-[#7F7F7F]">{{ formData.key.length }}/64</span>
<div class="flex gap-3">
<div class="relative flex-1">
<input
id="key"
v-model="formData.key"
type="text"
placeholder="请输入64位十六进制密钥"
class="w-full px-4 py-3 bg-white border border-[#EDEDED] rounded-lg font-mono text-sm focus:outline-none focus:ring-2 focus:ring-[#07C160] focus:border-transparent transition-all duration-200"
:class="{ 'border-red-500': formErrors.key }"
required
/>
<div v-if="formData.key" class="absolute right-3 top-1/2 transform -translate-y-1/2">
<span class="text-xs text-[#7F7F7F]">{{ formData.key.length }}/64</span>
</div>
</div>
<button
type="button"
@click="handleGetDbKey"
:disabled="isGettingDbKey"
class="flex-none inline-flex items-center px-4 py-3 bg-[#07C160] text-white rounded-lg text-sm font-medium hover:bg-[#06AD56] transition-all duration-200 disabled:opacity-50 disabled:cursor-wait whitespace-nowrap"
>
<svg v-if="isGettingDbKey" class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path>
</svg>
<svg v-else class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
{{ isGettingDbKey ? '获取中...' : '自动获取' }}
</button>
</div>
<p v-if="formErrors.key" class="mt-1 text-sm text-red-600 flex items-center">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -55,7 +71,7 @@
<svg class="w-4 h-4 mr-1 text-[#10AEEF]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
使用 <a href="https://github.com/ycccccccy/wx_key" target="_blank" class="text-[#07C160] hover:text-[#06AD56]">wx_key</a> 等工具获取的64位十六进制字符串
尝试自动获取或者使用 <a href="https://github.com/ycccccccy/wx_key" target="_blank" class="text-[#07C160] hover:text-[#06AD56]">wx_key</a> 等工具获取的64位十六进制字符串
</p>
</div>
@@ -131,6 +147,26 @@
<!-- 填写密钥 -->
<div class="mb-6">
<div class="bg-gray-50 rounded-lg p-4">
<div class="flex justify-between items-center mb-4 pb-3 border-b border-gray-200">
<span class="text-sm font-medium text-gray-500">手动输入或通过微信获取</span>
<button
type="button"
@click="handleGetImageKey"
:disabled="isGettingImageKey"
class="flex-none inline-flex items-center px-4 py-3 bg-[#07C160] text-white rounded-lg text-sm font-medium hover:bg-[#06AD56] transition-all duration-200 disabled:opacity-50 disabled:cursor-wait whitespace-nowrap"
>
<svg v-if="isGettingImageKey" class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path>
</svg>
<svg v-else class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
{{ isGettingImageKey ? '正在获取...' : '自动获取' }}
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-[#000000e6] mb-2">XOR必填</label>
@@ -158,7 +194,7 @@
<svg class="w-4 h-4 mr-1 text-[#10AEEF]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
使用 <a href="https://github.com/ycccccccy/wx_key" target="_blank" class="text-[#07C160] hover:text-[#06AD56]">wx_key</a> 获取图片密钥AES 可选V4-V2 需要
尝试自动获取使用 <a href="https://github.com/ycccccccy/wx_key" target="_blank" class="text-[#07C160] hover:text-[#06AD56]">wx_key</a> 获取图片密钥AES 可选V4-V2 需要
</p>
</div>
</div>
@@ -367,12 +403,14 @@
import { ref, reactive, computed, onMounted } from 'vue'
import { useApi } from '~/composables/useApi'
const { decryptDatabase, saveMediaKeys, getSavedKeys } = useApi()
const { decryptDatabase, saveMediaKeys, getSavedKeys, getDbKey, getImageKey } = useApi()
const loading = ref(false)
const error = ref('')
const currentStep = ref(0)
const mediaAccount = ref('')
const isGettingDbKey = ref(false)
const isGettingImageKey = ref(false)
// 步骤定义
const steps = [
@@ -453,6 +491,84 @@ const prefillKeysForAccount = async (account) => {
}
}
const handleGetDbKey = async () => {
if (isGettingDbKey.value) return
isGettingDbKey.value = true
error.value = ''
formErrors.key = ''
try {
const { data, error: fetchError } = await getDbKey()
if (fetchError.value) {
error.value = '请求失败: ' + fetchError.value.message
return
}
const res = data.value
if (res && (res.status === 0)) {
if (res.data?.db_key) {
formData.key = res.data.db_key
}
// 有错误信息且不是ok时弹出提示
if (res.errmsg && res.errmsg !== 'ok') {
error.value = res.errmsg
}
} else {
error.value = '获取失败: ' + (res?.errmsg || '未知错误')
}
} catch (e) {
console.error(e)
error.value = '系统错误: ' + e.message
} finally {
isGettingDbKey.value = false
}
}
const handleGetImageKey = async () => {
if (isGettingImageKey.value) return
isGettingImageKey.value = true
manualKeyErrors.xor_key = ''
manualKeyErrors.aes_key = ''
error.value = ''
try {
const { data, fetchError } = await getImageKey()
if (fetchError && fetchError.value) {
error.value = '请求失败: ' + fetchError.value.message
return
}
const res = data.value
if (res && res.status === 0) {
if (res.data?.aes_key) {
manualKeys.aes_key = res.data.aes_key
}
if (res.data?.xor_key) {
// 后端记得处理为16进制再返回
manualKeys.xor_key = res.data.xor_key
}
if (res.errmsg && res.errmsg !== 'ok') {
error.value = res.errmsg
}
} else {
error.value = '获取失败: ' + (res?.errmsg || '未知错误')
}
} catch (e) {
console.error(e)
error.value = '系统错误: ' + e.message
} finally {
isGettingImageKey.value = false
}
}
const applyManualKeys = () => {
manualKeyErrors.xor_key = ''
manualKeyErrors.aes_key = ''