Skip to content

Commit

Permalink
implements signin with GitHub
Browse files Browse the repository at this point in the history
  • Loading branch information
melpon committed Jun 24, 2017
1 parent a5f0471 commit c6b5792
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 1 deletion.
3 changes: 2 additions & 1 deletion kennel2/configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ if test "x$with_cppdb_lib" != x; then
cppdblibs="-L$with_cppdb_lib"
fi

AC_CHECK_LIB([curl], [curl_easy_init], [], [AC_MSG_ERROR([missing curl function])])
AC_CHECK_LIB([pcre], [pcre_compile], [], [AC_MSG_ERROR([missing pcre function])])
AC_CHECK_LIB([pthread], [pthread_create], [], [AC_MSG_ERROR([missing pthread function])])
AC_CHECK_LIB([sqlite3], [sqlite3_open_v2], [], [AC_MSG_ERROR([missing sqlite3 function])])
Expand All @@ -77,7 +78,7 @@ AC_CHECK_LIB([dl], [dlopen], [], [AC_MSG_ERROR([missing dl function])])

CXXFLAGS="$CXXFLAGS $cppcmsinc $cppdbinc"
CRYPT="-lgcrypt"
DEFAULT_LIBS="$LIBS $cppcmslibs $cppdblibs $cppcmslibnames $cppdblibnames -Wl,-Bstatic -lsqlite3 -Wl,-Bdynamic -lpcre -lz -lpthread -ldl"
DEFAULT_LIBS="$LIBS $cppcmslibs $cppdblibs $cppcmslibnames $cppdblibnames -Wl,-Bstatic -lsqlite3 -Wl,-Bdynamic -lpcre -lz -lpthread -ldl -lcurl"
LIBS="$DEFAULT_LIBS"
LDFLAGS="$LDFLAGS $cppcmsrpath $cppdbrpath"

Expand Down
7 changes: 7 additions & 0 deletions kennel2/kennel.json.in
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,11 @@
, "cache" :
{ "backend": "process_shared"
}
, "session" :
{ "location": "client"
, "client":
{ "encryptor": "aes"
, "key_file": ".session.key"
}
}
}
114 changes: 114 additions & 0 deletions kennel2/src/http_client.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#ifndef HTTP_CLIENT_H_INCLUDED
#define HTTP_CLIENT_H_INCLUDED

#include <string>
#include <vector>
#include <curl/curl.h>

struct http_client {
struct response {
long status_code;
std::string body;
// implements if needed
// std::map<std::string, std::string> headers;
};

static size_t receive_callback(void* contents, size_t size, size_t nmemb, void* userp) {
std::string& resp = *(std::string*)userp;

std::size_t realsize = size * nmemb;
resp.append((const char*)contents, realsize);

return realsize;
}

static http_client::response post(std::string url, std::vector<std::string> headers, std::string body) {
struct context {
CURL* curl;
curl_slist* chunk;
context() : curl(nullptr), chunk(nullptr) {}
~context() {
if (curl != nullptr) curl_easy_cleanup(curl);
if (chunk != nullptr) curl_slist_free_all(chunk);
}
} ctx;

ctx.curl = curl_easy_init();

// set url
curl_easy_setopt(ctx.curl, CURLOPT_URL, url.c_str());

// set body
curl_easy_setopt(ctx.curl, CURLOPT_POSTFIELDS, body.c_str());
curl_easy_setopt(ctx.curl, CURLOPT_POSTFIELDSIZE, body.size());

// set header
for (auto&& header: headers) {
ctx.chunk = curl_slist_append(ctx.chunk, header.c_str());
}
curl_easy_setopt(ctx.curl, CURLOPT_HTTPHEADER, ctx.chunk);

// set response callback
std::string resp_body;
curl_easy_setopt(ctx.curl, CURLOPT_WRITEFUNCTION, receive_callback);
curl_easy_setopt(ctx.curl, CURLOPT_WRITEDATA, &resp_body);

CURLcode curl_code = curl_easy_perform(ctx.curl);
if (curl_code != CURLE_OK) {
throw std::exception();
}

long status_code = 0;
curl_easy_getinfo(session, CURLINFO_RESPONSE_CODE, &status_code);

response r;
r.status_code = status_code;
r.body = resp_body;

return r;
}

static http_client::response get(std::string url, std::vector<std::string> headers) {
struct context {
CURL* curl;
curl_slist* chunk;
context() : curl(nullptr), chunk(nullptr) {}
~context() {
if (curl != nullptr) curl_easy_cleanup(curl);
if (chunk != nullptr) curl_slist_free_all(chunk);
}
} ctx;

ctx.curl = curl_easy_init();

// set url
curl_easy_setopt(ctx.curl, CURLOPT_URL, url.c_str());

// set header
for (auto&& header: headers) {
ctx.chunk = curl_slist_append(ctx.chunk, header.c_str());
}
curl_easy_setopt(ctx.curl, CURLOPT_HTTPHEADER, ctx.chunk);

// set response callback
std::string resp_body;
curl_easy_setopt(ctx.curl, CURLOPT_WRITEFUNCTION, receive_callback);
curl_easy_setopt(ctx.curl, CURLOPT_WRITEDATA, &resp_body);

CURLcode curl_code = curl_easy_perform(ctx.curl);
if (curl_code != CURLE_OK) {
throw std::exception();
}

long status_code = 0;
curl_easy_getinfo(session, CURLINFO_RESPONSE_CODE, &status_code);

response r;
r.status_code = status_code;
r.body = resp_body;

return r;
}
};

#endif // HTTP_CLIENT_H_INCLUDED
102 changes: 102 additions & 0 deletions kennel2/src/kennel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "protocol.h"
#include "eventsource.h"
#include "permlink.h"
#include "http_client.h"
#include "../../cattleshed/src/syslogstream.cc"

namespace cppcms {
Expand Down Expand Up @@ -44,6 +45,8 @@ class kennel : public cppcms::application {

dispatcher().assign("/permlink/([a-zA-Z0-9]+)/?", &kennel::get_permlink, this, 1);

dispatcher().assign("/login/github/callback", &kennel::get_github_callback, this);

dispatcher().assign("/api/list.json", &kennel::api_list, this);
dispatcher().assign("/api/compile.json", &kennel::api_compile, this);
dispatcher().assign("/api/permlink/([a-zA-Z0-9]+)/?", &kennel::api_permlink, this, 1);
Expand Down Expand Up @@ -245,6 +248,59 @@ class kennel : public cppcms::application {
return;
}

auto access_token = session()["access_token"];
if (access_token.empty()) {
} else {
std::cout << "access_token: " << session()["access_token"] << std::endl;

std::vector<std::string> headers = {
"Content-Type: application/json; charset=utf-8",
"Accept: application/json",
"User-Agent: Wandbox",
};
auto resp = http_client::get("https://api.github.com/user?access_token=" + access_token, headers);
// got following data
/*
{
"login": "melpon",
"id": 816539,
"avatar_url": "https://avatars0.githubusercontent.com/u/816539?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/melpon",
"html_url": "https://github.com/melpon",
"followers_url": "https://api.github.com/users/melpon/followers",
"following_url": "https://api.github.com/users/melpon/following{/other_user}",
"gists_url": "https://api.github.com/users/melpon/gists{/gist_id}",
"starred_url": "https://api.github.com/users/melpon/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/melpon/subscriptions",
"organizations_url": "https://api.github.com/users/melpon/orgs",
"repos_url": "https://api.github.com/users/melpon/repos",
"events_url": "https://api.github.com/users/melpon/events{/privacy}",
"received_events_url": "https://api.github.com/users/melpon/received_events",
"type": "User",
"site_admin": false,
"name": "melpon",
"company": null,
"blog": "http://melpon.org",
"location": "Tokyo, Japan",
"email": "shigemasa7watanabe+github@gmail.com",
"hireable": null,
"bio": null,
"public_repos": 28,
"public_gists": 28,
"followers": 97,
"following": 16,
"created_at": "2011-05-29T02:19:41Z",
"updated_at": "2017-06-04T05:56:10Z"
}
*/
if (resp.status_code != 200) {
// maybe session is expired
session()["access_token"] = "";
}
std::cout << "body: " << resp.body << std::endl;
}

content::root c(service());
c.set_compiler_infos(get_compiler_infos_or_cache()["compilers"]);
render("root", c);
Expand Down Expand Up @@ -582,6 +638,52 @@ class kennel : public cppcms::application {
result.save(response().out(), cppcms::json::readable);
}

void get_github_callback() {
if (!ensure_method_get()) {
return;
}

auto qs = request().query_string();
auto start_index = qs.find("code=") + 5;
if (start_index == std::string::npos) {
response().status(500);
return;
}

auto end_index = qs.find("&");

auto code = end_index == std::string::npos ? qs.substr(start_index) : qs.substr(start_index, end_index - start_index);

cppcms::json::object obj;
obj["client_id"] = "d097a8f338db3c15fe08";
obj["client_secret"] = "a5705f2106e90caa2e1b73e70274ea3ee2b5ec18";
obj["code"] = code;
obj["accept"] = "json";

cppcms::json::value body;
body.object(obj);
std::stringstream body_ss;
body.save(body_ss, cppcms::json::compact);

std::vector<std::string> headers = {
"Content-Type: application/json; charset=utf-8",
"Accept: application/json",
};
auto resp = http_client::post("https://github.com/login/oauth/access_token", std::move(headers), std::move(body_ss.str()));
if (resp.status_code == 200) {
cppcms::json::value resp_json;
std::stringstream resp_ss(resp.body);
resp_json.load(resp_ss, true, nullptr);

auto access_token = resp_json.object()["access_token"].str();
session()["access_token"] = access_token;
}

std::stringstream root_ss;
mapper().map(root_ss, "root");
response().set_redirect_header(root_ss.str());
}

void nojs_list() {
if (!ensure_method_get()) {
return;
Expand Down

0 comments on commit c6b5792

Please sign in to comment.