ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

dropboxstorage.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #define FORBIDDEN_SYMBOL_ALLOW_ALL
00024 
00025 #include <curl/curl.h>
00026 #include "backends/cloud/dropbox/dropboxstorage.h"
00027 #include "backends/cloud/dropbox/dropboxcreatedirectoryrequest.h"
00028 #include "backends/cloud/dropbox/dropboxinforequest.h"
00029 #include "backends/cloud/dropbox/dropboxlistdirectoryrequest.h"
00030 #include "backends/cloud/dropbox/dropboxuploadrequest.h"
00031 #include "backends/cloud/cloudmanager.h"
00032 #include "backends/networking/curl/connectionmanager.h"
00033 #include "backends/networking/curl/curljsonrequest.h"
00034 #include "common/config-manager.h"
00035 #include "common/debug.h"
00036 #include "common/json.h"
00037 
00038 #ifdef ENABLE_RELEASE
00039 #include "dists/clouds/cloud_keys.h"
00040 #endif
00041 
00042 namespace Cloud {
00043 namespace Dropbox {
00044 
00045 #define DROPBOX_OAUTH2_TOKEN "https://api.dropboxapi.com/oauth2/token"
00046 #define DROPBOX_API_FILES_DOWNLOAD "https://content.dropboxapi.com/2/files/download"
00047 
00048 char *DropboxStorage::KEY = nullptr; //can't use CloudConfig there yet, loading it on instance creation/auth
00049 char *DropboxStorage::SECRET = nullptr;
00050 
00051 void DropboxStorage::loadKeyAndSecret() {
00052 #ifdef ENABLE_RELEASE
00053     KEY = RELEASE_DROPBOX_KEY;
00054     SECRET = RELEASE_DROPBOX_SECRET;
00055 #else
00056     Common::String k = ConfMan.get("DROPBOX_KEY", ConfMan.kCloudDomain);
00057     KEY = new char[k.size() + 1];
00058     memcpy(KEY, k.c_str(), k.size());
00059     KEY[k.size()] = 0;
00060 
00061     k = ConfMan.get("DROPBOX_SECRET", ConfMan.kCloudDomain);
00062     SECRET = new char[k.size() + 1];
00063     memcpy(SECRET, k.c_str(), k.size());
00064     SECRET[k.size()] = 0;
00065 #endif
00066 }
00067 
00068 DropboxStorage::DropboxStorage(Common::String accessToken, Common::String userId): _token(accessToken), _uid(userId) {}
00069 
00070 DropboxStorage::DropboxStorage(Common::String code) {
00071     getAccessToken(code);
00072 }
00073 
00074 DropboxStorage::~DropboxStorage() {}
00075 
00076 void DropboxStorage::getAccessToken(Common::String code) {
00077     if (!KEY || !SECRET)
00078         loadKeyAndSecret();
00079     Networking::JsonCallback callback = new Common::Callback<DropboxStorage, Networking::JsonResponse>(this, &DropboxStorage::codeFlowComplete);
00080     Networking::ErrorCallback errorCallback = new Common::Callback<DropboxStorage, Networking::ErrorResponse>(this, &DropboxStorage::codeFlowFailed);
00081     Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(callback, errorCallback, DROPBOX_OAUTH2_TOKEN);
00082     request->addPostField("code=" + code);
00083     request->addPostField("grant_type=authorization_code");
00084     request->addPostField("client_id=" + Common::String(KEY));
00085     request->addPostField("client_secret=" + Common::String(SECRET));
00086     if (Cloud::CloudManager::couldUseLocalServer()) {
00087         request->addPostField("&redirect_uri=http%3A%2F%2Flocalhost%3A12345%2F");
00088     } else {
00089         request->addPostField("&redirect_uri=https%3A%2F%2Fwww.scummvm.org/c/code");
00090     }
00091     addRequest(request);
00092 }
00093 
00094 void DropboxStorage::codeFlowComplete(Networking::JsonResponse response) {
00095     Common::JSONValue *json = (Common::JSONValue *)response.value;
00096     if (json == nullptr) {
00097         debug(9, "DropboxStorage::codeFlowComplete: got NULL instead of JSON!");
00098         CloudMan.removeStorage(this);
00099         return;
00100     }
00101 
00102     if (!json->isObject()) {
00103         debug(9, "DropboxStorage::codeFlowComplete: Passed JSON is not an object!");
00104         CloudMan.removeStorage(this);
00105         delete json;
00106         return;
00107     }
00108 
00109     Common::JSONObject result = json->asObject();
00110     if (!Networking::CurlJsonRequest::jsonContainsString(result, "access_token", "DropboxStorage::codeFlowComplete") ||
00111         !Networking::CurlJsonRequest::jsonContainsString(result, "uid", "DropboxStorage::codeFlowComplete")) {
00112         warning("DropboxStorage: bad response, no token/uid passed");
00113         debug(9, "%s", json->stringify(true).c_str());
00114         CloudMan.removeStorage(this);
00115     } else {
00116         _token = result.getVal("access_token")->asString();
00117         _uid = result.getVal("uid")->asString();
00118         ConfMan.removeKey("dropbox_code", ConfMan.kCloudDomain);
00119         CloudMan.replaceStorage(this, kStorageDropboxId);
00120         ConfMan.flushToDisk();
00121     }
00122 
00123     delete json;
00124 }
00125 
00126 void DropboxStorage::codeFlowFailed(Networking::ErrorResponse error) {
00127     debug(9, "DropboxStorage: code flow failed (%s, %ld):", (error.failed ? "failed" : "interrupted"), error.httpResponseCode);
00128     debug(9, "%s", error.response.c_str());
00129     CloudMan.removeStorage(this);
00130 }
00131 
00132 void DropboxStorage::saveConfig(Common::String keyPrefix) {
00133     ConfMan.set(keyPrefix + "access_token", _token, ConfMan.kCloudDomain);
00134     ConfMan.set(keyPrefix + "user_id", _uid, ConfMan.kCloudDomain);
00135 }
00136 
00137 Common::String DropboxStorage::name() const {
00138     return "Dropbox";
00139 }
00140 
00141 Networking::Request *DropboxStorage::listDirectory(Common::String path, ListDirectoryCallback outerCallback, Networking::ErrorCallback errorCallback, bool recursive) {
00142     return addRequest(new DropboxListDirectoryRequest(_token, path, outerCallback, errorCallback, recursive));
00143 }
00144 
00145 Networking::Request *DropboxStorage::upload(Common::String path, Common::SeekableReadStream *contents, UploadCallback callback, Networking::ErrorCallback errorCallback) {
00146     return addRequest(new DropboxUploadRequest(_token, path, contents, callback, errorCallback));
00147 }
00148 
00149 Networking::Request *DropboxStorage::streamFileById(Common::String path, Networking::NetworkReadStreamCallback callback, Networking::ErrorCallback errorCallback) {
00150     Common::JSONObject jsonRequestParameters;
00151     jsonRequestParameters.setVal("path", new Common::JSONValue(path));
00152     Common::JSONValue value(jsonRequestParameters);
00153 
00154     Networking::CurlRequest *request = new Networking::CurlRequest(nullptr, nullptr, DROPBOX_API_FILES_DOWNLOAD); //TODO: is it OK to pass no callbacks?
00155     request->addHeader("Authorization: Bearer " + _token);
00156     request->addHeader("Dropbox-API-Arg: " + Common::JSON::stringify(&value));
00157     request->addHeader("Content-Type: "); //required to be empty (as we do POST, it's usually app/form-url-encoded)
00158 
00159     Networking::NetworkReadStreamResponse response = request->execute();
00160     if (callback)
00161         (*callback)(response);
00162     return response.request; // no leak here, response.request == request
00163 }
00164 
00165 Networking::Request *DropboxStorage::createDirectory(Common::String path, BoolCallback callback, Networking::ErrorCallback errorCallback) {
00166     if (!errorCallback)
00167         errorCallback = getErrorPrintingCallback();
00168     return addRequest(new DropboxCreateDirectoryRequest(_token, path, callback, errorCallback));
00169 }
00170 
00171 Networking::Request *DropboxStorage::info(StorageInfoCallback callback, Networking::ErrorCallback errorCallback) {
00172     if (!errorCallback)
00173         errorCallback = getErrorPrintingCallback();
00174     return addRequest(new DropboxInfoRequest(_token, callback, errorCallback));
00175 }
00176 
00177 Common::String DropboxStorage::savesDirectoryPath() { return "/saves/"; }
00178 
00179 DropboxStorage *DropboxStorage::loadFromConfig(Common::String keyPrefix) {
00180     loadKeyAndSecret();
00181 
00182     if (!ConfMan.hasKey(keyPrefix + "access_token", ConfMan.kCloudDomain)) {
00183         warning("DropboxStorage: no access_token found");
00184         return nullptr;
00185     }
00186 
00187     if (!ConfMan.hasKey(keyPrefix + "user_id", ConfMan.kCloudDomain)) {
00188         warning("DropboxStorage: no user_id found");
00189         return nullptr;
00190     }
00191 
00192     Common::String accessToken = ConfMan.get(keyPrefix + "access_token", ConfMan.kCloudDomain);
00193     Common::String userId = ConfMan.get(keyPrefix + "user_id", ConfMan.kCloudDomain);
00194 
00195     return new DropboxStorage(accessToken, userId);
00196 }
00197 
00198 } // End of namespace Dropbox
00199 } // End of namespace Cloud


Generated on Sat Mar 16 2019 05:01:25 for ResidualVM by doxygen 1.7.1
curved edge   curved edge