Last active
December 1, 2022 04:40
-
-
Save yihong0618/93cd79509fda0790cb9733d34d44b3f9 to your computer and use it in GitHub Desktop.
扇贝加密破解自动发送今日新词到 telegram
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
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(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@ALL
还是写了个 ACTIONS
https://github.com/yihong0618/shanbay_remember