/* This file is part of FediBlock-backend. * Copyright © 2020 tastytea * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include "cgi.hpp" #include "files.hpp" #include "fs-compat.hpp" #include "time.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace FediBlock::cgi { using fmt::format; using std::getline; using std::ios; using std::map; using std::ofstream; using std::runtime_error; using std::string; using std::string_view; using std::stringstream; using std::transform; using std::vector; using std::chrono::system_clock; entry_type parse_formdata() { entry_type entry; cgicc::Cgicc cgi; entry.instance = cgi("instance"); entry.tags = string_to_vector(cgi("tags")); transform(entry.tags.begin(), entry.tags.end(), entry.tags.begin(), [](const auto &tag) { return tolower(tag); }); entry.receipts = string_to_vector(cgi("receipts")); entry.description = cgi("description"); entry.report_time = time::to_string(system_clock::now()); for (const auto &screenshot : cgi.getFiles()) { constexpr size_t size_limit{1024 * 512}; if (screenshot.getDataLength() > size_limit) { throw runtime_error{format("The screenshot “{0:s}” is too big. " "The limit is {1:.1f} kilobyte (KiB).", screenshot.getFilename(), size_limit / 1024.0)}; } const string filepath{files::get_tmpdir() / screenshot.getFilename()}; ofstream file{filepath, ios::binary}; if (!file.good()) { throw runtime_error{"Could not open temporary file: " + filepath}; } screenshot.writeToStream(file); entry.screenshot_filepaths.push_back(filepath); } return entry; } vector string_to_vector(const string_view str) { vector vec; stringstream input{str.data()}; string element; while (getline(input, element, ',')) { if (!element.empty()) { const size_t startpos{element.find_first_not_of(' ')}; if (element[startpos] == *element.end()) { continue; } const size_t length{element.find_last_not_of(' ') - startpos + 1}; vec.push_back(element.substr(startpos, length)); } } return vec; } vector get_tags() { cgicc::Cgicc cgi; vector tags_form; vector tags_string; cgi.getElement("tags[]", tags_form); for (const auto &element : tags_form) { const string tag{element.getValue()}; if (!tag.empty()) { const auto new_tags{string_to_vector(tolower(tag))}; tags_string.insert(tags_string.end(), std::make_move_iterator(new_tags.begin()), std::make_move_iterator(new_tags.end())); } } return tags_string; } string tolower(const string_view str) { string result; const auto unistr{icu::UnicodeString(str.data(), "UTF-8").toLower()}; unistr.toUTF8String(result); return result; } string text2html(string text) { static const map entities{{"<", "<"}, {">", ">"}}; static const map html{{"\r\n", "
"}}; for (const auto &replacementmap : {entities, html}) { for (const auto &repl : replacementmap) { size_t pos{0}; while ((pos = text.find(repl.first, pos)) != string::npos) { text.replace(pos, repl.first.size(), repl.second); pos += repl.second.size(); } } } return text; } } // namespace FediBlock::cgi