CLOUD: Update storages to refresh token via cloud.scummvm.org

This commit is contained in:
Alexander Tkachev 2019-07-15 22:14:23 +07:00 committed by Matan Bareket
parent 4a427faf9c
commit 60504dce75
10 changed files with 145 additions and 191 deletions

View File

@ -41,7 +41,7 @@ void BaseStorage::getAccessToken(Common::String code) {
Networking::JsonCallback callback = new Common::Callback<BaseStorage, Networking::JsonResponse>(this, &BaseStorage::codeFlowComplete);
Networking::ErrorCallback errorCallback = new Common::Callback<BaseStorage, Networking::ErrorResponse>(this, &BaseStorage::codeFlowFailed);
Common::String url = Common::String::format("https://cloud.scummvm.org/%s/%s", cloudProvider().c_str(), code.c_str());
Common::String url = Common::String::format("https://cloud.scummvm.org/%s/token/%s", cloudProvider().c_str(), code.c_str());
Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(callback, errorCallback, url);
addRequest(request);
@ -82,17 +82,33 @@ void BaseStorage::codeFlowComplete(Networking::JsonResponse response) {
return;
}
if (!Networking::CurlJsonRequest::jsonContainsString(result, "access_token", "BaseStorage::codeFlowComplete")) {
warning("BaseStorage: bad response, no 'access_token' attribute passed");
if (!Networking::CurlJsonRequest::jsonContainsObject(result, "oauth", "BaseStorage::codeFlowComplete")) {
warning("BaseStorage: bad response, no 'oauth' attribute passed");
debug(9, "%s", json->stringify(true).c_str());
CloudMan.removeStorage(this);
} else {
debug(9, "%s", json->stringify(true).c_str()); // TODO: remove before commit
_token = result.getVal("access_token")->asString();
CloudMan.replaceStorage(this, storageIndex());
ConfMan.flushToDisk();
delete json;
return;
}
Common::JSONObject oauth = result.getVal("oauth")->asObject();
bool requiresRefreshToken = needsRefreshToken();
if (!Networking::CurlJsonRequest::jsonContainsString(oauth, "access_token", "BaseStorage::codeFlowComplete") ||
!Networking::CurlJsonRequest::jsonContainsString(oauth, "refresh_token", "BaseStorage::codeFlowComplete", !requiresRefreshToken)) {
warning("BaseStorage: bad response, no 'access_token' or 'refresh_token' attribute passed");
debug(9, "%s", json->stringify(true).c_str());
CloudMan.removeStorage(this);
delete json;
return;
}
debug(9, "%s", json->stringify(true).c_str()); // TODO: remove before commit
_token = oauth.getVal("access_token")->asString();
if (requiresRefreshToken) {
_refreshToken = oauth.getVal("refresh_token")->asString();
}
CloudMan.replaceStorage(this, storageIndex());
ConfMan.flushToDisk();
delete json;
}
@ -102,4 +118,97 @@ void BaseStorage::codeFlowFailed(Networking::ErrorResponse error) {
CloudMan.removeStorage(this);
}
void BaseStorage::refreshAccessToken(BoolCallback callback, Networking::ErrorCallback errorCallback) {
if (_refreshToken == "") {
warning("BaseStorage: no refresh token available to get new access token.");
if (callback) (*callback)(BoolResponse(nullptr, false));
return;
}
Networking::JsonCallback innerCallback = new Common::CallbackBridge<BaseStorage, BoolResponse, Networking::JsonResponse>(this, &BaseStorage::tokenRefreshed, callback);
if (errorCallback == nullptr)
errorCallback = getErrorPrintingCallback();
Common::String url = Common::String::format("https://cloud.scummvm.org/%s/refresh?code=%s", cloudProvider().c_str(), _refreshToken.c_str());
Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, errorCallback, url);
addRequest(request);
}
void BaseStorage::tokenRefreshed(BoolCallback callback, Networking::JsonResponse response) {
Common::JSONValue *json = response.value;
if (json == nullptr) {
debug(9, "BaseStorage::tokenRefreshed: got NULL instead of JSON!");
if (callback)
(*callback)(BoolResponse(nullptr, false));
delete callback;
return;
}
if (!json->isObject()) {
debug(9, "BaseStorage::tokenRefreshed: passed JSON is not an object!");
if (callback)
(*callback)(BoolResponse(nullptr, false));
delete json;
delete callback;
return;
}
Common::JSONObject result = json->asObject();
if (!Networking::CurlJsonRequest::jsonContainsAttribute(result, "error", "BaseStorage::tokenRefreshed")) {
warning("BaseStorage: bad response, no 'error' attribute passed");
debug(9, "%s", json->stringify(true).c_str());
if (callback)
(*callback)(BoolResponse(nullptr, false));
delete json;
delete callback;
return;
}
if (result.getVal("error")->asBool()) {
Common::String errorMessage = "{error: true}, message is missing";
if (Networking::CurlJsonRequest::jsonContainsString(result, "message", "BaseStorage::tokenRefreshed")) {
errorMessage = result.getVal("message")->asString();
}
warning("BaseStorage: response says error occurred: %s", errorMessage.c_str());
if (callback)
(*callback)(BoolResponse(nullptr, false));
delete json;
delete callback;
return;
}
if (!Networking::CurlJsonRequest::jsonContainsObject(result, "oauth", "BaseStorage::tokenRefreshed")) {
warning("BaseStorage: bad response, no 'oauth' attribute passed");
debug(9, "%s", json->stringify(true).c_str());
if (callback)
(*callback)(BoolResponse(nullptr, false));
delete json;
delete callback;
return;
}
Common::JSONObject oauth = result.getVal("oauth")->asObject();
bool requiresRefreshToken = needsRefreshToken(); // TODO: it seems Google Drive might not send new refresh token, and still accept old one
if (!Networking::CurlJsonRequest::jsonContainsString(oauth, "access_token", "BaseStorage::tokenRefreshed") ||
!Networking::CurlJsonRequest::jsonContainsString(oauth, "refresh_token", "BaseStorage::tokenRefreshed", !requiresRefreshToken)) {
warning("BaseStorage: bad response, no 'access_token' or 'refresh_token' attribute passed");
debug(9, "%s", json->stringify(true).c_str());
if (callback)
(*callback)(BoolResponse(nullptr, false));
delete json;
delete callback;
return;
}
_token = oauth.getVal("access_token")->asString();
if (requiresRefreshToken) {
_refreshToken = oauth.getVal("refresh_token")->asString();
}
CloudMan.save(); //ask CloudManager to save our new access_token and refresh_token
if (callback)
(*callback)(BoolResponse(nullptr, true));
delete json;
delete callback;
}
} // End of namespace Cloud

View File

@ -64,10 +64,24 @@ protected:
*/
virtual uint32 storageIndex() = 0;
/**
* Return whether storage needs refresh_token to work.
*/
virtual bool needsRefreshToken() = 0;
private:
void tokenRefreshed(BoolCallback callback, Networking::JsonResponse response);
public:
BaseStorage();
BaseStorage(Common::String token, Common::String refreshToken);
virtual ~BaseStorage();
/**
* Gets new access_token. Pass a callback, so you could
* continue your work when new token is available.
*/
virtual void refreshAccessToken(BoolCallback callback, Networking::ErrorCallback errorCallback = nullptr);
};
} // End of namespace Cloud

View File

@ -55,57 +55,7 @@ Common::String BoxStorage::cloudProvider() { return "box"; }
uint32 BoxStorage::storageIndex() { return kStorageBoxId; }
void BoxStorage::refreshAccessToken(BoolCallback callback, Networking::ErrorCallback errorCallback) {
if (_refreshToken == "") {
warning("BoxStorage: no refresh token available to get new access token.");
if (callback) (*callback)(BoolResponse(nullptr, false));
return;
}
Networking::JsonCallback innerCallback = new Common::CallbackBridge<BoxStorage, BoolResponse, Networking::JsonResponse>(this, &BoxStorage::tokenRefreshed, callback);
if (errorCallback == nullptr)
errorCallback = getErrorPrintingCallback();
Common::String url = "https://cloud.scummvm.org/box/refresh/" + _refreshToken; // TODO: subject to change
Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, errorCallback, url);
addRequest(request);
}
void BoxStorage::tokenRefreshed(BoolCallback callback, Networking::JsonResponse response) {
Common::JSONValue *json = response.value;
if (!json) {
warning("BoxStorage: got NULL instead of JSON");
if (callback)
(*callback)(BoolResponse(nullptr, false));
delete callback;
return;
}
if (!Networking::CurlJsonRequest::jsonIsObject(json, "BoxStorage")) {
if (callback)
(*callback)(BoolResponse(nullptr, false));
delete json;
delete callback;
return;
}
Common::JSONObject result = json->asObject();
if (!Networking::CurlJsonRequest::jsonContainsString(result, "access_token", "BoxStorage") ||
!Networking::CurlJsonRequest::jsonContainsString(result, "refresh_token", "BoxStorage")) {
warning("BoxStorage: bad response, no token passed");
debug(9, "%s", json->stringify().c_str());
if (callback)
(*callback)(BoolResponse(nullptr, false));
} else {
_token = result.getVal("access_token")->asString();
_refreshToken = result.getVal("refresh_token")->asString();
CloudMan.save(); //ask CloudManager to save our new refreshToken
if (callback)
(*callback)(BoolResponse(nullptr, true));
}
delete json;
delete callback;
}
bool BoxStorage::needsRefreshToken() { return true; }
void BoxStorage::saveConfig(Common::String keyPrefix) {
ConfMan.set(keyPrefix + "access_token", _token, ConfMan.kCloudDomain);

View File

@ -33,8 +33,6 @@ class BoxStorage: public Id::IdStorage {
/** This private constructor is called from loadFromConfig(). */
BoxStorage(Common::String token, Common::String refreshToken);
void tokenRefreshed(BoolCallback callback, Networking::JsonResponse response);
/** Constructs StorageInfo based on JSON response from cloud. */
void infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse json);
@ -51,6 +49,8 @@ protected:
*/
virtual uint32 storageIndex();
virtual bool needsRefreshToken();
public:
/** This constructor uses OAuth code flow to get tokens. */
BoxStorage(Common::String code);
@ -104,12 +104,6 @@ public:
virtual Common::String getRootDirectoryId();
/**
* Gets new access_token. Pass a callback, so you could
* continue your work when new token is available.
*/
void refreshAccessToken(BoolCallback callback, Networking::ErrorCallback errorCallback = nullptr);
Common::String accessToken() const { return _token; }
};

View File

@ -52,6 +52,8 @@ Common::String DropboxStorage::cloudProvider() { return "dropbox"; }
uint32 DropboxStorage::storageIndex() { return kStorageDropboxId; }
bool DropboxStorage::needsRefreshToken() { return false; }
void DropboxStorage::saveConfig(Common::String keyPrefix) {
ConfMan.set(keyPrefix + "access_token", _token, ConfMan.kCloudDomain);
}

View File

@ -45,6 +45,8 @@ protected:
*/
virtual uint32 storageIndex();
virtual bool needsRefreshToken();
public:
/** This constructor uses OAuth code flow to get tokens. */
DropboxStorage(Common::String code);

View File

@ -56,60 +56,7 @@ Common::String GoogleDriveStorage::cloudProvider() { return "gdrive"; }
uint32 GoogleDriveStorage::storageIndex() { return kStorageGoogleDriveId; }
void GoogleDriveStorage::refreshAccessToken(BoolCallback callback, Networking::ErrorCallback errorCallback) {
if (_refreshToken == "") {
warning("GoogleDriveStorage: no refresh token available to get new access token.");
if (callback)
(*callback)(BoolResponse(nullptr, false));
return;
}
Networking::JsonCallback innerCallback = new Common::CallbackBridge<GoogleDriveStorage, BoolResponse, Networking::JsonResponse>(this, &GoogleDriveStorage::tokenRefreshed, callback);
if (errorCallback == nullptr)
errorCallback = getErrorPrintingCallback();
Common::String url = "https://cloud.scummvm.org/gdrive/refresh/" + _refreshToken; // TODO: subject to change
Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, errorCallback, url);
addRequest(request);
}
void GoogleDriveStorage::tokenRefreshed(BoolCallback callback, Networking::JsonResponse response) {
Common::JSONValue *json = response.value;
if (!json) {
warning("GoogleDriveStorage: got NULL instead of JSON");
if (callback)
(*callback)(BoolResponse(nullptr, false));
delete callback;
return;
}
if (!Networking::CurlJsonRequest::jsonIsObject(json, "GoogleDriveStorage")) {
if (callback)
(*callback)(BoolResponse(nullptr, false));
delete json;
delete callback;
return;
}
Common::JSONObject result = json->asObject();
if (!Networking::CurlJsonRequest::jsonContainsString(result, "access_token", "GoogleDriveStorage")) {
warning("GoogleDriveStorage: bad response, no token passed");
debug(9, "%s", json->stringify().c_str());
if (callback)
(*callback)(BoolResponse(nullptr, false));
} else {
_token = result.getVal("access_token")->asString();
if (!Networking::CurlJsonRequest::jsonContainsString(result, "refresh_token", "GoogleDriveStorage"))
warning("GoogleDriveStorage: no refresh_token passed");
else
_refreshToken = result.getVal("refresh_token")->asString();
CloudMan.save(); //ask CloudManager to save our new refreshToken
if (callback)
(*callback)(BoolResponse(nullptr, true));
}
delete json;
delete callback;
}
bool GoogleDriveStorage::needsRefreshToken() { return true; }
void GoogleDriveStorage::saveConfig(Common::String keyPrefix) {
ConfMan.set(keyPrefix + "access_token", _token, ConfMan.kCloudDomain);

View File

@ -33,8 +33,6 @@ class GoogleDriveStorage: public Id::IdStorage {
/** This private constructor is called from loadFromConfig(). */
GoogleDriveStorage(Common::String token, Common::String refreshToken);
void tokenRefreshed(BoolCallback callback, Networking::JsonResponse response);
/** Constructs StorageInfo based on JSON response from cloud. */
void infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse json);
@ -54,6 +52,8 @@ protected:
*/
virtual uint32 storageIndex();
virtual bool needsRefreshToken();
public:
/** This constructor uses OAuth code flow to get tokens. */
GoogleDriveStorage(Common::String code);
@ -106,12 +106,6 @@ public:
virtual Common::String getRootDirectoryId();
/**
* Gets new access_token. Pass a callback, so you could
* continue your work when new token is available.
*/
void refreshAccessToken(BoolCallback callback, Networking::ErrorCallback errorCallback = nullptr);
Common::String accessToken() const { return _token; }
};

View File

@ -42,7 +42,7 @@ namespace OneDrive {
#define ONEDRIVE_API_SPECIAL_APPROOT_ID "https://api.onedrive.com/v1.0/drive/special/approot:/"
#define ONEDRIVE_API_SPECIAL_APPROOT "https://api.onedrive.com/v1.0/drive/special/approot"
OneDriveStorage::OneDriveStorage(Common::String token, Common::String refreshToken):
OneDriveStorage::OneDriveStorage(Common::String token, Common::String refreshToken):
BaseStorage(token, refreshToken) {}
OneDriveStorage::OneDriveStorage(Common::String code) {
@ -55,59 +55,7 @@ Common::String OneDriveStorage::cloudProvider() { return "onedrive"; }
uint32 OneDriveStorage::storageIndex() { return kStorageOneDriveId; }
void OneDriveStorage::refreshAccessToken(BoolCallback callback, Networking::ErrorCallback errorCallback) {
if (_refreshToken == "") {
warning("OneDriveStorage: no refresh token available to get new access token.");
if (callback)
(*callback)(BoolResponse(nullptr, false));
return;
}
Networking::JsonCallback innerCallback = new Common::CallbackBridge<OneDriveStorage, BoolResponse, Networking::JsonResponse>(this, &OneDriveStorage::tokenRefreshed, callback);
if (errorCallback == nullptr)
errorCallback = getErrorPrintingCallback();
Common::String url = "https://cloud.scummvm.org/onedrive/refresh/" + _refreshToken; // TODO: subject to change
Networking::CurlJsonRequest *request = new Networking::CurlJsonRequest(innerCallback, errorCallback, url);
addRequest(request);
}
void OneDriveStorage::tokenRefreshed(BoolCallback callback, Networking::JsonResponse response) {
Common::JSONValue *json = response.value;
if (!json) {
warning("OneDriveStorage: got NULL instead of JSON");
if (callback)
(*callback)(BoolResponse(nullptr, false));
delete callback;
return;
}
if (!Networking::CurlJsonRequest::jsonIsObject(json, "OneDriveStorage")) {
if (callback)
(*callback)(BoolResponse(nullptr, false));
delete json;
delete callback;
return;
}
Common::JSONObject result = json->asObject();
if (!Networking::CurlJsonRequest::jsonContainsString(result, "access_token", "OneDriveStorage") ||
!Networking::CurlJsonRequest::jsonContainsString(result, "user_id", "OneDriveStorage") ||
!Networking::CurlJsonRequest::jsonContainsString(result, "refresh_token", "OneDriveStorage")) {
warning("OneDriveStorage: bad response, no token or user_id passed");
debug(9, "%s", json->stringify().c_str());
if (callback)
(*callback)(BoolResponse(nullptr, false));
} else {
_token = result.getVal("access_token")->asString();
_refreshToken = result.getVal("refresh_token")->asString();
CloudMan.save(); //ask CloudManager to save our new refreshToken
if (callback)
(*callback)(BoolResponse(nullptr, true));
}
delete json;
delete callback;
}
bool OneDriveStorage::needsRefreshToken() { return true; }
void OneDriveStorage::saveConfig(Common::String keyPrefix) {
ConfMan.set(keyPrefix + "access_token", _token, ConfMan.kCloudDomain);

View File

@ -33,8 +33,6 @@ class OneDriveStorage: public Cloud::BaseStorage {
/** This private constructor is called from loadFromConfig(). */
OneDriveStorage(Common::String token, Common::String refreshToken);
void tokenRefreshed(BoolCallback callback, Networking::JsonResponse response);
/** Constructs StorageInfo based on JSON response from cloud. */
void infoInnerCallback(StorageInfoCallback outerCallback, Networking::JsonResponse json);
@ -51,6 +49,8 @@ protected:
*/
virtual uint32 storageIndex();
virtual bool needsRefreshToken();
public:
/** This constructor uses OAuth code flow to get tokens. */
OneDriveStorage(Common::String code);
@ -101,12 +101,6 @@ public:
*/
static OneDriveStorage *loadFromConfig(Common::String keyPrefix);
/**
* Gets new access_token. Pass a callback, so you could
* continue your work when new token is available.
*/
void refreshAccessToken(BoolCallback callback, Networking::ErrorCallback errorCallback = nullptr);
Common::String accessToken() const { return _token; }
};