Files
PiliPlus/lib/utils/wbi_sign.dart
My-Responsitories 37fb63c3b1 tweaks (#1252)
* opt: cache

* opt: MediaListPanel

* feat: nested replyreply panel

* tweaks

* opt: abstract class

* opt: PageStorageKey

* opt: contextExt

* opt: EpisodePanel

* opt

* opt: context instead GlobalKey

* feat: jump to reply

* refa: reply_reply

* fix: jump

* fix: index

* update

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>

* opt: keepalive

* reapply: nested replyreply

* mod: spacing

* opt: CommonSlidePageState

* fix drag bottomsheet

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>

* opt reply jump

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>

* opt reply2reply

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>

* tweaks

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>

* tweaks

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>

* reapply: jumpToReply

* fix: padding

* fix: anim

* fix some panels

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>

* opt: implements Scaffold

* opt: remove keepalive

* revert: GlobalKey

* tweaks

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>

---------

Co-authored-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-09-15 18:45:28 +08:00

116 lines
2.9 KiB
Dart

// Wbi签名 用于生成 REST API 请求中的 w_rid 和 wts 字段
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/misc/sign/wbi.md
// import md5 from 'md5'
// import axios from 'axios'
import 'dart:convert';
import 'package:PiliPlus/http/api.dart';
import 'package:PiliPlus/http/init.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/storage_key.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:crypto/crypto.dart';
import 'package:hive/hive.dart';
import 'package:synchronized/synchronized.dart';
abstract class WbiSign {
static Box localCache = GStorage.localCache;
static final Lock lock = Lock();
static final RegExp chrFilter = RegExp(r"[!\'\(\)\*]");
static const mixinKeyEncTab = <int>[
46,
47,
18,
2,
53,
8,
23,
32,
15,
50,
10,
31,
58,
3,
45,
35,
27,
43,
5,
49,
33,
9,
42,
19,
29,
28,
14,
39,
12,
38,
41,
13,
];
// 对 imgKey 和 subKey 进行字符顺序打乱编码
static String getMixinKey(String orig) {
return mixinKeyEncTab.map((i) => orig[i]).join();
}
// 为请求参数进行 wbi 签名
static void encWbi(Map<String, dynamic> params, String mixinKey) {
params['wts'] = DateTime.now().millisecondsSinceEpoch ~/ 1000;
// 按照 key 重排参数
final List<String> keys = params.keys.toList()..sort();
final queryStr = keys
.map(
(i) =>
'${Uri.encodeComponent(i)}=${Uri.encodeComponent(params[i].toString().replaceAll(chrFilter, ''))}',
)
.join('&');
params['w_rid'] = md5
.convert(utf8.encode(queryStr + mixinKey))
.toString(); // 计算 w_rid
}
// 获取最新的 img_key 和 sub_key 可以从缓存中获取
static Future<String> getWbiKeys() async {
final DateTime nowDate = DateTime.now();
String? mixinKey = localCache.get(LocalCacheKey.mixinKey);
if (mixinKey != null &&
DateTime.fromMillisecondsSinceEpoch(
localCache.get(LocalCacheKey.timeStamp) as int,
).day ==
nowDate.day) {
return mixinKey;
}
final resp = await Request().get(Api.userInfo);
try {
final wbiUrls = resp.data['data']['wbi_img'];
mixinKey = getMixinKey(
Utils.getFileName(wbiUrls['img_url'], fileExt: false) +
Utils.getFileName(wbiUrls['sub_url'], fileExt: false),
);
localCache
..put(LocalCacheKey.mixinKey, mixinKey)
..put(LocalCacheKey.timeStamp, nowDate.millisecondsSinceEpoch);
return mixinKey;
} catch (_) {
return '';
}
}
static Future<Map<String, dynamic>> makSign(
Map<String, dynamic> params,
) async {
// params 为需要加密的请求参数
final String mixinKey = await lock.synchronized(getWbiKeys);
encWbi(params, mixinKey);
return params;
}
}