// SafeC Standard Library — OAuth2 client implementation (see oauth2.h).
#pragma once
#include <std/http/oauth2.h>
#include <std/http/http.h>
#include <std/http/http.h>
#include <std/serial/value.h>
#include <std/serial/value.h>
#include <std/serial/json.h>
#include <std/serial/json.h>
#include <std/encoding/url.h>
#include <std/encoding/url.h>
#include <std/collections/string.h>
#include <std/collections/string.h>
#include <std/mem.h>
namespace std {
static void __form_add(struct String* body, const char* key, const char* val) {
unsafe {
if (body->length() > 0UL) { body->push("&"); }
body->push(key);
body->push("=");
struct String enc = url_encode(val);
body->push_str(&enc);
enc.free();
}
}
static struct OAuth2Token __token_from_json(const struct Value* root) {
struct OAuth2Token t;
t.accessToken = String::new();
t.refreshToken = String::new();
t.tokenType = String::new();
t.expiresIn = 0LL;
unsafe {
struct Value* at = root->object_get("access_token");
if (at != (struct Value*)0) { t.accessToken = String::from(at->as_string()); }
struct Value* rt = root->object_get("refresh_token");
if (rt != (struct Value*)0) { t.refreshToken = String::from(rt->as_string()); }
struct Value* tt = root->object_get("token_type");
if (tt != (struct Value*)0) { t.tokenType = String::from(tt->as_string()); }
struct Value* ei = root->object_get("expires_in");
if (ei != (struct Value*)0) { t.expiresIn = ei->as_int(); }
}
return t;
}
static struct OAuth2Token __empty_token() {
struct OAuth2Token t;
t.accessToken = String::new();
t.refreshToken = String::new();
t.tokenType = String::new();
t.expiresIn = 0LL;
return t;
}
static struct OAuth2Token __token_request(const char* tokenHost, unsigned short tokenPort,
const char* tokenPath, struct String* body, int* ok) {
int httpOk = 0;
struct HttpResponse resp;
unsafe {
resp = http_request_n_(tokenHost, tokenPort, "POST", tokenPath,
"Content-Type: application/x-www-form-urlencoded\r\n",
(const unsigned char*)body->data, body->len, &httpOk);
}
if (!httpOk || resp.status < 200 || resp.status >= 300) {
unsafe { *ok = 0; resp.free(); }
return __empty_token();
}
int parseOk;
struct Value root;
unsafe { root = json_parse(resp.body.as_ptr(), &parseOk); resp.free(); }
if (!parseOk) {
unsafe { *ok = 0; root.free(); }
return __empty_token();
}
struct OAuth2Token t = __token_from_json(&root);
unsafe { root.free(); }
int hasAccess;
unsafe { hasAccess = t.accessToken.length() > 0UL; }
unsafe { *ok = hasAccess; }
return t;
}
struct OAuth2Token OAuth2Token::exchange_code(const &char tokenHost, unsigned short tokenPort,
const &char tokenPath, const &char clientId,
const &char clientSecret, const &char code,
const &char redirectUri, ?&int ok) {
struct String body = String::new();
__form_add(&body, "grant_type", "authorization_code");
__form_add(&body, "code", code);
__form_add(&body, "redirect_uri", redirectUri);
__form_add(&body, "client_id", clientId);
__form_add(&body, "client_secret", clientSecret);
struct OAuth2Token t = __token_request(tokenHost, tokenPort, tokenPath, &body, ok);
unsafe { body.free(); }
return t;
}
struct OAuth2Token OAuth2Token::refresh(const &char tokenHost, unsigned short tokenPort,
const &char tokenPath, const &char clientId,
const &char clientSecret, const &char refreshToken, ?&int ok) {
struct String body = String::new();
__form_add(&body, "grant_type", "refresh_token");
__form_add(&body, "refresh_token", refreshToken);
__form_add(&body, "client_id", clientId);
__form_add(&body, "client_secret", clientSecret);
struct OAuth2Token t = __token_request(tokenHost, tokenPort, tokenPath, &body, ok);
unsafe { body.free(); }
return t;
}
void OAuth2Token::free() { self.drop(); }
void OAuth2Token::drop() {
self.accessToken.free();
self.refreshToken.free();
self.tokenType.free();
}
} // namespace std