From fec50bc14620e924250516043e997099f5e01f6e Mon Sep 17 00:00:00 2001 From: tastytea Date: Fri, 9 Feb 2018 22:19:25 +0100 Subject: [PATCH] app registering support --- CMakeLists.txt | 2 +- README.md | 5 +- src/examples/example7_register_app.cpp | 70 ++++++++++++++++++ src/mastodon-cpp.cpp | 99 +++++++++++++++++++++----- src/mastodon-cpp.hpp | 19 +++-- 5 files changed, 170 insertions(+), 25 deletions(-) create mode 100644 src/examples/example7_register_app.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c360164..b0c057b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 3.7) include(GNUInstallDirs) project (mastodon-cpp - VERSION 0.2.11 + VERSION 0.2.12 LANGUAGES CXX ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") diff --git a/README.md b/README.md index 93f7f36..387084c 100644 --- a/README.md +++ b/README.md @@ -93,12 +93,11 @@ If you use a debug build, you get more verbose error messages. * [x] Implement all PUT calls * [x] Implement all DELETE calls * Version 0.3.0 - * [ ] Handle HTTP statuses 301 & 302 - * [ ] Support registering as an application + * [x] Handle HTTP statuses 301 & 302 + * [x] Support registering as an application * Later * [ ] Asynchronous I/O * [ ] Handle X-RateLimit header - * [ ] Find out why the "short read" error occurs with PATCH and POST ## Status of implementation diff --git a/src/examples/example7_register_app.cpp b/src/examples/example7_register_app.cpp new file mode 100644 index 0000000..b4edd7b --- /dev/null +++ b/src/examples/example7_register_app.cpp @@ -0,0 +1,70 @@ +/* This file is part of mastodon-cpp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../mastodon-cpp.hpp" + +using Mastodon::API; + +int main(int argc, char *argv[]) +{ + if (argc < 2) + { + std::cerr << "usage: " << argv[0] << " \n"; + return 1; + } + + Mastodon::API masto(argv[1], ""); + masto.set_useragent("mastodon-cpp-example/1.3.3.7"); + + std::string answer; + std::uint16_t ret; + std::string client_id, client_secret, url; + + ret = masto.register_app1(argv[1], + "test123", + "urn:ietf:wg:oauth:2.0:oob", + "read follow", + "", + client_id, + client_secret, + url); + if (ret == 0) + { + std::cout << "Visit " << url << " to get the code.\n"; + + std::string code; + std::cout << "Insert code: "; + std::cin >> code; + + std::string access_token; + masto.register_app2(argv[1], + client_id, + client_secret, + "urn:ietf:wg:oauth:2.0:oob", + code, + access_token); + if (ret == 0) + { + std::cout << "Success!\nAccess-token: " << access_token << '\n'; + } + else + { + std::cerr << "Error code: " << ret << '\n'; + return ret; + } + } + else + { + std::cerr << "Error code: " << ret << '\n'; + return ret; + } + + return 0; +} diff --git a/src/mastodon-cpp.cpp b/src/mastodon-cpp.cpp index 35d0f40..0115f8b 100644 --- a/src/mastodon-cpp.cpp +++ b/src/mastodon-cpp.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include "version.hpp" @@ -149,21 +150,87 @@ const curlpp::Forms API::maptoformdata(const parametermap &map) return formdata; } -// const string API::register_app(const std::string &instance, -// const std::string &client_name, -// const std::string &redirect_uris, -// const std::string &scopes, -// const std::string &website) -// { -// API::parametermap parameters = -// { -// { "client_name", { client_name } }, -// { "redirect_uris", { redirect_uris } }, -// { "scopes", { scopes } }, -// { "website", { website } } -// }; +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) +{ + 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); + 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(); + + url = "https://" + instance + "/oauth/authorize" + + "?scope=" + urlencode(scopes) + "&response_type=code" + + "&redirect_uri=" + urlencode(redirect_uri) + + "&client_id=" + client_id; + if (!website.empty()) + { + url += "&website=" + website; + } + + return 0; + } + else + { + std::cerr << "Error code: " << ret << '\n'; + return ret; + } -// } +} + +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) +{ + 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(); + + return 0; + } + else + { + std::cerr << "Error code: " << ret << '\n'; + return ret; + } +} diff --git a/src/mastodon-cpp.hpp b/src/mastodon-cpp.hpp index 61c1964..1a43423 100644 --- a/src/mastodon-cpp.hpp +++ b/src/mastodon-cpp.hpp @@ -169,11 +169,20 @@ public: */ const std::string urlencode(const std::string &str) const; - // const std::string register_app(const std::string &instance, - // const std::string &client_name, - // const std::string &redirect_uris, - // const std::string &scopes, - // const std::string &website = ""); + const std::uint16_t register_app1(const std::string &instance, + const std::string &client_name, + const std::string &redirect_uri, + const std::string &scopes, + const std::string &website, + std::string &client_id, + std::string &client_secret, + std::string &url); + const std::uint16_t register_app2(const std::string &instance, + const std::string &client_id, + const std::string &client_secret, + const std::string &redirect_uri, + const std::string &code, + std::string &access_token); /*! * @brief Make a GET request which doesn't require an argument.