access tokenが取得できるように
This commit is contained in:
@@ -0,0 +1,237 @@
|
||||
#include "authenticate.h"
|
||||
#include "cocoatweet/util/util.h"
|
||||
#include <random>
|
||||
#include <ctime>
|
||||
#include <bitset>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <cocoatweet/exception/invalidParameterException.h>
|
||||
|
||||
extern "C" {
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/buffer.h>
|
||||
#include <curl/curl.h>
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
namespace CocoaTweet::Authentication {
|
||||
OAuth1::OAuth1() {
|
||||
method_ = AuthenticationMethod::OAUTH10A;
|
||||
}
|
||||
|
||||
OAuth1::OAuth1(const Key _key){
|
||||
key_ = _key;
|
||||
method_ = AuthenticationMethod::OAUTH10A;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> OAuth1::signature(
|
||||
const std::map<std::string, std::string>& _param, const std::string& _method,
|
||||
const std::string& _url) {
|
||||
std::vector<std::string> tmp;
|
||||
for (const auto& [key, value] : _param) {
|
||||
tmp.push_back(key + "=" + value);
|
||||
}
|
||||
|
||||
std::string query = CocoaTweet::Util::join(tmp, "&");
|
||||
|
||||
auto significateKey = key().consumerSecret() + "&" + key().accessTokenSecret();
|
||||
auto significateBase = _method + "&" + CocoaTweet::Util::urlEncode(_url) + "&" +
|
||||
CocoaTweet::Util::urlEncode(query);
|
||||
auto k64Sha1 = hmacSha1(significateKey, significateBase);
|
||||
|
||||
auto ret = std::map<std::string, std::string>{{"oauth_signature", k64Sha1}};
|
||||
return ret;
|
||||
}
|
||||
|
||||
const std::string OAuth1::calculateAuthHeader(std::map<std::string, std::string> _bodyParam,
|
||||
const std::string& _method,
|
||||
const std::string& _url) {
|
||||
auto authParam = oauthParam();
|
||||
auto sigingParam = authParam;
|
||||
if (!_bodyParam.empty()) {
|
||||
for (const auto [k, v] : _bodyParam) {
|
||||
sigingParam.insert_or_assign(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
auto sign = signature(sigingParam, _method, _url);
|
||||
|
||||
authParam.merge(sign);
|
||||
// ヘッダの構築
|
||||
std::string oauthHeader = "authorization: OAuth ";
|
||||
{
|
||||
std::vector<std::string> tmp;
|
||||
for (const auto& [key, value] : authParam) {
|
||||
tmp.push_back(key + "=" + CocoaTweet::Util::urlEncode(value));
|
||||
}
|
||||
oauthHeader += CocoaTweet::Util::join(tmp, ",");
|
||||
}
|
||||
|
||||
return oauthHeader;
|
||||
}
|
||||
|
||||
|
||||
// const std::string& OAuth1::generateBearerToken() {
|
||||
// auto signature = key_.consumerKey() + ":" + key_.consumerSecret();
|
||||
// auto k64Signature = base64(signature);
|
||||
// auto authHeader = std::string("Authorization: Basic ") + k64Signature;
|
||||
// auto contentType =
|
||||
// std::string("Content-Type: application/x-www-form-urlencoded;charset=UTF-8");
|
||||
// auto url = std::string("https://api.twitter.com/oauth2/token");
|
||||
// auto requestBody = std::string("grant_type=client_credentials");
|
||||
|
||||
// // do post
|
||||
// CURL* curl;
|
||||
// CURLcode res;
|
||||
// std::string rcv;
|
||||
// long responseCode;
|
||||
// curl = curl_easy_init();
|
||||
// if (curl) {
|
||||
// curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
// curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||
// curl_easy_setopt(curl, CURLOPT_POSTFIELDS, requestBody.c_str());
|
||||
// curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, requestBody.length());
|
||||
// curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
// curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlCallback_);
|
||||
// curl_easy_setopt(curl, CURLOPT_WRITEDATA, (std::string*)&rcv);
|
||||
// #ifndef NDEBUG
|
||||
// std::cout << "requestBody : " << requestBody << std::endl;
|
||||
// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
|
||||
// #endif
|
||||
// // Headerを保持するcurl_slist*を初期化
|
||||
// struct curl_slist* headers = NULL;
|
||||
// // Authorizationをヘッダに追加
|
||||
// headers = curl_slist_append(headers, authHeader.c_str());
|
||||
// headers = curl_slist_append(headers, contentType.c_str());
|
||||
// curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
// res = curl_easy_perform(curl);
|
||||
// curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
|
||||
// curl_easy_cleanup(curl);
|
||||
// }
|
||||
// if (res != CURLE_OK) {
|
||||
// throw std::runtime_error(std::string("INTERNAL ERROR : curl(") + std::to_string(res) + ")");
|
||||
// exit(1);
|
||||
// }
|
||||
|
||||
// auto j = nlohmann::json::parse(rcv);
|
||||
// if ((responseCode / 100) == 4) {
|
||||
// auto error = j["errors"][0]["code"];
|
||||
// auto message = j["errors"][0]["message"];
|
||||
// if (j.count("error") != 0) {
|
||||
// // この形式はエラーコードを持たないのでエラー種別が特定できない
|
||||
// throw new CocoaTweet::Exception::Exception(j["error"]);
|
||||
// }
|
||||
// if (error.get<int>() == 44) {
|
||||
// throw CocoaTweet::Exception::InvalidParameterException(
|
||||
// message.get<std::string>().c_str());
|
||||
// }
|
||||
// }
|
||||
|
||||
// key_.bearerToken(j["access_token"]);
|
||||
// authType_ = AuthType::Bearer;
|
||||
// return key_.bearerToken();
|
||||
// }
|
||||
|
||||
const std::string OAuth1::nonce() const {
|
||||
std::random_device engine;
|
||||
std::string nonceTable = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
std::uniform_int_distribution<std::size_t> dist(0, nonceTable.length() - 1);
|
||||
std::string nonce;
|
||||
|
||||
for (auto i = 0; i < 32; ++i) {
|
||||
nonce += nonceTable[dist(engine)];
|
||||
}
|
||||
|
||||
return nonce;
|
||||
}
|
||||
|
||||
const std::string OAuth1::timestamp() const {
|
||||
return std::to_string(time(nullptr));
|
||||
}
|
||||
|
||||
const std::string OAuth1::method() const {
|
||||
return "HMAC-SHA1";
|
||||
}
|
||||
|
||||
const std::string OAuth1::version() const {
|
||||
return "1.0";
|
||||
}
|
||||
|
||||
|
||||
std::map<std::string, std::string> OAuth1::oauthParam() const {
|
||||
auto tmp = std::map<std::string, std::string>{{"oauth_nonce", nonce()},
|
||||
{"oauth_signature_method", method()},
|
||||
{"oauth_timestamp", timestamp()},
|
||||
{"oauth_version", version()}};
|
||||
tmp.merge(key().noSecret());
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const std::string OAuth1::base64(const std::string& _raw) {
|
||||
auto base64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
std::stringstream ss;
|
||||
for (auto r : _raw) {
|
||||
ss << std::bitset<8>(r);
|
||||
}
|
||||
|
||||
if (_raw.length() % 3 == 1) {
|
||||
ss << "0000";
|
||||
} else if (_raw.length() % 3 == 2) {
|
||||
ss << "00";
|
||||
}
|
||||
|
||||
auto bin = ss.str();
|
||||
std::string base64 = "";
|
||||
for (auto i = 0; i < bin.length() / 6; i++) {
|
||||
base64 += base64Table[std::stoi(bin.substr(i * 6, 6), nullptr, 2)];
|
||||
}
|
||||
|
||||
if (base64.length() % 4 == 3) {
|
||||
base64 += "=";
|
||||
} else if (base64.length() % 4 == 2) {
|
||||
base64 += "==";
|
||||
} else if (base64.length() % 4 == 1) {
|
||||
base64 += "===";
|
||||
}
|
||||
|
||||
return base64;
|
||||
}
|
||||
|
||||
std::string OAuth1::hmacSha1(std::string _key, std::string _data) {
|
||||
unsigned char result[255];
|
||||
unsigned int length = 255;
|
||||
|
||||
HMAC(EVP_sha1(), reinterpret_cast<const unsigned char*>(_key.c_str()), _key.length(),
|
||||
reinterpret_cast<const unsigned char*>(_data.c_str()), _data.length(), result, &length);
|
||||
|
||||
auto sha1 = std::string(reinterpret_cast<char*>(result), length);
|
||||
|
||||
// base64 encodeもやっちゃえ日産
|
||||
BIO* encoder = BIO_new(BIO_f_base64());
|
||||
BIO* bmem = BIO_new(BIO_s_mem());
|
||||
encoder = BIO_push(encoder, bmem);
|
||||
BIO_write(encoder, sha1.c_str(), sha1.length());
|
||||
BIO_flush(encoder);
|
||||
|
||||
BUF_MEM* bptr;
|
||||
BIO_get_mem_ptr(encoder, &bptr);
|
||||
|
||||
char* k64 = (char*)std::malloc(bptr->length);
|
||||
std::memcpy(k64, bptr->data, bptr->length - 1);
|
||||
k64[bptr->length - 1] = 0;
|
||||
|
||||
BIO_free_all(encoder);
|
||||
|
||||
return static_cast<std::string>(k64);
|
||||
}
|
||||
|
||||
} // namespace CocoaTweet::Authentication
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef COCOATWEET_OAUTH_OAUTH_H_
|
||||
#define COCOATWEET_OAUTH_OAUTH_H_
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include "key.h"
|
||||
#include <cocoatweet/authentication/authenticator.h>
|
||||
|
||||
namespace CocoaTweet::Authentication {
|
||||
class OAuth1: public AuthenticatorBase {
|
||||
public:
|
||||
OAuth1();
|
||||
OAuth1(const Key _key);
|
||||
std::map<std::string, std::string> signature(const std::map<std::string, std::string>& _param,
|
||||
const std::string& _method,
|
||||
const std::string& _url);
|
||||
|
||||
// const std::string& generateBearerToken();
|
||||
|
||||
const std::string calculateAuthHeader(std::map<std::string, std::string> _bodyParam,
|
||||
const std::string& _method, const std::string& _url);
|
||||
|
||||
const std::string nonce() const;
|
||||
const std::string timestamp() const;
|
||||
const std::string method() const;
|
||||
const std::string version() const;
|
||||
std::map<std::string, std::string> oauthParam() const;
|
||||
std::string hmacSha1(std::string _key, std::string _data);
|
||||
const std::string base64(const std::string& _raw);
|
||||
|
||||
};
|
||||
} // namespace CocoaTweet::Authentication
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef COCOATWEET_AUTHENTICATION_AUTHENTICATORBASE_H
|
||||
#define COCOATWEET_AUTHENTICATION_AUTHENTICATORBASE_H
|
||||
|
||||
#include <cocoatweet/authentication/key.h>
|
||||
namespace CocoaTweet::Authentication{
|
||||
class AuthenticatorBase{
|
||||
public:
|
||||
enum class AuthenticationMethod{
|
||||
OAUTH10A,
|
||||
OAUTH2,
|
||||
PLAIN,
|
||||
NONE
|
||||
};
|
||||
|
||||
virtual const std::string calculateAuthHeader(std::map<std::string, std::string> _bodyParam,
|
||||
const std::string& _method, const std::string& _url) = 0;
|
||||
|
||||
const Key key() const{
|
||||
return key_;
|
||||
}
|
||||
|
||||
protected:
|
||||
AuthenticationMethod method_;
|
||||
Key key_;
|
||||
static size_t curlCallback_(char* _ptr, size_t _size, size_t _nmemb, std::string* _stream) {
|
||||
int realsize = _size * _nmemb;
|
||||
_stream->append(_ptr, realsize);
|
||||
return realsize;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "cocoatweet/authentication/key.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace CocoaTweet::Authentication {
|
||||
Key Key::fromJsonFile(const std::string _jsonFile) {
|
||||
std::ifstream ifs(_jsonFile);
|
||||
std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||
|
||||
auto j = nlohmann::json::parse(str);
|
||||
Key key;
|
||||
|
||||
key.authType(Key::AUTH_TYPE::OAUTH10A);
|
||||
|
||||
if (j.contains("consumer_key")) {
|
||||
key.consumerKey(j["consumer_key"].get<std::string>());
|
||||
}
|
||||
|
||||
if (j.contains("consumer_secret")) {
|
||||
key.consumerSecret(j["consumer_secret"].get<std::string>());
|
||||
}
|
||||
|
||||
if (j.contains("access_token")) {
|
||||
key.accessToken(j["access_token"].get<std::string>());
|
||||
}
|
||||
|
||||
if (j.contains("access_token_secret")) {
|
||||
key.accessTokenSecret(j["access_token_secret"].get<std::string>());
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
} // namespace CocoaTweet::Authentication
|
||||
@@ -0,0 +1,91 @@
|
||||
#ifndef COCOATWEET_OAUTH_KEY_H_
|
||||
#define COCOATWEET_OAUTH_KEY_H_
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace CocoaTweet::Authentication {
|
||||
class Key {
|
||||
public:
|
||||
enum AUTH_TYPE{
|
||||
OAUTH10A,
|
||||
OAUTH2,
|
||||
PLAIN
|
||||
};
|
||||
|
||||
private:
|
||||
std::string consumerKey_;
|
||||
std::string consumerSecret_;
|
||||
std::string accessToken_;
|
||||
std::string accessTokenSecret_;
|
||||
std::string bearerToken_;
|
||||
AUTH_TYPE authType_;
|
||||
public:
|
||||
Key() : consumerKey_(""), consumerSecret_(""), accessToken_(""), accessTokenSecret_("") {}
|
||||
Key(const std::string& _consumerKey, const std::string& _consumerSecret,
|
||||
const std::string& _accessToken, const std::string& _accessTokenSecret, const AUTH_TYPE _authType = AUTH_TYPE::OAUTH10A)
|
||||
: consumerKey_(_consumerKey),
|
||||
consumerSecret_(_consumerSecret),
|
||||
accessToken_(_accessToken),
|
||||
accessTokenSecret_(_accessTokenSecret), authType_(_authType) {}
|
||||
Key(const std::string& _consumerKey, const std::string& _consumerSecret, const AUTH_TYPE _authType = AUTH_TYPE::OAUTH2)
|
||||
: consumerKey_(_consumerKey), consumerSecret_(_consumerSecret), authType_(_authType){}
|
||||
|
||||
void consumerKey(const std::string& _consumerKey) {
|
||||
consumerKey_ = _consumerKey;
|
||||
}
|
||||
|
||||
void consumerSecret(const std::string& _consumerSecret) {
|
||||
consumerSecret_ = _consumerSecret;
|
||||
}
|
||||
|
||||
void accessToken(const std::string& _accessToken) {
|
||||
accessToken_ = _accessToken;
|
||||
}
|
||||
|
||||
void accessTokenSecret(const std::string& _accessTokenSecret) {
|
||||
accessTokenSecret_ = _accessTokenSecret;
|
||||
}
|
||||
|
||||
void bearerToken(const std::string& _bearer) {
|
||||
bearerToken_ = _bearer;
|
||||
}
|
||||
const std::string& consumerKey() const {
|
||||
return consumerKey_;
|
||||
}
|
||||
const std::string& consumerSecret() const {
|
||||
return consumerSecret_;
|
||||
}
|
||||
const std::string& accessToken() const {
|
||||
return accessToken_;
|
||||
}
|
||||
const std::string& accessTokenSecret() const {
|
||||
return accessTokenSecret_;
|
||||
}
|
||||
|
||||
const std::string& bearerToken() const {
|
||||
return bearerToken_;
|
||||
}
|
||||
|
||||
const AUTH_TYPE authType() const {
|
||||
return authType_;
|
||||
}
|
||||
|
||||
void authType(AUTH_TYPE _authType) {
|
||||
authType_ = _authType;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> noSecret() const {
|
||||
return std::map<std::string, std::string>{{"oauth_consumer_key", consumerKey_},
|
||||
{"oauth_token", accessToken_}};
|
||||
}
|
||||
const std::map<std::string, std::string> secret() const {
|
||||
return std::map<std::string, std::string>{{"oauth_consumer_key", consumerSecret_},
|
||||
{"oauth_token", accessTokenSecret_}};
|
||||
}
|
||||
|
||||
static Key fromJsonFile(const std::string _jsonFile);
|
||||
};
|
||||
} // namespace CocoaTweet::Authentication
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef COCOATWEET_AUTHENTICATION_PLAIN_H
|
||||
#define COCOATWEET_AUTHENTICATION_PLAIN_H
|
||||
|
||||
#include <cocoatweet/authentication/authenticator.h>
|
||||
|
||||
namespace CocoaTweet::Authentication{
|
||||
class Plain: public AuthenticatorBase {
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user