Adds support for macro detection (#7315)

* Adds the official client macro detection system.
* Includes the ability to load imagery at server boot.
* See doc/captcha_db.txt for more information!
Thanks to @Asheraf and @Lemongrass3110!
Co-authored-by: Lemongrass3110 <lemongrass@kstp.at>
This commit is contained in:
Aleos
2022-10-14 10:54:19 -04:00
committed by GitHub
parent 750c7d72de
commit d7bf5ebb58
19 changed files with 883 additions and 5 deletions

View File

@@ -21552,6 +21552,14 @@ void clif_parse_open_ui( int fd, struct map_session_data* sd ){
clif_msg_color( sd, MSG_ATTENDANCE_DISABLED, color_table[COLOR_RED] );
}
break;
#if PACKETVER >= 20160316
case IN_UI_MACRO_REGISTER:
clif_ui_open(*sd, OUT_UI_CAPTCHA, 0);
break;
case IN_UI_MACRO_DETECTOR:
clif_ui_open(*sd, OUT_UI_MACRO, 0);
break;
#endif
}
}
@@ -24628,6 +24636,265 @@ void clif_broadcast_refine_result(map_session_data& sd, t_itemid itemId, int8 le
#endif
}
void clif_parse_captcha_register(int fd, map_session_data *sd) {
#if PACKETVER >= 20160316
nullpo_retv(sd);
if (!pc_has_permission(sd, PC_PERM_MACRO_REGISTER)) {
clif_displaymessage(sd->fd, msg_txt(sd, 246)); // Your GM level doesn't authorize you to perform this action.
return;
}
PACKET_CZ_REQ_UPLOAD_MACRO_DETECTOR *p = (PACKET_CZ_REQ_UPLOAD_MACRO_DETECTOR *)RFIFOP(fd, 0);
pc_macro_captcha_register(*sd, p->imageSize, p->answer);
#endif
}
void clif_captcha_upload_request(map_session_data &sd) {
#if PACKETVER >= 20160330
PACKET_ZC_ACK_UPLOAD_MACRO_DETECTOR p = {};
p.PacketType = HEADER_ZC_ACK_UPLOAD_MACRO_DETECTOR;
safestrncpy(p.captchaKey, "", sizeof(p.captchaKey));
if (sd.captcha_upload.cd != nullptr) {
p.captchaFlag = 0;
} else {
p.captchaFlag = 1;
}
clif_send(&p, sizeof(p), &sd.bl, SELF);
#endif
}
void clif_parse_captcha_upload(int fd, map_session_data *sd) {
#if PACKETVER >= 20160316
nullpo_retv(sd);
if (!pc_has_permission(sd, PC_PERM_MACRO_REGISTER)) {
clif_displaymessage(sd->fd, msg_txt(sd, 246)); // Your GM level doesn't authorize you to perform this action.
return;
}
PACKET_CZ_UPLOAD_MACRO_DETECTOR_CAPTCHA *p = (PACKET_CZ_UPLOAD_MACRO_DETECTOR_CAPTCHA *)RFIFOP(fd, 0);
int16 upload_size = p->PacketLength - sizeof(PACKET_CZ_UPLOAD_MACRO_DETECTOR_CAPTCHA);
if (upload_size < 1 || upload_size > MAX_CAPTCHA_CHUNK_SIZE)
return;
if (sd->captcha_upload.upload_size + upload_size > sd->captcha_upload.cd->image_size)
return;
pc_macro_captcha_register_upload(*sd, upload_size, p->imageData);
#endif
}
void clif_captcha_upload_end(map_session_data &sd) {
#if PACKETVER >= 20160330
PACKET_ZC_COMPLETE_UPLOAD_MACRO_DETECTOR_CAPTCHA p = {};
p.PacketType = HEADER_ZC_COMPLETE_UPLOAD_MACRO_DETECTOR_CAPTCHA;
clif_send(&p, sizeof(p), &sd.bl, SELF);
#endif
}
void clif_parse_captcha_preview_request(int fd, map_session_data *sd) {
#if PACKETVER >= 20160323
nullpo_retv(sd);
if (!(pc_has_permission(sd, PC_PERM_MACRO_REGISTER) && pc_has_permission(sd, PC_PERM_MACRO_DETECT))) {
clif_displaymessage(sd->fd, msg_txt(sd, 246)); // Your GM level doesn't authorize you to perform this action.
return;
}
PACKET_CZ_REQ_PREVIEW_MACRO_DETECTOR *p = (PACKET_CZ_REQ_PREVIEW_MACRO_DETECTOR *)RFIFOP(fd, 0);
clif_captcha_preview_response(*sd, captcha_db.find(p->captchaID));
#endif
}
void clif_captcha_preview_response(map_session_data &sd, std::shared_ptr<s_captcha_data> cd) {
#if PACKETVER >= 20160330
PACKET_ZC_ACK_PREVIEW_MACRO_DETECTOR p = {};
p.PacketType = HEADER_ZC_ACK_PREVIEW_MACRO_DETECTOR;
safestrncpy(p.captchaKey, "", sizeof(p.captchaKey));
if (cd == nullptr) {
p.captchaFlag = 1;
p.imageSize = 0;
} else {
p.captchaFlag = 0;
p.imageSize = cd->image_size;
}
clif_send(&p, sizeof(p), &sd.bl, SELF);
if (cd != nullptr) {
for (uint16 offset = 0; offset < cd->image_size;) {
uint16 chunk_size = min(cd->image_size - offset, MAX_CAPTCHA_CHUNK_SIZE);
PACKET_ZC_PREVIEW_MACRO_DETECTOR_CAPTCHA *p2 = (PACKET_ZC_PREVIEW_MACRO_DETECTOR_CAPTCHA *)packet_buffer;
p2->PacketType = HEADER_ZC_PREVIEW_MACRO_DETECTOR_CAPTCHA;
p2->PacketLength = (int16)(sizeof(PACKET_ZC_PREVIEW_MACRO_DETECTOR_CAPTCHA) + chunk_size);
safestrncpy(p2->captchaKey, p.captchaKey, sizeof(p2->captchaKey));
memcpy(p2->imageData, &cd->image_data[offset], chunk_size);
clif_send(p2, p2->PacketLength, &sd.bl, SELF);
offset += chunk_size;
}
}
#endif
}
void clif_macro_detector_request(map_session_data &sd) {
#if PACKETVER >= 20160330
std::shared_ptr<s_captcha_data> cd = sd.macro_detect.cd;
if (cd == nullptr) {
return;
}
// Send preview initialization request to the client.
PACKET_ZC_APPLY_MACRO_DETECTOR p = {};
p.PacketType = HEADER_ZC_APPLY_MACRO_DETECTOR;
p.imageSize = cd->image_size;
safestrncpy(p.captchaKey, "", sizeof(p.captchaKey));
clif_send(&p, sizeof(p), &sd.bl, SELF);
for (uint16 offset = 0; offset < cd->image_size;) {
uint16 chunk_size = min(cd->image_size - offset, MAX_CAPTCHA_CHUNK_SIZE);
PACKET_ZC_APPLY_MACRO_DETECTOR_CAPTCHA *p2 = (PACKET_ZC_APPLY_MACRO_DETECTOR_CAPTCHA *)packet_buffer;
p2->PacketType = HEADER_ZC_APPLY_MACRO_DETECTOR_CAPTCHA;
p2->PacketLength = (int16)(sizeof(PACKET_ZC_APPLY_MACRO_DETECTOR_CAPTCHA) + chunk_size);
safestrncpy(p2->captchaKey, p.captchaKey, sizeof(p2->captchaKey));
memcpy(p2->imageData, &cd->image_data[offset], chunk_size);
clif_send(p2, p2->PacketLength, &sd.bl, SELF);
offset += chunk_size;
}
#endif
}
void clif_macro_detector_request_show(map_session_data &sd) {
#if PACKETVER >= 20160330
PACKET_ZC_REQ_ANSWER_MACRO_DETECTOR p = {};
p.PacketType = HEADER_ZC_REQ_ANSWER_MACRO_DETECTOR;
p.retryCount = sd.macro_detect.retry;
p.timeout = battle_config.macro_detection_timeout;
clif_send(&p, sizeof(p), &sd.bl, SELF);
#endif
}
void clif_parse_macro_detector_download_ack(int fd, map_session_data *sd) {
#if PACKETVER >= 20160316
nullpo_retv(sd);
if (sd->macro_detect.retry != 0) {
//PACKET_CZ_COMPLETE_APPLY_MACRO_DETECTOR_CAPTCHA *p = (PACKET_CZ_COMPLETE_APPLY_MACRO_DETECTOR_CAPTCHA *)RFIFOP(fd, 0);
clif_macro_detector_request_show(*sd);
}
#endif
}
void clif_parse_macro_detector_answer(int fd, map_session_data *sd) {
#if PACKETVER >= 20160316
nullpo_retv(sd);
PACKET_CZ_ACK_ANSWER_MACRO_DETECTOR *p = (PACKET_CZ_ACK_ANSWER_MACRO_DETECTOR *)RFIFOP(fd, 0);
pc_macro_detector_process_answer(*sd, p->answer);
#endif
}
void clif_macro_detector_status(map_session_data &sd, e_macro_detect_status stype) {
#if PACKETVER >= 20160330
PACKET_ZC_CLOSE_MACRO_DETECTOR p = {};
p.PacketType = HEADER_ZC_CLOSE_MACRO_DETECTOR;
p.status = stype;
clif_send(&p, sizeof(p), &sd.bl, SELF);
#endif
}
void clif_parse_macro_reporter_select(int fd, map_session_data *sd) {
#if PACKETVER >= 20160330
nullpo_retv(sd);
if (!pc_has_permission(sd, PC_PERM_MACRO_DETECT)) {
clif_displaymessage(sd->fd, msg_txt(sd, 246)); // Your GM level doesn't authorize you to perform this action.
return;
}
PACKET_CZ_REQ_PLAYER_AID_IN_RANGE *p = (PACKET_CZ_REQ_PLAYER_AID_IN_RANGE *)RFIFOP(fd, 0);
pc_macro_reporter_area_select(*sd, p->xPos, p->yPos, p->RadiusRange);
#endif
}
void clif_macro_reporter_select(map_session_data &sd, const std::vector<uint32> &aid_list) {
#if PACKETVER >= 20160330
PACKET_ZC_ACK_PLAYER_AID_IN_RANGE *p = (PACKET_ZC_ACK_PLAYER_AID_IN_RANGE *)packet_buffer;
p->PacketType = HEADER_ZC_ACK_PLAYER_AID_IN_RANGE;
p->PacketLength = static_cast<int16>(sizeof(PACKET_ZC_ACK_PLAYER_AID_IN_RANGE) + sizeof(uint32) * aid_list.size());
for (size_t i = 0; i < aid_list.size(); i++)
p->AID[i] = aid_list[static_cast<int32>(i)];
clif_send(p, p->PacketLength, &sd.bl, SELF);
#endif
}
void clif_parse_macro_reporter_ack(int fd, map_session_data *sd) {
#if PACKETVER >= 20160316
nullpo_retv(sd);
if (!pc_has_permission(sd, PC_PERM_MACRO_DETECT)) {
clif_displaymessage(sd->fd, msg_txt(sd, 246)); // Your GM level doesn't authorize you to perform this action.
return;
}
PACKET_CZ_REQ_APPLY_MACRO_DETECTOR *p = (PACKET_CZ_REQ_APPLY_MACRO_DETECTOR *)RFIFOP(fd, 0);
map_session_data *tsd = map_id2sd(p->AID);
if (tsd == nullptr) {
clif_displaymessage(fd, msg_txt(sd, 3)); // Character not found.
return;
}
if (tsd->macro_detect.retry != 0) {
clif_macro_reporter_status(*sd, MCR_INPROGRESS);
return;
}
if (captcha_db.empty()) {
clif_macro_reporter_status(*sd, MCR_NO_DATA);
return;
}
pc_macro_reporter_process(*sd, *tsd);
clif_macro_reporter_status(*sd, MCR_MONITORING);
#endif
}
void clif_macro_reporter_status(map_session_data &sd, e_macro_report_status stype) {
#if PACKETVER >= 20160330
PACKET_ZC_ACK_APPLY_MACRO_DETECTOR p = {};
p.PacketType = HEADER_ZC_ACK_APPLY_MACRO_DETECTOR;
p.status = stype;
clif_send(&p, sizeof(p), &sd.bl, SELF);
#endif
}
/*==========================================
* Main client packet processing function
*------------------------------------------*/