Skip to content

Commit

Permalink
[Cloud]Android oauth callback
Browse files Browse the repository at this point in the history
  • Loading branch information
OFFTKP committed Dec 16, 2023
1 parent 41f9237 commit bf340c1
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 37 deletions.
106 changes: 75 additions & 31 deletions src/cloud.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const char* se_get_pref_path();
#include <ctime>
#include <functional>
#include <map>
#include <thread>

#include "json.hpp"
#include "stb_image.h"
Expand All @@ -18,8 +19,12 @@ const char* se_get_pref_path();
#include "xxhash.h"

#ifndef EMSCRIPTEN
#include "httplib.h" // for server only
#include <curl/curl.h>
#ifdef SE_PLATFORM_ANDROID
#include <android/native_activity.h>
#else
#include "httplib.h" // for server only
#endif
#else
#include <emscripten.h>
#endif
Expand Down Expand Up @@ -49,6 +54,7 @@ void google_cloud_drive_init(cloud_drive_t*, std::function<void(cloud_drive_t*)>

#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
Expand Down Expand Up @@ -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<uint8_t>* data = (std::vector<uint8_t>*)d;
Expand Down Expand Up @@ -612,11 +617,77 @@ void google_cloud_drive_init(cloud_drive_t* drive, std::function<void(cloud_driv
});
}

void google_cloud_drive_use_auth_code(cloud_drive_t* drive, const std::string& auth_code, std::string code_verifier = "")
{
std::string query =
"client_id=" GOOGLE_CLIENT_ID "&client_secret=" + std::string(gsecret()) +
"&code=" + auth_code +
"&grant_type=authorization_code"
"&redirect_uri=http%3A//127.0.0.1%3A5000";
if (!code_verifier.empty())
{
query += "&code_verifier=" + code_verifier;
}

https_request(
http_request_e::POST, "https://oauth2.googleapis.com/token?" + query, "", {},
[drive](const std::vector<uint8_t>& 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<int>();
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;
Expand Down Expand Up @@ -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<uint8_t>& 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<int>();
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"))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -416,9 +419,10 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
Task<GoogleSignInAccount> 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);
}
Expand All @@ -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);
}

0 comments on commit bf340c1

Please sign in to comment.