00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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;
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);
00155 request->addHeader("Authorization: Bearer " + _token);
00156 request->addHeader("Dropbox-API-Arg: " + Common::JSON::stringify(&value));
00157 request->addHeader("Content-Type: ");
00158
00159 Networking::NetworkReadStreamResponse response = request->execute();
00160 if (callback)
00161 (*callback)(response);
00162 return response.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 }
00199 }