summaryrefslogtreecommitdiff
path: root/plugins/CloudFile/src/Services
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/CloudFile/src/Services')
-rw-r--r--plugins/CloudFile/src/Services/google_api.h7
-rw-r--r--plugins/CloudFile/src/Services/google_service.cpp2
-rw-r--r--plugins/CloudFile/src/Services/microsoft_api.h138
-rw-r--r--plugins/CloudFile/src/Services/microsoft_service.cpp262
-rw-r--r--plugins/CloudFile/src/Services/microsoft_service.h31
5 files changed, 435 insertions, 5 deletions
diff --git a/plugins/CloudFile/src/Services/google_api.h b/plugins/CloudFile/src/Services/google_api.h
index cf405dda36..50d12fc5d3 100644
--- a/plugins/CloudFile/src/Services/google_api.h
+++ b/plugins/CloudFile/src/Services/google_api.h
@@ -57,9 +57,9 @@ namespace GDriveAPI
StartUploadFileRequest(const char *token, const char *name) :
HttpRequest(REQUEST_POST, GDRIVE_UPLOAD)
{
- AddUrlParameter("access_token=%s", token);
AddUrlParameter("uploadType=resumable");
+ AddBearerAuthHeader(token);
AddHeader("Content-Type", "application/json");
JSONNode params(JSON_NODE);
@@ -91,7 +91,7 @@ namespace GDriveAPI
CreateFolderRequest(const char *token, const char *path) :
HttpRequest(REQUEST_PUT, GDRIVE_API)
{
- AddUrlParameter("access_token=%s", token);
+ AddBearerAuthHeader(token);
AddHeader("Content-Type", "application/json");
JSONNode params(JSON_NODE);
@@ -110,8 +110,7 @@ namespace GDriveAPI
GrantPermissionsRequest(const char *token, const char *fileId) :
HttpRequest(REQUEST_POST, FORMAT, GDRIVE_API "/%s/permissions", fileId)
{
- AddUrlParameter("access_token=%s", token);
-
+ AddBearerAuthHeader(token);
AddHeader("Content-Type", "application/json");
JSONNode params(JSON_NODE);
diff --git a/plugins/CloudFile/src/Services/google_service.cpp b/plugins/CloudFile/src/Services/google_service.cpp
index 3c88ffd366..f7ab294135 100644
--- a/plugins/CloudFile/src/Services/google_service.cpp
+++ b/plugins/CloudFile/src/Services/google_service.cpp
@@ -140,7 +140,7 @@ void CGDriveService::StartUploadFile(char *uploadUri, const char *name)
{
ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret"));
GDriveAPI::StartUploadFileRequest request(token, name);
- NETLIBHTTPREQUEST* response = request.Send(hConnection);
+ NLHR_PTR response(request.Send(hConnection));
if (response == NULL)
throw Exception(HttpStatusToError());
diff --git a/plugins/CloudFile/src/Services/microsoft_api.h b/plugins/CloudFile/src/Services/microsoft_api.h
new file mode 100644
index 0000000000..b7f6ebd073
--- /dev/null
+++ b/plugins/CloudFile/src/Services/microsoft_api.h
@@ -0,0 +1,138 @@
+#ifndef _ONEDRIVESERVICE_API_H_
+#define _ONEDRIVESERVICE_API_H_
+
+namespace OneDriveAPI
+{
+#define MS_OAUTH "https://login.microsoftonline.com/common/oauth2/v2.0"
+#define ONEDRIVE_API "https://graph.microsoft.com/v1.0/drive"
+
+#define MS_APP_ID "72b87ac7-42eb-4a97-a620-91a7f8d8b5ae"
+
+ class GetAccessTokenRequest : public HttpRequest
+ {
+ public:
+ GetAccessTokenRequest(const char *code) :
+ HttpRequest(REQUEST_POST, MS_OAUTH "/token")
+ {
+ AddHeader("Content-Type", "application/x-www-form-urlencoded");
+
+ CMStringA data = "redirect_uri=https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fnativeclient";
+ data.AppendFormat("&client_id=%s&grant_type=authorization_code&code=%s", MS_APP_ID, code);
+ SetData(data.GetBuffer(), data.GetLength());
+ }
+ };
+
+ class RefreshTokenRequest : public HttpRequest
+ {
+ public:
+ RefreshTokenRequest(const char *refreshToken) :
+ HttpRequest(REQUEST_POST, MS_OAUTH "/token")
+ {
+ AddHeader("Content-Type", "application/x-www-form-urlencoded");
+
+ CMStringA data(CMStringDataFormat::FORMAT,
+ "client_id=%s&client_secret=%s&grant_type=refresh_token&refresh_token=%s",
+ MS_APP_ID, MS_CLIENT_SECRET, refreshToken);
+ SetData(data.GetBuffer(), data.GetLength());
+ }
+ };
+
+ /*class RevokeAccessTokenRequest : public HttpRequest
+ {
+ public:
+ RevokeAccessTokenRequest(const char *token) :
+ HttpRequest(REQUEST_POST, MS_OAUTH "/logout")
+ {
+ AddUrlParameter("token=%s", token);
+ }
+ };*/
+
+ class CreateUploadSessionRequest : public HttpRequest
+ {
+ public:
+ CreateUploadSessionRequest(const char *token, const char *name) :
+ HttpRequest(REQUEST_POST, FORMAT, ONEDRIVE_API "/root:/%s:/createUploadSession", name)
+ {
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/json");
+
+ JSONNode params(JSON_NODE);
+ params
+ << JSONNode("@microsoft.graph.conflictBehavior", "rename")
+ << JSONNode("name", name);
+
+ json_string data = params.write();
+ SetData(data.c_str(), data.length());
+ }
+
+ CreateUploadSessionRequest(const char *token, const char *parentId, const char *name) :
+ HttpRequest(REQUEST_POST, FORMAT, ONEDRIVE_API "/items/%s:/%s:/createUploadSession", parentId, name)
+ {
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/json");
+
+ JSONNode params(JSON_NODE);
+ params
+ << JSONNode("@microsoft.graph.conflictBehavior", "rename")
+ << JSONNode("name", name);
+
+ json_string data = params.write();
+ SetData(data.c_str(), data.length());
+ }
+ };
+
+ class UploadFileChunkRequest : public HttpRequest
+ {
+ public:
+ UploadFileChunkRequest(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize) :
+ HttpRequest(REQUEST_PUT, uploadUri)
+ {
+ uint64_t rangeMin = offset;
+ uint64_t rangeMax = offset + chunkSize - 1;
+ CMStringA range(CMStringDataFormat::FORMAT, "bytes %I64u-%I64u/%I64u", rangeMin, rangeMax, fileSize);
+ AddHeader("Content-Range", range);
+
+ SetData(chunk, chunkSize);
+ }
+ };
+
+ class CreateFolderRequest : public HttpRequest
+ {
+ public:
+ CreateFolderRequest(const char *token, const char *path) :
+ HttpRequest(REQUEST_PUT, ONEDRIVE_API "/items/root/children")
+ {
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/json");
+
+ JSONNode params(JSON_NODE);
+ params
+ << JSONNode("name", path)
+ << JSONNode("folder", "");
+
+ json_string data = params.write();
+ SetData(data.c_str(), data.length());
+ }
+ };
+
+ class CreateSharedLinkRequest : public HttpRequest
+ {
+ public:
+ CreateSharedLinkRequest(const char *token, const char *path) :
+ HttpRequest(REQUEST_POST, FORMAT, ONEDRIVE_API "/items/%s/createLink", path)
+ {
+ AddBearerAuthHeader(token);
+ AddHeader("Content-Type", "application/json");
+
+ JSONNode params(JSON_NODE);
+ params
+ << JSONNode("type", "view")
+ << JSONNode("scope", "anonymous");
+
+ json_string data = params.write();
+ SetData(data.c_str(), data.length());
+ }
+ };
+};
+
+#endif //_ONEDRIVESERVICE_API_H_
diff --git a/plugins/CloudFile/src/Services/microsoft_service.cpp b/plugins/CloudFile/src/Services/microsoft_service.cpp
new file mode 100644
index 0000000000..d002db45e6
--- /dev/null
+++ b/plugins/CloudFile/src/Services/microsoft_service.cpp
@@ -0,0 +1,262 @@
+#include "..\stdafx.h"
+#include "microsoft_api.h"
+
+COneDriveService::COneDriveService(HNETLIBUSER hConnection)
+ : CCloudService(hConnection)
+{
+}
+
+const char* COneDriveService::GetModule() const
+{
+ return "Microsoft";
+}
+
+const wchar_t* COneDriveService::GetText() const
+{
+ return L"OneDrive";
+}
+
+HANDLE COneDriveService::GetIcon() const
+{
+ return GetIconHandle(IDI_ONEDRIVE);
+}
+
+bool COneDriveService::IsLoggedIn()
+{
+ ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret"));
+ if (!token || token[0] == 0)
+ return false;
+ time_t now = time(NULL);
+ time_t expiresIn = db_get_dw(NULL, GetModule(), "ExpiresIn");
+ return now < expiresIn;
+}
+
+void COneDriveService::Login()
+{
+ ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret"));
+ ptrA refreshToken(db_get_sa(NULL, GetModule(), "RefreshToken"));
+ if (token && refreshToken && refreshToken[0]) {
+ OneDriveAPI::RefreshTokenRequest request(refreshToken);
+ NLHR_PTR response(request.Send(hConnection));
+
+ JSONNode root = GetJsonResponse(response);
+
+ JSONNode node = root.at("access_token");
+ db_set_s(NULL, GetModule(), "TokenSecret", node.as_string().c_str());
+
+ node = root.at("expires_in");
+ time_t expiresIn = time(NULL) + node.as_int();
+ db_set_dw(NULL, GetModule(), "ExpiresIn", expiresIn);
+
+ return;
+ }
+
+ COAuthDlg dlg(this, MS_OAUTH "/authorize?response_type=code&scope=offline_access%20https%3A%2F%2Fgraph.microsoft.com%2Ffiles.readWrite&redirect_uri=https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fnativeclient&client_id=" MS_APP_ID, RequestAccessTokenThread);
+ dlg.DoModal();
+}
+
+void COneDriveService::Logout()
+{
+ mir_forkthreadex(RevokeAccessTokenThread, this);
+}
+
+unsigned COneDriveService::RequestAccessTokenThread(void *owner, void *param)
+{
+ HWND hwndDlg = (HWND)param;
+ COneDriveService *service = (COneDriveService*)owner;
+
+ if (service->IsLoggedIn())
+ service->Logout();
+
+ char requestToken[128];
+ GetDlgItemTextA(hwndDlg, IDC_OAUTH_CODE, requestToken, _countof(requestToken));
+
+ OneDriveAPI::GetAccessTokenRequest request(requestToken);
+ NLHR_PTR response(request.Send(service->hConnection));
+
+ if (response == NULL || response->resultCode != HTTP_CODE_OK) {
+ const char *error = response->dataLength
+ ? response->pData
+ : service->HttpStatusToError(response->resultCode);
+
+ Netlib_Logf(service->hConnection, "%s: %s", service->GetModule(), error);
+ ShowNotification(TranslateT("server does not respond"), MB_ICONERROR);
+ return 0;
+ }
+
+ JSONNode root = JSONNode::parse(response->pData);
+ if (root.empty()) {
+ Netlib_Logf(service->hConnection, "%s: %s", service->GetModule(), service->HttpStatusToError(response->resultCode));
+ ShowNotification(TranslateT("server does not respond"), MB_ICONERROR);
+ return 0;
+ }
+
+ JSONNode node = root.at("error");
+ if (!node.isnull()) {
+ ptrW error_description(mir_a2u_cp(node.as_string().c_str(), CP_UTF8));
+ Netlib_Logf(service->hConnection, "%s: %s", service->GetModule(), service->HttpStatusToError(response->resultCode));
+ ShowNotification((wchar_t*)error_description, MB_ICONERROR);
+ return 0;
+ }
+
+ node = root.at("access_token");
+ db_set_s(NULL, service->GetModule(), "TokenSecret", node.as_string().c_str());
+
+ node = root.at("expires_in");
+ time_t expiresIn = time(NULL) + node.as_int();
+ db_set_dw(NULL, service->GetModule(), "ExpiresIn", expiresIn);
+
+ node = root.at("refresh_token");
+ db_set_s(NULL, service->GetModule(), "RefreshToken", node.as_string().c_str());
+
+ SetDlgItemTextA(hwndDlg, IDC_OAUTH_CODE, "");
+
+ EndDialog(hwndDlg, 1);
+
+ return 0;
+}
+
+unsigned COneDriveService::RevokeAccessTokenThread(void *param)
+{
+ //COneDriveService *service = (COneDriveService*)param;
+
+ /*ptrA token(db_get_sa(NULL, service->GetModule(), "TokenSecret"));
+ OneDriveAPI::RevokeAccessTokenRequest request(token);
+ NLHR_PTR response(request.Send(service->hConnection));*/
+
+ return 0;
+}
+
+void COneDriveService::HandleJsonError(JSONNode &node)
+{
+ JSONNode error = node.at("error");
+ if (!error.isnull()) {
+ json_string tag = error.at("message").as_string();
+ throw Exception(tag.c_str());
+ }
+}
+
+void COneDriveService::CreateUploadSession(char *uploadUri, const char *name, const char *parentId)
+{
+ ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret"));
+ OneDriveAPI::CreateUploadSessionRequest request = mir_strlen(parentId)
+ ? OneDriveAPI::CreateUploadSessionRequest(token, parentId, name)
+ : OneDriveAPI::CreateUploadSessionRequest(token, name);
+ NLHR_PTR response(request.Send(hConnection));
+
+ JSONNode root = GetJsonResponse(response);
+ JSONNode node = root.at("uploadUrl");
+ mir_strcpy(uploadUri, node.as_string().c_str());
+}
+
+void COneDriveService::UploadFileChunk(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize, char *itemId)
+{
+ OneDriveAPI::UploadFileChunkRequest request(uploadUri, chunk, chunkSize, offset, fileSize);
+ NLHR_PTR response(request.Send(hConnection));
+
+ if (response == NULL)
+ throw Exception(HttpStatusToError());
+
+ if (response->resultCode == HTTP_CODE_ACCEPTED)
+ return;
+
+ if (HTTP_CODE_SUCCESS(response->resultCode)) {
+ JSONNode root = GetJsonResponse(response);
+ JSONNode id = root.at("id");
+ mir_strcpy(itemId, id.as_string().c_str());
+ return;
+ }
+
+ if (response->dataLength)
+ throw Exception(response->pData);
+ throw Exception(HttpStatusToError(response->resultCode));
+}
+
+void COneDriveService::CreateFolder(const char *path, char *itemId)
+{
+ ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret"));
+ OneDriveAPI::CreateFolderRequest request(token, path);
+ NLHR_PTR response(request.Send(hConnection));
+
+ JSONNode root = GetJsonResponse(response);
+ JSONNode node = root.at("id");
+ mir_strcpy(itemId, node.as_string().c_str());
+}
+
+void COneDriveService::CreateSharedLink(const char *itemId, char *url)
+{
+ ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret"));
+ OneDriveAPI::CreateSharedLinkRequest request(token, itemId);
+ NLHR_PTR response(request.Send(hConnection));
+
+ JSONNode root = GetJsonResponse(response);
+ JSONNode node = root.at("webUrl");
+ mir_strcpy(url, node.as_string().c_str());
+}
+
+UINT COneDriveService::Upload(FileTransferParam *ftp)
+{
+ try {
+ if (!IsLoggedIn())
+ Login();
+
+ if (!IsLoggedIn()) {
+ ftp->SetStatus(ACKRESULT_FAILED);
+ return ACKRESULT_FAILED;
+ }
+
+ char folderId[32] = { 0 };
+ const wchar_t *folderName = ftp->GetFolderName();
+ if (folderName) {
+ char path[MAX_PATH], link[MAX_PATH];
+ PreparePath(folderName, path);
+ CreateFolder(path, folderId);
+ CreateSharedLink(path, link);
+ ftp->AppendFormatData(L"%s\r\n", ptrW(mir_utf8decodeW(link)));
+ }
+
+ ftp->FirstFile();
+ do
+ {
+ const wchar_t *fileName = ftp->GetCurrentRelativeFilePath();
+ uint64_t fileSize = ftp->GetCurrentFileSize();
+
+ uint64_t offset = 0;
+ char fileId[32];
+ char uploadUri[1024];
+ CreateUploadSession(uploadUri, T2Utf(fileName), folderId);
+
+ size_t chunkSize = ftp->GetCurrentFileChunkSize();
+ mir_ptr<char>chunk((char*)mir_calloc(chunkSize));
+
+ size_t size = 0;
+ for (size_t i = 0; i < (fileSize / chunkSize); i++)
+ {
+ ftp->CheckCurrentFile();
+
+ size = ftp->ReadCurrentFile(chunk, chunkSize);
+ if (size == 0)
+ break;
+
+ UploadFileChunk(uploadUri, chunk, size, offset, fileSize, fileId);
+
+ offset += size;
+ ftp->Progress(size);
+ }
+
+ if (!wcschr(fileName, L'\\')) {
+ char url[MAX_PATH];
+ CreateSharedLink(fileId, url);
+ ftp->AppendFormatData(L"%s\r\n", ptrW(mir_utf8decodeW(url)));
+ }
+ } while (ftp->NextFile());
+ }
+ catch (Exception &ex) {
+ Netlib_Logf(hConnection, "%s: %s", MODULE, ex.what());
+ ftp->SetStatus(ACKRESULT_FAILED);
+ return ACKRESULT_FAILED;
+ }
+
+ ftp->SetStatus(ACKRESULT_SUCCESS);
+ return ACKRESULT_SUCCESS;
+}
diff --git a/plugins/CloudFile/src/Services/microsoft_service.h b/plugins/CloudFile/src/Services/microsoft_service.h
new file mode 100644
index 0000000000..bf689ee8c2
--- /dev/null
+++ b/plugins/CloudFile/src/Services/microsoft_service.h
@@ -0,0 +1,31 @@
+#ifndef _CLOUDFILE_ONEDRIVE_H_
+#define _CLOUDFILE_ONEDRIVE_H_
+
+class COneDriveService : public CCloudService
+{
+private:
+ static unsigned RequestAccessTokenThread(void *owner, void *param);
+ static unsigned __stdcall RevokeAccessTokenThread(void *param);
+
+ void HandleJsonError(JSONNode &node);
+
+ void CreateUploadSession(char *uploadUri, const char *name, const char *parentId = NULL);
+ void UploadFileChunk(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize, char *itemId);
+ void CreateFolder(const char *path, char *itemId);
+ void CreateSharedLink(const char *itemId, char *url);
+
+public:
+ COneDriveService(HNETLIBUSER hConnection);
+
+ const char* GetModule() const;
+ const wchar_t* GetText() const;
+ HANDLE GetIcon() const;
+
+ bool IsLoggedIn();
+ void Login();
+ void Logout();
+
+ UINT Upload(FileTransferParam *ftp);
+};
+
+#endif //_CLOUDFILE_ONEDRIVE_H_ \ No newline at end of file