Files
CocoaTweet/src/cocoatweet/oauth/oauth.cc
T
keita 68d6d478c6 statuses/destroyを叩くやつを反映した
また,CocoaTweet::Util::join()を使用するようにした
2021-02-18 18:38:01 +09:00

154 lines
4.2 KiB
C++

#include "oauth.h"
#include "cocoatweet/util/util.h"
#include <random>
#include <ctime>
#include <bitset>
#include <sstream>
#include <string>
#include <cstring>
#include <iterator>
#include <iostream>
extern "C" {
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <openssl/buffer.h>
}
namespace CocoaTweet::OAuth {
OAuth1::OAuth1() {}
OAuth1::OAuth1(const Key _key) : key_(_key) {}
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::cout << (key + "=" + value) << std::endl;
}
//std::ostringstream os;
//std::copy(tmp.begin(), tmp.end(), std::ostream_iterator<std::string>(os, "&"));
//std::string query = os.str();
/*std::string query = "";
for(auto v : tmp){
query += (v + "&");
}
if(!query.empty()){
query.pop_back();
}*/
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);
std::cout << "significate key : " << significateKey << std::endl;
std::cout << "significate base : " << significateBase << std::endl;
std::cout << "hmac-sha1 : " << k64Sha1 << std::endl;
auto ret = std::map<std::string, std::string>{{"oauth_signature", k64Sha1}};
return ret;
}
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 SIGNATURE_METHOD_;
}
const std::string OAuth1::version() const {
return OAUTH_VERSION_;
}
const Key OAuth1::key() const {
return key_;
}
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::OAuth