Completed
Push — master ( 24fe47...9f3995 )
by Equim
01:48
created

app.js (24 issues)

1
var http = require('http'),
2
    express = require('express'),
3
    superagent = require('superagent'),
4
    cheerio = require('cheerio'),
5
    escaper = require('true-html-escape'),
6
    colors = require('colors'),
7
    program = require('commander'),
8
    Date = require('./lib/Date.js');
0 ignored issues
show
Comprehensibility introduced by
You are shadowing the built-in type Date. This makes code hard to read, consider using a different name.
Loading history...
9
10
program
11
    .option('-h, --help')
12
    .option('-v, --version')
13
    .option('-p, --port [n]', parseInt)
0 ignored issues
show
The variable parseInt seems to be never declared. If this is a global, consider adding a /** global: parseInt */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
14
    .option('-f, --fulllog')
15
    .parse(process.argv);
16
17
// 别问我为什么这里逻辑这么奇怪……测试的结果确实是这样的啊hhh
18
if (!program.help || !program.version) {
19
    console.log(('CSUEMS API v1.0.0').rainbow);
1 ignored issue
show
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
20
    console.log(('by The Liberators').rainbow);
21
    if (!program.help) {
22
        console.log('Preparation:')
23
        console.log('  \\\\This section is WIP\\\\');
24
        console.log('\nUsage:');
25
        console.log('  npm start [-- <options>]');
26
        console.log('\nOptions:');
27
        console.log('  -h, --help          print this message and exit.');
28
        console.log('  -v, --version       print the version and exit.');
29
        console.log('  -f, --fulllog       enable full log, by default only errors are logged.');
30
        console.log('  -p, --port [value]  specify a port to listen, 2333 by default.');
31
        console.log('\nExamples:');
32
        console.log('  $ npm start -p 43715                      # listening to 43715');
33
        console.log('  # forever start app.js                    # deploy with forever as daemon (root access recommended)');
34
        console.log('  # pm2 start app.js -i 0 --name "CSUEMSR"  # deploy with pm2 as daemon  (root access recommended)');
35
    }
36
    process.exit(0);
1 ignored issue
show
Compatibility Debugging Code Best Practice introduced by
Use of process.exit() is discouraged as it will potentially stop the complete node.js application. Consider quitting gracefully instead by throwing an Error.
Loading history...
37
}
38
39
const timeStamp = () => new Date().format('[MM-dd hh:mm:ss] '),
40
      port = program.port || 2333;
41
      base = 'http://csujwc.its.csu.edu.cn';
0 ignored issues
show
The variable base seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.base.
Loading history...
42
43
// 直接从主页上扒下来的,哈希算法
44
const encodeInp = (input) => {
45
    let keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
46
    let output = "";
47
    let chr1, chr2, chr3 = "";
48
    let enc1, enc2, enc3, enc4 = "";
49
    let i = 0;
50
    do {
51
        chr1 = input.charCodeAt(i++);
52
        chr2 = input.charCodeAt(i++);
53
        chr3 = input.charCodeAt(i++);
54
        enc1 = chr1 >> 2;
55
        enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
56
        enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
57
        enc4 = chr3 & 63;
58
        if (isNaN(chr2)) {
59
            enc3 = enc4 = 64
60
        } else if (isNaN(chr3)) {
61
            enc4 = 64
62
        }
63
        output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);
64
        chr1 = chr2 = chr3 = "";
0 ignored issues
show
The assignment to variable chr2 seems to be never used. Consider removing it.
Loading history...
The assignment to variable chr3 seems to be never used. Consider removing it.
Loading history...
The assignment to variable chr1 seems to be never used. Consider removing it.
Loading history...
65
        enc1 = enc2 = enc3 = enc4 = ""
0 ignored issues
show
The assignment to variable enc4 seems to be never used. Consider removing it.
Loading history...
The assignment to variable enc3 seems to be never used. Consider removing it.
Loading history...
The assignment to variable enc2 seems to be never used. Consider removing it.
Loading history...
The assignment to variable enc1 seems to be never used. Consider removing it.
Loading history...
66
    } while (i < input.length);
67
    return output;
68
};
69
70
// 登出时用到的函数,一样是从原网页扒下来的
71
const getRandomUrl = (htmlurl) => {
72
    let count = htmlurl.indexOf("?");
73
    let date = new Date();
74
    let t = Date.parse(date);    
75
    if (count < 0) {
76
        htmlurl = htmlurl + "?tktime=" + t;
77
    } else {
78
        htmlurl = htmlurl + "&tktime=" + t;
79
    }
80
    return htmlurl;
81
}
82
83
// 登录模块
84
const login = (id, pwd, res, callback) => {
85
    // 通过GET首页,来获取cookie
86
    superagent.get('http://csujwc.its.csu.edu.cn/jsxsd')
87
        .end(function (err, ires) {
88
            if (err) {
89
                console.log((timeStamp() + 'Failed to get the Cookie.\n' + err.stack).red);
1 ignored issue
show
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
90
                res.send({ error: '获取Cookie失败' });
91
                return;
92
            }
93
            program.fulllog && console.log((timeStamp() + 'Successfully got the Cookie.').green);
94
95
            // 登录POST请求的headers,是我抓包来的
96
            let headers = {
97
                Host: 'csujwc.its.csu.edu.cn',
98
                Connection: 'keep-alive',
99
                'Cache-Control': 'max-age=0',
100
                Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
101
                Origin: 'http://csujwc.its.csu.edu.cn',
102
                'Upgrade-Insecure-Requests': 1,
103
                'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36',
104
                'Content-Type': 'application/x-www-form-urlencoded',
105
                Referer: 'http://csujwc.its.csu.edu.cn/jsxsd/',
106
                'Accept-Encoding': 'gzip, deflate',
107
                'Accept-Language': 'zh-CN,zh;q=0.8',
108
                Cookie: ires.headers['set-cookie']     // 猜测:感觉这个cookie也是不变的,不过出于稳定性,还是动态获取了
109
            }
110
111
            let account = encodeInp(id);
112
            let passwd = encodeInp(pwd);
113
            let encoded = escaper.escape(account + "%%%" + passwd);
114
115
            // POST登录
116
            superagent.post('http://csujwc.its.csu.edu.cn/jsxsd/xk/LoginToXk')
117
                .set(headers)
118
                .type('form')
119
                .send({ encoded: encoded })
120
                .end(function (err, iires) {
121
                    // 如果登录信息正确,这里是对http://csujwc.its.csu.edu.cn/jsxsd/framework/xsMain.jsp的GET请求
122
                    // 如果错误,会变成对http://csujwc.its.csu.edu.cn/jsxsd/xk/LoginToXk的POST请求
123
                    if (err || /POST/i.test(iires.req.method)) {
124
                        console.log((timeStamp() + 'Fail to login\n' + (err ? err.stack : 'Possibily id or password provided were wrong')).red);
1 ignored issue
show
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
125
                        res.send({ error: '登录失败,可能是用户名或密码错误' });
126
                        return;
127
                    }
128
                    program.fulllog && console.log((timeStamp() + 'Successfully logged in.').green);
129
                    // 将相应的headers和返回的response(刚进去的首页)传入callback
130
                    callback(headers, iires);
131
                });
132
        });
133
};
134
135
var app = express();
136
137
// 查成绩API,通过GET传入用户名和密码
138
app.get('/query/', function (req, res, next) {
139
    if (program.fulllog) {
140
        var start = new Date();
141
        console.log((timeStamp() + 'Started to proceed: ').cyan + req.query.id.yellow);
1 ignored issue
show
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
142
    }
143
    login(req.query.id, req.query.pwd, res, function (headers, iires) {
144
        var ret = {};
145
        var $ = cheerio.load(iires.text);
146
147
        // 进入成绩页面
148
        superagent.get(base + $('li[title="我的成绩"] a').attr('href'))
149
            .set(headers)
150
            .end(function (err, iiires) {
151
                if (err) {
152
                    console.log((timeStamp() + 'Fail to obtain grades\n' + err.stack).red);
1 ignored issue
show
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
153
                    ret.error = '获取成绩失败';
154
                    return next(err);
155
                }
156
                program.fulllog && console.log((timeStamp() + 'Successfully entered grades page.').green);
157
158
                $ = cheerio.load(iiires.text);
159
160
                // 获取成绩列表
161
                let grades = {};
162
                let failed = {};
163
                $('#dataList').each(function (index) {
164
                    // cheerio没有实现jQuery的lt
165
                    if (index >= 2)
166
                        return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
167
                    $(this).find('tr[class!="theadCss"]').each(function() {
168
                        // 这段写得真是要吐血了
169
                        let subject = escaper.unescape($(this).find('td[align="left"]').eq(1).text());
170
                        if (subject) {
171
                            let score = $(this).find('font');
172
                            if (score.text())
173
                                grades[subject] = score.text();
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
174
                            if (score.css('color'))
175
                                failed[subject] = score.text();
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
176
                        }
177
                    });
178
                });
179
                ret.grades = grades;
180
                ret['subject-count'] = Object.getOwnPropertyNames(grades).length;
181
                ret.failed = failed;
182
                ret['failed-count'] = Object.getOwnPropertyNames(failed).length;
183
184
                // 完成所有工作后,登出
185
                superagent.get(getRandomUrl(base + '/jsxsd/xk/LoginToXk?method=exit'))
186
                    .set(headers)
187
                    .end(function (err, iiiires) {
0 ignored issues
show
The parameter iiiires is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
188
                        if (err) {
189
                            console.log((timeStamp() + 'Fail to logout\n' + err.stack).red);
1 ignored issue
show
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
190
                            res.send({ error: '操作失败' });
191
                            return next(err);
192
                        }
193
194
                        // 第五步:返回JSON
195
                        res.send(JSON.stringify(ret));
196
                        program.fulllog && console.log((timeStamp() + 'Successfully logged out: ').green + req.query.id.yellow + (' (total time: ' + (new Date() - start) + 'ms)').green);
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
The variable start does not seem to be initialized in case program.fulllog on line 139 is false. Are you sure this can never be the case?
Loading history...
197
                    });
0 ignored issues
show
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
198
            });
199
    });
200
});
201
202
app.listen(port);
203
console.log((timeStamp() + 'The server is now running on port ' + port + '.').green);