-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhfutnet.cpp
More file actions
248 lines (216 loc) · 9.08 KB
/
Copy pathhfutnet.cpp
File metadata and controls
248 lines (216 loc) · 9.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#include <windows.h>
#include <wininet.h>
#include <wincrypt.h>
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <cctype>
#include "hfutnet/consts.h"
#include "hfutnet/utils.hpp"
#pragma comment(lib, "wininet.lib")
enum Operation {
LOGIN_OPERATION = 0,
LOGOUT_OPERATION = 1,
};
inline bool debug_mode = false;
inline std::ostringstream headers;
void print_usage() {
std::cout <<
R"(Usage:
hfutnet.exe <sid> <password> [--login | -i]
hfutnet.exe [<sid>] [<password>] (--logout | -o)
Description:
hfutnet is a command-line tool for logging in to or logging out of the
HFUT campus network.
Arguments:
<sid> Student ID (required for login)
<password> Network password (required for login)
Options:
--login, -i Log in to the campus network (default action)
--logout,-o Log out from the campus network
Behavior:
- If no option is specified, the program defaults to --login (-i).
- When using --login (-i):
<sid> and <password> are required.
- When using --logout (-o):
<sid> and <password> are optional.
Examples:
hfutnet.exe 2024213492 mypassword
hfutnet.exe 2024213492 mypassword --login
hfutnet.exe --logout
hfutnet.exe 2024213492 --logout
)";
}
void login(const HINTERNET& internet,
const HINTERNET& connect,
const std::string& sid,
const std::string& password) {
HINTERNET hRequest = HttpOpenRequestA(
connect, "POST", "/0.htm", NULL, NULL, NULL,
INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE, 0);
if (!hRequest) throw std::runtime_error("HttpOpenRequest failed");
std::string response;
try {
// Construct form data
// Dr.COM uses: DDDDD=<sid>&upass=md5(pid+<password>+calg)&R1=0&R2=1¶=00&0MKKey=123456&v6ip=
std::string upass_md5 = md5_hex(COM_PID + password + COM_CALG);
std::ostringstream form;
form << "DDDDD=" << url_encode(sid)
<< "&upass=" << upass_md5 << COM_CALG << COM_PID
<< "&R1=0&R2=1¶=00&0MKKey=" << COM_0MKKEY
<< "&v6ip=";
std::string body = form.str();
BOOL bSend = HttpSendRequestA(
hRequest, headers.str().c_str(), (DWORD) headers.str().length(),
(LPVOID) body.c_str(), (DWORD) body.size());
if (!bSend) throw std::runtime_error("HttpSendRequest failed");
char buffer[1025];
DWORD bytesRead = 0;
while (InternetReadFile(hRequest, buffer, 1024, &bytesRead) && bytesRead > 0) {
buffer[bytesRead] = '\0';
response += buffer;
}
response = gb2312_to_utf8(response);
// Login success check
if (std::regex_search(response, REGEX_LOGIN_SUCCESS)) {
std::cout << "登录成功!\n";
InternetCloseHandle(hRequest);
return;
}
// Login failure, parse message code
std::smatch match;
// No message code found
if (!std::regex_search(response, match, REGEX_MSG_CODE))
throw std::runtime_error("无法解析响应消息");
// Message code found, convert to integer
int msg_code;
try {
msg_code = std::stoi(match[1].str());
} catch (...) {
throw std::runtime_error("无法解析消息代码");
}
switch (msg_code) {
case 0:
case 1: {
std::smatch info_match;
if (!std::regex_search(response, info_match, REGEX_MSG_INFO))
throw std::runtime_error("未知错误");
std::string info = info_match[1].str();
if (info == "error0") throw std::runtime_error("当前IP地址已被禁止使用Web方式登录");
if (info == "error1") throw std::runtime_error("当前账号已被禁止使用Web方式登录");
if (info == "error2") throw std::runtime_error("当前账号不允许修改密码"); // what?!
if (info == "userid error1") throw std::runtime_error("账号不存在");
if (info == "userid error2") throw std::runtime_error("密码错误");
if (info == "userid error3") throw std::runtime_error("密码错误");
throw std::runtime_error("登录失败:" + info);
}
case 2: throw std::runtime_error("当前账号正在使用中");
case 3: throw std::runtime_error("当前账号只能在指定地址使用");
case 4: throw std::runtime_error("当前账号费用超支或时长、流量超过限制");
case 5: throw std::runtime_error("当前账号已暂停使用");
case 6: throw std::runtime_error("系统缓存已满,请稍后再试");
case 7: throw std::runtime_error("UT+UF+UM(疑似用量统计)"); // what?!
case 8: throw std::runtime_error("当前账号正在使用,无法修改"); // what?!
case 9: throw std::runtime_error("密码确认不匹配,无法修改"); // what?!
case 10: throw std::runtime_error("密码修改成功"); // what?!
case 11: throw std::runtime_error("当前账号只能在指定地址使用");
case 14: throw std::runtime_error("账号注销成功");
case 15: throw std::runtime_error("登录成功(?何意味)"); // what?!
}
} catch (std::exception& e) {
std::cerr << "登录失败:" << e.what() << "。\n";
if (debug_mode)
std::cerr << "Response was:\n" << response << "\n";
InternetCloseHandle(hRequest);
return;
}
InternetCloseHandle(hRequest);
return;
}
void logout() {
// Implementation of logout function (if needed separately)
}
int main(int argc, char* argv[]) {
SetConsoleOutputCP(CP_UTF8);
std::string sid, password;
auto op = LOGIN_OPERATION;
bool op_set = false;
auto set_op = [&](Operation _op) -> bool {
if (op_set && op != _op) {
std::cerr << "Conflicting operations specified.\n";
print_usage();
return false;
}
op = _op;
op_set = true;
return true;
};
// Parse command-line arguments
bool pos_only = false;
for (int i = 1; i < argc; ++i) {
const std::string arg = argv[i];
/** Parse flags **/
if (!pos_only) {
if (arg == "--") { pos_only = true; continue; }
if (arg == "--help" || arg == "-h") { print_usage(); return 0; }
if (arg == "--version" || arg == "-v") { std::cout << "1.0\n"; return 0; }
if (arg == "--debug" || arg == "-d") { debug_mode = true; continue; }
if (arg == "--logout" || arg == "-o") { if (!set_op(LOGOUT_OPERATION)) return 1; continue; }
if (arg == "--login" || arg == "-i") { if (!set_op(LOGIN_OPERATION)) return 1; continue; }
if (!arg.empty() && arg[0] == '-') {
std::cerr << "Unknown flag: " << arg << "\n";
print_usage();
return 1;
}
}
/** Parse positional **/
/**/ if (sid.empty()) sid = arg;
else if (password.empty()) password = arg;
else {
std::cerr << "Too many arguments: " << arg << "\n";
print_usage();
return 1;
}
}
// Validate required arguments
if (op == LOGIN_OPERATION && (sid.empty() || password.empty())) {
std::cerr << "SID and password are required for login operation.\n";
print_usage();
return 1;
}
HINTERNET hInternet = InternetOpenA(
"HFUT Campus Network", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hInternet) {
std::cerr << "InternetOpen failed\n";
return 2;
}
HINTERNET hConnect = InternetConnectA(
hInternet, "172.16.200.11", INTERNET_DEFAULT_HTTP_PORT,
NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (!hConnect) {
std::cerr << "InternetConnect failed\n";
InternetCloseHandle(hInternet);
return 2;
}
headers << "User-Agent: " << USER_AGENT << "\r\n"
<< "Accept: " << ACCEPT << "\r\n"
<< "Accept-Language: " << ACCEPT_LANGUAGE << "\r\n"
<< "Accept-Encoding: " << ACCEPT_ENCODING << "\r\n"
<< "Cache-Control: " << CACHE_CONTROL << "\r\n"
<< "Connection: " << CONNECTION << "\r\n"
<< "Content-Type: " << CONTENT_TYPE << "\r\n"
<< "Upgrade-Insecure-Requests: " << UPGRADE_INSECURE_REQUESTS << "\r\n";
// Perform the operation
switch (op) {
case LOGIN_OPERATION:
login(hInternet, hConnect, sid, password);
break;
case LOGOUT_OPERATION:
logout();
break;
}
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
return 0;
}