From 7bf13035235661dcf74cd66cdc0003544a29b31a Mon Sep 17 00:00:00 2001 From: Howard Wu Date: Wed, 3 Jan 2024 21:31:51 +0800 Subject: [PATCH] =?UTF-8?q?perf(balh):=20=E6=96=B0=20API=20=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=20access=5Ftoken=20(#1295)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf(balh): 新 API 获取 access_token * perf(balh): access_token 失效时删除 * wip: 整理代码 * chore: biliplus_login -> bilibili_login --------- Co-authored-by: ipcjs --- .../unblock-area-limit/src/api/biliplus.ts | 3 + .../src/feature/bili/area_limit_for_vue.ts | 4 +- .../src/feature/bili/area_limit_xhr_.ts | 8 +- .../src/feature/bili/bilibili_login.ts | 152 ++++++++++++++++++ .../src/feature/bili/biliplus_login.ts | 144 ----------------- .../src/feature/bili/index.ts | 2 +- .../src/feature/bili/settings.ts | 8 +- packages/unblock-area-limit/src/main.ts | 9 +- packages/unblock-area-limit/src/main.user.js | 2 +- packages/unblock-area-limit/src/util/ui.ts | 15 +- 10 files changed, 181 insertions(+), 166 deletions(-) create mode 100644 packages/unblock-area-limit/src/feature/bili/bilibili_login.ts delete mode 100644 packages/unblock-area-limit/src/feature/bili/biliplus_login.ts diff --git a/packages/unblock-area-limit/src/api/biliplus.ts b/packages/unblock-area-limit/src/api/biliplus.ts index bda37692..2a9762fd 100644 --- a/packages/unblock-area-limit/src/api/biliplus.ts +++ b/packages/unblock-area-limit/src/api/biliplus.ts @@ -1,3 +1,4 @@ +import { bilibili_login } from "../feature/bili/bilibili_login"; import { balh_config } from "../feature/config"; import { Async } from "../util/async"; import { Converters, uposMap } from "../util/converters"; @@ -407,6 +408,8 @@ export async function fixThailandPlayUrlJson(originJson: object) { } let origin: OriginResult = JSON.parse(JSON.stringify(originJson)) + if (origin.code === 401) + bilibili_login.clearLoginFlag() interface LooseObject { [key: string]: any } diff --git a/packages/unblock-area-limit/src/feature/bili/area_limit_for_vue.ts b/packages/unblock-area-limit/src/feature/bili/area_limit_for_vue.ts index 35909838..6a4e5d1d 100644 --- a/packages/unblock-area-limit/src/feature/bili/area_limit_for_vue.ts +++ b/packages/unblock-area-limit/src/feature/bili/area_limit_for_vue.ts @@ -12,6 +12,7 @@ import { ifNotNull } from "../../util/utils" import { balh_config, isClosed } from "../config" import { util_page } from "../page" import pageTemplate from './bangumi-play-page-template.html' +import { bilibili_login } from "./bilibili_login" export function modifyGlobalValue( name: string, @@ -117,7 +118,8 @@ async function fixThailandSeason(ep_id: string, season_id: string) { // https://github.com/yujincheng08/BiliRoaming/issues/112 const thailandApi = new BiliBiliApi(balh_config.server_custom_th) const origin = await thailandApi.getSeasonInfoByEpSsIdOnThailand(ep_id, season_id) - + if (origin.code === 401) + bilibili_login.clearLoginFlag() origin.result.actors = origin.result.actor.info origin.result.is_paster_ads = 0 origin.result.jp_title = origin.result.origin_name diff --git a/packages/unblock-area-limit/src/feature/bili/area_limit_xhr_.ts b/packages/unblock-area-limit/src/feature/bili/area_limit_xhr_.ts index 1f184ca6..d9c4af3f 100644 --- a/packages/unblock-area-limit/src/feature/bili/area_limit_xhr_.ts +++ b/packages/unblock-area-limit/src/feature/bili/area_limit_xhr_.ts @@ -16,7 +16,7 @@ import { Strings } from '../../util/strings' import { util_init } from '../../util/initiator' import { util_ui_msg } from '../../util/message' import { RegExps } from '../../util/regexps' -import { biliplus_login } from './biliplus_login'; +import { bilibili_login } from './bilibili_login'; import { injectFetch, injectFetch4Mobile } from '../../feature/bili/area_limit_fetch' import space_account_info_map from '../../feature/bili/space_account_info_map' import * as OpenCC from 'opencc-js' @@ -812,11 +812,11 @@ export const area_limit_xhr = (() => { } else { return Promise.reject(new AjaxException(`服务器错误: ${JSON.stringify(data)}`, data ? data.code : 0)) } - } else if (isAreaLimitForPlayUrl(data)) { + } else if (isAreaLimitForPlayUrl(data) || data.code === 401) { util_error('>>area limit'); ui.pop({ - content: `突破黑洞失败\n需要登录\n点此确定进行登录`, - onConfirm: biliplus_login.showLogin + content: `突破黑洞失败\n${data.message}\n需要登录\n点此确定进行登录`, + onConfirm: bilibili_login.showLogin }) } else { if (balh_config.flv_prefer_ws) { diff --git a/packages/unblock-area-limit/src/feature/bili/bilibili_login.ts b/packages/unblock-area-limit/src/feature/bili/bilibili_login.ts new file mode 100644 index 00000000..a588366e --- /dev/null +++ b/packages/unblock-area-limit/src/feature/bili/bilibili_login.ts @@ -0,0 +1,152 @@ +import { Async } from "../../util/async" +import { Converters } from "../../util/converters" +import { cookieStorage } from "../../util/cookie" +import { util_init } from "../../util/initiator" +import { _ } from "../../util/react" +import { ui } from "../../util/ui" +import { balh_config } from "../config" +import { util_page } from "../page" +import { FALSE, TRUE, r } from "../r" + + +function isLogin() { + return localStorage.access_key && localStorage.oauth_expires_at && Date.now() < +localStorage.oauth_expires_at +} + +function clearLoginFlag() { + // 只要清除过期时间, isLogin()就会返回false + delete localStorage.oauth_expires_at +} + +function showLogout() { + ui.alert('确定取消授权登出?', () => { + // 登出, 则应该清除所有授权相关的字段 + delete localStorage.oauth_expires_at + delete localStorage.access_key + delete localStorage.refresh_token + }) +} + +function isLoginBiliBili() { + return cookieStorage['DedeUserID'] !== undefined +} +// 当前在如下情况才会弹一次登录提示框: +// 1. 第一次使用 +// 2. 主站+服务器都退出登录后, 再重新登录主站 +function checkLoginState() { + // 给一些状态,设置初始值 + localStorage.balh_must_remind_login_v3 === undefined && (localStorage.balh_must_remind_login_v3 = TRUE) + + if (isLoginBiliBili()) { + if (!localStorage.balh_old_isLoginBiliBili // 主站 不登录 => 登录 + || localStorage.balh_pre_server !== balh_config.server // 代理服务器改变了 + || localStorage.balh_must_remind_login_v3) { // 设置了"必须提醒"flag + if (!isLogin()) { + // 保证一定要交互一次, 才不提醒 + localStorage.balh_must_remind_login_v3 = TRUE; + ui.pop({ + content: [ + _('text', `${GM_info.script.name}\n要不要考虑进行一下授权?\n\n授权后可以观看区域限定番剧的1080P\n(如果你是大会员或承包过这部番的话)\n\n你可以随时在设置中打开授权页面`) + ], + onConfirm: () => { + localStorage.balh_must_remind_login_v3 = FALSE; + showLogin(); + document.querySelector('#AHP_Notice')?.remove() + }, + closeBtn: '不再提醒', + onClose: () => { + localStorage.balh_must_remind_login_v3 = FALSE; + } + }) + } + } + } + localStorage.balh_old_isLoginBiliBili = isLoginBiliBili() ? TRUE : FALSE + localStorage.balh_pre_server = balh_config.server +} + +async function showLogin() { + const balh_auth_window = window.open('about:blank')!; + balh_auth_window.document.title = 'BALH - 授权'; + balh_auth_window.document.body.innerHTML = '正在获取授权,请稍候……'; + window.balh_auth_window = balh_auth_window; + + try { + const { sign, params } = Converters.generateSign({ + appkey: '27eb53fc9058f8c3', + local_id: "0", + ts: (Date.now() / 1000).toFixed(0) + }, 'c2ed53a74eeefe3cf99fbd01d8c9c375') + const data1 = await (await fetch('https://passport.bilibili.com/x/passport-tv-login/qrcode/auth_code?' + params + '&sign=' + sign, { + method: 'POST' + })).json() + + if (data1.code === 0 && data1.data.auth_code) { + let authCode = data1.data.auth_code + balh_auth_window.document.body.innerHTML += '
正在确认…… auth_code=' + authCode; + const bili_jct = cookieStorage.get('bili_jct') + const { params } = Converters.generateSign({ + auth_code: authCode, + build: "7082000", + csrf: bili_jct + }, 'c2ed53a74eeefe3cf99fbd01d8c9c375') + const data2 = await (await fetch(('https://passport.bilibili.com/x/passport-tv-login/h5/qrcode/confirm?' + params), { + method: 'POST', + credentials: 'include', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + } + })).json() + + if (data2.code === 0 && data2.message === "0") { + balh_auth_window.document.body.innerHTML += '
授权成功,正在获取token……'; + const { sign, params } = Converters.generateSign({ + appkey: '27eb53fc9058f8c3', + local_id: "0", + auth_code: authCode, + ts: (Date.now() / 1000).toFixed(0) + }, 'c2ed53a74eeefe3cf99fbd01d8c9c375') + const data3 = await (await fetch('https://passport.bilibili.com/x/passport-tv-login/qrcode/poll?' + params + '&sign=' + sign, { + method: "POST", + })).json() + + const access_token = data3.data.token_info.access_token + const oauth_expires_at = (Date.now() / 1000 + data3.data.token_info.expires_in) * 1000 + balh_auth_window.document.body.innerHTML += '
正在保存…… access_token=' + access_token + ', 过期于 ' + new Date(oauth_expires_at).toLocaleString(); + if (data3.code === 0 && data3.message === "0") { + localStorage.access_key = access_token + localStorage.refresh_token = data3.data.token_info.refresh_token + localStorage.oauth_expires_at = oauth_expires_at + balh_auth_window.document.body.innerHTML += '
保存成功!3秒后关闭'; + await Async.timeout(3000) + } + } else { + ui.alert(data2.message, () => { + location.href = 'https://passport.bilibili.com/login' + }) + } + } else { + ui.alert('必须登录B站才能正常授权', () => { + location.href = 'https://passport.bilibili.com/login' + }) + } + } catch (e: any) { + ui.alert(e.message ?? '授权出错') + } finally { + balh_auth_window.close() + } +} + +util_init(() => { + if (!(util_page.player() || util_page.av())) { + checkLoginState() + } +}, util_init.PRIORITY.DEFAULT, util_init.RUN_AT.DOM_LOADED_AFTER) + +export const bilibili_login = { + showLogin, + showLogout, + isLogin, + isLoginBiliBili, + clearLoginFlag, +} diff --git a/packages/unblock-area-limit/src/feature/bili/biliplus_login.ts b/packages/unblock-area-limit/src/feature/bili/biliplus_login.ts deleted file mode 100644 index 16bf68bd..00000000 --- a/packages/unblock-area-limit/src/feature/bili/biliplus_login.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { Async } from "../../util/async" -import { cookieStorage } from "../../util/cookie" -import { util_init } from "../../util/initiator" -import { _ } from "../../util/react" -import { ui } from "../../util/ui" -import { balh_config } from "../config" -import { util_page } from "../page" -import { r } from "../r" - - -function isLogin() { - return localStorage.oauthTime !== undefined -} -function clearLoginFlag() { - delete localStorage.oauthTime -} - -function updateLoginFlag(loadCallback: (success: boolean) => void) { - Async.jsonp(balh_config.server + '/login?act=expiretime') - .then(() => loadCallback && loadCallback(true)) - // .catch(() => loadCallback && loadCallback(false)) // 请求失败不需要回调 -} -function isLoginBiliBili() { - return cookieStorage['DedeUserID'] !== undefined -} -// 当前在如下情况才会弹一次登录提示框: -// 1. 第一次使用 -// 2. 主站+服务器都退出登录后, 再重新登录主站 -function checkLoginState() { - // 给一些状态,设置初始值 - localStorage.balh_must_remind_login_v3 === undefined && (localStorage.balh_must_remind_login_v3 = r.const.TRUE) - - if (isLoginBiliBili()) { - if (!localStorage.balh_old_isLoginBiliBili // 主站 不登录 => 登录 - || localStorage.balh_pre_server !== balh_config.server // 代理服务器改变了 - || localStorage.balh_must_remind_login_v3) { // 设置了"必须提醒"flag - clearLoginFlag() - updateLoginFlag(() => { - if (!isLogin() || !localStorage.access_key) { - localStorage.balh_must_remind_login_v3 = r.const.FALSE; - ui.pop({ - content: [ - _('text', `${GM_info.script.name}\n要不要考虑进行一下授权?\n\n授权后可以观看区域限定番剧的1080P\n(如果你是大会员或承包过这部番的话)\n\n你可以随时在设置中打开授权页面`) - ], - onConfirm: () => { - biliplus_login.showLogin(); - document.querySelector('#AHP_Notice')?.remove() - } - }) - } - }) - } else if ((isLogin() && Date.now() - parseInt(localStorage.oauthTime) > 24 * 60 * 60 * 1000) // 已登录,每天为周期检测key有效期,过期前五天会自动续期 - || localStorage.balh_must_updateLoginFlag) {// 某些情况下,必须更新一次 - updateLoginFlag(() => localStorage.balh_must_updateLoginFlag = r.const.FALSE); - } - } - localStorage.balh_old_isLoginBiliBili = isLoginBiliBili() ? r.const.TRUE : r.const.FALSE - localStorage.balh_pre_server = balh_config.server -} - -function showLogin() { - const balh_auth_window = window.open('about:blank')!; - balh_auth_window.document.title = 'BALH - 授权'; - balh_auth_window.document.body.innerHTML = '正在获取授权,请稍候……'; - window.balh_auth_window = balh_auth_window; - window.$.ajax('https://passport.bilibili.com/login/app/third?appkey=27eb53fc9058f8c3&api=https%3A%2F%2Fwww.mcbbs.net%2Ftemplate%2Fmcbbs%2Fimage%2Fspecial_photo_bg.png&sign=04224646d1fea004e79606d3b038c84a', { - xhrFields: { withCredentials: true }, - type: 'GET', - dataType: 'json', - success: (data: any) => { - if (data.data.has_login) { - balh_auth_window.document.body.innerHTML = '正在跳转……'; - balh_auth_window.location.href = data.data.confirm_uri; - } else { - balh_auth_window.close() - ui.alert('必须登录B站才能正常授权', () => { - location.href = 'https://passport.bilibili.com/login' - }) - } - }, - error: (e: any) => { - alert('error'); - } - }) -} - -function showLoginByPassword() { - const loginUrl = balh_config.server + '/login' - ui.pop({ - content: `B站当前关闭了第三方登录的接口
目前只能使用帐号密码的方式登录代理服务器

登录完成后, 请手动刷新当前页面`, - confirmBtn: '前往登录页面', - onConfirm: () => { - window.open(loginUrl) - } - }) -} - -function showLogout() { - ui.popFrame(balh_config.server + '/login?act=logout') -} - -// 监听登录message -window.addEventListener('message', function (e) { - if (typeof e.data !== 'string') return // 只处理e.data为string的情况 - switch (e.data.split(':')[0]) { - case 'BiliPlus-Login-Success': { - //登入 - localStorage.balh_must_updateLoginFlag = r.const.TRUE - Promise.resolve('start') - .then(() => Async.jsonp(balh_config.server + '/login?act=getlevel')) - .then(() => location.reload()) - .catch(() => location.reload()) - break; - } - case 'BiliPlus-Logout-Success': { - //登出 - clearLoginFlag() - location.reload() - break; - } - case 'balh-login-credentials': { - window.balh_auth_window?.close(); - let url = e.data.split(': ')[1]; - const access_key = new URL(url).searchParams.get('access_key'); - localStorage.access_key = access_key - ui.popFrame(url.replace('https://www.mcbbs.net/template/mcbbs/image/special_photo_bg.png', balh_config.server + '/login')); - break; - } - } -}) - - -util_init(() => { - if (!(util_page.player() || util_page.av())) { - checkLoginState() - } -}, util_init.PRIORITY.DEFAULT, util_init.RUN_AT.DOM_LOADED_AFTER) - -export const biliplus_login = { - showLogin, - showLogout, - isLogin, - isLoginBiliBili, -} diff --git a/packages/unblock-area-limit/src/feature/bili/index.ts b/packages/unblock-area-limit/src/feature/bili/index.ts index 3fa8d2a1..2c078180 100644 --- a/packages/unblock-area-limit/src/feature/bili/index.ts +++ b/packages/unblock-area-limit/src/feature/bili/index.ts @@ -6,7 +6,7 @@ export * from './biliplus_check_area_limit' export * from './fill_season_page' export * from './redirect_to_bangumi_or_insert_player' export * from './area_limit_for_vue' -export * from './biliplus_login' +export * from './bilibili_login' export * from './settings' export * from './remove_pre_ad' export * from './hide_adblock_tips' diff --git a/packages/unblock-area-limit/src/feature/bili/settings.ts b/packages/unblock-area-limit/src/feature/bili/settings.ts index abf98beb..ce7a0c99 100644 --- a/packages/unblock-area-limit/src/feature/bili/settings.ts +++ b/packages/unblock-area-limit/src/feature/bili/settings.ts @@ -6,7 +6,7 @@ import { balh_config } from "../config" import { util_page } from "../page" import { r } from "../r" import { util_ui_msg } from '../../util/message' -import { biliplus_login } from "./biliplus_login" +import { bilibili_login } from "./bilibili_login" import css from './settings.scss' const balh_feature_runPing = function () { @@ -171,10 +171,10 @@ export function settings() { switch ((event.target as any).attributes['data-sign'].value) { default: case 'in': - biliplus_login.showLogin(); + bilibili_login.showLogin(); break; case 'out': - biliplus_login.showLogout(); + bilibili_login.showLogout(); break; } } @@ -390,7 +390,7 @@ export function settings() { ]), _('br'), _('a', { href: 'javascript:', 'data-sign': 'in', event: { click: onSignClick } }, [_('text', '帐号授权')]), _('text', ' '), - _('a', { href: 'javascript:', 'data-sign': 'out', event: { click: onSignClick } }, [_('text', '取消授权')]), + bilibili_login.isLogin() ? _('a', { href: 'javascript:', 'data-sign': 'out', event: { click: onSignClick } }, [_('text', '取消授权')]) : _('span'), _('text', '  '), _('a', { href: 'javascript:', event: { click: function () { util_ui_msg.show(window.$(this), '如果你的帐号进行了付费,不论是大会员还是承包,\n进行授权之后将可以在解除限制时正常享有这些权益\n\n你可以随时在这里授权或取消授权\n\n不进行授权不会影响脚本的正常使用,但可能会缺失1080P', 1e4); } } }, [_('text', '(这是什么?)')]), _('br'), _('br'), diff --git a/packages/unblock-area-limit/src/main.ts b/packages/unblock-area-limit/src/main.ts index feea7e0c..4187592b 100644 --- a/packages/unblock-area-limit/src/main.ts +++ b/packages/unblock-area-limit/src/main.ts @@ -59,15 +59,15 @@ function scriptContent() { 'generate_sub:', balh_config.generate_sub, 'enable_in_av:', balh_config.enable_in_av, 'readyState:', document.readyState, - 'isLogin:', bili.biliplus_login.isLogin(), - 'isLoginBiliBili:', bili.biliplus_login.isLoginBiliBili() + 'isLogin:', bili.bilibili_login.isLogin(), + 'isLoginBiliBili:', bili.bilibili_login.isLoginBiliBili() ) // 暴露接口 window.bangumi_area_limit_hack = { setCookie: cookieStorage.set, getCookie: cookieStorage.get, - login: bili.biliplus_login.showLogin, - logout: bili.biliplus_login.showLogout, + login: bili.bilibili_login.showLogin, + logout: bili.bilibili_login.showLogout, getLog: () => { return logHub.getAllMsg({ [localStorage.access_key]: '{{access_key}}' }) }, @@ -92,7 +92,6 @@ function scriptContent() { delete localStorage.balh_h5_not_first delete localStorage.balh_old_isLoginBiliBili delete localStorage.balh_must_remind_login_v3 - delete localStorage.balh_must_updateLoginFlag } } } diff --git a/packages/unblock-area-limit/src/main.user.js b/packages/unblock-area-limit/src/main.user.js index 0817a7a5..f067e1db 100644 --- a/packages/unblock-area-limit/src/main.user.js +++ b/packages/unblock-area-limit/src/main.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name 解除B站区域限制 // @namespace https://github.com/ipcjs -// @version 8.4.6 +// @version 8.5.0 // @description 通过替换获取视频地址接口的方式, 实现解除B站区域限制; // @author ipcjs // @supportURL https://github.com/ipcjs/bilibili-helper/blob/user.js/packages/unblock-area-limit/README.md diff --git a/packages/unblock-area-limit/src/util/ui.ts b/packages/unblock-area-limit/src/util/ui.ts index 6ec850cb..4e98315c 100644 --- a/packages/unblock-area-limit/src/util/ui.ts +++ b/packages/unblock-area-limit/src/util/ui.ts @@ -38,19 +38,22 @@ export namespace ui { } interface PopParam { + /** 内容元素数组/HTML */ content: any + /** 是否显示确定按钮 */ showConfirm?: boolean + /** 确定按钮的文字 */ confirmBtn?: string + /** 关闭按钮的文字 */ + closeBtn?: string + /** 确定回调 */ onConfirm?: Function + /** 关闭回调 */ onClose?: Function } /** - * - param.content: 内容元素数组/HTML - * - param.showConfirm: 是否显示确定按钮 - * - param.confirmBtn: 确定按钮的文字 - * - param.onConfirm: 确定回调 - * - param.onClose: 关闭回调 + * 确定弹窗 */ export const pop = function (param: PopParam) { if (typeof param.content === 'string') { @@ -75,7 +78,7 @@ export namespace ui { children.push(_('input', { value: param.confirmBtn || _t('ok'), type: 'button', className: 'confirm', event: { click: param.onConfirm } })); } children.push(_('input', { - value: _t('close'), type: 'button', className: 'close', event: { + value: param.closeBtn || _t('close'), type: 'button', className: 'close', event: { click: function () { param.onClose && param.onClose(); div.style.height = '0';