yz-yuki-plugin 2.0.5-9 → 2.0.6-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,12 +6,12 @@ import { promisify } from 'node:util';
6
6
  import path from 'path';
7
7
  import QRCode from 'qrcode';
8
8
  import YAML from 'yaml';
9
- import { Segment, Bot, Redis } from 'yunzaijs';
9
+ import { Segment, Redis } from 'yunzaijs';
10
10
  import { renderPage } from '../../utils/image.js';
11
11
  import { _paths } from '../../utils/paths.js';
12
- import { BiliApi } from './bilibili.api.js';
13
- import { gen_buvid_fp } from './bilibili.buid.fp.js';
14
- import { getBiliTicket } from './bilibili.ticket.js';
12
+ import BiliApi from './bilibili.main.api.js';
13
+ import { gen_buvid_fp } from './bilibili.risk.buid.fp.js';
14
+ import { getBiliTicket } from './bilibili.risk.ticket.js';
15
15
 
16
16
  /**
17
17
  * *******************************************************************
@@ -29,10 +29,10 @@ async function applyLoginQRCode(e) {
29
29
  if (!response.ok) {
30
30
  throw new Error(`获取B站登录二维码URL网络请求失败,状态码: ${response.status}`);
31
31
  }
32
- const res = await response.json();
32
+ const res = (await response.json());
33
33
  if (res?.code === 0) {
34
- const qrcodeKey = res.data.qrcode_key;
35
- const qrcodeUrl = res.data.url;
34
+ const qrcodeKey = res?.data?.qrcode_key;
35
+ const qrcodeUrl = res?.data?.url;
36
36
  let loginUrlQrcodeData = await QRCode.toDataURL(`${qrcodeUrl}`);
37
37
  const LoginPropsData = {
38
38
  data: { url: loginUrlQrcodeData }
@@ -61,8 +61,8 @@ async function applyLoginQRCode(e) {
61
61
  return qrcodeKey;
62
62
  }
63
63
  else {
64
- e.reply(`获取B站登录二维码失败: ${res.data?.message}`);
65
- throw new Error(`获取B站登录二维码失败: ${res.data?.message}`);
64
+ e.reply(`获取B站登录二维码失败: ${JSON.stringify(res.data)}`);
65
+ throw new Error(`获取B站登录二维码失败: ${JSON.stringify(res.data)}`);
66
66
  }
67
67
  }
68
68
  /**处理扫码结果 */
@@ -76,28 +76,37 @@ async function pollLoginQRCode(e, qrcodeKey) {
76
76
  if (!response.ok) {
77
77
  throw new Error(`处理B站登录token网络请求失败,状态码: ${response.status}`);
78
78
  }
79
- const data = await response.json();
79
+ const data = (await response.json());
80
80
  if (data.code === 0) {
81
- if (data.data.code === 0) {
81
+ if (data?.data?.code === 0) {
82
82
  // 登录成功,获取 cookie
83
83
  const LoginCookie = response.headers.get('set-cookie');
84
+ let loginCk = '';
85
+ try {
86
+ const nomalCk = await getNewTempCk();
87
+ loginCk = `${nomalCk}${LoginCookie}`;
88
+ }
89
+ catch (error) {
90
+ loginCk = LoginCookie;
91
+ logger.debug(`优纪插件: 获取B站登录ck缺失部分: ${error}`);
92
+ }
84
93
  e.reply(`~B站登陆成功~`);
85
- return LoginCookie;
94
+ return loginCk;
86
95
  }
87
- else if (data.data.code === 86101) {
96
+ else if (data?.data?.code === 86101) {
88
97
  // 未扫码
89
98
  // 继续轮询
90
99
  await new Promise(resolve => setTimeout(resolve, 2000));
91
- (logger ?? Bot.logger)?.mark(`优纪插件:扫码B站登录:未扫码,轮询中...`);
100
+ global?.logger?.mark(`优纪插件:扫码B站登录:未扫码,轮询中...`);
92
101
  return pollLoginQRCode(e, qrcodeKey);
93
102
  }
94
- else if (data.data.code === 86090) {
103
+ else if (data?.data?.code === 86090) {
95
104
  // 已扫码未确认
96
105
  // 继续轮询
97
106
  await new Promise(resolve => setTimeout(resolve, 2000));
98
107
  return pollLoginQRCode(e, qrcodeKey);
99
108
  }
100
- else if (data.data.code === 86038) {
109
+ else if (data?.data?.code === 86038) {
101
110
  // 二维码已失效
102
111
  e.reply('B站登陆二维码已失效');
103
112
  return null;
@@ -115,26 +124,33 @@ async function pollLoginQRCode(e, qrcodeKey) {
115
124
  /**查看app扫码登陆获取的ck的有效状态*/
116
125
  async function checkBiliLogin(e) {
117
126
  const LoginCookie = await readLoginCookie();
118
- const res = await fetch('https://api.bilibili.com/x/web-interface/nav', {
119
- method: 'GET',
120
- headers: lodash.merge(BiliApi.BIlIBILI_LOGIN_HEADERS, { 'User-agent': BiliApi.BILIBILI_HEADERS['User-Agent'] }, { Cookie: `${LoginCookie}` }),
121
- redirect: 'follow'
122
- });
123
- const resData = await res.json();
124
- Bot.logger?.debug(`B站验证登录状态:${JSON.stringify(resData)}`);
125
- if (resData.code === 0) {
126
- let uname = resData.data?.uname;
127
- let mid = resData.data?.mid;
128
- let money = resData.data?.money;
129
- let level_info = resData.data?.level_info;
130
- let current_level = level_info?.current_level;
131
- let current_exp = level_info?.current_exp;
132
- let next_exp = level_info?.next_exp;
133
- e.reply(`~B站账号已登陆~\n昵称:${uname}\nuid:${mid}\n硬币:${money}\n经验等级:${current_level}\n当前经验值exp:${current_exp}\n下一等级所需exp:${next_exp}`);
127
+ if (String(LoginCookie).trim().length < 10) {
128
+ e.reply('啊咧?B站登录CK呢?哦,没 #扫码B站登录# 或失效了啊,那没事了。');
129
+ return;
134
130
  }
135
131
  else {
136
- // 处理其他情况
137
- return;
132
+ const res = await fetch('https://api.bilibili.com/x/web-interface/nav', {
133
+ method: 'GET',
134
+ headers: lodash.merge(BiliApi.BIlIBILI_LOGIN_HEADERS, { 'User-agent': BiliApi.BILIBILI_HEADERS['User-Agent'] }, { Cookie: `${LoginCookie}` }),
135
+ redirect: 'follow'
136
+ });
137
+ const resData = await res.json();
138
+ global?.logger?.debug(`B站验证登录状态:${JSON.stringify(resData)}`);
139
+ if (resData.code === 0) {
140
+ let uname = resData.data?.uname;
141
+ let mid = resData.data?.mid;
142
+ let money = resData.data?.money;
143
+ let level_info = resData.data?.level_info;
144
+ let current_level = level_info?.current_level;
145
+ let current_exp = level_info?.current_exp;
146
+ let next_exp = level_info?.next_exp;
147
+ e.reply(`~B站账号已登陆~\n昵称:${uname}\nuid:${mid}\n硬币:${money}\n经验等级:${current_level}\n当前经验值exp:${current_exp}\n下一等级所需exp:${next_exp}`);
148
+ }
149
+ else {
150
+ // 处理其他情况
151
+ e.reply('意外情况,未能成功获取登录ck的有效状态');
152
+ return;
153
+ }
138
154
  }
139
155
  }
140
156
  /**退出B站账号登录,将会删除redis缓存的LoginCK,并在服务器注销该登录 Token (SESSDATA)*/
@@ -245,7 +261,22 @@ async function saveLocalBiliCk(data) {
245
261
  async function readTempCk() {
246
262
  const CK_KEY = 'Yz:yuki:bili:tempCookie';
247
263
  const tempCk = await Redis.get(CK_KEY);
248
- return tempCk ?? '';
264
+ if (!tempCk) {
265
+ const newTempCk = await getNewTempCk();
266
+ await saveTempCk(newTempCk);
267
+ const result = await postGateway(newTempCk);
268
+ const data = await result.data; // 解析校验结果
269
+ if (data?.code !== 0) {
270
+ logger?.error(`优纪插件:tempCK,Gateway校验失败:${JSON.stringify(data)}`);
271
+ }
272
+ else if (data?.code === 0) {
273
+ logger?.mark(`优纪插件:tempCK,Gateway校验成功:${JSON.stringify(data)}`);
274
+ }
275
+ return newTempCk;
276
+ }
277
+ else {
278
+ return tempCk;
279
+ }
249
280
  }
250
281
  /**保存tempCK*/
251
282
  async function saveTempCk(newTempCk) {
@@ -362,231 +393,26 @@ async function getBuvid3_4(uuid) {
362
393
  /**获取新的tempCK*/
363
394
  async function getNewTempCk() {
364
395
  const uuid = await genUUID();
396
+ const b_nut = `b_nut=${Date.now() / 1000};`;
365
397
  const buvid3_buvid4 = await getBuvid3_4(uuid);
366
398
  const b_lsid = await gen_b_lsid();
367
- //const buvid_fp = await get_buvid_fp(uuid);
368
- let newTempCk = `${uuid}${buvid3_buvid4}${b_lsid}`; //${buvid_fp}`;
369
- await saveTempCk(newTempCk);
370
- const result = await postGateway(newTempCk);
371
- const data = await result.data; // 解析校验结果
372
- if (data?.code !== 0) {
373
- logger?.error(`优纪插件:tempCK,Gateway校验失败:${JSON.stringify(data)}`);
374
- }
375
- else if (data?.code === 0) {
376
- logger?.mark(`优纪插件:tempCK,Gateway校验成功:${JSON.stringify(data)}`);
377
- }
399
+ const buvid_fp = await get_buvid_fp(uuid);
400
+ return `${uuid}${buvid3_buvid4}${b_lsid}${buvid_fp}${b_nut}`;
378
401
  }
379
402
  /**
380
403
  * *******************************************************************
381
404
  * 风控相关函数
382
405
  * *******************************************************************
383
406
  */
384
- /**获取GatWay payload */
385
- async function getPayload(cookie) {
386
- const payloadOriginData = {
387
- '3064': 1, // ptype, mobile => 2, others => 1
388
- '5062': `${Date.now()}`, // timestamp
389
- '03bf': 'https://www.bilibili.com/', // url accessed
390
- '39c8': '333.999.fp.risk',
391
- '34f1': '', // target_url, default empty now
392
- 'd402': '', // screenx, default empty
393
- '654a': '', // screeny, default empty
394
- '6e7c': '878x1066', // browser_resolution, window.innerWidth || document.body && document.body.clientWidth + "x" + window.innerHeight || document.body && document.body.clientHeight
395
- '3c43': {
396
- // 3c43 => msg
397
- '2673': 0, // hasLiedResolution, window.screen.width < window.screen.availWidth || window.screen.height < window.screen.availHeight
398
- '5766': 24, // colorDepth, window.screen.colorDepth
399
- '6527': 0, // addBehavior, !!window.HTMLElement.prototype.addBehavior, html5 api
400
- '7003': 1, // indexedDb, !!window.indexedDB, html5 api
401
- '807e': 1, // cookieEnabled, navigator.cookieEnabled
402
- 'b8ce': BiliApi.BILIBILI_HEADERS['User-Agent'], // ua "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:127.0) Gecko/20100101 Firefox/127.0",
403
- '641c': 0, // webdriver, navigator.webdriver, like Selenium
404
- '07a4': 'zh-CN', // language
405
- '1c57': 'not available', // deviceMemory in GB, navigator.deviceMemory
406
- '0bd0': 16, // hardwareConcurrency, navigator.hardwareConcurrency
407
- '748e': [1920, 1200], // window.screen.width window.screen.height
408
- 'd61f': [1920, 1152], // window.screen.availWidth window.screen.availHeight
409
- 'fc9d': -480, // timezoneOffset, (new Date).getTimezoneOffset()
410
- '6aa9': 'Asia/Shanghai', //Intl.DateTimeFormat().resolvedOptions().timeZone, // timezone, (new window.Intl.DateTimeFormat).resolvedOptions().timeZone
411
- '75b8': 1, // sessionStorage, window.sessionStorage, html5 api
412
- '3b21': 1, // localStorage, window.localStorage, html5 api
413
- '8a1c': 0, // openDatabase, window.openDatabase, html5 api
414
- 'd52f': 'not available', // cpuClass, navigator.cpuClass
415
- 'adca': BiliApi.BILIBILI_HEADERS['User-Agent'].includes('Windows') ? 'Win32' : 'Linux', // platform, navigator.platform
416
- '80c9': [
417
- [
418
- 'PDF Viewer',
419
- 'Portable Document Format',
420
- [
421
- ['application/pdf', 'pdf'],
422
- ['text/pdf', 'pdf']
423
- ]
424
- ],
425
- [
426
- 'Chrome PDF Viewer',
427
- 'Portable Document Format',
428
- [
429
- ['application/pdf', 'pdf'],
430
- ['text/pdf', 'pdf']
431
- ]
432
- ],
433
- [
434
- 'Chromium PDF Viewer',
435
- 'Portable Document Format',
436
- [
437
- ['application/pdf', 'pdf'],
438
- ['text/pdf', 'pdf']
439
- ]
440
- ],
441
- [
442
- 'Microsoft Edge PDF Viewer',
443
- 'Portable Document Format',
444
- [
445
- ['application/pdf', 'pdf'],
446
- ['text/pdf', 'pdf']
447
- ]
448
- ],
449
- [
450
- 'WebKit built-in PDF',
451
- 'Portable Document Format',
452
- [
453
- ['application/pdf', 'pdf'],
454
- ['text/pdf', 'pdf']
455
- ]
456
- ]
457
- ], // plugins
458
- '13ab': 'f3YAAAAASUVORK5CYII=', // canvas fingerprint
459
- 'bfe9': 'kABYpRAGAVYzWJooB9Bf4P+UortSvxRY0AAAAASUVORK5CYII=', // webgl_str
460
- 'a3c1': [
461
- 'extensions:ANGLE_instanced_arrays;EXT_blend_minmax;EXT_color_buffer_half_float;EXT_float_blend;EXT_frag_depth;EXT_shader_texture_lod;EXT_sRGB;EXT_texture_compression_bptc;EXT_texture_compression_rgtc;EXT_texture_filter_anisotropic;OES_element_index_uint;OES_fbo_render_mipmap;OES_standard_derivatives;OES_texture_float;OES_texture_float_linear;OES_texture_half_float;OES_texture_half_float_linear;OES_vertex_array_object;WEBGL_color_buffer_float;WEBGL_compressed_texture_s3tc;WEBGL_compressed_texture_s3tc_srgb;WEBGL_debug_renderer_info;WEBGL_debug_shaders;WEBGL_depth_texture;WEBGL_draw_buffers;WEBGL_lose_context;WEBGL_provoking_vertex',
462
- 'webgl aliased line width range:[1, 1]',
463
- 'webgl aliased point size range:[1, 1024]',
464
- 'webgl alpha bits:8',
465
- 'webgl antialiasing:yes',
466
- 'webgl blue bits:8',
467
- 'webgl depth bits:24',
468
- 'webgl green bits:8',
469
- 'webgl max anisotropy:16',
470
- 'webgl max combined texture image units:32',
471
- 'webgl max cube map texture size:16384',
472
- 'webgl max fragment uniform vectors:1024',
473
- 'webgl max render buffer size:16384',
474
- 'webgl max texture image units:16',
475
- 'webgl max texture size:16384',
476
- 'webgl max varying vectors:30',
477
- 'webgl max vertex attribs:16',
478
- 'webgl max vertex texture image units:16',
479
- 'webgl max vertex uniform vectors:4096',
480
- 'webgl max viewport dims:[32767, 32767]',
481
- 'webgl red bits:8',
482
- 'webgl renderer:ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar',
483
- 'webgl shading language version:WebGL GLSL ES 1.0',
484
- 'webgl stencil bits:0',
485
- 'webgl vendor:Mozilla',
486
- 'webgl version:WebGL 1.0',
487
- 'webgl unmasked vendor:Google Inc. (Intel)',
488
- 'webgl unmasked renderer:ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar',
489
- 'webgl vertex shader high float precision:23',
490
- 'webgl vertex shader high float precision rangeMin:127',
491
- 'webgl vertex shader high float precision rangeMax:127',
492
- 'webgl vertex shader medium float precision:23',
493
- 'webgl vertex shader medium float precision rangeMin:127',
494
- 'webgl vertex shader medium float precision rangeMax:127',
495
- 'webgl vertex shader low float precision:23',
496
- 'webgl vertex shader low float precision rangeMin:127',
497
- 'webgl vertex shader low float precision rangeMax:127',
498
- 'webgl fragment shader high float precision:23',
499
- 'webgl fragment shader high float precision rangeMin:127',
500
- 'webgl fragment shader high float precision rangeMax:127',
501
- 'webgl fragment shader medium float precision:23',
502
- 'webgl fragment shader medium float precision rangeMin:127',
503
- 'webgl fragment shader medium float precision rangeMax:127',
504
- 'webgl fragment shader low float precision:23',
505
- 'webgl fragment shader low float precision rangeMin:127',
506
- 'webgl fragment shader low float precision rangeMax:127',
507
- 'webgl vertex shader high int precision:0',
508
- 'webgl vertex shader high int precision rangeMin:31',
509
- 'webgl vertex shader high int precision rangeMax:30',
510
- 'webgl vertex shader medium int precision:0',
511
- 'webgl vertex shader medium int precision rangeMin:31',
512
- 'webgl vertex shader medium int precision rangeMax:30',
513
- 'webgl vertex shader low int precision:0',
514
- 'webgl vertex shader low int precision rangeMin:31',
515
- 'webgl vertex shader low int precision rangeMax:30',
516
- 'webgl fragment shader high int precision:0',
517
- 'webgl fragment shader high int precision rangeMin:31',
518
- 'webgl fragment shader high int precision rangeMax:30',
519
- 'webgl fragment shader medium int precision:0',
520
- 'webgl fragment shader medium int precision rangeMin:31',
521
- 'webgl fragment shader medium int precision rangeMax:30',
522
- 'webgl fragment shader low int precision:0',
523
- 'webgl fragment shader low int precision rangeMin:31',
524
- 'webgl fragment shader low int precision rangeMax:30'
525
- ], // webgl_params, cab be set to [] if webgl is not supported
526
- '6bc5': 'Google Inc. (Intel)~ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar', // webglVendorAndRenderer
527
- 'ed31': 0,
528
- '72bd': 0,
529
- '097b': 0,
530
- '52cd': [0, 0, 0],
531
- 'a658': [
532
- 'Arial',
533
- 'Arial Black',
534
- 'Calibri',
535
- 'Cambria',
536
- 'Cambria Math',
537
- 'Comic Sans MS',
538
- 'Consolas',
539
- 'Courier',
540
- 'Courier New',
541
- 'Georgia',
542
- 'Helvetica',
543
- 'Impact',
544
- 'Lucida Console',
545
- 'Lucida Sans Unicode',
546
- 'Microsoft Sans Serif',
547
- 'MS Gothic',
548
- 'MS PGothic',
549
- 'MS Sans Serif',
550
- 'MS Serif',
551
- 'Palatino Linotype',
552
- 'Segoe Print',
553
- 'Segoe Script',
554
- 'Segoe UI',
555
- 'Segoe UI Light',
556
- 'Segoe UI Symbol',
557
- 'Tahoma',
558
- 'Times',
559
- 'Times New Roman',
560
- 'Trebuchet MS',
561
- 'Verdana',
562
- 'Wingdings'
563
- ],
564
- 'd02f': '35.749972093850374'
565
- },
566
- '54ef': {
567
- 'in_new_ab ': true,
568
- 'ab_version ': {
569
- 'waterfall_article ': 'SHOW '
570
- },
571
- 'ab_split_num ': {
572
- 'waterfall_article ': 0
573
- }
574
- },
575
- '8b94': '',
576
- 'df35': `${await readSavedCookieItems(cookie, ['_uuid'], false)}`, // _uuid, set from cookie, generated by client side(algorithm remains unknown)
577
- '07a4': 'zh-CN',
578
- '5f45': null,
579
- 'db46': 0
580
- };
581
- return JSON.stringify(payloadOriginData);
582
- }
583
407
  /**
584
408
  * 请求参数POST接口(ExClimbWuzhi)过校验
585
409
  * @param cookie 请求所需的cookie
586
410
  * @returns 返回POST请求的结果
587
411
  */
588
412
  async function postGateway(cookie) {
589
- const data = { payload: await getPayload(cookie) };
413
+ const _uuid = await readSavedCookieItems(cookie, ['_uuid'], false);
414
+ const payloadJsonData = await BiliApi.BILIBILI_BROWSER_DATA(_uuid);
415
+ const data = { payload: JSON.stringify(payloadJsonData) };
590
416
  const requestUrl = 'https://api.bilibili.com/x/internal/gaia-gateway/ExClimbWuzhi';
591
417
  const config = {
592
418
  headers: lodash.merge({}, BiliApi.BILIBILI_HEADERS, {
@@ -612,8 +438,8 @@ async function postGateway(cookie) {
612
438
  */
613
439
  async function get_buvid_fp(cookie) {
614
440
  const uuid = await readSavedCookieItems(cookie, ['_uuid'], false);
615
- const seedget = Math.floor(Math.random() * (60 - 1 + 1) + 1);
616
- let buvidFp = gen_buvid_fp(uuid, seedget);
441
+ const fingerprintData = BiliApi.BILIBILI_FINGERPRINT_DATA(uuid);
442
+ const buvidFp = gen_buvid_fp(fingerprintData);
617
443
  return `buvid_fp=${buvidFp};`;
618
444
  }
619
445
  /**
@@ -629,8 +455,13 @@ async function cookieWithBiliTicket(cookie) {
629
455
  try {
630
456
  const csrf = await readSavedCookieItems(cookie, ['bili_jct'], false);
631
457
  const { ticket, ttl } = await getBiliTicket(csrf);
632
- await Redis.set(BiliJctKey, ticket, { EX: ttl });
633
- return cookie + `;bili_ticket=${ticket};`;
458
+ if (ticket && ttl) {
459
+ await Redis.set(BiliJctKey, ticket, { EX: ttl });
460
+ return cookie + `;bili_ticket=${ticket};`;
461
+ }
462
+ else {
463
+ return cookie;
464
+ }
634
465
  }
635
466
  catch (error) {
636
467
  logger?.error(`${error}`);