Skip to content

Commit

Permalink
🔖 bump version to 1.4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
ManiaciaChao committed Apr 25, 2021
1 parent 8583317 commit 76aeed6
Show file tree
Hide file tree
Showing 10 changed files with 308 additions and 111 deletions.
32 changes: 23 additions & 9 deletions dist/QRSign.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const ws_1 = __importDefault(require("ws"));
const qrcode_1 = require("qrcode");
const consts_1 = require("./consts");
const utils_1 = require("./utils");
const debugLogger = utils_1.makeDebugLogger('QRSign::');
var QRType;
(function (QRType) {
QRType[QRType["default"] = 0] = "default";
Expand All @@ -16,7 +17,7 @@ var QRType;
QRType[QRType["result"] = 3] = "result";
})(QRType || (QRType = {}));
class QRSign {
constructor(info) {
constructor(ctx, info) {
// fields
this._seqId = 0;
this.clientId = '';
Expand All @@ -27,13 +28,12 @@ class QRSign {
this.start = () => new Promise((resolve, reject) => {
this.startSync(resolve, reject);
});
//
this.sendMessage = (msg) => {
console.log(msg);
debugLogger(`sendMessage`, msg);
const raw = JSON.stringify(msg ? [msg] : []);
this.client?.send(raw);
};
this.handleQRSubscription = (message) => {
this.handleQRSubscription = async (message) => {
const { data } = message;
switch (data.type) {
case QRType.code: {
Expand All @@ -42,6 +42,18 @@ class QRSign {
return;
}
this.currentQRUrl = qrUrl;
// TODO: should devtools conflict with printer?
if (this.ctx.devtools) {
// automation via devtools
const { openId } = await this.ctx.devtools.finishQRSign(qrUrl);
// reset openId is mandatory, for scanning QR code triggering another oauth
this.ctx.openId = openId;
// Currently, QRType.result is still used for more infomations
// if (result.success) {
// this.onSuccess?.({} as IQRStudentResult);
// }
}
// manually print or execute command
switch (consts_1.qr.mode) {
case 'terminal': {
qrcode_1.toString(this.currentQRUrl, { type: 'terminal' }).then(console.log);
Expand All @@ -61,7 +73,8 @@ class QRSign {
}
case QRType.result: {
const { student } = data;
if (student && student.name === consts_1.qr.name) {
// TODO: get student info from devtools
if (student && student.name === this.ctx.studentName) {
this.onSuccess?.(student);
}
break;
Expand All @@ -82,15 +95,15 @@ class QRSign {
if (!successful) {
// qr subscription
if (QRSign.testQRSubscription(message)) {
console.log(`${channel}: successful!`);
debugLogger(`${channel}: successful!`);
this.handleQRSubscription(message);
}
else {
throw `${channel}: failed!`;
}
}
else {
console.log(`${channel}: successful!`);
debugLogger(`${channel}: successful!`);
switch (message.channel) {
case '/meta/handshake': {
const { clientId } = message;
Expand All @@ -114,7 +127,7 @@ class QRSign {
}
}
catch (err) {
console.log(`QR: ${err}`);
console.error(`QR: ${err}`);
}
};
this.handshake = () => this.sendMessage({
Expand Down Expand Up @@ -152,6 +165,7 @@ class QRSign {
});
this.courseId = info.courseId;
this.signId = info.signId;
this.ctx = ctx;
}
startSync(cb, err) {
this.onError = err ?? null;
Expand All @@ -161,7 +175,7 @@ class QRSign {
this.handshake();
});
this.client.on('message', (data) => {
console.log(data);
debugLogger(`receiveMessage`, data);
this.handleMessage(data.toString());
});
this.onError && this.client.on('error', this.onError);
Expand Down
100 changes: 100 additions & 0 deletions dist/cdp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WechatDevtools = void 0;
const CDP = require("chrome-remote-interface");
const consts_1 = require("./consts");
const utils_1 = require("./utils");
const baseConfig = {
port: 8000,
local: true,
host: '127.0.0.1',
};
const generateOpenWeixinRedirectURL = (url) => `https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxa153455f3ef1d9f9&redirect_uri=${url}&response_type=code&scope=snsapi_userinfo&state=#wechat_redirect`;
class WechatDevtools {
constructor(options) {
this._cdp = null;
this.api = 'https://v18.teachermate.cn/api/v1/wechat/r';
this.throttle = null;
this.init = async () => {
const { host, port, local } = this;
this.cdp = await CDP({
host,
port,
local,
target: (targets) => {
const target = targets[0];
if (target) {
if (target.id && !target.webSocketDebuggerUrl) {
target.webSocketDebuggerUrl = `ws://${this.host}:${this.port}/devtools/page/${target.id}`;
}
return target;
}
else {
throw new Error('No inspectable targets');
}
},
});
const { Network, Page, Runtime } = this.cdp;
await Network.enable();
await Page.enable();
await this.cdp.Network.setUserAgentOverride({ userAgent: consts_1.userAgent });
return this.cdp;
};
this.destroy = () => this.cdp?.close();
this.navigateTo = (url) => this.cdp.Page.navigate({
url,
});
this.fetchNextOpenIDFromRequest = (filter = 'openid=') => this.waitForNextRequestUrl(filter).then(utils_1.extractOpenId);
this.waitForNextRequestUrl = (filter) => new Promise((resolve) => {
const cleaner = this.cdp.Network.requestWillBeSent((params) => {
const url = params.request.url;
if (url.includes(filter)) {
this.throttle = utils_1.sleep(10 * 1000);
cleaner();
resolve(url);
}
});
});
this.generateOpenId = async () => {
await this.throttle;
this.navigateTo(generateOpenWeixinRedirectURL(`${this.api}?m=ssr_hub`));
return this.fetchNextOpenIDFromRequest();
};
this.finishQRSign = async (qrSignUrl) => {
await this.throttle;
// const url = generateOpenWeixinRedirectURL(
// `${this.api}?isTeacher=0&m=s_qr_sign&extra=${qrSignId}`
// );
this.navigateTo(qrSignUrl);
const resultUrl = await this.waitForNextRequestUrl('signresult?openid=');
const result = utils_1.urlParamsToObject(resultUrl.split('?').pop());
return {
success: result.success === '1',
openId: result.openid,
rank: result.studentRank,
};
};
const opt = { ...baseConfig, ...options };
this.host = opt.host;
this.port = opt.port;
this.local = opt.local;
}
get cdp() {
if (!this._cdp)
throw 'cdp: uninitialized';
return this._cdp;
}
set cdp(val) {
if (this._cdp)
throw 'cdp: already connected';
this._cdp = val;
}
}
exports.WechatDevtools = WechatDevtools;
// (async () => {
// const devtool = new WechatDevtools();
// await devtool.init();
// // console.log(await devtool.generateOpenId());
// await devtool.navigateTo("");
// await devtool.destroy();
// })();
6 changes: 3 additions & 3 deletions dist/consts.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CHECK_ALIVE_INTERVAL = exports.userAgent = exports.qr = exports.config = void 0;
exports.CHECK_ALIVE_INTERVAL = exports.userAgent = exports.devtools = exports.qr = exports.config = void 0;
const fs_1 = require("fs");
const path_1 = require("path");
const configFile = fs_1.readFileSync(path_1.join('./', 'config.json'));
Expand All @@ -10,7 +10,7 @@ _a = exports.config.qr, exports.qr = _a === void 0 ? {
name: '',
mode: 'terminal',
copyCmd: undefined,
} : _a;
} : _a, exports.devtools = exports.config.devtools;
exports.userAgent = exports.config.ua ??
`Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4427.5 Safari/537.36`;
`Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36 QBCore/4.0.1326.400 QQBrowser/9.0.2524.400 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2875.116 Safari/537.36 NetType/WIFI MicroMessenger/7.0.20.1781(0x6700143B) WindowsWechat(0x63010200)`;
exports.CHECK_ALIVE_INTERVAL = 4; // request `/role` per a given amount of `/active_signs`
112 changes: 38 additions & 74 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@ const readline_sync_1 = require("readline-sync");
const process_1 = require("process");
const requests_1 = require("./requests");
const consts_1 = require("./consts");
const QRSign_1 = require("./QRSign");
const utils_1 = require("./utils");
const getOpenId = async () => {
const cdp_1 = require("./cdp");
const sign_1 = require("./sign");
const getOpenId = async ({ devtools, openIdSet }) => {
let openId;
if (consts_1.config.clipboard?.paste) {
if (devtools) {
openId = await devtools.generateOpenId();
}
else if (consts_1.config.clipboard?.paste) {
while (true) {
openId = utils_1.extractOpenId(utils_1.pasteFromClipBoard());
if (openId) {
Expand All @@ -29,83 +33,43 @@ const getOpenId = async () => {
}
return openId;
};
const signedIdSet = new Set();
const openIdSet = new Set();
let lastSignId = 0;
let qrSign;
const main = async (openId) => {
return await requests_1.activeSign(openId)
.then(async (data) => {
if (!data.length) {
qrSign?.destory();
throw 'No sign-in available';
}
const queue = [
...data.filter((sign) => !sign.isQR),
...data.filter((sign) => sign.isQR),
];
for (const sign of queue) {
const { signId, courseId, isGPS, isQR, name } = sign;
console.log('current sign-in:', sign.name);
if (signedIdSet.has(signId)) {
throw `${name} already signed in`;
}
utils_1.sendNotificaition(`INFO: ${name} sign-in is going on!`);
if (isQR) {
if (signId === lastSignId) {
return;
(async () => {
const ctx = {
openId: '',
studentName: '',
lastSignId: 0,
signedIdSet: new Set(),
openIdSet: new Set(),
};
if (consts_1.config.devtools) {
ctx.devtools = new cdp_1.WechatDevtools();
await ctx.devtools.init();
}
for (;;) {
try {
if (!ctx.openId.length || (await requests_1.checkInvaild(ctx.openId))) {
let prompt = 'Error: expired or invaild openId!';
if (consts_1.config.clipboard) {
prompt = `${prompt} Waiting for new openId from clipboard...`;
}
else if (ctx.devtools) {
prompt = `${prompt} Generating new openId via devtools...`;
}
lastSignId = signId;
utils_1.sendNotificaition(`WARNING: ${name} QR sign-in is going on!`);
qrSign?.destory();
qrSign = new QRSign_1.QRSign({ courseId, signId });
const result = await qrSign.start();
const prompt = 'Signed in successfully. However, you need to submit new openid!';
console.log(result);
signedIdSet.add(signId);
utils_1.sendNotificaition(prompt);
console.warn(prompt);
openId = '';
// process.exit(0);
}
else {
let signInQuery = { courseId, signId };
if (isGPS) {
const { lat, lon } = consts_1.config;
signInQuery = { ...signInQuery, lat, lon };
if (!ctx.openIdSet.has(ctx.openId)) {
ctx.openIdSet.add(ctx.openId);
}
await utils_1.sleep(consts_1.config.wait);
await requests_1.signIn(openId, signInQuery)
.then((data) => {
if (!data.errorCode || data.errorCode === 305) {
signedIdSet.add(signId);
}
console.log(data);
})
.catch((e) => {
console.log(e);
utils_1.sendNotificaition(`Error: failed to ${name} sign in. See output plz.`);
});
ctx.openId = await getOpenId(ctx);
console.log('Applied new openId:', ctx.openId);
ctx.studentName = await requests_1.getStudentName(ctx.openId);
console.log(ctx.studentName);
}
await sign_1.signOnce(ctx);
await utils_1.sleep(consts_1.config.interval);
}
})
.catch((e) => {
console.log(e);
});
};
(async () => {
let openId = '';
for (;;) {
if (!openId.length || (await requests_1.checkInvaild(openId))) {
const prompt = 'Error: expired or invaild openId! Waiting for new openId from clipboard...';
utils_1.sendNotificaition(prompt);
console.warn(prompt);
if (!openIdSet.has(openId)) {
openIdSet.add(openId);
}
openId = await getOpenId();
catch (err) {
console.warn('Error:', err);
}
await main(openId);
await utils_1.sleep(consts_1.config.interval);
}
})();
Loading

0 comments on commit 76aeed6

Please sign in to comment.