Skip to content

Commit 9d5d9de

Browse files
committed
optimize: risk control, add bili_ticket
1 parent 4fab65c commit 9d5d9de

File tree

5 files changed

+111
-17
lines changed

5 files changed

+111
-17
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 2.0.4
2+
* 优化B站风控相关,新增bili_tiket参数
23
* fix Repeated Instantiation Puppeteer
34
* 优化获取B站登录ck
45
* 添加截图列队,优化配置文件注释

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "yz-yuki-plugin",
3-
"version": "2.0.4-3",
3+
"version": "2.0.4-4",
44
"description": "优纪插件,yunzaijs 关于 微博推送、B站推送 等功能的拓展插件",
55
"author": "snowtafir",
66
"type": "module",

src/models/bilibili/bilibili.get.web.data.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import axios from "axios";
22
import lodash from "lodash";
33
import { BiliApi } from '@/models/bilibili//bilibili.api';
4-
import { readSavedCookieItems, readSavedCookieOtherItems, readSyncCookie } from '@/models/bilibili/bilibili.models';
4+
import { cookieWithBiliTicket, readSavedCookieItems, readSavedCookieOtherItems, readSyncCookie } from '@/models/bilibili/bilibili.models';
55
import { getWbiSign } from '@/models/bilibili//bilibili.wbi';
66

77
export class BiliGetWebData {
@@ -12,6 +12,7 @@ export class BiliGetWebData {
1212
async getBiliDynamicListDataByUid(uid: any) {
1313
const url = BiliApi.BILIBIL_API.biliDynamicInfoList;
1414
let { cookie } = await readSyncCookie();
15+
cookie = await cookieWithBiliTicket(cookie);
1516

1617
const data = {
1718
offset: '',
@@ -43,6 +44,7 @@ export class BiliGetWebData {
4344
async getBilibiUserInfoByUid(uid: any) {
4445
const url = BiliApi.BILIBIL_API.biliSpaceUserInfoWbi;
4546
let { cookie } = await readSyncCookie();
47+
cookie = await cookieWithBiliTicket(cookie);
4648

4749
const data = {
4850
mid: uid,
@@ -67,6 +69,7 @@ export class BiliGetWebData {
6769
async searchBiliUserInfoByKeyword(keyword: string) {
6870
const url = BiliApi.BILIBIL_API.biliSearchUpWbi;
6971
let { cookie } = await readSyncCookie();
72+
cookie = await cookieWithBiliTicket(cookie);
7073

7174
const data = {
7275
keyword: keyword,

src/models/bilibili/bilibili.models.ts

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { _paths } from '@/utils/paths';
1313
import { ScreenshotOptions } from '@/utils/puppeteer.render';
1414
import { BiliApi } from '@/models/bilibili/bilibili.api';
1515
import { gen_buvid_fp } from '@/models/bilibili/bilibili.buid.fp';
16+
import { getBiliTicket } from '@/models/bilibili/bilibili.ticket';
1617

1718
declare const logger: any;
1819

@@ -427,11 +428,11 @@ export async function getNewTempCk() {
427428

428429
const result = await postGateway(newTempCk);
429430

430-
const { code, data } = await result.data; // 解析校验结果
431+
const data = await result.data; // 解析校验结果
431432

432-
if (code !== 0) {
433-
logger?.mark(`优纪插件:tempCK,Gateway校验失败:${JSON.stringify(data)}`);
434-
} else if (code === 0) {
433+
if (data?.code !== 0) {
434+
logger?.error(`优纪插件:tempCK,Gateway校验失败:${JSON.stringify(data)}`);
435+
} else if (data?.code === 0) {
435436
logger?.mark(`优纪插件:tempCK,Gateway校验成功:${JSON.stringify(data)}`);
436437
}
437438
}
@@ -594,21 +595,22 @@ async function getPayload(cookie: string) {
594595
* @returns 返回POST请求的结果
595596
*/
596597
export async function postGateway(cookie: string) {
597-
const payload = getPayload(cookie);
598+
const data = { payload: await getPayload(cookie) };
598599
const requestUrl = 'https://api.bilibili.com/x/internal/gaia-gateway/ExClimbWuzhi';
599600

600-
const headers = lodash.merge({}, BiliApi.BILIBILI_HEADERS, {
601-
'Cookie': cookie,
602-
'Content-type': 'Application/json',
603-
'Charset': 'UTF-8',
604-
}, {
605-
'Host': 'api.bilibili.com',
606-
'Origin': 'https://www.bilibili.com',
607-
'Referer': 'https://www.bilibili.com/',
608-
});
601+
const config = {
602+
headers: lodash.merge({}, BiliApi.BILIBILI_HEADERS, {
603+
'Cookie': cookie,
604+
'Content-type': 'application/json;charset=UTF-8',
605+
}, {
606+
'Host': 'api.bilibili.com',
607+
'Origin': 'https://www.bilibili.com',
608+
'Referer': 'https://www.bilibili.com/',
609+
})
610+
}
609611

610612
try {
611-
const res = await axios.post(requestUrl, { payload }, { headers });
613+
const res = await axios.post(requestUrl, data, config);
612614
return res;
613615
} catch (error) {
614616
logger.error('Error making POST request:', error);
@@ -625,3 +627,27 @@ export async function get_buvid_fp(cookie: string) {
625627
let buvidFp = gen_buvid_fp(uuid, seedget);
626628
return `buvid_fp=${buvidFp};`;
627629
}
630+
631+
/**
632+
* 获取有效bili_ticket并添加到cookie
633+
* @param {string} cookie
634+
* @returns {Promise<{ cookie: string; }>} 返回包含最新有效的bili_ticket的cookie
635+
*/
636+
export async function cookieWithBiliTicket(cookie: string): Promise<string> {
637+
const BiliJctKey = "Yz:yuki:bili:bili_ticket"
638+
cookie = await readSavedCookieItems(cookie, ['bili_ticket'], true);
639+
const biliTicket = await Redis.get(BiliJctKey);
640+
if (!biliTicket) {
641+
try {
642+
const csrf = await readSavedCookieItems(cookie, ['bili_jct'], false);
643+
const { ticket, ttl } = await getBiliTicket(csrf);
644+
await Redis.set(BiliJctKey, ticket, { EX: ttl });
645+
return cookie + `;bili_ticket=${ticket};`;
646+
} catch (error) {
647+
logger?.error(`${error}`);
648+
return cookie;
649+
}
650+
} else {
651+
return cookie + `;bili_ticket=${biliTicket};`;
652+
}
653+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { createHmac } from 'crypto';
2+
import { BiliApi } from '@/models/bilibili/bilibili.api';
3+
4+
/**
5+
* Generate HMAC-SHA256 signature
6+
* @param {string} key The key string to use for the HMAC-SHA256 hash
7+
* @param {string} message The message string to hash
8+
* @returns {string} The HMAC-SHA256 signature as a hex string
9+
*/
10+
function hmacSha256(key: string, message: string): string {
11+
return createHmac('sha256', key).update(message).digest('hex');
12+
}
13+
14+
/**
15+
* Get Bilibili web ticket
16+
* @param {string | null} csrf CSRF token, can be empty or null, or the cookie's bili_jct value
17+
* @returns {Promise<{ code: number, ticket: string, created_at: number, ttl: number }>}
18+
* Promise that resolves to an object containing code, ticket, created_at, and ttl values
19+
*/
20+
export async function getBiliTicket(csrf: string | null): Promise<{ code?: number; ticket?: string; created_at?: number; ttl?: number }> {
21+
const ts = Math.floor(Date.now() / 1000);
22+
const hexSign = hmacSha256('XgwSnGZ1p', `ts${ts}`);
23+
const url = 'https://api.bilibili.com/bapis/bilibili.api.ticket.v1.Ticket/GenWebTicket';
24+
25+
const params = new URLSearchParams({
26+
key_id: 'ec02',
27+
hexsign: hexSign,
28+
'context[ts]': String(ts),
29+
csrf: csrf ?? '' // 使用空字符串代替null
30+
});
31+
32+
try {
33+
const response = await fetch(`${url}?${params}`, {
34+
method: 'POST',
35+
headers: {
36+
'User-Agent': BiliApi.BILIBILI_HEADERS['User-Agent']
37+
}
38+
});
39+
40+
if (!response.ok) {
41+
throw new Error(`get bili_jct HTTP error! status: ${response.status}`);
42+
}
43+
44+
const data = await response.json();
45+
46+
if (data.code !== 0) {
47+
if (data.code === 400) {
48+
throw new Error(`get bili_jct Parameter error! ${data.message}`);
49+
}
50+
throw new Error(`Failed to retrieve bili ticket: ${data.message}`);
51+
}
52+
53+
// 返回所需的对象结构
54+
return {
55+
code: data.code,
56+
ticket: data.data?.ticket,
57+
created_at: data.data?.created_at,
58+
ttl: data.data?.ttl
59+
};
60+
61+
} catch (error) {
62+
throw new Error(`Failed to fetch Bilibili ticket: ${error instanceof Error ? error.message : String(error)}`);
63+
}
64+
}

0 commit comments

Comments
 (0)