#include "SimpleHandlers.hpp" #include "Response.hpp" #include #include #include #include #include #include #include #include using namespace Response; Handler::json Handler::klingerHandler(std::string const &arguments, std::string const &session, void *payload) { (void) payload; return simple_response("Bonjour!"); } Handler::json Handler::wikiHandler(std::string const &arguments, std::string const &session, void *payload) { (void) payload; std::vector linkAnnotations; linkAnnotations.emplace_back(create_annotation(Reply::AnnotationType::link, "Wikipedia")); linkAnnotations.emplace_back(create_annotation(Reply::AnnotationType::underline)); std::vector reply_vec; reply_vec.emplace_back(create_text("Visit ")); reply_vec.emplace_back(create_text("https://eo.wikipedia.org/", std::move(linkAnnotations))); reply_vec.emplace_back(create_text(" today!")); return create_response(std::move(reply_vec), session, true); } Handler::json Handler::helpHandler(std::string const &arguments, std::string const &session, void *payload) { auto commands = (std::vector *) payload; std::vector reply_vec; reply_vec.emplace_back(create_text( "Reading from the gospel according to saint N,\n" "And you shall feast upon the fruits and vegetables as I do in the offering for they will make you strong.\n" "\n" "Dear my fellow users, these are my official commands, which are offered to my believers.\n" "\n")); for (auto const &itor : *commands) { std::vector commandAnnotations; commandAnnotations.emplace_back( create_annotation(Reply::AnnotationType::command, std::move(itor.get_description()))); reply_vec.emplace_back(create_text("- ")); reply_vec.emplace_back(create_text(itor.command, std::move(commandAnnotations))); } reply_vec.emplace_back(create_text( "\n" "Thanks for using me. Takk skal du ha.\n" "Bussy\n" "N")); return create_response(std::move(reply_vec), session, true); } Handler::json Handler::stopHandler(std::string const &arguments, std::string const &session, void *payload) { auto app = (crow::SimpleApp *) payload; auto args = tokenizeArguments(arguments); if (args.empty()) { return simple_response("Needs PIN!", session, true); } int admin_pin; std::ifstream infile("/root/.n_admin_pin"); if (!(infile >> admin_pin) || admin_pin != std::stoi(args.at(0))) { return simple_response("No PIN registered on server, admin commands unavailable", session, true); } app->stop(); std::vector annotations; annotations.emplace_back(create_annotation(Reply::AnnotationType::bold)); std::vector reply_vec; reply_vec.emplace_back(create_text("stopped", std::move(annotations))); return create_response(std::move(reply_vec), session, true); } json Handler::sayHandler(const std::string &arguments, const std::string &session, void *payload) { (void) payload; return simple_response(arguments, session, true); } std::string url_encode(std::string const &value) { std::ostringstream escaped; escaped.fill('0'); escaped << std::hex; for (char c : value) { // Keep alphanumeric and other accepted characters intact if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { escaped << c; continue; } // Any other characters are percent-encoded escaped << std::uppercase; escaped << '%' << std::setw(2) << int((unsigned char) c); escaped << std::nouppercase; } return escaped.str(); } std::string exec(const char* cmd) { std::array buffer{}; std::string result; std::unique_ptr pipe(popen(cmd, "r"), pclose); if (!pipe) { throw std::runtime_error("popen() failed!"); } while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { result += buffer.data(); } return result; } static std::string const base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; std::string base64_encode(unsigned char const *input, unsigned int const len) { std::string ret; size_t i = 0; unsigned char bytes[3]; unsigned char sextets[4]; while (i <= (len - 3)) { bytes[0] = *(input++); bytes[1] = *(input++); bytes[2] = *(input++); sextets[0] = (bytes[0] & 0xfc) >> 2; // Cuts last two bits off of first byte sextets[1] = ((bytes[0] & 0x03) << 4) + ((bytes[1] & 0xf0) >> 4); // Takes last two bits from first byte and adds it to first 4 bits of 2nd byte sextets[2] = ((bytes[1] & 0x0f) << 2) + ((bytes[2] & 0xc0) >> 6); // Takes last 4 bits of 2nd byte and adds it to first 2 bits of third byte sextets[3] = bytes[2] & 0x3f; // takes last 6 bits of third byte for (unsigned char sextet : sextets) { ret += base64_chars[sextet]; } i += 3; // increases to go to third byte } if (i != len) { size_t k = 0; size_t j = len - i; // Find index of last byte while (k < j) { // Sets first bytes bytes[k] = *(input++); ++k; } while (j < 3) { // Set last bytes to 0x00 bytes[j] = '\0'; ++j; } sextets[0] = (bytes[0] & 0xfc) >> 2; // Cuts last two bits off of first byte sextets[1] = ((bytes[0] & 0x03) << 4) + ((bytes[1] & 0xf0) >> 4); // Takes last two bits from first byte and adds it to first 4 bits of 2nd byte sextets[2] = ((bytes[1] & 0x0f) << 2) + ((bytes[2] & 0xc0) >> 6); // Takes last 4 bits of 2nd byte and adds it to first 2 bits of third byte // No last one is needed, because if there were 4, then (i == len) == true for (j = 0; j < (len - i) + 1; ++j) { // Gets sextets that include data ret += base64_chars[sextets[j]]; // Appends them to string } while ((j++) < 4) // Appends remaining ='s ret += '='; } return ret; } std::string base64_encode_file(std::string const &path) { std::vector temp; std::ifstream infile; infile.open(path, std::ios::binary); // Open file in binary mode if (infile.is_open()) { while (!infile.eof()) { char c = (char) infile.get(); temp.push_back(c); } infile.close(); } else { std::cerr << path << " Error: " << strerror(errno) << std::endl; return "File could not be opened"; } std::string ret(temp.begin(), temp.end() - 1); ret = base64_encode((unsigned const char *) ret.c_str(), ret.size()); return ret; } json Handler::latexRenderHandler(std::string const &arguments, std::string const &session, void *payload) { (void) payload; std::string file = exec("mktemp"); std::cout << ("file " + file) << exec(("file " + file).c_str()) << std::endl; std::string result = exec(("curl -s 'https://latex.codecogs.com/png.latex?" + url_encode(arguments) + "' " "-H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0' " "-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' " "-H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'DNT: 1' -H 'Connection: keep-alive' " "-H 'Upgrade-Insecure-Requests: 1' --output " + file).c_str()); std::cout << ("file " + file) << exec(("file " + file).c_str()) << std::endl; if (!result.empty()) return simple_response("Error: " + result + "\n" "Please report to an admin", session, false); std::vector reply_vec; std::vector annotations; annotations.emplace_back( create_annotation(Reply::AnnotationType::attachment, "latex.png;png;" + base64_encode_file(file))); reply_vec.emplace_back(create_text("", std::move(annotations))); return create_response(std::move(reply_vec), session, true); }