├── .github
└── workflows
│ └── npm-publish.yml
├── .gitignore
├── README.md
├── des.ts
├── dist
├── captcha.d.ts
├── captcha.js
├── des.d.ts
├── des.js
├── index.d.ts
├── index.js
├── recognize.d.ts
└── recognize.js
├── index.ts
├── package.json
├── recognize.ts
├── tsconfig.json
└── yarn.lock
/.github/workflows/npm-publish.yml:
--------------------------------------------------------------------------------
1 | name: npm-publish
2 | on: push
3 |
4 | jobs:
5 | publish:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - uses: actions/checkout@v1
9 | - uses: actions/setup-node@v1
10 | with:
11 | node-version: 12
12 | - run: npm install --dev
13 | - uses: JS-DevTools/npm-publish@v1
14 | with:
15 | token: ${{ secrets.NPM_TOKEN }}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | yarn-error.log
3 | *.traineddata
4 | test.*
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
Welcome to node-hustpass 👋
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | > HUSTPass auth library for Node.js. Node.js 华科统一身份认证库。
12 |
13 | ## Requirement
14 |
15 | None.
16 |
17 | ## Install
18 |
19 | ```sh
20 | yarn add node-hustpass
21 | ```
22 |
23 | ## Usage
24 |
25 | ```javascript
26 | const { init } = require("node-hustpass");
27 |
28 | (async () => {
29 | const { fetch, jar, login } = await init();
30 |
31 | await login({
32 | username: "U201X12345",
33 | password: "QZBSQZZH",
34 | url:
35 | "https://pass.hust.edu.cn/cas/login?service=http%3A%2F%2Fhubs.hust.edu.cn%2Fhustpass.action"
36 | });
37 | /**
38 | * do something cool here!
39 | * you can simply use this `fetch` method,
40 | * or pass `jar` into your own request library.
41 | */
42 | })();
43 | ```
44 |
45 | ## Author
46 |
47 | 👤 **maniacata**
48 |
49 |
50 | ## Show your support
51 |
52 | Give a ⭐️ if this project helped you!
53 |
54 | ***
55 | _This README was generated with ❤️ by [readme-md-generator](https://github.com/kefranabg/readme-md-generator)_
56 |
--------------------------------------------------------------------------------
/des.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file was originally written by winderica
3 | */
4 |
5 | import { createCipheriv } from "crypto";
6 |
7 | const magicTable = [
8 | 0,
9 | 1,
10 | 2,
11 | 6,
12 | 38,
13 | 37,
14 | 36,
15 | 7,
16 | 8,
17 | 9,
18 | 10,
19 | 14,
20 | 46,
21 | 45,
22 | 44,
23 | 15,
24 | 16,
25 | 17,
26 | 18,
27 | 22,
28 | 54,
29 | 53,
30 | 52,
31 | 23,
32 | 24,
33 | 25,
34 | 26,
35 | 30,
36 | 62,
37 | 61,
38 | 60,
39 | 31,
40 | 32,
41 | 33,
42 | 34,
43 | 35,
44 | 5,
45 | 4,
46 | 3,
47 | 39,
48 | 40,
49 | 41,
50 | 42,
51 | 43,
52 | 13,
53 | 12
54 | /**
55 | * This method was originally written by winderica
56 | * @author winderica
57 | * @license MIT
58 | * @see {@link https://github.com/winderica/DailyReport}
59 | * @param {string} plain
60 | * @param {string} k1
61 | * @param {string} k2
62 | * @param {string} k3
63 | * @description RSA is actually DES, their implementation of which is not surprisingly incorrect.
64 | */,
65 | 11,
66 | 47,
67 | 48,
68 | 49,
69 | 50,
70 | 51,
71 | 21,
72 | 20,
73 | 19,
74 | 55,
75 | 56,
76 | 57,
77 | 58,
78 | 59,
79 | 29,
80 | 28,
81 | 27,
82 | 63,
83 | ];
84 |
85 | const toBuffer = (t: string) =>
86 | Buffer.from(t.padEnd(Math.ceil(t.length / 4) * 4, "\0"), "utf16le").swap16();
87 | const toBits = (str: string) =>
88 | [...toBuffer(str)].flatMap((i) =>
89 | i.toString(2).padStart(8, "0").split("").map(Number)
90 | );
91 | const desEncrypt = (plain: Buffer, key: string) => {
92 | const k = magicTable
93 | .map((i) => toBits(key)[i])
94 | .join("")
95 | .match(/.{1,8}/g)!
96 | .map((i) => parseInt(i, 2));
97 | const cipher = createCipheriv("DES-ECB", Buffer.from(k), null).setAutoPadding(
98 | false
99 | );
100 | return Buffer.concat([cipher.update(plain), cipher.final()]);
101 | };
102 |
103 | /**
104 | * This method was originally written by winderica
105 | * @author winderica
106 | * @license MIT
107 | * @see {@link https://github.com/winderica/DailyReport}
108 | * @param {string} plain
109 | * @param {string} k1
110 | * @param {string} k2
111 | * @param {string} k3
112 | * @description RSA is actually DES, their implementation of which is not surprisingly incorrect.
113 | */
114 |
115 | export const desEEE = (plain: string, k1: string, k2: string, k3: string) => {
116 | return desEncrypt(desEncrypt(desEncrypt(toBuffer(plain), k1), k2), k3)
117 | .toString("hex")
118 | .toUpperCase();
119 | };
120 |
--------------------------------------------------------------------------------
/dist/captcha.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | declare module "gm" {
3 | interface State {
4 | selectFrame(frame: number): this;
5 | }
6 | }
7 | export declare const readCaptcha: (captcha: Buffer) => Promise;
8 |
--------------------------------------------------------------------------------
/dist/captcha.js:
--------------------------------------------------------------------------------
1 | import { createWorker } from "tesseract.js";
2 | import * as gm from "gm";
3 | const im = gm.subClass({ imageMagick: true });
4 | const processImage = (buffer) => new Promise((resolve, reject) => {
5 | im(buffer)
6 | .selectFrame(1)
7 | .threshold(90, true)
8 | .in("-morphology", "close:2", "1x4: 0,1,1,0")
9 | .crop(84, 20, 0, 18) // original image size: 90x58
10 | .normalize()
11 | .toBuffer("png", (err, buffer) => {
12 | if (err)
13 | reject(err);
14 | if (buffer)
15 | resolve(buffer);
16 | });
17 | });
18 | export const readCaptcha = async (captcha) => {
19 | const after = await processImage(captcha);
20 | const worker = createWorker({
21 | langPath: "http://cdn.outsiders.top",
22 | });
23 | await worker.load();
24 | await worker.loadLanguage("eng");
25 | await worker.initialize("eng", 0 /* TESSERACT_ONLY */);
26 | await worker.setParameters({
27 | tessedit_pageseg_mode: "7" /* SINGLE_LINE */,
28 | tessedit_char_whitelist: "0123456789",
29 | });
30 | const { data: { text }, } = await worker.recognize(after);
31 | await worker.terminate();
32 | const code = text.replace(/[ \n]/g, "");
33 | if (code.length !== 4)
34 | return false;
35 | return code;
36 | };
37 |
--------------------------------------------------------------------------------
/dist/des.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file was originally written by winderica
3 | */
4 | /**
5 | * This method was originally written by winderica
6 | * @author winderica
7 | * @license MIT
8 | * @see {@link https://github.com/winderica/DailyReport}
9 | * @param {string} plain
10 | * @param {string} k1
11 | * @param {string} k2
12 | * @param {string} k3
13 | * @description RSA is actually DES, their implementation of which is not surprisingly incorrect.
14 | */
15 | export declare const desEEE: (plain: string, k1: string, k2: string, k3: string) => string;
16 |
--------------------------------------------------------------------------------
/dist/des.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This file was originally written by winderica
3 | */
4 | import { createCipheriv } from "crypto";
5 | const magicTable = [
6 | 0,
7 | 1,
8 | 2,
9 | 6,
10 | 38,
11 | 37,
12 | 36,
13 | 7,
14 | 8,
15 | 9,
16 | 10,
17 | 14,
18 | 46,
19 | 45,
20 | 44,
21 | 15,
22 | 16,
23 | 17,
24 | 18,
25 | 22,
26 | 54,
27 | 53,
28 | 52,
29 | 23,
30 | 24,
31 | 25,
32 | 26,
33 | 30,
34 | 62,
35 | 61,
36 | 60,
37 | 31,
38 | 32,
39 | 33,
40 | 34,
41 | 35,
42 | 5,
43 | 4,
44 | 3,
45 | 39,
46 | 40,
47 | 41,
48 | 42,
49 | 43,
50 | 13,
51 | 12
52 | /**
53 | * This method was originally written by winderica
54 | * @author winderica
55 | * @license MIT
56 | * @see {@link https://github.com/winderica/DailyReport}
57 | * @param {string} plain
58 | * @param {string} k1
59 | * @param {string} k2
60 | * @param {string} k3
61 | * @description RSA is actually DES, their implementation of which is not surprisingly incorrect.
62 | */ ,
63 | 11,
64 | 47,
65 | 48,
66 | 49,
67 | 50,
68 | 51,
69 | 21,
70 | 20,
71 | 19,
72 | 55,
73 | 56,
74 | 57,
75 | 58,
76 | 59,
77 | 29,
78 | 28,
79 | 27,
80 | 63,
81 | ];
82 | const toBuffer = (t) => Buffer.from(t.padEnd(Math.ceil(t.length / 4) * 4, "\0"), "utf16le").swap16();
83 | const toBits = (str) => [...toBuffer(str)].flatMap((i) => i.toString(2).padStart(8, "0").split("").map(Number));
84 | const desEncrypt = (plain, key) => {
85 | const k = magicTable
86 | .map((i) => toBits(key)[i])
87 | .join("")
88 | .match(/.{1,8}/g)
89 | .map((i) => parseInt(i, 2));
90 | const cipher = createCipheriv("DES-ECB", Buffer.from(k), null).setAutoPadding(false);
91 | return Buffer.concat([cipher.update(plain), cipher.final()]);
92 | };
93 | /**
94 | * This method was originally written by winderica
95 | * @author winderica
96 | * @license MIT
97 | * @see {@link https://github.com/winderica/DailyReport}
98 | * @param {string} plain
99 | * @param {string} k1
100 | * @param {string} k2
101 | * @param {string} k3
102 | * @description RSA is actually DES, their implementation of which is not surprisingly incorrect.
103 | */
104 | export const desEEE = (plain, k1, k2, k3) => {
105 | return desEncrypt(desEncrypt(desEncrypt(toBuffer(plain), k1), k2), k3)
106 | .toString("hex")
107 | .toUpperCase();
108 | };
109 |
--------------------------------------------------------------------------------
/dist/index.d.ts:
--------------------------------------------------------------------------------
1 | import { CookieJar, MemoryCookieStore } from "tough-cookie";
2 | import nodeFetch from "node-fetch";
3 | interface InitOptions {
4 | jar?: CookieJar;
5 | redirect?: boolean;
6 | }
7 | interface LoginOptions {
8 | username: string;
9 | password: string;
10 | url: string;
11 | }
12 | export declare const init: (options?: InitOptions) => {
13 | jar: CookieJar;
14 | store: MemoryCookieStore;
15 | fetch: typeof nodeFetch;
16 | login: (options: LoginOptions) => Promise;
17 | };
18 | export {};
19 |
--------------------------------------------------------------------------------
/dist/index.js:
--------------------------------------------------------------------------------
1 | import { URLSearchParams } from "url";
2 | import { CookieJar, MemoryCookieStore } from "tough-cookie";
3 | import nodeFetch from "node-fetch";
4 | import { desEEE } from "./des.js";
5 | import { recognize } from "./recognize.js";
6 | import withCookie from "fetch-cookie";
7 | const regex = {
8 | action: /action="(.*?)"/,
9 | lt: /LT-.*?-cas/,
10 | ticket: /ST-.*?-cas/,
11 | };
12 | export const init = (options = {}) => {
13 | var _a, _b;
14 | const redirect = (_a = options.redirect) !== null && _a !== void 0 ? _a : true;
15 | const store = new MemoryCookieStore();
16 | const jar = (_b = options.jar) !== null && _b !== void 0 ? _b : new CookieJar(store);
17 | const fetch = withCookie(nodeFetch, jar);
18 | const login = async (options) => {
19 | const { username, password, url } = options;
20 | let resp = await fetch(url);
21 | const html = await resp.text();
22 | const lt = html.match(regex.lt)[0];
23 | const action = html.match(regex.action)[1];
24 | let code = false;
25 | while (!code) {
26 | resp = await fetch(`https://pass.hust.edu.cn/cas/code?${Math.random()}`);
27 | const captcha = await resp.arrayBuffer();
28 | code = await recognize(captcha);
29 | }
30 | const form = {
31 | ul: username.length + "",
32 | pl: password.length + "",
33 | lt,
34 | code,
35 | rsa: desEEE(username + password + lt, "1", "2", "3"),
36 | execution: "e1s1",
37 | _eventId: "submit",
38 | };
39 | resp = await fetch(`https://pass.hust.edu.cn${action}`, {
40 | method: "POST",
41 | redirect: "manual",
42 | body: new URLSearchParams(form),
43 | });
44 | const ticket = resp.headers.get("location");
45 | if (!ticket) {
46 | throw Error("Login failed!");
47 | }
48 | if (redirect) {
49 | await fetch(ticket);
50 | }
51 | return ticket;
52 | };
53 | return { jar, store, fetch, login };
54 | };
55 |
--------------------------------------------------------------------------------
/dist/recognize.d.ts:
--------------------------------------------------------------------------------
1 | export declare const recognize: (ab: ArrayBuffer) => Promise;
2 |
--------------------------------------------------------------------------------
/dist/recognize.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This file was originally written by winderica
3 | */
4 | import sharp from "sharp";
5 | // https://github.com/winderica/DailyReport/blob/4ab18c3850e60ba3074db4f2fcb76695c0335ab8/assets/digits.png
6 | const digitsStr = `iVBORw0KGgoAAAANSUhEUgAAALQAAAAUBAMAAADW/wrvAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAwUExURQAAAP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFulh5UAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFiSURBVEjHhZULEsMgCESXG8D9L9sYgV1snXamieHzJIAE8fwAi/3zvfCUPHdEqZZoCUqWSlAkmse2lHYSCUo0DjTSiOjipDtKlyJTL0fvmtv6MJ5o1y2exYvef0G/6+ciyarNYrxEJXLvkV75gMrha+hMeiXCK0c+0LTcT8EQM0xDrw6HQucdNtG4oO2GPvqBIk+7BtKy8rF2W16epTT06je6CxtdoVJLy7Jl4j+aDVZhsfjp2c0TbFmrKuGK7ufyCkGzCSFBC9reywVdwSa7qxN55LwvLMBoayaEGdQ4CNLmYUK7xHnjG9kqTpVA0dq06POqPYPhJWLLcG5o7az/aDkS49Wgou+Dc0NLQJ0PGxm1n2gN+jzwIXNCE36g34C8pkpItyck5EBv1+Bw7cwad+RMWw/dqj1cMcelJEYkMlwbfXhhy+KKti/0+FrowMK0QfRn5wsdQo75iaIO8wi0JuIDUWRHd/3sb80AAAAASUVORK5CYII=`;
7 | const transpose = (data, width) => {
8 | return [...new Array(width).keys()].map((i) => [...data].filter((_, j) => j % width === i));
9 | };
10 | const match = (pixels, digits) => {
11 | const scores = [...new Array(10)].map(() => 0);
12 | for (let i = 0; i < 180; i++) {
13 | for (let j = 0; j < 20; j++) {
14 | if (pixels[i % 18][j] === digits[i][j]) {
15 | scores[~~(i / 18)]++;
16 | }
17 | }
18 | }
19 | return scores.indexOf(Math.max(...scores));
20 | };
21 | export const recognize = async (ab) => {
22 | const buffer = new Uint8Array(ab);
23 | const data = await sharp(buffer, { page: 1 })
24 | .extract({ left: 0, top: 19, width: 87, height: 20 })
25 | .toColourspace("b-w")
26 | .threshold(254)
27 | .raw()
28 | .toBuffer();
29 | const digitsImage = Buffer.from(digitsStr, "base64");
30 | const digits = transpose(await sharp(digitsImage).toColourspace("b-w").raw().toBuffer(), 180);
31 | const pixels = [[...new Array(20)].map(() => 255), ...transpose(data, 87)];
32 | return [...new Array(4).keys()]
33 | .map((i) => match(pixels.slice(i * 22, i * 22 + 18), digits))
34 | .join("");
35 | };
36 |
--------------------------------------------------------------------------------
/index.ts:
--------------------------------------------------------------------------------
1 | import { URLSearchParams } from "url";
2 | import { CookieJar, MemoryCookieStore } from "tough-cookie";
3 | import nodeFetch from "node-fetch";
4 | import { desEEE } from "./des.js";
5 | import { recognize } from "./recognize.js";
6 | import withCookie from "fetch-cookie";
7 |
8 | const regex = {
9 | action: /action="(.*?)"/,
10 | lt: /LT-.*?-cas/,
11 | ticket: /ST-.*?-cas/,
12 | };
13 |
14 | interface InitOptions {
15 | jar?: CookieJar;
16 | redirect?: boolean;
17 | }
18 | interface LoginOptions {
19 | username: string;
20 | password: string;
21 | url: string;
22 | }
23 |
24 | export const init = (options: InitOptions = {}) => {
25 | const redirect = options.redirect ?? true;
26 | const store = new MemoryCookieStore();
27 | const jar = options.jar ?? new CookieJar(store);
28 | const fetch = withCookie(nodeFetch, jar) as typeof nodeFetch;
29 |
30 | const login = async (options: LoginOptions) => {
31 | const { username, password, url } = options;
32 | let resp = await fetch(url);
33 | const html = await resp.text();
34 | const lt = (html.match(regex.lt) as string[])[0];
35 | const action = (html.match(regex.action) as string[])[1];
36 | let code: boolean | string = false;
37 | while (!code) {
38 | resp = await fetch(`https://pass.hust.edu.cn/cas/code?${Math.random()}`);
39 | const captcha = await resp.arrayBuffer();
40 | code = await recognize(captcha);
41 | }
42 | const form = {
43 | ul: username.length + "",
44 | pl: password.length + "",
45 | lt,
46 | code,
47 | rsa: desEEE(username + password + lt, "1", "2", "3"),
48 | execution: "e1s1",
49 | _eventId: "submit",
50 | };
51 | resp = await fetch(`https://pass.hust.edu.cn${action}`, {
52 | method: "POST",
53 | redirect: "manual",
54 | body: new URLSearchParams(form),
55 | });
56 | const ticket = resp.headers.get("location");
57 | if (!ticket) {
58 | throw Error("Login failed!");
59 | }
60 | if (redirect) {
61 | await fetch(ticket);
62 | }
63 | return ticket;
64 | };
65 |
66 | return { jar, store, fetch, login };
67 | };
68 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-hustpass",
3 | "version": "2.2.1",
4 | "description": "HUSTPass auth library for Node.js. Node.js 华科统一身份认证库。",
5 | "main": "./dist/index.js",
6 | "typings": "./dist/index.d.ts",
7 | "type": "module",
8 | "author": "maniacata",
9 | "license": "MIT",
10 | "files": [
11 | "dist"
12 | ],
13 | "scripts": {
14 | "prepublish": "yarn build",
15 | "build": "tsc"
16 | },
17 | "dependencies": {
18 | "fetch-cookie": "^2.0.5",
19 | "gm": "^1.23.1",
20 | "node-fetch": "^3.2.5",
21 | "sharp": "^0.30.6",
22 | "tesseract.js": "^2.1.5",
23 | "tough-cookie": "^4.0.0"
24 | },
25 | "devDependencies": {
26 | "@types/gm": "^1.18.12",
27 | "@types/node": "^13.9.0",
28 | "@types/node-fetch": "^2.6.1",
29 | "@types/sharp": "^0.30.2",
30 | "@types/tough-cookie": "^4.0.2",
31 | "typescript": "^3.8.3"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/recognize.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file was originally written by winderica
3 | */
4 | import sharp from "sharp";
5 |
6 | // https://github.com/winderica/DailyReport/blob/4ab18c3850e60ba3074db4f2fcb76695c0335ab8/assets/digits.png
7 | const digitsStr = `iVBORw0KGgoAAAANSUhEUgAAALQAAAAUBAMAAADW/wrvAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAwUExURQAAAP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFulh5UAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFiSURBVEjHhZULEsMgCESXG8D9L9sYgV1snXamieHzJIAE8fwAi/3zvfCUPHdEqZZoCUqWSlAkmse2lHYSCUo0DjTSiOjipDtKlyJTL0fvmtv6MJ5o1y2exYvef0G/6+ciyarNYrxEJXLvkV75gMrha+hMeiXCK0c+0LTcT8EQM0xDrw6HQucdNtG4oO2GPvqBIk+7BtKy8rF2W16epTT06je6CxtdoVJLy7Jl4j+aDVZhsfjp2c0TbFmrKuGK7ufyCkGzCSFBC9reywVdwSa7qxN55LwvLMBoayaEGdQ4CNLmYUK7xHnjG9kqTpVA0dq06POqPYPhJWLLcG5o7az/aDkS49Wgou+Dc0NLQJ0PGxm1n2gN+jzwIXNCE36g34C8pkpItyck5EBv1+Bw7cwad+RMWw/dqj1cMcelJEYkMlwbfXhhy+KKti/0+FrowMK0QfRn5wsdQo75iaIO8wi0JuIDUWRHd/3sb80AAAAASUVORK5CYII=`;
8 |
9 | const transpose = (data: Buffer, width: number) => {
10 | return [...new Array(width).keys()].map((i) =>
11 | [...data].filter((_, j) => j % width === i)
12 | );
13 | };
14 |
15 | const match = (pixels: number[][], digits: number[][]) => {
16 | const scores = [...new Array(10)].map(() => 0);
17 | for (let i = 0; i < 180; i++) {
18 | for (let j = 0; j < 20; j++) {
19 | if (pixels[i % 18][j] === digits[i][j]) {
20 | scores[~~(i / 18)]++;
21 | }
22 | }
23 | }
24 | return scores.indexOf(Math.max(...scores));
25 | };
26 |
27 | export const recognize = async (ab: ArrayBuffer) => {
28 | const buffer = new Uint8Array(ab);
29 | const data = await sharp(buffer, { page: 1 })
30 | .extract({ left: 0, top: 19, width: 87, height: 20 })
31 | .toColourspace("b-w")
32 | .threshold(254)
33 | .raw()
34 | .toBuffer();
35 | const digitsImage = Buffer.from(digitsStr, "base64");
36 | const digits = transpose(
37 | await sharp(digitsImage).toColourspace("b-w").raw().toBuffer(),
38 | 180
39 | );
40 | const pixels = [[...new Array(20)].map(() => 255), ...transpose(data, 87)];
41 | return [...new Array(4).keys()]
42 | .map((i) => match(pixels.slice(i * 22, i * 22 + 18), digits))
43 | .join("");
44 | };
45 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2019", // ts-node doesn't recognize "esnext"
4 | "module": "es2020",
5 | "esModuleInterop": true,
6 | "moduleResolution": "node",
7 | "strict": true,
8 | "declaration": true,
9 | "outDir": "dist"
10 | },
11 | "ts-node": {
12 | "esm": true
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@types/gm@^1.18.7":
6 | version "1.18.7"
7 | resolved "https://registry.npmjs.org/@types/gm/-/gm-1.18.7.tgz#03a90d5140496b94c3ce406df62a1ba3defb594a"
8 | integrity sha512-7gOsCmtTqq3NSKinO2WsYA2uC2RVcW0wlPWXsMDP3rPNoV8Ba+8+OZhfkVstCjar2Yud0RM3jwAIv/h2cLTcSA==
9 | dependencies:
10 | "@types/node" "*"
11 |
12 | "@types/node-fetch@^2.5.5":
13 | version "2.5.10"
14 | resolved "https://registry.npm.taobao.org/@types/node-fetch/download/@types/node-fetch-2.5.10.tgz#9b4d4a0425562f9fcea70b12cb3fcdd946ca8132"
15 | integrity sha1-m01KBCVWL5/OpwsSyz/N2UbKgTI=
16 | dependencies:
17 | "@types/node" "*"
18 | form-data "^3.0.0"
19 |
20 | "@types/node@*":
21 | version "14.14.41"
22 | resolved "https://registry.npm.taobao.org/@types/node/download/@types/node-14.14.41.tgz?cache=0&sync_timestamp=1618543947232&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-14.14.41.tgz#d0b939d94c1d7bd53d04824af45f1139b8c45615"
23 | integrity sha1-0Lk52Uwde9U9BIJK9F8RObjEVhU=
24 |
25 | "@types/node@^13.9.0":
26 | version "13.9.0"
27 | resolved "https://registry.npmjs.org/@types/node/-/node-13.9.0.tgz#5b6ee7a77faacddd7de719017d0bc12f52f81589"
28 | integrity sha512-0ARSQootUG1RljH2HncpsY2TJBfGQIKOOi7kxzUY6z54ePu/ZD+wJA8zI2Q6v8rol2qpG/rvqsReco8zNMPvhQ==
29 |
30 | "@types/tough-cookie@^2.3.6":
31 | version "2.3.6"
32 | resolved "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.6.tgz#c880579e087d7a0db13777ff8af689f4ffc7b0d5"
33 | integrity sha512-wHNBMnkoEBiRAd3s8KTKwIuO9biFtTf0LehITzBhSco+HQI0xkXZbLOD55SW3Aqw3oUkHstkm5SPv58yaAdFPQ==
34 |
35 | array-parallel@~0.1.3:
36 | version "0.1.3"
37 | resolved "https://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz#8f785308926ed5aa478c47e64d1b334b6c0c947d"
38 | integrity sha1-j3hTCJJu1apHjEfmTRszS2wMlH0=
39 |
40 | array-series@~0.1.5:
41 | version "0.1.5"
42 | resolved "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz#df5d37bfc5c2ef0755e2aa4f92feae7d4b5a972f"
43 | integrity sha1-3103v8XC7wdV4qpPkv6ufUtaly8=
44 |
45 | asynckit@^0.4.0:
46 | version "0.4.0"
47 | resolved "https://registry.nlark.com/asynckit/download/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
48 | integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
49 |
50 | bmp-js@^0.1.0:
51 | version "0.1.0"
52 | resolved "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz#e05a63f796a6c1ff25f4771ec7adadc148c07233"
53 | integrity sha1-4Fpj95amwf8l9Hcex62twUjAcjM=
54 |
55 | combined-stream@^1.0.8:
56 | version "1.0.8"
57 | resolved "https://registry.nlark.com/combined-stream/download/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
58 | integrity sha1-w9RaizT9cwYxoRCoolIGgrMdWn8=
59 | dependencies:
60 | delayed-stream "~1.0.0"
61 |
62 | cross-spawn@^4.0.0:
63 | version "4.0.2"
64 | resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41"
65 | integrity sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=
66 | dependencies:
67 | lru-cache "^4.0.1"
68 | which "^1.2.9"
69 |
70 | debug@^3.1.0:
71 | version "3.2.6"
72 | resolved "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
73 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
74 | dependencies:
75 | ms "^2.1.1"
76 |
77 | delayed-stream@~1.0.0:
78 | version "1.0.0"
79 | resolved "https://registry.npm.taobao.org/delayed-stream/download/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
80 | integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
81 |
82 | es6-denodeify@^0.1.1:
83 | version "0.1.5"
84 | resolved "https://registry.npmjs.org/es6-denodeify/-/es6-denodeify-0.1.5.tgz#31d4d5fe9c5503e125460439310e16a2a3f39c1f"
85 | integrity sha1-MdTV/pxVA+ElRgQ5MQ4WoqPznB8=
86 |
87 | fetch-cookie@^0.7.3:
88 | version "0.7.3"
89 | resolved "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.7.3.tgz#b8d023f421dd2b2f4a0eca9cd7318a967ed4eed8"
90 | integrity sha512-rZPkLnI8x5V+zYAiz8QonAHsTb4BY+iFowFBI1RFn0zrO343AVp9X7/yUj/9wL6Ef/8fLls8b/vGtzUvmyAUGA==
91 | dependencies:
92 | es6-denodeify "^0.1.1"
93 | tough-cookie "^2.3.3"
94 |
95 | file-type@^12.4.1:
96 | version "12.4.2"
97 | resolved "https://registry.npmjs.org/file-type/-/file-type-12.4.2.tgz#a344ea5664a1d01447ee7fb1b635f72feb6169d9"
98 | integrity sha512-UssQP5ZgIOKelfsaB5CuGAL+Y+q7EmONuiwF3N5HAH0t27rvrttgi6Ra9k/+DVaY9UF6+ybxu5pOXLUdA8N7Vg==
99 |
100 | form-data@^3.0.0:
101 | version "3.0.1"
102 | resolved "https://registry.npm.taobao.org/form-data/download/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
103 | integrity sha1-69U3kbeDVqma+aMA1CgsTV65dV8=
104 | dependencies:
105 | asynckit "^0.4.0"
106 | combined-stream "^1.0.8"
107 | mime-types "^2.1.12"
108 |
109 | gm@^1.23.1:
110 | version "1.23.1"
111 | resolved "https://registry.npmjs.org/gm/-/gm-1.23.1.tgz#2edeeb958084d0f8ea7988e5d995b1c7dfc14777"
112 | integrity sha1-Lt7rlYCE0PjqeYjl2ZWxx9/BR3c=
113 | dependencies:
114 | array-parallel "~0.1.3"
115 | array-series "~0.1.5"
116 | cross-spawn "^4.0.0"
117 | debug "^3.1.0"
118 |
119 | idb-keyval@^3.2.0:
120 | version "3.2.0"
121 | resolved "https://registry.npmjs.org/idb-keyval/-/idb-keyval-3.2.0.tgz#cbbf354deb5684b6cdc84376294fc05932845bd6"
122 | integrity sha512-slx8Q6oywCCSfKgPgL0sEsXtPVnSbTLWpyiDcu6msHOyKOLari1TD1qocXVCft80umnkk3/Qqh3lwoFt8T/BPQ==
123 |
124 | is-electron@^2.2.0:
125 | version "2.2.0"
126 | resolved "https://registry.npmjs.org/is-electron/-/is-electron-2.2.0.tgz#8943084f09e8b731b3a7a0298a7b5d56f6b7eef0"
127 | integrity sha512-SpMppC2XR3YdxSzczXReBjqs2zGscWQpBIKqwXYBFic0ERaxNVgwLCHwOLZeESfdJQjX0RDvrJ1lBXX2ij+G1Q==
128 |
129 | is-url@^1.2.4:
130 | version "1.2.4"
131 | resolved "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52"
132 | integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==
133 |
134 | isexe@^2.0.0:
135 | version "2.0.0"
136 | resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
137 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
138 |
139 | lru-cache@^4.0.1:
140 | version "4.1.5"
141 | resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
142 | integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
143 | dependencies:
144 | pseudomap "^1.0.2"
145 | yallist "^2.1.2"
146 |
147 | mime-db@1.47.0:
148 | version "1.47.0"
149 | resolved "https://registry.npm.taobao.org/mime-db/download/mime-db-1.47.0.tgz?cache=0&sync_timestamp=1617306524622&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime-db%2Fdownload%2Fmime-db-1.47.0.tgz#8cb313e59965d3c05cfbf898915a267af46a335c"
150 | integrity sha1-jLMT5Zll08Bc+/iYkVomevRqM1w=
151 |
152 | mime-types@^2.1.12:
153 | version "2.1.30"
154 | resolved "https://registry.npm.taobao.org/mime-types/download/mime-types-2.1.30.tgz?cache=0&sync_timestamp=1617340186693&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime-types%2Fdownload%2Fmime-types-2.1.30.tgz#6e7be8b4c479825f85ed6326695db73f9305d62d"
155 | integrity sha1-bnvotMR5gl+F7WMmaV23P5MF1i0=
156 | dependencies:
157 | mime-db "1.47.0"
158 |
159 | ms@^2.1.1:
160 | version "2.1.2"
161 | resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
162 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
163 |
164 | node-fetch@^2.6.0:
165 | version "2.6.1"
166 | resolved "https://registry.npm.taobao.org/node-fetch/download/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
167 | integrity sha1-BFvTI2Mfdu0uK1VXM5RBa2OaAFI=
168 |
169 | opencollective-postinstall@^2.0.2:
170 | version "2.0.2"
171 | resolved "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz#5657f1bede69b6e33a45939b061eb53d3c6c3a89"
172 | integrity sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==
173 |
174 | pseudomap@^1.0.2:
175 | version "1.0.2"
176 | resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
177 | integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
178 |
179 | psl@^1.1.28:
180 | version "1.7.0"
181 | resolved "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz#f1c4c47a8ef97167dea5d6bbf4816d736e884a3c"
182 | integrity sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==
183 |
184 | punycode@^2.1.1:
185 | version "2.1.1"
186 | resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
187 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
188 |
189 | regenerator-runtime@^0.13.3:
190 | version "0.13.5"
191 | resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"
192 | integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==
193 |
194 | resolve-url@^0.2.1:
195 | version "0.2.1"
196 | resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
197 | integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
198 |
199 | tesseract.js-core@^2.2.0:
200 | version "2.2.0"
201 | resolved "https://registry.npmjs.org/tesseract.js-core/-/tesseract.js-core-2.2.0.tgz#6ef78051272a381969fac3e45a226e85022cffef"
202 | integrity sha512-a8L+OJTbUipBsEDsJhDPlnLB0TY1MkTZqw5dqUwmiDSjUzwvU7HWLg/2+WDRulKUi4LE+7PnHlaBlW0k+V0U0w==
203 |
204 | tesseract.js@^2.1.1:
205 | version "2.1.1"
206 | resolved "https://registry.npmjs.org/tesseract.js/-/tesseract.js-2.1.1.tgz#5c50fc95542ce8d834cb952bfb75a8fc85f1441d"
207 | integrity sha512-utg0A8UzT1KwBvZf+UMGmM8LU6izeol6yIem0Z44+7Qqd/YWgRVQ99XOG18ApTOXX48lGE++PDwlcZYkv0ygRQ==
208 | dependencies:
209 | bmp-js "^0.1.0"
210 | file-type "^12.4.1"
211 | idb-keyval "^3.2.0"
212 | is-electron "^2.2.0"
213 | is-url "^1.2.4"
214 | node-fetch "^2.6.0"
215 | opencollective-postinstall "^2.0.2"
216 | regenerator-runtime "^0.13.3"
217 | resolve-url "^0.2.1"
218 | tesseract.js-core "^2.2.0"
219 | zlibjs "^0.3.1"
220 |
221 | tough-cookie@^2.3.3:
222 | version "2.5.0"
223 | resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
224 | integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
225 | dependencies:
226 | psl "^1.1.28"
227 | punycode "^2.1.1"
228 |
229 | typescript@^3.8.3:
230 | version "3.8.3"
231 | resolved "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061"
232 | integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==
233 |
234 | which@^1.2.9:
235 | version "1.3.1"
236 | resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
237 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
238 | dependencies:
239 | isexe "^2.0.0"
240 |
241 | yallist@^2.1.2:
242 | version "2.1.2"
243 | resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
244 | integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
245 |
246 | zlibjs@^0.3.1:
247 | version "0.3.1"
248 | resolved "https://registry.npmjs.org/zlibjs/-/zlibjs-0.3.1.tgz#50197edb28a1c42ca659cc8b4e6a9ddd6d444554"
249 | integrity sha1-UBl+2yihxCymWcyLTmqd3W1ERVQ=
250 |
--------------------------------------------------------------------------------