-
Notifications
You must be signed in to change notification settings - Fork 108
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
149 additions
and
150 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,10 +29,11 @@ abstract class AppClient { | |
protected static readonly __secretKey: string = '560c52ccd288fed045859ed18bffd973' | ||
public static readonly appKey: string = '1d8b6e7d45233436' | ||
public static get biliLocalId(): string { return this.RandomID(64) } | ||
public static readonly build: string = '5570300' | ||
public static readonly build: string = '6060300' | ||
public static get buvid(): string { return this.RandomID(37).toLocaleUpperCase() } | ||
public static readonly Clocale: string = 'zh_CN' | ||
public static readonly channel: string = 'bili' | ||
public static readonly device: string = 'phone' | ||
public static readonly device: string = 'android' | ||
// 同一客户端与biliLocalId相同 | ||
public static get deviceId(): string { return this.biliLocalId } | ||
public static readonly deviceName: string = 'SonyJ9110' | ||
|
@@ -41,7 +42,8 @@ abstract class AppClient { | |
public static get localId(): string { return this.buvid } | ||
public static readonly mobiApp: string = 'android' | ||
public static readonly platform: string = 'android' | ||
public static readonly statistics: string = '%7B%22appId%22%3A1%2C%22platform%22%3A3%2C%22version%22%3A%225.57.0%22%2C%22abtest%22%3A%22%22%7D' | ||
public static readonly Slocale: string = 'zh_CN' | ||
public static readonly statistics: string = encodeURIComponent('{"appId":1,"platform":3,"version":"6.6.0","abtest":""}') | ||
|
||
// bilibili 国际版 | ||
// protected static readonly __loginSecretKey: string = 'c75875c596a69eb55bd119e74b07cfe3' | ||
|
@@ -169,11 +171,10 @@ abstract class AppClient { | |
*/ | ||
public static get headers(): IncomingHttpHeaders { | ||
return { | ||
'User-Agent': 'Mozilla/5.0 BiliDroid/5.57.0 ([email protected]) os/android model/J9110 mobi_app/android build/5570300 channel/bili innerVer/5570300 osVer/10 network/2', | ||
'User-Agent': 'Mozilla/5.0 BiliDroid/6.6.0 ([email protected]) os/android model/J9110 mobi_app/android build/6060300 channel/bili innerVer/6060300 osVer/10 network/2', | ||
'APP-KEY': this.mobiApp, | ||
'Buvid': this.buvid, | ||
'Device-ID': this.deviceId, | ||
'Display-ID': `${this.buvid}-${this.TS}`, | ||
'env': 'prod' | ||
} | ||
} | ||
|
@@ -186,8 +187,8 @@ abstract class AppClient { | |
* @memberof AppClient | ||
*/ | ||
public static get baseQuery(): string { | ||
return `actionKey=${this.actionKey}&appkey=${this.appKey}&build=${this.build}&channel=${this.channel}\ | ||
&device=${this.device}&mobi_app=${this.mobiApp}&platform=${this.platform}&statistics=${this.statistics}` | ||
return `actionKey=${this.actionKey}&appkey=${this.appKey}&build=${this.build}&c_locale=${this.Clocale}&channel=${this.channel}\ | ||
&device=${this.device}&mobi_app=${this.mobiApp}&platform=${this.platform}&s_locale=${this.Slocale}&statistics=${this.statistics}` | ||
} | ||
/** | ||
* 登录请求参数 | ||
|
@@ -264,6 +265,7 @@ abstract class AppClient { | |
public appKey: string = AppClient.appKey | ||
public biliLocalId = AppClient.biliLocalId | ||
public build: string = AppClient.build | ||
public Clocale: string = AppClient.Clocale | ||
public buvid = AppClient.buvid | ||
public channel: string = AppClient.channel | ||
public device: string = AppClient.device | ||
|
@@ -273,6 +275,7 @@ abstract class AppClient { | |
public localId: string = this.buvid | ||
public mobiApp: string = AppClient.mobiApp | ||
public platform: string = AppClient.platform | ||
public Slocale: string = AppClient.Slocale | ||
public statistics: string = AppClient.statistics | ||
/** | ||
* 请求头 | ||
|
@@ -281,11 +284,10 @@ abstract class AppClient { | |
* @memberof AppClient | ||
*/ | ||
public headers: IncomingHttpHeaders = { | ||
'User-Agent': 'Mozilla/5.0 BiliDroid/5.57.0 ([email protected]) os/android model/J9110 mobi_app/android build/5570300 channel/bili innerVer/5570300 osVer/10 network/2', | ||
'User-Agent': 'Mozilla/5.0 BiliDroid/6.6.0 ([email protected]) os/android model/J9110 mobi_app/android build/6060300 channel/bili innerVer/6060300 osVer/10 network/2', | ||
'APP-KEY': this.mobiApp, | ||
'Buvid': this.buvid, | ||
'Device-ID': this.deviceId, | ||
'Display-ID': `${this.buvid}-${AppClient.TS}`, | ||
'env': 'prod' | ||
} | ||
/** | ||
|
@@ -294,8 +296,8 @@ abstract class AppClient { | |
* @type {string} | ||
* @memberof AppClient | ||
*/ | ||
public baseQuery: string = `actionKey=${this.actionKey}&appkey=${this.appKey}&build=${this.build}&channel=${this.channel}\ | ||
&device=${this.device}&mobi_app=${this.mobiApp}&platform=${this.platform}&statistics=${this.statistics}` | ||
public baseQuery: string = `actionKey=${this.actionKey}&appkey=${this.appKey}&build=${this.build}&c_locale=${this.Clocale}&channel=${this.channel}\ | ||
&device=${this.device}&mobi_app=${this.mobiApp}&platform=${this.platform}&s_locale=${this.Slocale}&statistics=${this.statistics}` | ||
/** | ||
* 登录请求参数 | ||
* | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,7 +28,7 @@ class Tools extends EventEmitter { | |
return { | ||
'Connection': 'Keep-Alive', | ||
'env': 'prod', | ||
'User-Agent': 'Mozilla/5.0 BiliDroid/5.57.0 ([email protected]) os/android model/J9110 mobi_app/android build/5570300 channel/bili innerVer/5570300 osVer/10 network/2' | ||
'User-Agent': 'Mozilla/5.0 BiliDroid/6.6.0 ([email protected]) os/android model/J9110 mobi_app/android build/6060300 channel/bili innerVer/6060300 osVer/10 network/2' | ||
} | ||
case 'WebView': | ||
return { | ||
|
@@ -39,7 +39,7 @@ class Tools extends EventEmitter { | |
'Sec-Fetch-Dest': 'empty', | ||
'Sec-Fetch-Mode': 'cors', | ||
'Sec-Fetch-Site': 'same-site', | ||
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; J9110 Build/55.1.A.3.107; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/80.0.3987.162 Mobile Safari/537.36 BiliApp/5570300', | ||
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; J9110 Build/55.1.A.3.107; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/84.0.4147.89 Mobile Safari/537.36 BiliApp/6060300', | ||
'X-Requested-With': 'tv.danmaku.bili' | ||
} | ||
default: | ||
|
@@ -52,7 +52,7 @@ class Tools extends EventEmitter { | |
'Sec-Fetch-Dest': 'empty', | ||
'Sec-Fetch-Mode': 'cors', | ||
'Sec-Fetch-Site': 'same-site', | ||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36' | ||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36' | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,137 +1,134 @@ | ||
"use strict"; | ||
let ECDH = (() => { | ||
class ECDH { | ||
constructor(curve_name) { | ||
this.privateKey = 0n; | ||
this.publicKey = { x: 0n, y: 0n }; | ||
this.zero = { x: 0n, y: 0n }; | ||
if (ECDH.curve[curve_name] !== undefined) | ||
this.curve = ECDH.curve[curve_name]; | ||
else | ||
throw 'curve_name error'; | ||
} | ||
static randomBytes(length) { | ||
const random = window.crypto.getRandomValues(new Uint8Array(length)); | ||
return ECDH.buf2hex(random); | ||
} | ||
static hex2buf(hex) { | ||
return new Uint8Array(hex.match(/.{2}/g).map(byte => parseInt(byte, 16))); | ||
} | ||
static buf2hex(buf) { | ||
return [...buf].map(b => b.toString(16).padStart(2, '0')).join(''); | ||
} | ||
static point2hex(point) { | ||
return `04${point.x.toString(16).padStart(132, '0')}${point.y.toString(16).padStart(132, '0')}`; | ||
} | ||
static hex2point(point) { | ||
const x = BigInt(`0x${point.slice(2, (point.length + 2) / 2)}`); | ||
const y = BigInt(`0x${point.slice((point.length + 2) / 2)}`); | ||
return { x, y }; | ||
} | ||
static createECDH(curve_name) { | ||
return new ECDH(curve_name); | ||
} | ||
generateKeys() { | ||
const { private_key, public_key } = this.make_keypair(); | ||
this.privateKey = private_key; | ||
this.publicKey = public_key; | ||
} | ||
getPublicKey() { | ||
return ECDH.point2hex(this.publicKey); | ||
} | ||
computeSecret(bobPublicKey) { | ||
const sharedSecret = this.scalar_mult(this.privateKey, ECDH.hex2point(bobPublicKey)); | ||
const sharedSecretKey = ECDH.point2hex(sharedSecret); | ||
return sharedSecretKey.slice(2, (sharedSecretKey.length - 2) / 2); | ||
} | ||
eq({ x: x1, y: y1 }, { x: x2, y: y2 }) { | ||
return x1 === x2 && y1 === y2; | ||
} | ||
mod(m, n) { | ||
return ((m % n) + n) % n; | ||
} | ||
inverse_mod(k, p) { | ||
if (k === 0n) | ||
throw 'division by zero'; | ||
if (k < 0n) | ||
return p - this.inverse_mod(-k, p); | ||
let [s, oldS] = [0n, 1n]; | ||
let [t, oldT] = [1n, 0n]; | ||
let [r, oldR] = [p, k]; | ||
while (r !== 0n) { | ||
const quotient = oldR / r; | ||
[oldR, r] = [r, oldR - quotient * r]; | ||
[oldS, s] = [s, oldS - quotient * s]; | ||
[oldT, t] = [t, oldT - quotient * t]; | ||
} | ||
return this.mod(oldS, p); | ||
} | ||
is_on_curve(point) { | ||
if (this.eq(point, this.zero)) | ||
return true; | ||
let { x, y } = point; | ||
return this.mod(y ** 2n - x ** 3n - this.curve.a * x - this.curve.b, this.curve.p) === 0n; | ||
} | ||
point_neg(point) { | ||
if (this.eq(point, this.zero)) | ||
return this.zero; | ||
const { x, y } = point; | ||
const result = { x, y: this.mod(-y, this.curve.p) }; | ||
return result; | ||
} | ||
point_add(point1, point2) { | ||
if (this.eq(point1, this.zero)) | ||
return point2; | ||
if (this.eq(point2, this.zero)) | ||
return point1; | ||
const { x: x1, y: y1 } = point1; | ||
const { x: x2, y: y2 } = point2; | ||
if (x1 === x2 && y1 !== y2) | ||
return this.zero; | ||
let m; | ||
if (x1 === x2) | ||
m = (3n * x1 ** 2n + this.curve.a) * this.inverse_mod(2n * y1, this.curve.p); | ||
else | ||
m = (y1 - y2) * this.inverse_mod(x1 - x2, this.curve.p); | ||
const x3 = m ** 2n - x1 - x2; | ||
const y3 = y1 + m * (x3 - x1); | ||
const result = { x: this.mod(x3, this.curve.p), y: this.mod(-y3, this.curve.p) }; | ||
return result; | ||
} | ||
scalar_mult(k, point) { | ||
if (this.mod(k, this.curve.n) === 0n || this.eq(point, this.zero)) | ||
return this.zero; | ||
if (k < 0n) | ||
return this.scalar_mult(-k, this.point_neg(point)); | ||
let result = this.zero; | ||
let addend = point; | ||
while (k) { | ||
if (k & 1n) | ||
result = this.point_add(result, addend); | ||
addend = this.point_add(addend, addend); | ||
k >>= 1n; | ||
} | ||
return result; | ||
} | ||
make_keypair() { | ||
const private_key = BigInt(`0x${ECDH.randomBytes(66)}`); | ||
const public_key = this.scalar_mult(private_key, this.curve.g); | ||
return { private_key, public_key }; | ||
} | ||
class ECDH { | ||
constructor(curve_name) { | ||
this.privateKey = 0n; | ||
this.publicKey = { x: 0n, y: 0n }; | ||
this.zero = { x: 0n, y: 0n }; | ||
if (ECDH.curve[curve_name] !== undefined) | ||
this.curve = ECDH.curve[curve_name]; | ||
else | ||
throw 'curve_name error'; | ||
} | ||
ECDH.curve = { | ||
secp521r1: { | ||
p: 0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn, | ||
a: 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcn, | ||
b: 0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00n, | ||
g: { | ||
x: 0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66n, | ||
y: 0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650n, | ||
toString: () => '0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650' | ||
}, | ||
n: 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409n, | ||
h: 1n | ||
} | ||
}; | ||
return ECDH; | ||
})(); | ||
static randomBytes(length) { | ||
const random = window.crypto.getRandomValues(new Uint8Array(length)); | ||
return ECDH.buf2hex(random); | ||
} | ||
static hex2buf(hex) { | ||
return new Uint8Array(hex.match(/.{2}/g).map(byte => parseInt(byte, 16))); | ||
} | ||
static buf2hex(buf) { | ||
return [...buf].map(b => b.toString(16).padStart(2, '0')).join(''); | ||
} | ||
static point2hex(point) { | ||
return `04${point.x.toString(16).padStart(132, '0')}${point.y.toString(16).padStart(132, '0')}`; | ||
} | ||
static hex2point(point) { | ||
const x = BigInt(`0x${point.slice(2, (point.length + 2) / 2)}`); | ||
const y = BigInt(`0x${point.slice((point.length + 2) / 2)}`); | ||
return { x, y }; | ||
} | ||
static createECDH(curve_name) { | ||
return new ECDH(curve_name); | ||
} | ||
generateKeys() { | ||
const { private_key, public_key } = this.make_keypair(); | ||
this.privateKey = private_key; | ||
this.publicKey = public_key; | ||
} | ||
getPublicKey() { | ||
return ECDH.point2hex(this.publicKey); | ||
} | ||
computeSecret(bobPublicKey) { | ||
const sharedSecret = this.scalar_mult(this.privateKey, ECDH.hex2point(bobPublicKey)); | ||
const sharedSecretKey = ECDH.point2hex(sharedSecret); | ||
return sharedSecretKey.slice(2, (sharedSecretKey.length - 2) / 2); | ||
} | ||
eq({ x: x1, y: y1 }, { x: x2, y: y2 }) { | ||
return x1 === x2 && y1 === y2; | ||
} | ||
mod(m, n) { | ||
return ((m % n) + n) % n; | ||
} | ||
inverse_mod(k, p) { | ||
if (k === 0n) | ||
throw 'division by zero'; | ||
if (k < 0n) | ||
return p - this.inverse_mod(-k, p); | ||
let [s, oldS] = [0n, 1n]; | ||
let [t, oldT] = [1n, 0n]; | ||
let [r, oldR] = [p, k]; | ||
while (r !== 0n) { | ||
const quotient = oldR / r; | ||
[oldR, r] = [r, oldR - quotient * r]; | ||
[oldS, s] = [s, oldS - quotient * s]; | ||
[oldT, t] = [t, oldT - quotient * t]; | ||
} | ||
return this.mod(oldS, p); | ||
} | ||
is_on_curve(point) { | ||
if (this.eq(point, this.zero)) | ||
return true; | ||
let { x, y } = point; | ||
return this.mod(y ** 2n - x ** 3n - this.curve.a * x - this.curve.b, this.curve.p) === 0n; | ||
} | ||
point_neg(point) { | ||
if (this.eq(point, this.zero)) | ||
return this.zero; | ||
const { x, y } = point; | ||
const result = { x, y: this.mod(-y, this.curve.p) }; | ||
return result; | ||
} | ||
point_add(point1, point2) { | ||
if (this.eq(point1, this.zero)) | ||
return point2; | ||
if (this.eq(point2, this.zero)) | ||
return point1; | ||
const { x: x1, y: y1 } = point1; | ||
const { x: x2, y: y2 } = point2; | ||
if (x1 === x2 && y1 !== y2) | ||
return this.zero; | ||
let m; | ||
if (x1 === x2) | ||
m = (3n * x1 ** 2n + this.curve.a) * this.inverse_mod(2n * y1, this.curve.p); | ||
else | ||
m = (y1 - y2) * this.inverse_mod(x1 - x2, this.curve.p); | ||
const x3 = m ** 2n - x1 - x2; | ||
const y3 = y1 + m * (x3 - x1); | ||
const result = { x: this.mod(x3, this.curve.p), y: this.mod(-y3, this.curve.p) }; | ||
return result; | ||
} | ||
scalar_mult(k, point) { | ||
if (this.mod(k, this.curve.n) === 0n || this.eq(point, this.zero)) | ||
return this.zero; | ||
if (k < 0n) | ||
return this.scalar_mult(-k, this.point_neg(point)); | ||
let result = this.zero; | ||
let addend = point; | ||
while (k) { | ||
if (k & 1n) | ||
result = this.point_add(result, addend); | ||
addend = this.point_add(addend, addend); | ||
k >>= 1n; | ||
} | ||
return result; | ||
} | ||
make_keypair() { | ||
const private_key = BigInt(`0x${ECDH.randomBytes(66)}`); | ||
const public_key = this.scalar_mult(private_key, this.curve.g); | ||
return { private_key, public_key }; | ||
} | ||
} | ||
ECDH.curve = { | ||
secp521r1: { | ||
p: 0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn, | ||
a: 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcn, | ||
b: 0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00n, | ||
g: { | ||
x: 0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66n, | ||
y: 0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650n, | ||
toString: () => '0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650' | ||
}, | ||
n: 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409n, | ||
h: 1n | ||
} | ||
}; |