mirror of
https://github.com/iLay1678/i-tools.git
synced 2025-07-03 18:52:17 +08:00
修复cf pages无法使用
This commit is contained in:
parent
815a2542ef
commit
2b83ecd8dd
17
package-lock.json
generated
17
package-lock.json
generated
@ -11,13 +11,12 @@
|
|||||||
"@nuxtjs/tailwindcss": "^6.12.2",
|
"@nuxtjs/tailwindcss": "^6.12.2",
|
||||||
"ant-design-vue": "^4.2.6",
|
"ant-design-vue": "^4.2.6",
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-es": "^2.1.0",
|
||||||
"nuxt": "^3.14.1592",
|
"nuxt": "^3.14.1592",
|
||||||
"vue": "latest",
|
"vue": "latest",
|
||||||
"vue-router": "latest"
|
"vue-router": "latest"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/crypto-js": "^4.2.2",
|
|
||||||
"nitropack": "^2.10.4",
|
"nitropack": "^2.10.4",
|
||||||
"sass-embedded": "^1.82.0"
|
"sass-embedded": "^1.82.0"
|
||||||
}
|
}
|
||||||
@ -2514,12 +2513,6 @@
|
|||||||
"node": ">=10.13.0"
|
"node": ">=10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/crypto-js": {
|
|
||||||
"version": "4.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz",
|
|
||||||
"integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||||
@ -3900,10 +3893,10 @@
|
|||||||
"uncrypto": "^0.1.3"
|
"uncrypto": "^0.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/crypto-js": {
|
"node_modules/crypto-es": {
|
||||||
"version": "4.2.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/crypto-es/-/crypto-es-2.1.0.tgz",
|
||||||
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
|
"integrity": "sha512-C5Dbuv4QTPGuloy5c5Vv/FZHtmK+lobLAypFfuRaBbwCsk3qbCWWESCH3MUcBsrgXloRNMrzwUAiPg4U6+IaKA=="
|
||||||
},
|
},
|
||||||
"node_modules/css-declaration-sorter": {
|
"node_modules/css-declaration-sorter": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.0",
|
||||||
|
@ -7,20 +7,20 @@
|
|||||||
"dev": "nuxt dev",
|
"dev": "nuxt dev",
|
||||||
"start": "nuxt start",
|
"start": "nuxt start",
|
||||||
"generate": "nuxt generate",
|
"generate": "nuxt generate",
|
||||||
"postinstall": "nuxt prepare"
|
"postinstall": "nuxt prepare",
|
||||||
|
"cf-dev": "npx nuxi build --preset=cloudflare_pages && npx wrangler pages dev dist/"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design-vue/nuxt": "^1.4.6",
|
"@ant-design-vue/nuxt": "^1.4.6",
|
||||||
"@nuxtjs/tailwindcss": "^6.12.2",
|
"@nuxtjs/tailwindcss": "^6.12.2",
|
||||||
"ant-design-vue": "^4.2.6",
|
"ant-design-vue": "^4.2.6",
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-es": "^2.1.0",
|
||||||
"nuxt": "^3.14.1592",
|
"nuxt": "^3.14.1592",
|
||||||
"vue": "latest",
|
"vue": "latest",
|
||||||
"vue-router": "latest"
|
"vue-router": "latest"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/crypto-js": "^4.2.2",
|
|
||||||
"nitropack": "^2.10.4",
|
"nitropack": "^2.10.4",
|
||||||
"sass-embedded": "^1.82.0"
|
"sass-embedded": "^1.82.0"
|
||||||
}
|
}
|
||||||
|
108
pages/index.vue
108
pages/index.vue
@ -4,13 +4,11 @@
|
|||||||
<div class="mx-auto w-full max-w-3xl bg-white shadow-lg rounded-lg p-8">
|
<div class="mx-auto w-full max-w-3xl bg-white shadow-lg rounded-lg p-8">
|
||||||
<div class="flex justify-between items-center mb-6">
|
<div class="flex justify-between items-center mb-6">
|
||||||
<h1 class="text-2xl font-bold text-gray-800">与「阿里云盘」连接</h1>
|
<h1 class="text-2xl font-bold text-gray-800">与「阿里云盘」连接</h1>
|
||||||
<a href="https://ghcr.io/ilay1678/alipan-tv-token"
|
<a href="https://ghcr.io/ilay1678/alipan-tv-token" target="_blank" rel="noopener noreferrer"
|
||||||
target="_blank"
|
class="text-gray-600 hover:text-blue-500 transition-colors" title="Docker Image">
|
||||||
rel="noopener noreferrer"
|
|
||||||
class="text-gray-600 hover:text-blue-500 transition-colors"
|
|
||||||
title="Docker Image">
|
|
||||||
<svg class="h-6 w-6" viewBox="0 0 24 24" fill="currentColor">
|
<svg class="h-6 w-6" viewBox="0 0 24 24" fill="currentColor">
|
||||||
<path d="M13.983 11.078h2.119a.186.186 0 00.186-.185V9.006a.186.186 0 00-.186-.186h-2.119a.185.185 0 00-.185.185v1.888c0 .102.083.185.185.185m-2.954-5.43h2.118a.186.186 0 00.186-.186V3.574a.186.186 0 00-.186-.185h-2.118a.185.185 0 00-.185.185v1.888c0 .102.082.185.185.185m0 2.716h2.118a.187.187 0 00.186-.186V6.29a.186.186 0 00-.186-.185h-2.118a.185.185 0 00-.185.185v1.887c0 .102.082.185.185.186m-2.93 0h2.12a.186.186 0 00.184-.186V6.29a.185.185 0 00-.185-.185H8.1a.185.185 0 00-.185.185v1.887c0 .102.083.185.185.186m-2.964 0h2.119a.186.186 0 00.185-.186V6.29a.185.185 0 00-.185-.185H5.136a.186.186 0 00-.186.185v1.887c0 .102.084.185.186.186m5.893 2.715h2.118a.186.186 0 00.186-.185V9.006a.186.186 0 00-.186-.186h-2.118a.185.185 0 00-.185.185v1.888c0 .102.082.185.185.185m-2.93 0h2.12a.185.185 0 00.184-.185V9.006a.185.185 0 00-.184-.186h-2.12a.185.185 0 00-.184.185v1.888c0 .102.083.185.185.185m-2.964 0h2.119a.185.185 0 00.185-.185V9.006a.185.185 0 00-.184-.186h-2.12a.186.186 0 00-.186.186v1.887c0 .102.084.185.186.185m-2.92 0h2.12a.185.185 0 00.184-.185V9.006a.185.185 0 00-.184-.186h-2.12a.185.185 0 00-.184.185v1.888c0 .102.082.185.185.185M23.763 9.89c-.065-.051-.672-.51-1.954-.51-.338.001-.676.03-1.01.087-.248-1.7-1.653-2.53-1.716-2.566l-.344-.199-.226.327c-.284.438-.49.922-.612 1.43-.23.97-.09 1.882.403 2.661-.595.332-1.55.413-1.744.42H.751a.751.751 0 00-.75.748 11.376 11.376 0 00.692 4.062c.545 1.428 1.355 2.48 2.41 3.124 1.18.723 3.1 1.137 5.275 1.137.983.003 1.963-.086 2.93-.266a12.248 12.248 0 003.823-1.389c.98-.567 1.86-1.288 2.61-2.136 1.252-1.418 1.998-2.997 2.553-4.4h.221c1.372 0 2.215-.549 2.68-1.009.309-.293.55-.65.707-1.046l.098-.288z"/>
|
<path
|
||||||
|
d="M13.983 11.078h2.119a.186.186 0 00.186-.185V9.006a.186.186 0 00-.186-.186h-2.119a.185.185 0 00-.185.185v1.888c0 .102.083.185.185.185m-2.954-5.43h2.118a.186.186 0 00.186-.186V3.574a.186.186 0 00-.186-.185h-2.118a.185.185 0 00-.185.185v1.888c0 .102.082.185.185.185m0 2.716h2.118a.187.187 0 00.186-.186V6.29a.186.186 0 00-.186-.185h-2.118a.185.185 0 00-.185.185v1.887c0 .102.082.185.185.186m-2.93 0h2.12a.186.186 0 00.184-.186V6.29a.185.185 0 00-.185-.185H8.1a.185.185 0 00-.185.185v1.887c0 .102.083.185.185.186m-2.964 0h2.119a.186.186 0 00.185-.186V6.29a.185.185 0 00-.185-.185H5.136a.186.186 0 00-.186.185v1.887c0 .102.084.185.186.186m5.893 2.715h2.118a.186.186 0 00.186-.185V9.006a.186.186 0 00-.186-.186h-2.118a.185.185 0 00-.185.185v1.888c0 .102.082.185.185.185m-2.93 0h2.12a.185.185 0 00.184-.185V9.006a.185.185 0 00-.184-.186h-2.12a.185.185 0 00-.184.185v1.888c0 .102.083.185.185.185m-2.964 0h2.119a.185.185 0 00.185-.185V9.006a.185.185 0 00-.184-.186h-2.12a.186.186 0 00-.186.186v1.887c0 .102.084.185.186.185m-2.92 0h2.12a.185.185 0 00.184-.185V9.006a.185.185 0 00-.184-.186h-2.12a.185.185 0 00-.184.185v1.888c0 .102.082.185.185.185M23.763 9.89c-.065-.051-.672-.51-1.954-.51-.338.001-.676.03-1.01.087-.248-1.7-1.653-2.53-1.716-2.566l-.344-.199-.226.327c-.284.438-.49.922-.612 1.43-.23.97-.09 1.882.403 2.661-.595.332-1.55.413-1.744.42H.751a.751.751 0 00-.75.748 11.376 11.376 0 00.692 4.062c.545 1.428 1.355 2.48 2.41 3.124 1.18.723 3.1 1.137 5.275 1.137.983.003 1.963-.086 2.93-.266a12.248 12.248 0 003.823-1.389c.98-.567 1.86-1.288 2.61-2.136 1.252-1.418 1.998-2.997 2.553-4.4h.221c1.372 0 2.215-.549 2.68-1.009.309-.293.55-.65.707-1.046l.098-.288z" />
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -18,25 +16,17 @@
|
|||||||
<div class="space-y-8">
|
<div class="space-y-8">
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<textarea
|
<textarea id="accessToken" v-model="accessToken"
|
||||||
id="accessToken"
|
|
||||||
v-model="accessToken"
|
|
||||||
class="w-full rounded font-mono text-sm leading-normal border-2 border-dashed border-gray-300 p-3 pr-10 bg-white resize-none focus:outline-none focus:border-blue-500 transition-colors min-h-[120px] whitespace-pre-wrap overflow-auto placeholder:text-gray-400"
|
class="w-full rounded font-mono text-sm leading-normal border-2 border-dashed border-gray-300 p-3 pr-10 bg-white resize-none focus:outline-none focus:border-blue-500 transition-colors min-h-[120px] whitespace-pre-wrap overflow-auto placeholder:text-gray-400"
|
||||||
readonly
|
readonly spellcheck="false" placeholder="访问令牌" />
|
||||||
spellcheck="false"
|
<button data-clipboard-target="#accessToken" :class="`absolute top-2 right-2 p-1 rounded transition-colors ${hasAccessToken
|
||||||
placeholder="访问令牌"
|
? 'hover:bg-gray-100 text-gray-500 hover:text-blue-500'
|
||||||
/>
|
: 'text-gray-300 cursor-not-allowed'
|
||||||
<button
|
}`" :disabled="!hasAccessToken">
|
||||||
data-clipboard-target="#accessToken"
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24"
|
||||||
:class="`absolute top-2 right-2 p-1 rounded transition-colors ${
|
stroke="currentColor">
|
||||||
hasAccessToken
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
? 'hover:bg-gray-100 text-gray-500 hover:text-blue-500'
|
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
||||||
: 'text-gray-300 cursor-not-allowed'
|
|
||||||
}`"
|
|
||||||
:disabled="!hasAccessToken"
|
|
||||||
>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -44,25 +34,17 @@
|
|||||||
|
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<textarea
|
<textarea id="refreshToken" v-model="refreshToken"
|
||||||
id="refreshToken"
|
|
||||||
v-model="refreshToken"
|
|
||||||
class="w-full rounded font-mono text-sm leading-normal border-2 border-dashed border-gray-300 p-3 pr-10 bg-white resize-none focus:outline-none focus:border-blue-500 transition-colors min-h-[120px] whitespace-pre-wrap overflow-auto placeholder:text-gray-400"
|
class="w-full rounded font-mono text-sm leading-normal border-2 border-dashed border-gray-300 p-3 pr-10 bg-white resize-none focus:outline-none focus:border-blue-500 transition-colors min-h-[120px] whitespace-pre-wrap overflow-auto placeholder:text-gray-400"
|
||||||
readonly
|
readonly spellcheck="false" placeholder="刷新令牌" />
|
||||||
spellcheck="false"
|
<button data-clipboard-target="#refreshToken" :class="`absolute top-2 right-2 p-1 rounded transition-colors ${hasRefreshToken
|
||||||
placeholder="刷新令牌"
|
? 'hover:bg-gray-100 text-gray-500 hover:text-blue-500'
|
||||||
/>
|
: 'text-gray-300 cursor-not-allowed'
|
||||||
<button
|
}`" :disabled="!hasRefreshToken">
|
||||||
data-clipboard-target="#refreshToken"
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24"
|
||||||
:class="`absolute top-2 right-2 p-1 rounded transition-colors ${
|
stroke="currentColor">
|
||||||
hasRefreshToken
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
? 'hover:bg-gray-100 text-gray-500 hover:text-blue-500'
|
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
||||||
: 'text-gray-300 cursor-not-allowed'
|
|
||||||
}`"
|
|
||||||
:disabled="!hasRefreshToken"
|
|
||||||
>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -73,18 +55,15 @@
|
|||||||
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
|
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
|
||||||
<span class="ml-3 text-gray-600">正在获取授权链接...</span>
|
<span class="ml-3 text-gray-600">正在获取授权链接...</span>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button v-else @click="handleAuth(authUrl)" :disabled="authorizing" :class="`block w-full bg-blue-500 text-white text-center py-3 px-4 rounded transition-colors relative ${authorizing ? 'bg-blue-400 cursor-not-allowed' : 'hover:bg-blue-600'
|
||||||
v-else
|
}`">
|
||||||
@click="handleAuth(authUrl)"
|
|
||||||
:disabled="authorizing"
|
|
||||||
:class="`block w-full bg-blue-500 text-white text-center py-3 px-4 rounded transition-colors relative ${
|
|
||||||
authorizing ? 'bg-blue-400 cursor-not-allowed' : 'hover:bg-blue-600'
|
|
||||||
}`"
|
|
||||||
>
|
|
||||||
<div class="flex items-center justify-center">
|
<div class="flex items-center justify-center">
|
||||||
<div v-if="authorizing" class="animate-spin rounded-full h-5 w-5 border-2 border-white border-t-transparent mr-2"></div>
|
<div v-if="authorizing"
|
||||||
<svg v-else xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
class="animate-spin rounded-full h-5 w-5 border-2 border-white border-t-transparent mr-2"></div>
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1" />
|
<svg v-else xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1" />
|
||||||
</svg>
|
</svg>
|
||||||
{{ authorizing ? '授权中...' : '授权登录' }}
|
{{ authorizing ? '授权中...' : '授权登录' }}
|
||||||
</div>
|
</div>
|
||||||
@ -94,14 +73,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<a-modal
|
<a-modal v-model:open="isNoticeOpen" title="使用说明" @ok="closeNotice" :maskClosable="false" :closable="false"
|
||||||
v-model:open="isNoticeOpen"
|
:keyboard="false">
|
||||||
title="使用说明"
|
|
||||||
@ok="closeNotice"
|
|
||||||
:maskClosable="false"
|
|
||||||
:closable="false"
|
|
||||||
:keyboard="false"
|
|
||||||
>
|
|
||||||
<p>本工具能帮助你一键获取「阿里云盘TV版」的刷新令牌,完全免费。TV接口能绕过三方应用权益包的速率限制,但前提你得是SVIP。</p>
|
<p>本工具能帮助你一键获取「阿里云盘TV版」的刷新令牌,完全免费。TV接口能绕过三方应用权益包的速率限制,但前提你得是SVIP。</p>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<a-button type="primary" @click="closeNotice">我知道了</a-button>
|
<a-button type="primary" @click="closeNotice">我知道了</a-button>
|
||||||
@ -110,7 +83,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, watch } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
import ClipboardJS from 'clipboard'
|
import ClipboardJS from 'clipboard'
|
||||||
|
|
||||||
@ -127,8 +100,7 @@ const refreshToken = ref('')
|
|||||||
async function generateAuthUrl() {
|
async function generateAuthUrl() {
|
||||||
try {
|
try {
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
const response = await fetch("/generate_qr", { method: "POST" })
|
const data = await $fetch("/generate_qr", { method: "POST" })
|
||||||
const data = await response.json()
|
|
||||||
authUrl.value = `https://www.alipan.com/o/oauth/authorize?sid=${data.sid}`
|
authUrl.value = `https://www.alipan.com/o/oauth/authorize?sid=${data.sid}`
|
||||||
checkStatus(data.sid)
|
checkStatus(data.sid)
|
||||||
} finally {
|
} finally {
|
||||||
@ -142,8 +114,7 @@ function closeNotice() {
|
|||||||
|
|
||||||
async function checkStatus(sid) {
|
async function checkStatus(sid) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/check_status/" + sid)
|
const data = await $fetch("/check_status/" + sid)
|
||||||
const data = await response.json()
|
|
||||||
if (data.status === "LoginSuccess") {
|
if (data.status === "LoginSuccess") {
|
||||||
accessToken.value = data.access_token
|
accessToken.value = data.access_token
|
||||||
refreshToken.value = data.refresh_token
|
refreshToken.value = data.refresh_token
|
||||||
@ -191,6 +162,7 @@ const handleAuth = (url) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
// 先显示弹框
|
||||||
isNoticeOpen.value = true
|
isNoticeOpen.value = true
|
||||||
if (!hasGenerated.value) {
|
if (!hasGenerated.value) {
|
||||||
generateAuthUrl()
|
generateAuthUrl()
|
||||||
@ -200,6 +172,4 @@ onMounted(() => {
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
|
|
||||||
</style>
|
|
@ -1,32 +1,32 @@
|
|||||||
import { decrypt, getParams } from '@/utils/decode';
|
import { decrypt, getParams } from '@/utils/decode';
|
||||||
import { defineEventHandler, getRouterParams } from 'h3'
|
import { defineEventHandler, getRouterParams } from 'h3'
|
||||||
|
import type { QrCodeStatus, TokenResponseEncrypt, TokenRequest } from '~/types/api'
|
||||||
|
|
||||||
export const runtime = 'edge'
|
export const runtime = 'edge'
|
||||||
|
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
try {
|
try {
|
||||||
const { sid } = getRouterParams(event);
|
const { sid } = getRouterParams(event);
|
||||||
const response = await fetch(`https://openapi.alipan.com/oauth/qrcode/${sid}/status`);
|
const statusData = await $fetch<QrCodeStatus>(`https://openapi.alipan.com/oauth/qrcode/${sid}/status`);
|
||||||
const statusData:any = await response.json();
|
if (statusData.status === 'LoginSuccess' && statusData.authCode) {
|
||||||
|
|
||||||
if (statusData.status === 'LoginSuccess') {
|
|
||||||
try {
|
try {
|
||||||
const authCode = statusData.authCode;
|
|
||||||
const t = Math.floor(Date.now() / 1000);
|
const t = Math.floor(Date.now() / 1000);
|
||||||
const sendData = { ...getParams(t), code: authCode, "Content-Type": "application/json"};
|
const sendData = {
|
||||||
|
...getParams(t),
|
||||||
|
code: statusData.authCode,
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
} as TokenRequest;
|
||||||
|
|
||||||
const headers = Object.fromEntries(
|
const headers = Object.fromEntries(
|
||||||
Object.entries(sendData).map(([k, v]) => [k, String(v)])
|
Object.entries(sendData).map(([k, v]) => [k, String(v)])
|
||||||
);
|
);
|
||||||
|
|
||||||
const tokenResponse = await fetch('http://api.extscreen.com/aliyundrive/v3/token', {
|
const tokenResponse = await $fetch<TokenResponseEncrypt>('http://api.extscreen.com/aliyundrive/v3/token', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: headers,
|
headers: headers,
|
||||||
body: JSON.stringify(sendData)
|
body: JSON.stringify(sendData)
|
||||||
});
|
});
|
||||||
|
const plainData = decrypt(tokenResponse.data.ciphertext, tokenResponse.data.iv, t);
|
||||||
const tokenData:any = await tokenResponse.json();
|
|
||||||
const jsonp = tokenData.data;
|
|
||||||
const plainData = decrypt(jsonp.ciphertext, jsonp.iv, t);
|
|
||||||
const tokenInfo = JSON.parse(plainData);
|
const tokenInfo = JSON.parse(plainData);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -34,13 +34,14 @@ export default defineEventHandler(async (event) => {
|
|||||||
refresh_token: tokenInfo.refresh_token,
|
refresh_token: tokenInfo.refresh_token,
|
||||||
access_token: tokenInfo.access_token
|
access_token: tokenInfo.access_token
|
||||||
};
|
};
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { status: 'LoginFailed' };
|
return { status: 'LoginFailed' } as QrCodeStatus;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return { status: statusData.status };
|
|
||||||
}
|
}
|
||||||
} catch (error:any) {
|
|
||||||
|
return statusData;
|
||||||
|
} catch (error: any) {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: 500,
|
statusCode: 500,
|
||||||
message: error.message
|
message: error.message
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { defineEventHandler } from 'h3'
|
import { defineEventHandler } from 'h3'
|
||||||
|
import type { ApiResponse, QrCodeData } from '~/types/api'
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('http://api.extscreen.com/aliyundrive/qrcode', {
|
const response = await $fetch<ApiResponse<QrCodeData>>('http://api.extscreen.com/aliyundrive/qrcode', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@ -11,10 +11,9 @@ export default defineEventHandler(async (event) => {
|
|||||||
height: 500,
|
height: 500,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
const data:any = await response.json()
|
|
||||||
return {
|
return {
|
||||||
qr_link: data.data.qrCodeUrl,
|
qr_link: response.data.qrCodeUrl,
|
||||||
sid: data.data.sid
|
sid: response.data.sid
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
throw createError({
|
throw createError({
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { decrypt, getParams } from "@/utils/decode";
|
import { decrypt, getParams } from "@/utils/decode";
|
||||||
import { defineEventHandler } from 'h3'
|
import { defineEventHandler } from 'h3'
|
||||||
|
import type { ApiResponse, TokenResponseEncrypt } from '~/types/api'
|
||||||
|
|
||||||
export const runtime = 'edge'
|
export const runtime = 'edge'
|
||||||
|
|
||||||
@ -17,15 +18,12 @@ export default defineEventHandler(async (event) => {
|
|||||||
Object.entries(sendData).map(([k, v]) => [k, String(v)])
|
Object.entries(sendData).map(([k, v]) => [k, String(v)])
|
||||||
);
|
);
|
||||||
|
|
||||||
const response = await fetch('http://api.extscreen.com/aliyundrive/v3/token', {
|
const tokenData = await $fetch<TokenResponseEncrypt>('http://api.extscreen.com/aliyundrive/v3/token', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: headers,
|
headers: headers,
|
||||||
body: JSON.stringify(sendData)
|
body: JSON.stringify(sendData)
|
||||||
});
|
});
|
||||||
|
const plainData = decrypt(tokenData.data.ciphertext, tokenData.data.iv, t);
|
||||||
const tokenData :any = await response.json();
|
|
||||||
const jsonp = tokenData.data;
|
|
||||||
const plainData = decrypt(jsonp.ciphertext, jsonp.iv, t);
|
|
||||||
const tokenInfo = JSON.parse(plainData);
|
const tokenInfo = JSON.parse(plainData);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -34,10 +32,14 @@ export default defineEventHandler(async (event) => {
|
|||||||
refresh_token: tokenInfo.refresh_token,
|
refresh_token: tokenInfo.refresh_token,
|
||||||
expires_in: tokenInfo.expires_in
|
expires_in: tokenInfo.expires_in
|
||||||
};
|
};
|
||||||
|
// 直接返回响应数据
|
||||||
|
return tokenData;
|
||||||
|
|
||||||
} catch (error:any) {
|
} catch (error:any) {
|
||||||
return {
|
return {
|
||||||
error: error.message,
|
code: 500,
|
||||||
statusCode: 500
|
message: error.message,
|
||||||
}
|
data: null
|
||||||
|
} as ApiResponse
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
45
types/api.ts
Normal file
45
types/api.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
export interface ApiResponse<T = any> {
|
||||||
|
code: number;
|
||||||
|
message: string;
|
||||||
|
data: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface QrCodeData {
|
||||||
|
qrCodeUrl: string;
|
||||||
|
sid: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TokenInfo {
|
||||||
|
token_type: string;
|
||||||
|
access_token: string;
|
||||||
|
refresh_token: string;
|
||||||
|
expires_in: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TokenResponseEncrypt extends ApiResponse<{
|
||||||
|
ciphertext: string;
|
||||||
|
iv: string;
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
export interface QrCodeStatus {
|
||||||
|
status: 'WaitLogin' | 'LoginSuccess' | 'LoginFailed';
|
||||||
|
authCode?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DeviceInfo {
|
||||||
|
akv: string;
|
||||||
|
apv: string;
|
||||||
|
b: string;
|
||||||
|
d: string;
|
||||||
|
m: string;
|
||||||
|
mac: string;
|
||||||
|
n: string;
|
||||||
|
t: number;
|
||||||
|
wifiMac: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TokenRequest extends DeviceInfo {
|
||||||
|
refresh_token?: string;
|
||||||
|
code?: string;
|
||||||
|
'Content-Type': string;
|
||||||
|
}
|
@ -1,18 +1,16 @@
|
|||||||
import pkg from 'crypto-js';
|
import CryptoES from 'crypto-es';
|
||||||
const { AES, enc, mode, pad, MD5 } = pkg;
|
|
||||||
|
|
||||||
const decrypt = function (ciphertext: string, iv: string, t: number): string {
|
const decrypt = function (ciphertext: string, iv: string, t: number): string {
|
||||||
try {
|
try {
|
||||||
const key = generateKey(t);
|
const key = generateKey(t);
|
||||||
const decrypted = AES.decrypt(ciphertext, enc.Utf8.parse(key), {
|
const decrypted = CryptoES.AES.decrypt(ciphertext, CryptoES.enc.Utf8.parse(key), {
|
||||||
iv: enc.Hex.parse(iv),
|
iv: CryptoES.enc.Hex.parse(iv),
|
||||||
mode:mode.CBC,
|
mode: CryptoES.mode.CBC,
|
||||||
padding: pad.Pkcs7
|
padding: CryptoES.pad.Pkcs7
|
||||||
});
|
});
|
||||||
const dec = enc.Utf8.stringify(decrypted).toString();
|
const dec = CryptoES.enc.Utf8.stringify(decrypted).toString();
|
||||||
return dec;
|
return dec;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Decryption failed", error);
|
|
||||||
console.error("Decryption failed", error);
|
console.error("Decryption failed", error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@ -60,7 +58,7 @@ const generateKey = function (t: number): string {
|
|||||||
|
|
||||||
const keyArray = concatenatedParams.split("");
|
const keyArray = concatenatedParams.split("");
|
||||||
const hashedKey = h(keyArray, t);
|
const hashedKey = h(keyArray, t);
|
||||||
return MD5(hashedKey).toString(enc.Hex);
|
return CryptoES.MD5(hashedKey).toString(CryptoES.enc.Hex);
|
||||||
};
|
};
|
||||||
|
|
||||||
export { decrypt, getParams };
|
export { decrypt, getParams };
|
||||||
|
Loading…
x
Reference in New Issue
Block a user