rsshub
Version:
Make RSS Great Again!
76 lines (60 loc) • 2.03 kB
text/typescript
// Copied from https://github.com/huandu/heybox-url
import { createHash } from 'node:crypto';
const dict = 'JKMNPQRTX1234OABCDFG56789H';
const md5 = (str) => {
const h = createHash('md5');
h.update(str);
return h.digest();
};
function c0(v) {
return c1(v) ^ c2(v) ^ c3(v);
}
function c1(v) {
return c2(c3(convertByte(v)));
}
function c2(v) {
return c3(convertByte(v));
}
function c3(v) {
return convertByte(v) ^ v;
}
function convertByte(v) {
return v & 0x80 ? 0xFF & ((v << 1) ^ 0x1B) : v << 1;
}
/**
* Calculate checksum for a 4-byte data.
* @param {number[]} data
* @returns {number}
*/
const checksum = (data) =>
[c0(data[0]) ^ c1(data[1]) ^ c2(data[2]) ^ c3(data[3]), c3(data[0]) ^ c0(data[1]) ^ c1(data[2]) ^ c2(data[3]), c2(data[0]) ^ c3(data[1]) ^ c0(data[2]) ^ c1(data[3]), c1(data[0]) ^ c2(data[1]) ^ c3(data[2]) ^ c0(data[3])].reduce(
(prev, value) => prev + value
) % 100;
export const calculate = (url, timestamp = 0, nonce = '') => {
timestamp ||= Math.trunc(Date.now() / 1000);
nonce ||= md5(Math.random().toString()).toString('hex').toUpperCase();
const { pathname } = new URL(url);
const ts = timestamp + 1;
const u = '/' + pathname.split('/').filter(Boolean).join('/') + '/';
let key = '';
const nonceHash = md5((nonce + dict).replaceAll(/\D/g, ''))
.toString('hex')
.toLowerCase();
const rnd = md5(ts + u + nonceHash)
.toString('hex')
.replaceAll(/\D/g, '')
.slice(0, 9)
.padEnd(9, '0');
for (let c = +rnd, i = 0; i < 5; i++) {
const u = c % dict.length;
c = Math.trunc(c / dict.length);
key += dict[u];
}
const suffix = checksum([...key].slice(-4).map((c) => c.codePointAt(0)))
.toString()
.padStart(2, '0');
const query = `hkey=${key}${suffix}&_time=${timestamp}&nonce=${nonce}`;
const urlObj = new URL(url);
urlObj.search += urlObj.search ? '&' + query : query;
return urlObj.toString();
};