mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Implemented basic authentication
Also fixed Tankers and AWACS which now operate as expected
This commit is contained in:
parent
57b74bd1b1
commit
91f8996fba
@ -12,10 +12,6 @@ var usersRouter = require('./routes/users');
|
||||
|
||||
var app = express();
|
||||
|
||||
app.use('/demo', basicAuth({
|
||||
users: { 'admin': 'socks' }
|
||||
}))
|
||||
|
||||
app.use(logger('dev'));
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: false }));
|
||||
@ -31,7 +27,8 @@ app.set('view engine', 'ejs');
|
||||
|
||||
let rawdata = fs.readFileSync('../olympus.json');
|
||||
let config = JSON.parse(rawdata);
|
||||
app.get('/config', (req, res) => res.send(config));
|
||||
if (config["server"] != undefined)
|
||||
app.get('/config', (req, res) => res.send(config["server"]));
|
||||
|
||||
module.exports = app;
|
||||
|
||||
@ -43,5 +40,8 @@ app.get('/demo/bullseyes', (req, res) => demoDataGenerator.bullseyes(req, res));
|
||||
app.get('/demo/airbases', (req, res) => demoDataGenerator.airbases(req, res));
|
||||
app.get('/demo/mission', (req, res) => demoDataGenerator.mission(req, res));
|
||||
|
||||
app.use('/demo', basicAuth({
|
||||
users: { 'admin': 'socks' }
|
||||
}))
|
||||
|
||||
|
||||
|
||||
@ -82,9 +82,9 @@ function setup() {
|
||||
}
|
||||
|
||||
function readConfig(config: any) {
|
||||
if (config && config["server"] != undefined && config["server"]["address"] != undefined && config["server"]["port"] != undefined) {
|
||||
const address = config["server"]["address"];
|
||||
const port = config["server"]["port"];
|
||||
if (config && config["address"] != undefined && config["port"] != undefined) {
|
||||
const address = config["address"];
|
||||
const port = config["port"];
|
||||
if (typeof address === 'string' && typeof port == 'number')
|
||||
setAddress(address == "*" ? window.location.hostname : address, <number>port);
|
||||
}
|
||||
|
||||
@ -219,7 +219,7 @@ export class UnitControlPanel extends Panel {
|
||||
|
||||
// Default values for "normal" units
|
||||
this.#radioCallsignDropdown.setOptions(["Enfield", "Springfield", "Uzi", "Colt", "Dodge", "Ford", "Chevy", "Pontiac"]);
|
||||
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign);
|
||||
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign - 1);
|
||||
|
||||
// Input values
|
||||
var tankerCheckbox = this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.querySelector("input")
|
||||
@ -241,7 +241,7 @@ export class UnitControlPanel extends Panel {
|
||||
this.#radioDecimalsDropdown.setValue("." + radioDecimals);
|
||||
|
||||
// Make sure its in the valid range
|
||||
if (!this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign))
|
||||
if (!this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign - 1))
|
||||
this.#radioCallsignDropdown.selectValue(0);
|
||||
|
||||
// Set options for tankers
|
||||
@ -249,7 +249,7 @@ export class UnitControlPanel extends Panel {
|
||||
if (roles != undefined && Array.prototype.concat.apply([], roles)?.includes("Tanker")){
|
||||
this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.classList.remove("hide");
|
||||
this.#radioCallsignDropdown.setOptions(["Texaco", "Arco", "Shell"]);
|
||||
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign);
|
||||
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign - 1);
|
||||
}
|
||||
else {
|
||||
this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.classList.add("hide");
|
||||
@ -259,7 +259,7 @@ export class UnitControlPanel extends Panel {
|
||||
if (roles != undefined && Array.prototype.concat.apply([], roles)?.includes("AWACS")){
|
||||
this.#advancedSettingsDialog.querySelector("#AWACS-checkbox")?.classList.remove("hide");
|
||||
this.#radioCallsignDropdown.setOptions(["Overlord", "Magic", "Wizard", "Focus", "Darkstar"]);
|
||||
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign);
|
||||
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign - 1);
|
||||
} else {
|
||||
this.#advancedSettingsDialog.querySelector("#AWACS-checkbox")?.classList.add("hide");
|
||||
}
|
||||
@ -276,7 +276,7 @@ export class UnitControlPanel extends Panel {
|
||||
const TACANCallsign = <string> this.#advancedSettingsDialog.querySelector("#tacan-callsign")?.querySelector("input")?.value
|
||||
const radioMHz = Number(this.#advancedSettingsDialog.querySelector("#radio-mhz")?.querySelector("input")?.value);
|
||||
const radioDecimals = this.#radioDecimalsDropdown.getValue();
|
||||
const radioCallsign = this.#radioCallsignDropdown.getIndex();
|
||||
const radioCallsign = this.#radioCallsignDropdown.getIndex() + 1;
|
||||
const radioCallsignNumber = Number(this.#advancedSettingsDialog.querySelector("#radio-callsign-number")?.querySelector("input")?.value);
|
||||
|
||||
var radioFrequency = (radioMHz * 1000 + Number(radioDecimals.substring(1))) * 1000;
|
||||
|
||||
@ -52,6 +52,10 @@ export function GET(callback: CallableFunction, uri: string, options?: string) {
|
||||
setConnected(false);
|
||||
}
|
||||
};
|
||||
xmlHttp.onreadystatechange = function (res) {
|
||||
console.error("An error occurred during the XMLHttpRequest");
|
||||
setConnected(false);
|
||||
};
|
||||
xmlHttp.onerror = function (res) {
|
||||
console.error("An error occurred during the XMLHttpRequest");
|
||||
setConnected(false);
|
||||
|
||||
@ -2,5 +2,8 @@
|
||||
"server": {
|
||||
"address": "localhost",
|
||||
"port": 30000
|
||||
},
|
||||
"authentication": {
|
||||
"password": "password"
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,7 +185,7 @@
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>include;..\..\third-party\lua\include;..\utils\include;..\shared\include;..\dcstools\include;..\logger\include;..\luatools\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>include;..\..\third-party\base64\include;..\..\third-party\lua\include;..\utils\include;..\shared\include;..\dcstools\include;..\logger\include;..\luatools\include</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
||||
@ -27,5 +27,7 @@ private:
|
||||
void task();
|
||||
|
||||
atomic<bool> runListener;
|
||||
|
||||
wstring password = L"";
|
||||
};
|
||||
|
||||
|
||||
@ -96,14 +96,13 @@ public:
|
||||
void pushActivePathBack(Coords newActivePathBack);
|
||||
void popActivePathFront();
|
||||
void setTargetID(int newTargetID) { targetID = newTargetID; addMeasure(L"targetID", json::value(newTargetID));}
|
||||
void setIsTanker(bool newIsTanker) { isTanker = newIsTanker; addMeasure(L"isTanker", json::value(newIsTanker));}
|
||||
void setIsAWACS(bool newIsAWACS) { isAWACS = newIsAWACS; addMeasure(L"isAWACS", json::value(newIsAWACS));}
|
||||
void setTACANOn(bool newTACANOn);
|
||||
void setIsTanker(bool newIsTanker);
|
||||
void setIsAWACS(bool newIsAWACS);
|
||||
void setTACANChannel(int newTACANChannel);
|
||||
void setTACANXY(wstring newTACANXY);
|
||||
void setTACANCallsign(wstring newTACANCallsign);
|
||||
void setTACAN();
|
||||
void setRadioOn(bool newRadioOn);
|
||||
void setEPLRS(bool state);
|
||||
void setRadioFrequency(int newRadioFrequency);
|
||||
void setRadioCallsign(int newRadioCallsign);
|
||||
void setRadioCallsignNumber(int newRadioCallsignNumber);
|
||||
@ -116,11 +115,9 @@ public:
|
||||
int getTargetID() { return targetID; }
|
||||
bool getIsTanker() { return isTanker; }
|
||||
bool getIsAWACS() { return isAWACS; }
|
||||
bool getTACANOn() { return TACANOn; }
|
||||
int getTACANChannel() { return TACANChannel; }
|
||||
wstring getTACANXY() { return TACANXY; }
|
||||
wstring getTACANCallsign() { return TACANCallsign; }
|
||||
bool getRadioOn() { return radioOn; }
|
||||
int getRadioFrequency() { return radioFrequency; }
|
||||
int getRadioCallsign() { return radioCallsign; }
|
||||
int getRadioCallsignNumber() { return radioCallsignNumber; }
|
||||
@ -182,11 +179,9 @@ protected:
|
||||
int targetID = NULL;
|
||||
bool isTanker = false;
|
||||
bool isAWACS = false;
|
||||
bool TACANOn = false;
|
||||
int TACANChannel = 40;
|
||||
wstring TACANXY = L"X";
|
||||
wstring TACANCallsign = L"TKR";
|
||||
bool radioOn = false;
|
||||
int radioFrequency = 260000000; // MHz
|
||||
int radioCallsign = 1;
|
||||
int radioCallsignNumber = 1;
|
||||
|
||||
@ -251,13 +251,11 @@ void Scheduler::handleRequest(wstring key, json::value value)
|
||||
unit->setIsTanker(value[L"isTanker"].as_bool());
|
||||
unit->setIsAWACS(value[L"isAWACS"].as_bool());
|
||||
|
||||
unit->setTACANOn(true); // TODO Remove
|
||||
unit->setTACANChannel(value[L"TACANChannel"].as_number().to_int32());
|
||||
unit->setTACANXY(value[L"TACANXY"].as_string());
|
||||
unit->setTACANCallsign(value[L"TACANCallsign"].as_string());
|
||||
unit->setTACAN();
|
||||
|
||||
unit->setRadioOn(true); // TODO Remove
|
||||
unit->setRadioFrequency(value[L"radioFrequency"].as_number().to_int32());
|
||||
unit->setRadioCallsign(value[L"radioCallsign"].as_number().to_int32());
|
||||
unit->setRadioCallsignNumber(value[L"radioCallsignNumber"].as_number().to_int32());
|
||||
|
||||
@ -6,9 +6,11 @@
|
||||
#include "luatools.h"
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include "base64.hpp"
|
||||
|
||||
#include <chrono>
|
||||
using namespace std::chrono;
|
||||
using namespace base64;
|
||||
|
||||
extern UnitsManager* unitsManager;
|
||||
extern Scheduler* scheduler;
|
||||
@ -54,10 +56,10 @@ void Server::stop(lua_State* L)
|
||||
void Server::handle_options(http_request request)
|
||||
{
|
||||
http_response response(status_codes::OK);
|
||||
response.headers().add(U("Allow"), U("GET, POST, PUT, OPTIONS"));
|
||||
response.headers().add(U("Allow"), U("GET, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Origin"), U("*"));
|
||||
response.headers().add(U("Access-Control-Allow-Methods"), U("GET, POST, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type"));
|
||||
response.headers().add(U("Access-Control-Allow-Methods"), U("GET, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type, Authorization"));
|
||||
|
||||
request.reply(response);
|
||||
}
|
||||
@ -68,87 +70,102 @@ void Server::handle_get(http_request request)
|
||||
lock_guard<mutex> guard(mutexLock);
|
||||
|
||||
http_response response(status_codes::OK);
|
||||
response.headers().add(U("Allow"), U("GET, POST, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Origin"), U("*"));
|
||||
response.headers().add(U("Access-Control-Allow-Methods"), U("GET, POST, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type"));
|
||||
string authorization = to_base64("admin:" + to_string(password));
|
||||
if (password == L"" || (request.headers().has(L"Authorization") && request.headers().find(L"Authorization")->second == L"Basic " + to_wstring(authorization)))
|
||||
{
|
||||
std::exception_ptr eptr;
|
||||
try {
|
||||
auto answer = json::value::object();
|
||||
auto path = uri::split_path(uri::decode(request.relative_uri().path()));
|
||||
|
||||
std::exception_ptr eptr;
|
||||
try {
|
||||
auto answer = json::value::object();
|
||||
auto path = uri::split_path(uri::decode(request.relative_uri().path()));
|
||||
|
||||
if (path.size() > 0)
|
||||
{
|
||||
if (path[0] == UNITS_URI)
|
||||
if (path.size() > 0)
|
||||
{
|
||||
map<utility::string_t, utility::string_t> query = request.relative_uri().split_query(request.relative_uri().query());
|
||||
long long time = 0;
|
||||
if (query.find(L"time") != query.end())
|
||||
if (path[0] == UNITS_URI)
|
||||
{
|
||||
try {
|
||||
time = stoll((*(query.find(L"time"))).second);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
time = 0;
|
||||
map<utility::string_t, utility::string_t> query = request.relative_uri().split_query(request.relative_uri().query());
|
||||
long long time = 0;
|
||||
if (query.find(L"time") != query.end())
|
||||
{
|
||||
try {
|
||||
time = stoll((*(query.find(L"time"))).second);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
time = 0;
|
||||
}
|
||||
}
|
||||
unitsManager->getData(answer, time);
|
||||
}
|
||||
unitsManager->getData(answer, time);
|
||||
}
|
||||
else if (path[0] == LOGS_URI)
|
||||
{
|
||||
auto logs = json::value::object();
|
||||
getLogsJSON(logs, 100); // By reference, for thread safety. Get the last 100 log entries
|
||||
answer[L"logs"] = logs;
|
||||
}
|
||||
else if (path[0] == AIRBASES_URI)
|
||||
answer[L"airbases"] = airbases;
|
||||
else if (path[0] == BULLSEYE_URI)
|
||||
answer[L"bullseyes"] = bullseyes;
|
||||
else if (path[0] == MISSION_URI)
|
||||
answer[L"mission"] = mission;
|
||||
else if (path[0] == LOGS_URI)
|
||||
{
|
||||
auto logs = json::value::object();
|
||||
getLogsJSON(logs, 100); // By reference, for thread safety. Get the last 100 log entries
|
||||
answer[L"logs"] = logs;
|
||||
}
|
||||
else if (path[0] == AIRBASES_URI)
|
||||
answer[L"airbases"] = airbases;
|
||||
else if (path[0] == BULLSEYE_URI)
|
||||
answer[L"bullseyes"] = bullseyes;
|
||||
else if (path[0] == MISSION_URI)
|
||||
answer[L"mission"] = mission;
|
||||
|
||||
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
|
||||
answer[L"time"] = json::value::string(to_wstring(ms.count()));
|
||||
answer[L"sessionHash"] = json::value::string(to_wstring(sessionHash));
|
||||
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
|
||||
answer[L"time"] = json::value::string(to_wstring(ms.count()));
|
||||
answer[L"sessionHash"] = json::value::string(to_wstring(sessionHash));
|
||||
}
|
||||
|
||||
response.set_body(answer);
|
||||
}
|
||||
catch (...) {
|
||||
eptr = std::current_exception(); // capture
|
||||
}
|
||||
handle_eptr(eptr);
|
||||
}
|
||||
else {
|
||||
response = status_codes::Unauthorized;
|
||||
}
|
||||
|
||||
response.set_body(answer);
|
||||
}
|
||||
catch (...) {
|
||||
eptr = std::current_exception(); // capture
|
||||
}
|
||||
handle_eptr(eptr);
|
||||
response.headers().add(U("Allow"), U("GET, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Origin"), U("*"));
|
||||
response.headers().add(U("Access-Control-Allow-Methods"), U("GET, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type, Authorization"));
|
||||
|
||||
request.reply(response);
|
||||
}
|
||||
|
||||
void Server::handle_request(http_request request, function<void(json::value const&, json::value&)> action)
|
||||
{
|
||||
auto answer = json::value::object();
|
||||
request.extract_json().then([&answer, &action](pplx::task<json::value> task)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto const& jvalue = task.get();
|
||||
|
||||
if (!jvalue.is_null())
|
||||
{
|
||||
action(jvalue, answer);
|
||||
}
|
||||
}
|
||||
catch (http_exception const& e)
|
||||
{
|
||||
log(e.what());
|
||||
}
|
||||
}).wait();
|
||||
|
||||
http_response response(status_codes::OK);
|
||||
response.headers().add(U("Allow"), U("GET, POST, PUT, OPTIONS"));
|
||||
string authorization = to_base64("admin:" + to_string(password));
|
||||
if (password == L"" || (request.headers().has(L"Authorization") && request.headers().find(L"Authorization")->second == L"Basic " + to_wstring(authorization)))
|
||||
{
|
||||
auto answer = json::value::object();
|
||||
request.extract_json().then([&answer, &action](pplx::task<json::value> task)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto const& jvalue = task.get();
|
||||
|
||||
if (!jvalue.is_null())
|
||||
{
|
||||
action(jvalue, answer);
|
||||
}
|
||||
}
|
||||
catch (http_exception const& e)
|
||||
{
|
||||
log(e.what());
|
||||
}
|
||||
}).wait();
|
||||
response.set_body(answer);
|
||||
}
|
||||
else {
|
||||
response = status_codes::Unauthorized;
|
||||
}
|
||||
|
||||
response.headers().add(U("Allow"), U("GET, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Origin"), U("*"));
|
||||
response.headers().add(U("Access-Control-Allow-Methods"), U("GET, POST, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type"));
|
||||
response.set_body(answer);
|
||||
response.headers().add(U("Access-Control-Allow-Methods"), U("GET, PUT, OPTIONS"));
|
||||
response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type, Authorization"));
|
||||
|
||||
request.reply(response);
|
||||
}
|
||||
|
||||
@ -197,9 +214,15 @@ void Server::task()
|
||||
log(L"Starting server on " + address);
|
||||
}
|
||||
else
|
||||
{
|
||||
log(L"Error reading configuration file. Starting server on " + address);
|
||||
|
||||
if (config.is_object() && config.has_object_field(L"authentication") &&
|
||||
config[L"authentication"].has_string_field(L"password"))
|
||||
{
|
||||
password = config[L"authentication"][L"password"].as_string();
|
||||
}
|
||||
else
|
||||
log(L"Error reading configuration file. No password set.");
|
||||
free(buf);
|
||||
}
|
||||
else
|
||||
|
||||
@ -337,9 +337,17 @@ void Unit::landAt(Coords loc) {
|
||||
setState(State::LAND);
|
||||
}
|
||||
|
||||
void Unit::setTACANOn(bool newTACANOn) {
|
||||
TACANOn = newTACANOn;
|
||||
addMeasure(L"TACANOn", json::value(newTACANOn));
|
||||
void Unit::setIsTanker(bool newIsTanker) {
|
||||
isTanker = newIsTanker;
|
||||
resetTask();
|
||||
addMeasure(L"isTanker", json::value(newIsTanker));
|
||||
}
|
||||
|
||||
void Unit::setIsAWACS(bool newIsAWACS) {
|
||||
isAWACS = newIsAWACS;
|
||||
resetTask();
|
||||
addMeasure(L"isAWACS", json::value(newIsAWACS));
|
||||
setEPLRS(true);
|
||||
}
|
||||
|
||||
void Unit::setTACANChannel(int newTACANChannel) {
|
||||
@ -356,11 +364,6 @@ void Unit::setTACANCallsign(wstring newTACANCallsign) {
|
||||
addMeasure(L"TACANCallsign", json::value(newTACANCallsign));
|
||||
}
|
||||
|
||||
void Unit::setRadioOn(bool newRadioOn) {
|
||||
radioOn = newRadioOn;
|
||||
addMeasure(L"radioOn", json::value(newRadioOn));
|
||||
}
|
||||
|
||||
void Unit::setRadioFrequency(int newRadioFrequency) {
|
||||
radioFrequency = newRadioFrequency;
|
||||
addMeasure(L"radioFrequency", json::value(newRadioFrequency));
|
||||
@ -376,6 +379,19 @@ void Unit::setRadioCallsignNumber(int newRadioCallsignNumber) {
|
||||
addMeasure(L"radioCallsignNumber", json::value(newRadioCallsignNumber));
|
||||
}
|
||||
|
||||
void Unit::setEPLRS(bool state)
|
||||
{
|
||||
std::wostringstream commandSS;
|
||||
commandSS << "{"
|
||||
<< "id = 'EPLRS',"
|
||||
<< "params = {"
|
||||
<< "value = " << (state? "true": "false") << ", "
|
||||
<< "}"
|
||||
<< "}";
|
||||
Command* command = dynamic_cast<Command*>(new SetCommand(ID, commandSS.str()));
|
||||
scheduler->appendCommand(command);
|
||||
}
|
||||
|
||||
void Unit::setTACAN()
|
||||
{
|
||||
std::wostringstream commandSS;
|
||||
@ -383,9 +399,9 @@ void Unit::setTACAN()
|
||||
<< "id = 'ActivateBeacon',"
|
||||
<< "params = {"
|
||||
<< "type = " << ((TACANXY.compare(L"X") == 0)? 4: 5) << ","
|
||||
<< "system = 4,"
|
||||
<< "name = Olympus_TACAN,"
|
||||
<< "callsign = " << TACANCallsign << ", "
|
||||
<< "system = 3,"
|
||||
<< "name = \"Olympus_TACAN\","
|
||||
<< "callsign = \"" << TACANCallsign << "\", "
|
||||
<< "frequency = " << TACANChannelToFrequency(TACANChannel, TACANXY) << ","
|
||||
<< "}"
|
||||
<< "}";
|
||||
|
||||
81
third-party/base64/include/base64.hpp
vendored
Normal file
81
third-party/base64/include/base64.hpp
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
#ifndef BASE_64_HPP
|
||||
#define BASE_64_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
namespace base64 {
|
||||
|
||||
inline std::string get_base64_chars() {
|
||||
static std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
return base64_chars;
|
||||
}
|
||||
|
||||
inline std::string to_base64(std::string const &data) {
|
||||
int counter = 0;
|
||||
uint32_t bit_stream = 0;
|
||||
const std::string base64_chars = get_base64_chars();
|
||||
std::string encoded;
|
||||
int offset = 0;
|
||||
for (unsigned char c : data) {
|
||||
auto num_val = static_cast<unsigned int>(c);
|
||||
offset = 16 - counter % 3 * 8;
|
||||
bit_stream += num_val << offset;
|
||||
if (offset == 16) {
|
||||
encoded += base64_chars.at(bit_stream >> 18 & 0x3f);
|
||||
}
|
||||
if (offset == 8) {
|
||||
encoded += base64_chars.at(bit_stream >> 12 & 0x3f);
|
||||
}
|
||||
if (offset == 0 && counter != 3) {
|
||||
encoded += base64_chars.at(bit_stream >> 6 & 0x3f);
|
||||
encoded += base64_chars.at(bit_stream & 0x3f);
|
||||
bit_stream = 0;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
if (offset == 16) {
|
||||
encoded += base64_chars.at(bit_stream >> 12 & 0x3f);
|
||||
encoded += "==";
|
||||
}
|
||||
if (offset == 8) {
|
||||
encoded += base64_chars.at(bit_stream >> 6 & 0x3f);
|
||||
encoded += '=';
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
inline std::string from_base64(std::string const &data) {
|
||||
int counter = 0;
|
||||
uint32_t bit_stream = 0;
|
||||
std::string decoded;
|
||||
int offset = 0;
|
||||
const std::string base64_chars = get_base64_chars();
|
||||
for (unsigned char c : data) {
|
||||
auto num_val = base64_chars.find(c);
|
||||
if (num_val != std::string::npos) {
|
||||
offset = 18 - counter % 4 * 6;
|
||||
bit_stream += num_val << offset;
|
||||
if (offset == 12) {
|
||||
decoded += static_cast<char>(bit_stream >> 16 & 0xff);
|
||||
}
|
||||
if (offset == 6) {
|
||||
decoded += static_cast<char>(bit_stream >> 8 & 0xff);
|
||||
}
|
||||
if (offset == 0 && counter != 4) {
|
||||
decoded += static_cast<char>(bit_stream & 0xff);
|
||||
bit_stream = 0;
|
||||
}
|
||||
} else if (c != '=') {
|
||||
return std::string();
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
return decoded;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // BASE_64_HPP
|
||||
Loading…
x
Reference in New Issue
Block a user