// WBI signature algorithm for Bilibili API // https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/misc/sign/wbi.md const MIXIN_KEY_ENC_TAB = [ 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, 37,48,7,16,24,55,40,61,26,17,0,1,60,51,30,4, 22,25,54,21,56,59,6,63,57,62,11,36,20,34,44,52, ]; function getMixinKey(imgKey: string, subKey: string): string { const raw = imgKey + subKey; return MIXIN_KEY_ENC_TAB.slice(0, 32).map(i => raw[i]).join(''); } // Minimal MD5 implementation (no dependencies) function md5(input: string): string { function safeAdd(x: number, y: number) { const lsw=(x&0xffff)+(y&0xffff); const msw=(x>>16)+(y>>16)+(lsw>>16); return (msw<<16)|(lsw&0xffff); } function bitRotateLeft(num: number, cnt: number) { return (num<>>(32-cnt)); } function md5cmn(q:number,a:number,b:number,x:number,s:number,t:number){return safeAdd(bitRotateLeft(safeAdd(safeAdd(a,q),safeAdd(x,t)),s),b);} function md5ff(a:number,b:number,c:number,d:number,x:number,s:number,t:number){return md5cmn((b&c)|(~b&d),a,b,x,s,t);} function md5gg(a:number,b:number,c:number,d:number,x:number,s:number,t:number){return md5cmn((b&d)|(c&~d),a,b,x,s,t);} function md5hh(a:number,b:number,c:number,d:number,x:number,s:number,t:number){return md5cmn(b^c^d,a,b,x,s,t);} function md5ii(a:number,b:number,c:number,d:number,x:number,s:number,t:number){return md5cmn(c^(b|~d),a,b,x,s,t);} function md5blks(s: string): number[] { const nblk = ((s.length+8)>>6)+1; const blks = new Array(nblk*16).fill(0); for(let i=0;i>2]|=s.charCodeAt(i)<<((i%4)*8); blks[s.length>>2]|=0x80<<((s.length%4)*8); blks[nblk*16-2]=s.length*8; return blks; } const x = md5blks(input); let a=1732584193,b=-271733879,c=-1732584194,d=271733878; for(let i=0;i>8)&0xff).toString(16)).slice(-2)+('0'+((n>>16)&0xff).toString(16)).slice(-2)+('0'+((n>>24)&0xff).toString(16)).slice(-2); } return hex(a)+hex(b)+hex(c)+hex(d); } export function signWbi( params: Record, imgKey: string, subKey: string, ): Record { const mixinKey = getMixinKey(imgKey, subKey); const wts = Math.floor(Date.now() / 1000); const all: Record = { ...params, wts }; const query = Object.keys(all) .sort() .map(k => { const v = String(all[k]).replace(/[!'()*]/g, ''); return `${k}=${v}`; }) .join('&'); const w_rid = md5(query + mixinKey); return { ...all, w_rid }; }