feat: login qr code

This commit is contained in:
Hakadao
2023-11-13 02:32:41 +08:00
parent 84060fad07
commit a65d24e901
5 changed files with 138 additions and 7 deletions

View File

@@ -74,10 +74,13 @@
"webextension-polyfill": "^0.10.0"
},
"dependencies": {
"@types/md5": "^2.3.5",
"dplayer": "^1.27.1",
"md5": "^2.3.0",
"mitt": "^3.0.1",
"overlayscrollbars": "^2.0.0",
"overlayscrollbars-vue": "^0.5.5",
"qrcode.vue": "^3.4.1",
"vue-i18n": "^9.2.2"
}
}

38
pnpm-lock.yaml generated
View File

@@ -9,6 +9,7 @@ specifiers:
'@rollup/plugin-replace': ^5.0.2
'@types/dplayer': ^1.25.2
'@types/fs-extra': ^9.0.13
'@types/md5': ^2.3.5
'@types/node': ^18.17.1
'@types/webextension-polyfill': ^0.9.2
'@typescript-eslint/eslint-plugin': ^5.62.0
@@ -27,10 +28,12 @@ specifiers:
fs-extra: ^10.1.0
jsdom: ^20.0.3
kolorist: ^1.8.0
md5: ^2.3.0
mitt: ^3.0.1
npm-run-all: ^4.1.5
overlayscrollbars: ^2.0.0
overlayscrollbars-vue: ^0.5.5
qrcode.vue: ^3.4.1
rimraf: ^3.0.2
sass: ^1.64.2
terser: ^5.19.2
@@ -50,10 +53,13 @@ specifiers:
webextension-polyfill: ^0.10.0
dependencies:
'@types/md5': 2.3.5
dplayer: 1.27.1
md5: 2.3.0
mitt: 3.0.1
overlayscrollbars: 2.3.2
overlayscrollbars-vue: 0.5.5_b1fafd02612d7393176cab8eb5f579d8
qrcode.vue: 3.4.1_vue@3.3.4
vue-i18n: 9.2.2_vue@3.3.4
devDependencies:
@@ -974,6 +980,10 @@ packages:
resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==}
dev: true
/@types/md5/2.3.5:
resolution: {integrity: sha512-/i42wjYNgE6wf0j2bcTX6kuowmdL/6PE4IVitMpm2eYKBUuYCprdcWVK+xEF0gcV6ufMCRhtxmReGfc6hIK7Jw==}
dev: false
/@types/mdast/3.0.10:
resolution: {integrity: sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==}
dependencies:
@@ -2149,6 +2159,10 @@ packages:
resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==}
dev: true
/charenc/0.0.2:
resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==}
dev: false
/check-error/1.0.2:
resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==}
dev: true
@@ -2431,6 +2445,10 @@ packages:
pbf: 3.2.1
dev: true
/crypt/0.0.2:
resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
dev: false
/crypto-random-string/4.0.0:
resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==}
engines: {node: '>=12'}
@@ -4295,6 +4313,10 @@ packages:
has-tostringtag: 1.0.0
dev: true
/is-buffer/1.1.6:
resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
dev: false
/is-builtin-module/3.2.1:
resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==}
engines: {node: '>=6'}
@@ -4932,6 +4954,14 @@ packages:
resolution: {integrity: sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==}
dev: true
/md5/2.3.0:
resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==}
dependencies:
charenc: 0.0.2
crypt: 0.0.2
is-buffer: 1.1.6
dev: false
/mdast-util-from-markdown/0.8.5:
resolution: {integrity: sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==}
dependencies:
@@ -5808,6 +5838,14 @@ packages:
escape-goat: 4.0.0
dev: true
/qrcode.vue/3.4.1_vue@3.3.4:
resolution: {integrity: sha512-wq/zHsifH4FJ1GXQi8/wNxD1KfQkckIpjK1KPTc/qwYU5/Bkd4me0w4xZSg6EXk6xLBkVDE0zxVagewv5EMAVA==}
peerDependencies:
vue: ^3.0.0
dependencies:
vue: 3.3.4
dev: false
/qs/6.5.3:
resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==}
engines: {node: '>=0.6'}

View File

@@ -1,14 +1,16 @@
<script lang="ts" setup>
import type { Ref } from 'vue'
import { useI18n } from 'vue-i18n'
import QRCodeVue from 'qrcode.vue'
import SearchPage from './SearchPage.vue'
import { grantAccessKey, revokeAccessKey } from '~/utils/authProvider'
import { getTVLoginQRCode, grantAccessKey, revokeAccessKey } from '~/utils/authProvider'
import { settings } from '~/logic'
const { t } = useI18n()
const authorizeBtn = ref<HTMLButtonElement>() as Ref<HTMLButtonElement>
const showSearchPageModeSharedSettings = ref<boolean>(false)
const loginQRCodeUrl = ref<string>()
const preventCloseSettings = inject('preventCloseSettings') as Ref<boolean>
@@ -20,11 +22,10 @@ function handleRevoke() {
revokeAccessKey()
}
function openQRCode() {
browser.runtime.sendMessage({
contentScriptQuery: 'getLoginQRCode',
}).then((res) => {
console.log(res)
function setLoginQRCode() {
getTVLoginQRCode().then((res) => {
if (res.code === 0)
loginQRCodeUrl.value = res.data.url
})
}
@@ -83,7 +84,7 @@ function handleCloseSearchPageModeSharedSettings() {
</template>
<div w-full>
<Button @click="openQRCode">
<Button @click="setLoginQRCode">
Open QRCode
</Button>
<!-- <button
@@ -103,6 +104,10 @@ function handleCloseSearchPageModeSharedSettings() {
</button> -->
</div>
</SettingsItem>
<SettingsItem title="Login QR Code" next-line>
<QRCodeVue v-if="loginQRCodeUrl" :value="loginQRCodeUrl" width="200" />
<!-- <iframe v-if="loginQRCodeUrl" :src="loginQRCodeUrl" width="200" height="200" frameborder="0" /> -->
</SettingsItem>
</SettingsItemGroup>
<SettingsItemGroup :title="$t('settings.group_search_page_mode')">

14
src/utils/appSign.ts Normal file
View File

@@ -0,0 +1,14 @@
import md5 from 'md5'
/**
* 为请求参数进行 APP 签名
* https://socialsisteryi.github.io/bilibili-API-collect/docs/misc/sign/APP.html#typescript-javascript
*/
type Params = Record<string, any>
export function appSign(params: Params, appkey: string, appsec: string): string {
params.appkey = appkey
const searchParams = new URLSearchParams(params)
searchParams.sort()
return md5(searchParams.toString() + appsec)
}

View File

@@ -6,12 +6,18 @@
/* eslint-disable no-throw-literal */
import browser from 'webextension-polyfill'
import { appSign } from './appSign'
import { accessKey } from '~/logic/storage'
export function revokeAccessKey() {
accessKey.value = null
}
/**
* @deprecated
* @param t
* @param element
*/
export function grantAccessKey(t: any, element: HTMLButtonElement): void {
const originalInnerHTML = element.innerHTML
element.innerHTML = `
@@ -65,3 +71,68 @@ export function grantAccessKey(t: any, element: HTMLButtonElement): void {
console.error(`${error.msg}: `, error.data)
})
}
// export async function getAccesskeyNew() {
// let res = await getLoginQRCode()
// if (res.code === 0) {
// res = await pollQRCode(res.data.auth_code)
// console.log(res)
// }
// }
const TVAppKey = {
appkey: '4409e2ce8ffd12b8',
appsec: '59b43e04ad6965f34319062b478f83dd',
}
// https://github.com/magicdawn/bilibili-app-recommend/blob/e91722cc076fe65b98116fb0248236851ae6e1dc/src/utility/access-key/tv-qrcode/api.ts#L8
function tvSignSearchParams(params: Record<string, any>) {
const sign = appSign(params, TVAppKey.appkey, TVAppKey.appsec)
return new URLSearchParams({
...params,
sign,
})
}
export function pollTVLoginQRCode(authCode: string): Promise<any> {
const url = 'https://passport.bilibili.com/x/passport-tv-login/qrcode/poll'
return new Promise<void>((resolve, reject) => {
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
},
body: tvSignSearchParams({
appkey: TVAppKey.appkey,
auth_code: authCode,
local_id: '0',
ts: '0',
}),
})
.then(response => response.json())
.then(data => resolve(data))
.catch(error => reject(error))
})
}
export function getTVLoginQRCode(): Promise<any> {
const url = 'https://passport.bilibili.com/x/passport-tv-login/qrcode/auth_code'
return new Promise<void>((resolve, reject) => {
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
},
body: tvSignSearchParams({
appkey: TVAppKey.appkey,
local_id: '0',
ts: '0',
}),
})
.then(response => response.json())
.then(data => resolve(data))
.catch(error => reject(error))
})
}