Skip to content

Instantly share code, notes, and snippets.

@yihong0618
Last active December 1, 2022 04:40
Show Gist options
  • Save yihong0618/93cd79509fda0790cb9733d34d44b3f9 to your computer and use it in GitHub Desktop.
Save yihong0618/93cd79509fda0790cb9733d34d44b3f9 to your computer and use it in GitHub Desktop.
扇贝加密破解自动发送今日新词到 telegram
const https = require("https");
const token = ""; // change this to you telegram bot token!
const chatId = ""; // change this to your telegram chat id!
const cookie = ""; // change this to your shanbay cookie!
const PATH_API = (page) =>
`/wordsapp/user_material_books/blozps/learning/words/today_learning_items?ipp=10&page=${page}&type_of=NEW`;
const options = {
hostname: "apiv3.shanbay.com",
method: "GET",
"Content-Type": "application/json",
headers: { Cookie: cookie },
};
class Func {
static loop(cnt, func) {
"v"
.repeat(cnt)
.split("")
.map((_, idx) => func(idx));
}
}
class Num {
static get(num) {
return num >>> 0;
}
static xor(a, b) {
return this.get(this.get(a) ^ this.get(b));
}
static and(a, b) {
return this.get(this.get(a) & this.get(b));
}
static mul(a, b) {
const high16 = ((a & 0xffff0000) >>> 0) * b;
const low16 = (a & 0x0000ffff) * b;
return this.get((high16 >>> 0) + (low16 >>> 0));
}
static or(a, b) {
return this.get(this.get(a) | this.get(b));
}
static not(a) {
return this.get(~this.get(a));
}
static shiftLeft(a, b) {
return this.get(this.get(a) << b);
}
static shiftRight(a, b) {
return this.get(a) >>> b;
}
static mod(a, b) {
return this.get(this.get(a) % b);
}
}
const MIN_LOOP = 8;
const PRE_LOOP = 8;
const BAY_SH0 = 1;
const BAY_SH1 = 10;
const BAY_SH8 = 8;
const BAY_MASK = 0x7fffffff;
class Random {
constructor() {
this.status = [];
this.mat1 = 0;
this.mat2 = 0;
this.tmat = 0;
}
seed(seeds) {
Func.loop(4, (idx) => {
if (seeds.length > idx) {
this.status[idx] = Num.get(seeds.charAt(idx).charCodeAt());
} else {
this.status[idx] = Num.get(110);
}
});
[, this.mat1, this.mat2, this.tmat] = this.status;
this.init();
}
init() {
Func.loop(MIN_LOOP - 1, (idx) => {
this.status[(idx + 1) & 3] = Num.xor(
this.status[(idx + 1) & 3],
idx +
1 +
Num.mul(
1812433253,
Num.xor(
this.status[idx & 3],
Num.shiftRight(this.status[idx & 3], 30)
)
)
);
});
if (
(this.status[0] & BAY_MASK) === 0 &&
this.status[1] === 0 &&
this.status[2] === 0 &&
this.status[3] === 0
) {
this.status[0] = 66;
this.status[1] = 65;
this.status[2] = 89;
this.status[3] = 83;
}
Func.loop(PRE_LOOP, () => this.nextState());
}
nextState() {
let x;
let y;
[, , , y] = this.status;
x = Num.xor(
Num.and(this.status[0], BAY_MASK),
Num.xor(this.status[1], this.status[2])
);
x = Num.xor(x, Num.shiftLeft(x, BAY_SH0));
y = Num.xor(y, Num.xor(Num.shiftRight(y, BAY_SH0), x));
[, this.status[0], this.status[1]] = this.status;
this.status[2] = Num.xor(x, Num.shiftLeft(y, BAY_SH1));
this.status[3] = y;
this.status[1] = Num.xor(
this.status[1],
Num.and(-Num.and(y, 1), this.mat1)
);
this.status[2] = Num.xor(
this.status[2],
Num.and(-Num.and(y, 1), this.mat2)
);
}
generate(max) {
this.nextState();
let t0;
[, , , t0] = this.status;
const t1 = Num.xor(this.status[0], Num.shiftRight(this.status[2], BAY_SH8));
t0 = Num.xor(t0, t1);
t0 = Num.xor(Num.and(-Num.and(t1, 1), this.tmat), t0);
return t0 % max;
}
}
class Node {
constructor() {
this.char = ".";
this.children = {};
}
getChar() {
return this.char;
}
getChildren() {
return this.children;
}
setChar(char) {
this.char = char;
}
setChildren(k, v) {
this.children[k] = v;
}
}
const B32_CODE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
const B64_CODE =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const CNT = [1, 2, 2, 2, 2, 2];
class Tree {
constructor() {
this.random = new Random();
this.sign = "";
this.inter = {};
this.head = new Node();
}
init(sign) {
this.random.seed(sign);
this.sign = sign;
Func.loop(64, (i) => {
this.addSymbol(B64_CODE[i], CNT[parseInt((i + 1) / 11, 10)]);
});
this.inter["="] = "=";
}
addSymbol(char, len) {
let ptr = this.head;
let symbol = "";
Func.loop(len, () => {
let innerChar = B32_CODE[this.random.generate(32)];
while (
innerChar in ptr.getChildren() &&
ptr.getChildren()[innerChar].getChar() !== "."
) {
innerChar = B32_CODE[this.random.generate(32)];
}
symbol += innerChar;
if (!(innerChar in ptr.getChildren())) {
ptr.setChildren(innerChar, new Node());
}
ptr = ptr.getChildren()[innerChar];
});
ptr.setChar(char);
this.inter[char] = symbol;
return symbol;
}
decode(enc) {
let dec = "";
for (let i = 4; i < enc.length; ) {
if (enc[i] === "=") {
dec += "=";
i++;
continue; // eslint-disable-line
}
let ptr = this.head;
while (enc[i] in ptr.getChildren()) {
ptr = ptr.getChildren()[enc[i]];
i++;
}
dec += ptr.getChar();
}
return dec;
}
}
const getIdx = (c) => {
const x = c.charCodeAt();
if (x >= 65) {
return x - 65;
}
return x - 65 + 41;
};
const VERSION = 1;
const checkVersion = (s) => {
const wi = getIdx(s[0]) * 32 + getIdx(s[1]);
const x = getIdx(s[2]);
const check = getIdx(s[3]);
return VERSION >= (wi * x + check) % 32;
};
const decode = (enc) => {
if (!checkVersion(enc)) {
return "";
}
const tree = new Tree();
tree.init(enc.substr(0, 4));
const rawEncode = tree.decode(enc);
let buff = Buffer.from(rawEncode, "base64");
return JSON.parse(buff.toString("utf8"));
};
function send2telegram(text) {
const data = JSON.stringify({
chat_id: chatId,
text: text,
parse_mode: "MarkdownV2",
});
const options = {
hostname: "api.telegram.org",
port: 443,
path: "/bot" + token + "/sendMessage",
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": data.length,
},
};
const req = https.request(options, (res) => {
console.log(`statusCode: ${res.statusCode}`);
res.on("data", () => {
console.log("succeed");
// process.stdout.write(d);
});
});
req.on("error", (error) => {
console.error(error);
});
req.write(data);
req.end();
}
function get_and_send_result(message = "", page = 1) {
let results = "";
options.path = PATH_API(page);
let req = https.request(options, function (res) {
res.on("data", function (chunk) {
results = results + chunk;
});
res.on("end", function () {
const resultJson = decode(JSON.parse(results).data);
const totalNew = resultJson.total
const pageCount = Math.ceil(resultJson.total / 10);
let wordsArray = [];
const wordsObject = resultJson.objects;
wordsObject.forEach((w) => {
wordsArray.push(w.vocab_with_senses.word);
});
if (page === 1) {
message += `今天的 ${totalNew} 个新词\n`;
}
message += wordsArray.join("\n");
message += "\n";
if (page < pageCount) {
page += 1;
get_and_send_result(message, page);
} else {
send2telegram(message);
}
});
});
req.on("error", function (e) {
console.log("error");
});
req.end();
}
get_and_send_result();
@yihong0618
Copy link
Author

yihong0618 commented Dec 2, 2020

@yihong0618
Copy link
Author

如果有疑问可以到 https://github.com/yihong0618/shanbay_remember 这个项目里提 issue.
这个 gist 就不更新了。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment