2018-01-06 21:33:52 +01:00
|
|
|
/* This file is part of mastodon-cpp.
|
|
|
|
* Copyright © 2018 tastytea <tastytea@tastytea.de>
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU 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 General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2018-01-09 22:12:11 +01:00
|
|
|
#include <string>
|
2018-01-15 20:23:21 +01:00
|
|
|
#include <map>
|
|
|
|
#include <vector>
|
2018-02-09 16:01:24 +01:00
|
|
|
#include <sstream>
|
2018-02-09 22:19:25 +01:00
|
|
|
#include <regex>
|
2018-02-09 16:01:24 +01:00
|
|
|
#include <curlpp/cURLpp.hpp>
|
|
|
|
#include <curlpp/Easy.hpp>
|
2018-01-09 22:12:11 +01:00
|
|
|
#include "version.hpp"
|
2018-01-15 20:23:21 +01:00
|
|
|
#include "macros.hpp"
|
2018-01-06 21:33:52 +01:00
|
|
|
#include "mastodon-cpp.hpp"
|
|
|
|
|
2018-01-15 20:23:21 +01:00
|
|
|
#include <iostream>
|
|
|
|
|
2018-01-09 22:12:11 +01:00
|
|
|
using namespace Mastodon;
|
|
|
|
using std::string;
|
2018-01-06 21:33:52 +01:00
|
|
|
|
2018-01-09 22:12:11 +01:00
|
|
|
API::API(const string &instance, const string &access_token)
|
|
|
|
: _instance(instance)
|
|
|
|
, _access_token(access_token)
|
|
|
|
, _useragent(string("mastodon-cpp/") + global::version)
|
2018-01-10 18:19:19 +01:00
|
|
|
, _http(*this, instance, access_token)
|
2018-01-06 21:33:52 +01:00
|
|
|
{
|
2018-01-09 22:12:11 +01:00
|
|
|
//
|
|
|
|
}
|
|
|
|
|
|
|
|
const void API::set_useragent(const std::string &useragent)
|
|
|
|
{
|
|
|
|
_useragent = useragent;
|
2018-01-06 21:33:52 +01:00
|
|
|
}
|
2018-01-10 18:19:19 +01:00
|
|
|
|
2018-01-15 20:23:21 +01:00
|
|
|
const string API::get_useragent() const
|
2018-01-10 18:19:19 +01:00
|
|
|
{
|
|
|
|
return _useragent;
|
|
|
|
}
|
2018-01-15 20:23:21 +01:00
|
|
|
|
|
|
|
const string API::maptostr(const parametermap &map, const bool &firstparam)
|
|
|
|
{
|
|
|
|
string result = "";
|
|
|
|
char delim = '?';
|
|
|
|
if (!firstparam)
|
|
|
|
{
|
|
|
|
delim = '&';
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto &it : map)
|
|
|
|
{
|
|
|
|
if (it.second.size() == 1)
|
|
|
|
{
|
2018-02-22 03:04:15 +01:00
|
|
|
result += (delim + it.first + "=" + curlpp::escape(it.second.front()));
|
2018-01-15 20:23:21 +01:00
|
|
|
if (delim == '?')
|
|
|
|
{
|
|
|
|
delim = '&';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (const string &str : it.second)
|
|
|
|
{
|
2018-02-22 03:04:15 +01:00
|
|
|
result += (delim + it.first + "[]=" + curlpp::escape(str));
|
2018-01-15 20:23:21 +01:00
|
|
|
if (delim == '?')
|
|
|
|
{
|
|
|
|
delim = '&';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ttdebug << "Constructed parameter string: " << result << '\n';
|
|
|
|
return result;
|
|
|
|
}
|
2018-02-09 16:01:24 +01:00
|
|
|
|
|
|
|
const curlpp::Forms API::maptoformdata(const parametermap &map)
|
2018-01-17 23:51:59 +01:00
|
|
|
{
|
2018-02-09 16:01:24 +01:00
|
|
|
curlpp::Forms formdata;
|
|
|
|
|
2018-01-21 23:54:42 +01:00
|
|
|
if (map.size() == 0)
|
|
|
|
{
|
2018-02-09 16:01:24 +01:00
|
|
|
return formdata;
|
2018-01-21 23:54:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto &it : map)
|
2018-01-17 23:51:59 +01:00
|
|
|
{
|
2018-01-21 23:54:42 +01:00
|
|
|
if (it.second.size() == 1)
|
2018-02-09 20:14:50 +01:00
|
|
|
{ // If the file is not base64-encoded, treat as filename
|
|
|
|
if ((it.first == "avatar" ||
|
|
|
|
it.first == "header" ||
|
|
|
|
it.first == "file") &&
|
|
|
|
it.second.front().substr(0, 4).compare("data") != 0)
|
|
|
|
{
|
|
|
|
ttdebug << it.first << ": Filename detected.\n";
|
|
|
|
formdata.push_back(
|
|
|
|
new curlpp::FormParts::File(it.first, it.second.front()));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
formdata.push_back(
|
|
|
|
new curlpp::FormParts::Content(it.first, it.second.front()));
|
|
|
|
}
|
2018-01-22 02:09:44 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (const string &str : it.second)
|
|
|
|
{
|
2018-02-09 16:01:24 +01:00
|
|
|
formdata.push_back(new curlpp::FormParts::Content(it.first + "[]",
|
|
|
|
str));
|
2018-01-22 02:09:44 +01:00
|
|
|
}
|
2018-01-17 23:51:59 +01:00
|
|
|
}
|
|
|
|
}
|
2018-01-21 23:54:42 +01:00
|
|
|
|
2018-02-09 16:01:24 +01:00
|
|
|
return formdata;
|
2018-01-17 23:51:59 +01:00
|
|
|
}
|
2018-02-05 14:56:16 +01:00
|
|
|
|
2018-02-28 07:51:49 +01:00
|
|
|
const std::string API::urlencode(const std::string &str) const
|
|
|
|
{
|
|
|
|
return curlpp::escape(str);
|
|
|
|
}
|
|
|
|
|
2018-02-09 22:19:25 +01:00
|
|
|
const std::uint16_t API::register_app1(const string &instance,
|
|
|
|
const string &client_name,
|
|
|
|
const string &redirect_uri,
|
|
|
|
const string &scopes,
|
|
|
|
const string &website,
|
|
|
|
string &client_id,
|
|
|
|
string &client_secret,
|
|
|
|
string &url)
|
2018-02-28 07:00:24 +01:00
|
|
|
{
|
2018-02-28 07:54:31 +01:00
|
|
|
return register_app1(client_name, redirect_uri, scopes, website,
|
2018-02-28 07:00:24 +01:00
|
|
|
client_id, client_secret, url);
|
|
|
|
}
|
|
|
|
const std::uint16_t API::register_app1(const string &client_name,
|
|
|
|
const string &redirect_uri,
|
|
|
|
const string &scopes,
|
|
|
|
const string &website,
|
|
|
|
string &client_id,
|
|
|
|
string &client_secret,
|
|
|
|
string &url)
|
2018-02-09 22:19:25 +01:00
|
|
|
{
|
|
|
|
API::parametermap parameters =
|
|
|
|
{
|
|
|
|
{ "client_name", { client_name } },
|
|
|
|
{ "redirect_uris", { redirect_uri } },
|
|
|
|
{ "scopes", { scopes } },
|
|
|
|
{ "website", { website } }
|
|
|
|
};
|
|
|
|
|
|
|
|
string answer;
|
|
|
|
std::uint16_t ret = post(API::v1::apps, parameters, answer);
|
|
|
|
|
|
|
|
if (ret == 0)
|
|
|
|
{
|
|
|
|
std::smatch match;
|
|
|
|
std::regex reid("client_id\":\"([0-9a-fA-F]+)\"");
|
|
|
|
std::regex resecret("client_secret\":\"([0-9a-fA-F]+)\"");
|
|
|
|
|
|
|
|
std::regex_search(answer, match, reid);
|
|
|
|
client_id = match[1].str();
|
|
|
|
std::regex_search(answer, match, resecret);
|
|
|
|
client_secret = match[1].str();
|
|
|
|
|
2018-02-28 07:00:24 +01:00
|
|
|
url = "https://" + _instance + "/oauth/authorize" +
|
2018-02-22 03:04:15 +01:00
|
|
|
"?scope=" + curlpp::escape(scopes) + "&response_type=code" +
|
|
|
|
"&redirect_uri=" + curlpp::escape(redirect_uri) +
|
2018-02-09 22:19:25 +01:00
|
|
|
"&client_id=" + client_id;
|
|
|
|
if (!website.empty())
|
|
|
|
{
|
|
|
|
url += "&website=" + website;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2018-02-28 22:37:30 +01:00
|
|
|
else if (ret == 13)
|
2018-02-17 20:01:51 +01:00
|
|
|
{
|
|
|
|
url = answer;
|
|
|
|
return ret;
|
|
|
|
}
|
2018-02-09 22:19:25 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cerr << "Error code: " << ret << '\n';
|
|
|
|
return ret;
|
|
|
|
}
|
2018-02-05 14:56:16 +01:00
|
|
|
|
2018-02-09 22:19:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const std::uint16_t API::register_app2(const string &instance,
|
|
|
|
const string &client_id,
|
|
|
|
const string &client_secret,
|
|
|
|
const string &redirect_uri,
|
|
|
|
const string &code,
|
|
|
|
string &access_token)
|
2018-02-28 07:00:24 +01:00
|
|
|
{
|
2018-02-28 07:54:31 +01:00
|
|
|
return register_app2(client_id, client_secret, redirect_uri, code, access_token);
|
2018-02-28 07:00:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const std::uint16_t API::register_app2(const string &client_id,
|
|
|
|
const string &client_secret,
|
|
|
|
const string &redirect_uri,
|
|
|
|
const string &code,
|
|
|
|
string &access_token)
|
2018-02-09 22:19:25 +01:00
|
|
|
{
|
|
|
|
API::parametermap parameters =
|
|
|
|
{
|
|
|
|
{ "client_id", { client_id } },
|
|
|
|
{ "client_secret", { client_secret } },
|
|
|
|
{ "grant_type", { "authorization_code" } },
|
|
|
|
{ "redirect_uri", { redirect_uri } },
|
|
|
|
{ "code", { code } },
|
|
|
|
};
|
|
|
|
|
|
|
|
std::string answer;
|
|
|
|
std::uint16_t ret = post("/oauth/token", parameters, answer);
|
|
|
|
if (ret == 0)
|
|
|
|
{
|
|
|
|
std::smatch match;
|
|
|
|
std::regex retoken("access_token\":\"([0-9a-fA-F]+)\"");
|
|
|
|
|
|
|
|
std::regex_search(answer, match, retoken);
|
|
|
|
access_token = match[1].str();
|
2018-02-11 12:26:42 +01:00
|
|
|
_access_token = access_token;
|
2018-02-09 22:19:25 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::cerr << "Error code: " << ret << '\n';
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2018-02-25 23:20:02 +01:00
|
|
|
|
|
|
|
const string API::get_header(const std::string &header) const
|
|
|
|
{
|
|
|
|
string headers;
|
|
|
|
_http.get_headers(headers);
|
|
|
|
size_t startpos = headers.find(header);
|
|
|
|
if (startpos != std::string::npos)
|
|
|
|
{
|
|
|
|
startpos = headers.find(':', startpos) + 2;
|
|
|
|
size_t endpos = headers.find("\r\n", startpos);
|
|
|
|
return headers.substr(startpos, endpos - startpos);
|
|
|
|
}
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|