From bf340c1489952be0f467192db10de5369a18d669 Mon Sep 17 00:00:00 2001 From: offtkp Date: Sat, 16 Dec 2023 18:33:03 +0200 Subject: [PATCH] [Cloud]Android oauth callback --- src/cloud.cpp | 106 +++++++++++++----- .../sky/SkyEmu/EnhancedNativeActivity.java | 17 ++- 2 files changed, 86 insertions(+), 37 deletions(-) diff --git a/src/cloud.cpp b/src/cloud.cpp index f49be6f68..868016b35 100644 --- a/src/cloud.cpp +++ b/src/cloud.cpp @@ -10,6 +10,7 @@ const char* se_get_pref_path(); #include #include #include +#include #include "json.hpp" #include "stb_image.h" @@ -18,8 +19,12 @@ const char* se_get_pref_path(); #include "xxhash.h" #ifndef EMSCRIPTEN -#include "httplib.h" // for server only #include +#ifdef SE_PLATFORM_ANDROID +#include +#else +#include "httplib.h" // for server only +#endif #else #include #endif @@ -49,6 +54,7 @@ void google_cloud_drive_init(cloud_drive_t*, std::function #define GOOGLE_CLIENT_ID "617320710875-o9ev86s5ad18bmmgb98p0dkbqlfufekr.apps.googleusercontent.com" #define GOOGLE_CLIENT_ID_WEB "617320710875-dakb2f10lgnnn3a97bgva18l83221pc3.apps.googleusercontent.com" +#define GOOGLE_CLIENT_ID_ANDROID "1056817960763-4fsvq0q3r8n73p7gbs96bmau6f7rfg1h.apps.googleusercontent.com" // Secrets are not really secret in native oauth2 apps // It's encoded in hexadecimal here so automatic scanners don't complain @@ -90,7 +96,6 @@ static void em_flush_fs() } #ifndef EMSCRIPTEN - size_t curl_write_data(void* buffer, size_t size, size_t nmemb, void* d) { std::vector* data = (std::vector*)d; @@ -612,11 +617,77 @@ void google_cloud_drive_init(cloud_drive_t* drive, std::function& data) { + std::string refresh_path = drive->save_directory + "refresh_token.txt"; + nlohmann::json json = nlohmann::json::parse(data); + if (json.find("error") != json.end()) + { + std::string error = json["error"]; + std::string error_description = json["error_description"]; + printf("[cloud] got response with error while authenticating: %s: %s\n", + error.c_str(), error_description.c_str()); + delete drive; + return; + } + + drive->access_token = json["access_token"]; + drive->refresh_token = json["refresh_token"]; + nlohmann::json expires_in = json["expires_in"]; + drive->expire_timestamp = time(NULL) + expires_in.get(); + sb_save_file_data(refresh_path.c_str(), (uint8_t*)drive->refresh_token.c_str(), + drive->refresh_token.size() + 1); + em_flush_fs(); + google_cloud_drive_init(drive, drive->ready_callback); + }); +} + +#ifdef SE_PLATFORM_ANDROID +void Java_com_sky_SkyEmu_EnhancedNativeActivity_cloud_1oauth_1callback(JNIEnv* env, jobject thiz, jlong drivePtr, jstring authCode) { + cloud_drive_t* drive = (cloud_drive_t*)drivePtr; + const char* auth_code = env->GetStringUTFChars(authCode, NULL); + printf("[cloud] got auth code: %s\n", auth_code); + google_cloud_drive_use_auth_code(drive, auth_code); + env->ReleaseStringUTFChars(authCode, auth_code); +} +extern "C" const void* sapp_android_get_native_activity(); +#endif + void cloud_drive_authenticate(cloud_drive_t* drive) { #ifdef EMSCRIPTEN return em_oath_sign_in(drive, GOOGLE_CLIENT_ID_WEB); -#elif !defined(SE_PLATFORM_ANDROID) && !defined(SE_PLATFORM_IOS) +#elif defined(SE_PLATFORM_ANDROID) + ANativeActivity* activity = (ANativeActivity*)sapp_android_get_native_activity(); + JavaVM* pJavaVM = activity->vm; + JNIEnv* pJNIEnv = activity->env; + jint nResult = pJavaVM->AttachCurrentThread(&pJNIEnv, NULL); + if (nResult != JNI_ERR) + { + jobject nativeActivity = activity->clazz; + jclass ClassNativeActivity = pJNIEnv->GetObjectClass(nativeActivity); + // Method signature -> void(long, String) + jstring clientID = pJNIEnv->NewStringUTF(GOOGLE_CLIENT_ID_ANDROID); + jmethodID MethodAuthenticateDrive = pJNIEnv->GetMethodID(ClassNativeActivity, "authenticateDrive", "(JLjava/lang/String;)V"); + pJNIEnv->CallVoidMethod(nativeActivity, MethodAuthenticateDrive, (jlong)drive, clientID); + pJavaVM->DetachCurrentThread(); + } + return; +#elif defined(SE_PLATFORM_IOS) +#else srand(time(NULL)); const char* charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; std::string code_verifier; @@ -666,34 +737,7 @@ void cloud_drive_authenticate(cloud_drive_t* drive) // Exchange authorization code for refresh and access tokens res.set_content("You may close this tab", "text/plain"); std::string auth_code = req.get_param_value("code"); - std::string query = - "client_id=" GOOGLE_CLIENT_ID "&client_secret=" + std::string(gsecret()) + - "&code=" + auth_code + "&code_verifier=" + code_verifier + - "&grant_type=authorization_code" - "&redirect_uri=http%3A//127.0.0.1%3A5000"; - https_request( - http_request_e::POST, "https://oauth2.googleapis.com/token?" + query, "", {}, - [drive, &refresh_path](const std::vector& data) { - nlohmann::json json = nlohmann::json::parse(data); - if (json.find("error") != json.end()) - { - std::string error = json["error"]; - std::string error_description = json["error_description"]; - printf("[cloud] got response with error while authenticating: %s: %s\n", - error.c_str(), error_description.c_str()); - delete drive; - return; - } - - drive->access_token = json["access_token"]; - drive->refresh_token = json["refresh_token"]; - nlohmann::json expires_in = json["expires_in"]; - drive->expire_timestamp = time(NULL) + expires_in.get(); - sb_save_file_data(refresh_path.c_str(), (uint8_t*)drive->refresh_token.c_str(), - drive->refresh_token.size() + 1); - em_flush_fs(); - google_cloud_drive_init(drive, drive->ready_callback); - }); + google_cloud_drive_use_auth_code(drive, auth_code, code_verifier); } else if (req.has_param("error")) { diff --git a/tools/android_project/app/src/main/java/com/sky/SkyEmu/EnhancedNativeActivity.java b/tools/android_project/app/src/main/java/com/sky/SkyEmu/EnhancedNativeActivity.java index 3b561ded5..0bb29768c 100644 --- a/tools/android_project/app/src/main/java/com/sky/SkyEmu/EnhancedNativeActivity.java +++ b/tools/android_project/app/src/main/java/com/sky/SkyEmu/EnhancedNativeActivity.java @@ -385,22 +385,25 @@ public void loadURI(Uri selectedFileUri, boolean is_rom){ } } } - public void authenticateDrive(){ - String serverClientId = "1056817960763-4fsvq0q3r8n73p7gbs96bmau6f7rfg1h.apps.googleusercontent.com"; + public void authenticateDrive(long drivePtr, String clientId){ + Log.i(TAG, "1authenticateDrive: " + clientId); + Log.i(TAG, "2authenticateDrive: " + drivePtr); GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestScopes(new Scope(Scopes.DRIVE_FILE)) - .requestServerAuthCode(serverClientId) + .requestServerAuthCode(clientId) .requestEmail() .build(); GoogleSignInClient signInClient = GoogleSignIn.getClient(this, gso); Intent signInIntent = signInClient.getSignInIntent(); + signInIntent.putExtra("drivePtr", drivePtr); startActivityForResult(signInIntent, GOOGLE_OAUTH_RESPONSE_CODE); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); // If the selection didn't work if (resultCode != RESULT_OK) { - // Exit without doing anything else + Log.e(TAG, "onActivityResult: Result code was not OK: " + resultCode); return; } else { switch (requestCode) @@ -416,9 +419,10 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { Task task = GoogleSignIn.getSignedInAccountFromIntent(data); try { GoogleSignInAccount account = task.getResult(ApiException.class); + long drivePtr = data.getLongExtra("drivePtr", 0); String authCode = account.getServerAuthCode(); - - Log.w(TAG, "Sign-in succeeded: " + account.getDisplayName() + " " + account.getEmail() + " " + authCode); + Log.i(TAG, "Google Drive OAuth2 token: " + authCode); + cloud_oauth_callback(drivePtr, authCode); } catch (ApiException e) { Log.w(TAG, "Sign-in failed", e); } @@ -432,4 +436,5 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { } public native void se_android_load_file(String filePath); public native void se_android_load_rom(String filePath); + public native void cloud_oauth_callback(long drivePtr, String authCode); }