118 lines
4.9 KiB
C++
Raw Normal View History

2022-08-28 17:37:09 +02:00
#pragma clang diagnostic push
#pragma ide diagnostic ignored "performance-unnecessary-value-param"
#pragma ide diagnostic ignored "readability-make-member-function-const"
#pragma ide diagnostic ignored "readability-convert-member-functions-to-static"
#include <utility>
#include "controllers/controllers.h"
#include "dto/dto.h"
const std::string GITLAB_ID = "98bcbad78cb1f880d1d1de62291d70a791251a7bea077bfe7df111ef3c115760";
const std::string GITLAB_SECRET = "7ee01d2b204aff3a05f9d028f004d169b6d381ec873e195f314b3935fa150959";
const std::string GITLAB_URL = "https://gitlab.mattv.de";
const std::string GITLAB_API_URL = "https://ssh.gitlab.mattv.de";
std::string get_redirect_uri(req_type req) {
auto host_header = req->headers().find("host");
std::stringstream ss;
ss << (req->isOnSecureConnection() ? "https" : "http")
<< "://"
<< (host_header != req->headers().end() ? host_header->second : "127.0.0.1:1234")
<< "/api/auth/gitlab_callback";
return drogon::utils::urlEncode(ss.str());
}
const drogon::HttpClientPtr& get_gitlab_client() {
static drogon::HttpClientPtr client = drogon::HttpClient::newHttpClient(GITLAB_API_URL, drogon::app().getLoop(), false, false);
return client;
}
namespace api {
std::optional<auth::gitlab_tokens> auth::get_gitlab_tokens(req_type req, const std::string& code_or_token, bool token) {
std::stringstream ss;
ss << "/oauth/token"
<< "?redirect_uri=" << get_redirect_uri(req)
<< "&client_id=" << GITLAB_ID
<< "&client_secret=" << GITLAB_SECRET
<< (token ? "&refresh_token=" : "&code=") << code_or_token
<< "&grant_type=" << (token ? "refresh_token" : "authorization_code");
auto gitlab_req = drogon::HttpRequest::newHttpRequest();
gitlab_req->setPathEncode(false);
gitlab_req->setPath(ss.str());
gitlab_req->setMethod(drogon::HttpMethod::Post);
auto res_tuple = get_gitlab_client()->sendRequest(gitlab_req);
auto res = res_tuple.second;
if ((res->statusCode() != drogon::HttpStatusCode::k200OK) && (res->statusCode() != drogon::HttpStatusCode::k201Created))
return std::nullopt;
auto json = *res->jsonObject();
return std::make_optional<gitlab_tokens>(
json["access_token"].as<std::string>(),
json["refresh_token"].as<std::string>()
);
}
std::optional<auth::gitlab_user> auth::get_gitlab_user(const std::string& at) {
auto gitlab_req = drogon::HttpRequest::newHttpRequest();
gitlab_req->setPath("/api/v4/user");
gitlab_req->addHeader("Authorization", "Bearer " + at);
gitlab_req->setMethod(drogon::HttpMethod::Get);
auto res_tuple = get_gitlab_client()->sendRequest(gitlab_req);
auto res = res_tuple.second;
if (res->statusCode() != drogon::HttpStatusCode::k200OK)
return std::nullopt;
auto json = *res->jsonObject();
return std::make_optional<gitlab_user>(
json["username"].as<std::string>(),
json.get("is_admin", false).as<bool>()
);
}
void auth::gitlab(req_type req, cbk_type cbk) {
std::stringstream ss;
ss << GITLAB_URL << "/oauth/authorize"
<< "?redirect_uri=" << get_redirect_uri(req)
<< "&client_id=" << GITLAB_ID
<< "&scope=read_user&response_type=code";
cbk(drogon::HttpResponse::newRedirectionResponse(ss.str()));
}
void auth::gitlab_callback(req_type req, cbk_type cbk, std::string code) {
auto tokens = get_gitlab_tokens(req, code, false);
if (!tokens.has_value())
return cbk(dto::Responses::get_unauth_res("Invalid code"));
auto info = get_gitlab_user(tokens->at);
if (!info.has_value())
return cbk(dto::Responses::get_unauth_res("Invalid code"));
db::MapperUser user_mapper(drogon::app().getDbClient());
auto db_users = user_mapper.findBy(
db::Criteria(db::User::Cols::_name, db::CompareOps::EQ, info->name) &&
db::Criteria(db::User::Cols::_gitlab, db::CompareOps::EQ, 1)
);
if (db_users.empty()) {
db::User new_user;
new_user.setName(info->name);
new_user.setPassword("");
new_user.setGitlab(1);
new_user.setRole(info->is_admin ? db::UserRole::ADMIN : db::UserRole::DISABLED);
new_user.setRootId(0);
new_user.setTfaType(db::tfaTypes::NONE);
user_mapper.insert(new_user);
generate_root(new_user);
db_users.push_back(new_user);
}
db::User& db_user = db_users.at(0);
db_user.setGitlabAt(tokens->at);
db_user.setGitlabRt(tokens->rt);
user_mapper.update(db_user);
const std::string& token = get_token(db_user);
cbk(drogon::HttpResponse::newRedirectionResponse("/set_token?token="+token));
}
}
#pragma clang diagnostic pop