2020-06-29 06:10:40 +02:00
|
|
|
/* This file is part of FediBlock-backend.
|
|
|
|
* Copyright © 2020 tastytea <tastytea@tastytea.de>
|
|
|
|
*
|
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2020-06-29 05:21:23 +02:00
|
|
|
#include "cgi.hpp"
|
2020-11-15 20:30:42 +01:00
|
|
|
|
2020-07-01 01:41:07 +02:00
|
|
|
#include "files.hpp"
|
2020-06-29 23:15:14 +02:00
|
|
|
#include "fs-compat.hpp"
|
2020-07-05 08:01:30 +02:00
|
|
|
#include "time.hpp"
|
2020-06-29 05:21:23 +02:00
|
|
|
|
|
|
|
#include <cgicc/Cgicc.h>
|
2020-10-18 01:27:29 +02:00
|
|
|
#include <curl/curl.h>
|
2020-11-15 20:50:47 +01:00
|
|
|
#include <fmt/format.h>
|
2020-10-15 04:42:25 +02:00
|
|
|
#include <unicode/unistr.h>
|
2020-06-29 05:21:23 +02:00
|
|
|
|
2020-10-15 04:42:25 +02:00
|
|
|
#include <algorithm>
|
2020-07-05 08:01:30 +02:00
|
|
|
#include <chrono>
|
2020-06-29 22:37:09 +02:00
|
|
|
#include <fstream>
|
|
|
|
#include <ios>
|
2020-06-29 05:59:45 +02:00
|
|
|
#include <iostream>
|
2020-10-15 04:42:25 +02:00
|
|
|
#include <iterator>
|
2020-10-18 01:27:29 +02:00
|
|
|
#include <map>
|
2020-06-29 05:21:23 +02:00
|
|
|
#include <sstream>
|
2020-06-29 22:37:09 +02:00
|
|
|
#include <stdexcept>
|
2020-06-29 05:21:23 +02:00
|
|
|
#include <string>
|
2020-10-17 03:15:40 +02:00
|
|
|
#include <string_view>
|
2020-06-29 05:21:23 +02:00
|
|
|
#include <vector>
|
|
|
|
|
2020-07-01 20:51:35 +02:00
|
|
|
namespace FediBlock::cgi
|
2020-06-29 05:21:23 +02:00
|
|
|
{
|
|
|
|
|
2020-11-15 20:30:42 +01:00
|
|
|
using fmt::format;
|
2020-10-15 04:42:25 +02:00
|
|
|
using std::back_inserter;
|
2020-06-29 05:21:23 +02:00
|
|
|
using std::getline;
|
2020-06-29 22:37:09 +02:00
|
|
|
using std::ios;
|
2020-10-18 01:27:29 +02:00
|
|
|
using std::map;
|
2020-06-29 22:37:09 +02:00
|
|
|
using std::ofstream;
|
|
|
|
using std::runtime_error;
|
2020-06-29 05:21:23 +02:00
|
|
|
using std::string;
|
|
|
|
using std::string_view;
|
|
|
|
using std::stringstream;
|
2020-10-15 04:42:25 +02:00
|
|
|
using std::transform;
|
2020-06-29 05:21:23 +02:00
|
|
|
using std::vector;
|
2020-07-05 08:01:30 +02:00
|
|
|
using std::chrono::system_clock;
|
2020-06-29 05:21:23 +02:00
|
|
|
|
|
|
|
entry_type parse_formdata()
|
|
|
|
{
|
2020-06-29 07:05:04 +02:00
|
|
|
entry_type entry;
|
2020-06-29 22:37:09 +02:00
|
|
|
|
2020-07-02 03:20:27 +02:00
|
|
|
cgicc::Cgicc cgi;
|
|
|
|
entry.instance = cgi("instance");
|
|
|
|
entry.tags = string_to_vector(cgi("tags"));
|
2020-10-15 04:42:25 +02:00
|
|
|
transform(entry.tags.begin(), entry.tags.end(), entry.tags.begin(),
|
|
|
|
[](const auto &tag) { return tolower(tag); });
|
2020-07-02 03:20:27 +02:00
|
|
|
entry.receipts = string_to_vector(cgi("receipts"));
|
|
|
|
entry.description = cgi("description");
|
2020-07-05 08:01:30 +02:00
|
|
|
entry.report_time = time::to_string(system_clock::now());
|
2020-07-02 03:20:27 +02:00
|
|
|
|
2020-11-15 20:30:42 +01:00
|
|
|
for (const auto &screenshot : cgi.getFiles())
|
2020-07-02 03:20:27 +02:00
|
|
|
{
|
2020-11-15 21:30:19 +01:00
|
|
|
constexpr size_t size_limit{1024 * 512};
|
2020-11-15 20:30:42 +01:00
|
|
|
if (screenshot.getDataLength() > size_limit)
|
2020-06-29 22:37:09 +02:00
|
|
|
{
|
2020-11-15 20:30:42 +01:00
|
|
|
throw runtime_error{format("The screenshot “{0:s}” is too big. "
|
2020-11-15 21:30:19 +01:00
|
|
|
"The limit is {1:.1f} kilobyte (KiB).",
|
2020-11-15 20:30:42 +01:00
|
|
|
screenshot.getFilename(),
|
2020-11-15 21:30:19 +01:00
|
|
|
size_limit / 1024.0)};
|
2020-07-02 03:20:27 +02:00
|
|
|
}
|
2020-06-29 22:37:09 +02:00
|
|
|
|
2020-11-15 20:30:42 +01:00
|
|
|
const string filepath{files::get_tmpdir() / screenshot.getFilename()};
|
2020-07-02 03:20:27 +02:00
|
|
|
ofstream file{filepath, ios::binary};
|
|
|
|
if (!file.good())
|
|
|
|
{
|
|
|
|
throw runtime_error{"Could not open temporary file: " + filepath};
|
2020-06-29 22:37:09 +02:00
|
|
|
}
|
2020-11-15 20:30:42 +01:00
|
|
|
screenshot.writeToStream(file);
|
|
|
|
entry.screenshot_filepaths.push_back(filepath);
|
2020-06-29 05:21:23 +02:00
|
|
|
}
|
|
|
|
|
2020-06-29 07:05:04 +02:00
|
|
|
return entry;
|
2020-06-29 05:21:23 +02:00
|
|
|
}
|
|
|
|
|
2020-06-29 07:05:04 +02:00
|
|
|
vector<string> string_to_vector(const string_view str)
|
2020-06-29 05:21:23 +02:00
|
|
|
{
|
2020-06-29 07:05:04 +02:00
|
|
|
vector<string> vec;
|
2020-06-29 05:21:23 +02:00
|
|
|
|
2020-07-02 03:20:27 +02:00
|
|
|
stringstream input{str.data()};
|
2020-06-29 08:38:27 +02:00
|
|
|
string element;
|
2020-06-29 05:59:45 +02:00
|
|
|
|
2020-06-29 08:38:27 +02:00
|
|
|
while (getline(input, element, ','))
|
2020-06-29 05:21:23 +02:00
|
|
|
{
|
2020-06-30 07:33:15 +02:00
|
|
|
if (!element.empty())
|
|
|
|
{
|
2020-07-14 17:19:52 +02:00
|
|
|
const size_t startpos{element.find_first_not_of(' ')};
|
2020-10-19 07:54:04 +02:00
|
|
|
if (element[startpos] == *element.end())
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2020-07-14 17:19:52 +02:00
|
|
|
const size_t length{element.find_last_not_of(' ') - startpos + 1};
|
|
|
|
vec.push_back(element.substr(startpos, length));
|
2020-06-30 07:33:15 +02:00
|
|
|
}
|
2020-06-29 05:21:23 +02:00
|
|
|
}
|
|
|
|
|
2020-06-29 07:05:04 +02:00
|
|
|
return vec;
|
2020-06-29 05:21:23 +02:00
|
|
|
}
|
|
|
|
|
2020-10-15 04:42:25 +02:00
|
|
|
vector<string> get_tags()
|
|
|
|
{
|
|
|
|
cgicc::Cgicc cgi;
|
|
|
|
vector<cgicc::FormEntry> tags_form;
|
|
|
|
vector<string> tags_string;
|
|
|
|
|
|
|
|
cgi.getElement("tags[]", tags_form);
|
2020-10-16 23:52:08 +02:00
|
|
|
for (const auto &element : tags_form)
|
|
|
|
{
|
2020-10-17 03:15:40 +02:00
|
|
|
const string tag{element.getValue()};
|
2020-10-16 23:52:08 +02:00
|
|
|
if (!tag.empty())
|
|
|
|
{
|
2020-10-19 07:56:24 +02:00
|
|
|
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()));
|
2020-10-16 23:52:08 +02:00
|
|
|
}
|
|
|
|
}
|
2020-10-15 04:42:25 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-10-18 01:27:29 +02:00
|
|
|
string text2html(string text)
|
|
|
|
{
|
|
|
|
static const map<string_view, string_view> entities{{"<", "<"},
|
|
|
|
{">", ">"}};
|
|
|
|
static const map<string_view, string_view> html{{"\r\n", "<br>"}};
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2020-07-01 20:51:35 +02:00
|
|
|
} // namespace FediBlock::cgi
|