diff --git a/frontend/composables/useApi.js b/frontend/composables/useApi.js index cbf1c5f..3858c35 100644 --- a/frontend/composables/useApi.js +++ b/frontend/composables/useApi.js @@ -344,6 +344,20 @@ export const useApi = () => { const url = `/wrapped/annual/cards/${safeId}` + (query.toString() ? `?${query.toString()}` : '') return await request(url) } + + // 获取数据库解密密钥 + const getDbKey = () => { + return useFetch('/api/get_db_key', { + method: 'GET', + }) + } + + // 获取图片解密密钥 + const getImageKey = () => { + return useFetch('/api/get_image_key', { + method: 'GET', + }) + } return { detectWechat, @@ -375,6 +389,8 @@ export const useApi = () => { cancelChatExport, getWrappedAnnual, getWrappedAnnualMeta, - getWrappedAnnualCard + getWrappedAnnualCard, + getDbKey, + getImageKey, } } diff --git a/frontend/package.json b/frontend/package.json index aff4c28..b527734 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,5 +19,8 @@ "ogl": "^1.0.11", "vue": "^3.5.17", "vue-router": "^4.5.1" + }, + "devDependencies": { + "tailwindcss": "3.4.17" } } diff --git a/frontend/pages/decrypt.vue b/frontend/pages/decrypt.vue index fb76aec..2942d26 100644 --- a/frontend/pages/decrypt.vue +++ b/frontend/pages/decrypt.vue @@ -26,24 +26,40 @@
-
- -
- {{ formData.key.length }}/64 + +
+
+ +
+ {{ formData.key.length }}/64 +
+ +

@@ -55,7 +71,7 @@ - 使用 wx_key 等工具获取的64位十六进制字符串 + 尝试自动获取,或者使用 wx_key 等工具获取的64位十六进制字符串

@@ -131,6 +147,26 @@
+ +
+ 手动输入或通过微信获取 + +
+
@@ -158,7 +194,7 @@ - 使用 wx_key 获取图片密钥;AES 可选(V4-V2 需要) + 尝试自动获取,或使用 wx_key 获取图片密钥;AES 可选(V4-V2 需要)

@@ -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 = ''