Add Instance::ObtainToken.
This commit is contained in:
parent
deeffc5adf
commit
02b0b05aa1
|
@ -192,6 +192,84 @@ public:
|
|||
return _cainfo;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Simplifies obtaining an OAuth 2.0 Bearer Access Token.
|
||||
*
|
||||
* * Create an Instance() and initialize this class with it.
|
||||
* * Call step_1() to get the URI your user has to visit.
|
||||
* * Get the authorization code from your user.
|
||||
* * Call step_2() with the code.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* mastodonpp::Instance instance("example.com", {});
|
||||
* mastodonpp::Instance::ObtainToken token(instance);
|
||||
* auto answer{token.step1("Good program", "read:blocks read:mutes", "")};
|
||||
* if (answer)
|
||||
* {
|
||||
* std::cout << "Please visit " << answer << "\nand paste the code: ";
|
||||
* std::string code;
|
||||
* std::cin >> code;
|
||||
* answer = access_token{token.step2(code)};
|
||||
* if (answer)
|
||||
* {
|
||||
* std::cout << "Success!\n";
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @since 0.3.0
|
||||
*/
|
||||
class ObtainToken : public CURLWrapper
|
||||
{
|
||||
public:
|
||||
ObtainToken(Instance &instance);
|
||||
|
||||
/*!
|
||||
* @brief Creates an application via `/api/v1/apps`.
|
||||
*
|
||||
* The `body` of the returned @link answer_type answer @endlink
|
||||
* contains only the URI, not the whole JSON response.
|
||||
*
|
||||
* @param client_name The name of your application.
|
||||
* @param scopes Space separated list of scopes. Defaults to
|
||||
* “read” if empty.
|
||||
* @param website The URI to the homepage of your application. Can
|
||||
* be an empty string.
|
||||
*
|
||||
* @return The URI your user has to visit.
|
||||
*
|
||||
* @since 0.3.0
|
||||
*/
|
||||
[[nodiscard]]
|
||||
answer_type step_1(string_view client_name, string_view scopes,
|
||||
string_view website);
|
||||
|
||||
/*!
|
||||
* @brief Creates a token via `/oauth/token`.
|
||||
*
|
||||
* The `body` of the returned @link answer_type answer @endlink
|
||||
* contains only the access token, not the whole JSON response.
|
||||
*
|
||||
* The access token will be set in the parent Instance.
|
||||
*
|
||||
* @param code The authorization code you got from the user.
|
||||
*
|
||||
* @return The access token.
|
||||
*
|
||||
* @since 0.3.0
|
||||
*/
|
||||
[[nodiscard]]
|
||||
answer_type step_2(string_view code);
|
||||
|
||||
private:
|
||||
Instance &_instance;
|
||||
const string _baseuri;
|
||||
string _scopes;
|
||||
string _client_id;
|
||||
string _client_secret;
|
||||
};
|
||||
|
||||
private:
|
||||
const string _hostname;
|
||||
const string _baseuri;
|
||||
|
|
118
src/instance.cpp
118
src/instance.cpp
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <regex>
|
||||
|
||||
namespace mastodonpp
|
||||
{
|
||||
|
@ -27,6 +28,9 @@ namespace mastodonpp
|
|||
using std::sort;
|
||||
using std::stoull;
|
||||
using std::exception;
|
||||
using std::regex;
|
||||
using std::regex_search;
|
||||
using std::smatch;
|
||||
|
||||
Instance::Instance(const string_view hostname, const string_view access_token)
|
||||
: _hostname{hostname}
|
||||
|
@ -158,24 +162,108 @@ vector<string> Instance::get_post_formats() noexcept
|
|||
return _post_formats;
|
||||
}
|
||||
|
||||
Instance::ObtainToken::ObtainToken(Instance &instance)
|
||||
: _instance{instance}
|
||||
, _baseuri{instance.get_baseuri()}
|
||||
{
|
||||
auto proxy{_instance.get_proxy()};
|
||||
if (!proxy.empty())
|
||||
{
|
||||
debuglog << "Couldn't find metadata.postFormats.\n";
|
||||
_post_formats = {default_value};
|
||||
return _post_formats;
|
||||
}
|
||||
pos += searchstring.size();
|
||||
auto endpos{answer.body.find("],", pos)};
|
||||
string formats{answer.body.substr(pos, endpos - pos)};
|
||||
debuglog << "Extracted postFormats: " << formats << '\n';
|
||||
|
||||
while ((pos = formats.find('"', 1)) != string::npos)
|
||||
{
|
||||
_post_formats.push_back(formats.substr(1, pos - 1));
|
||||
formats.erase(0, pos + 2); // 2 is the length of: ",
|
||||
debuglog << "Found postFormat: " << _post_formats.back() << '\n';
|
||||
CURLWrapper::set_proxy(proxy);
|
||||
}
|
||||
|
||||
return _post_formats;
|
||||
if (!_instance.get_access_token().empty())
|
||||
{
|
||||
CURLWrapper::set_access_token(_instance.get_access_token());
|
||||
}
|
||||
if (!_instance.get_cainfo().empty())
|
||||
{
|
||||
CURLWrapper::set_cainfo(_instance.get_cainfo());
|
||||
}
|
||||
}
|
||||
|
||||
answer_type Instance::ObtainToken::step_1(const string_view client_name,
|
||||
const string_view scopes,
|
||||
const string_view website)
|
||||
{
|
||||
parametermap parameters
|
||||
{
|
||||
{"client_name", client_name},
|
||||
{"redirect_uris", "urn:ietf:wg:oauth:2.0:oob"}
|
||||
};
|
||||
if (!scopes.empty())
|
||||
{
|
||||
_scopes = scopes;
|
||||
parameters.insert({"scopes", scopes});
|
||||
}
|
||||
if (!website.empty())
|
||||
{
|
||||
parameters.insert({"website", website});
|
||||
}
|
||||
|
||||
auto answer{make_request(http_method::POST, _baseuri + "/api/v1/apps",
|
||||
parameters)};
|
||||
if (answer)
|
||||
{
|
||||
const regex re_id{R"("client_id"\s*:\s*"([^"]+)\")"};
|
||||
const regex re_secret{R"("client_secret"\s*:\s*"([^"]+)\")"};
|
||||
smatch match;
|
||||
|
||||
if (regex_search(answer.body, match, re_id))
|
||||
{
|
||||
_client_id = match[1].str();
|
||||
}
|
||||
if (regex_search(answer.body, match, re_secret))
|
||||
{
|
||||
_client_secret = match[1].str();
|
||||
}
|
||||
|
||||
string uri{_baseuri + "/oauth/authorize?scope=" + escape_url(scopes)
|
||||
+ "&response_type=code"
|
||||
"&redirect_uri=" + escape_url("urn:ietf:wg:oauth:2.0:oob")
|
||||
+ "&client_id=" + _client_id};
|
||||
if (!website.empty())
|
||||
{
|
||||
uri += "&website=" + escape_url(website);
|
||||
}
|
||||
answer.body = uri;
|
||||
debuglog << "Built URI.";
|
||||
}
|
||||
|
||||
return answer;
|
||||
}
|
||||
|
||||
answer_type Instance::ObtainToken::step_2(const string_view code)
|
||||
{
|
||||
parametermap parameters
|
||||
{
|
||||
{"client_id", _client_id},
|
||||
{"client_secret", _client_secret},
|
||||
{"redirect_uri", "urn:ietf:wg:oauth:2.0:oob"},
|
||||
{"code", code},
|
||||
{"grant_type", "client_credentials"}
|
||||
};
|
||||
if (!_scopes.empty())
|
||||
{
|
||||
parameters.insert({"scope", _scopes});
|
||||
}
|
||||
|
||||
auto answer{make_request(http_method::POST, _baseuri + "/oauth/token",
|
||||
parameters)};
|
||||
if (answer)
|
||||
{
|
||||
const regex re_token{R"("access_token"\s*:\s*"([^"]+)\")"};
|
||||
smatch match;
|
||||
|
||||
if (regex_search(answer.body, match, re_token))
|
||||
{
|
||||
answer.body = match[1].str();
|
||||
debuglog << "Got access token.\n";
|
||||
_instance.set_access_token(answer.body);
|
||||
}
|
||||
}
|
||||
|
||||
return answer;
|
||||
}
|
||||
|
||||
} // namespace mastodonpp
|
||||
|
|
Loading…
Reference in New Issue
Block a user