mirror of
https://github.com/BewlyBewly/BewlyBewly.git
synced 2025-04-14 13:15:29 +00:00
feat: login qr code
This commit is contained in:
@@ -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
38
pnpm-lock.yaml
generated
@@ -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'}
|
||||
|
||||
@@ -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
14
src/utils/appSign.ts
Normal 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)
|
||||
}
|
||||
@@ -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))
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user