From 7cd169a40d01069f978cbbb97a2582c89df41050 Mon Sep 17 00:00:00 2001 From: Remek Zajac# Date: Sat, 29 Apr 2017 09:58:52 +0100 Subject: [PATCH] review comments --- README.md | 5 +-- plugin.xml | 1 - src/android/GooglePlus.java | 72 ++++++++++++++++++++++--------------- 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index d2908c28..9706ce8d 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ Login on iOS takes the user to a [SafariViewController](https://developer.apple. ### Android To configure Android, [generate a configuration file here](https://developers.google.com/mobile/add?platform=android&cntapi=signin). Once Google Sign-In is enabled Google will automatically create necessary credentials in Developer Console. There is no need to add the generated google-services.json file into your cordova project. -Make sure you execute the `keytool` steps as explained [here](https://developers.google.com/android/guides/client-auth) or authentication will fail. +Make sure you execute the `keytool` steps as explained [here](https://developers.google.com/drive/android/auth) or authentication will fail (do this for both release and debug keystores). IMPORTANT: * The step above, about `keytool`, show 2 types of certificate fingerprints, the **Release** and the **Debug**, when generating the configuration file, it's better to use the **Debug** certificate fingerprint, after that, you have to go on [Google Credentials Manager](https://console.developers.google.com/apis/credentials), and manually create a credential for **OAuth2 client** with your **Release** certificate fingerprint. This is necessary to your application work on both Development and Production releases. @@ -148,7 +148,7 @@ function deviceReady() { The login function walks the user through the Google Auth process. All parameters are optional, however there are a few caveats. -To get an `idToken` on Android, you ***must*** pass in your `webClientId`. On iOS, the `idToken` is included in the sign in result by default. +To get an `idToken` on Android, you ***must*** pass in your `webClientId` (a frequent mistake is to supply Android Client ID). On iOS, the `idToken` is included in the sign in result by default. To get a `serverAuthCode`, you must pass in your `webClientId` _and_ set `offline` to true. If offline is true, but no webClientId is provided, the `serverAuthCode` will _**NOT**_ be requested. @@ -183,6 +183,7 @@ The success callback (second argument) gets a JSON object with the following con obj.imageUrl // 'http://link-to-my-profilepic.google.com' obj.idToken // idToken that can be exchanged to verify user identity. obj.serverAuthCode // Auth code that can be exchanged for an access token and refresh token for offline access + obj.accessToken // OAuth2 access token ``` Additional user information is available by use case. Add the scopes needed to the scopes option then return the info to the result object being created in the `handleSignInResult` and `didSignInForUser` functions on Android and iOS, respectively. diff --git a/plugin.xml b/plugin.xml index f93a5546..85a3268c 100755 --- a/plugin.xml +++ b/plugin.xml @@ -31,7 +31,6 @@ - diff --git a/src/android/GooglePlus.java b/src/android/GooglePlus.java index fd3ee316..4e643707 100644 --- a/src/android/GooglePlus.java +++ b/src/android/GooglePlus.java @@ -28,14 +28,16 @@ import org.json.JSONException; import org.json.JSONObject; +import java.io.BufferedInputStream; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; import java.security.MessageDigest; import android.content.pm.Signature; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; - /** * Originally written by Eddy Verbruggen (http://github.com/EddyVerbruggen/cordova-plugin-googleplus) * Forked/Duplicated and Modified by PointSource, LLC, 2016. @@ -49,10 +51,10 @@ public class GooglePlus extends CordovaPlugin implements GoogleApiClient.OnConne public static final String ACTION_DISCONNECT = "disconnect"; public static final String ACTION_GET_SIGNING_CERTIFICATE_FINGERPRINT = "getSigningCertificateFingerprint"; - private final static String KAccess_Token = "access_token"; - private final static String KTokenExpires = "expires"; - - private final static String KVerifyTokenUrl = "https://www.googleapis.com/oauth2/v1/tokeninfo?access_token="; + private final static String FIELD_ACCESS_TOKEN = "accessToken"; + private final static String FIELD_TOKEN_EXPIRES = "expires"; + private final static String FIELD_TOKEN_EXPIRES_IN = "expires_in"; + private final static String VERIFY_TOKEN_URL = "https://www.googleapis.com/oauth2/v1/tokeninfo?access_token="; //String options/config object names passed in to login and trySilentLogin public static final String ARGUMENT_WEB_CLIENT_ID = "webClientId"; @@ -343,8 +345,9 @@ protected Void doInBackground(Void... params) { JSONObject accessTokenBundle = getAuthToken( cordova.getActivity(), acct.getAccount(), true ); - result.put(KAccess_Token, accessTokenBundle.get(KAccess_Token)); - result.put(KTokenExpires, accessTokenBundle.get(KTokenExpires)); + result.put(FIELD_ACCESS_TOKEN, accessTokenBundle.get(FIELD_ACCESS_TOKEN)); + result.put(FIELD_TOKEN_EXPIRES, accessTokenBundle.get(FIELD_TOKEN_EXPIRES)); + result.put(FIELD_TOKEN_EXPIRES_IN, accessTokenBundle.get(FIELD_TOKEN_EXPIRES_IN)); result.put("email", acct.getEmail()); result.put("idToken", acct.getIdToken()); result.put("serverAuthCode", acct.getServerAuthCode()); @@ -413,32 +416,43 @@ private JSONObject getAuthToken(Activity activity, Account account, boolean retr } private JSONObject verifyToken(String authToken) throws IOException, JSONException { - OkHttpClient client = client = new OkHttpClient.Builder().build(); - Request request = new Request.Builder() - .url(KVerifyTokenUrl+authToken) - .get().build(); - Response response = client.newCall(request).execute(); - /* expecting: - { - "issued_to": "608941808256-43vtfndets79kf5hac8ieujto8837660.apps.googleusercontent.com", - "audience": "608941808256-43vtfndets79kf5hac8ieujto8837660.apps.googleusercontent.com", - "user_id": "107046534809469736555", - "scope": "https://www.googleapis.com/auth/userinfo.profile", - "expires_in": 3595, - "access_type": "offline" - }*/ - - String stringResponse = response.body().string(); + URL url = new URL(VERIFY_TOKEN_URL+authToken); + HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); + urlConnection.setInstanceFollowRedirects(true); + String stringResponse = fromStream( + new BufferedInputStream(urlConnection.getInputStream()) + ); + /* expecting: + { + "issued_to": "608941808256-43vtfndets79kf5hac8ieujto8837660.apps.googleusercontent.com", + "audience": "608941808256-43vtfndets79kf5hac8ieujto8837660.apps.googleusercontent.com", + "user_id": "107046534809469736555", + "scope": "https://www.googleapis.com/auth/userinfo.profile", + "expires_in": 3595, + "access_type": "offline" + }*/ + Log.d("AuthenticatedBackend", "token: " + authToken + ", verification: " + stringResponse); JSONObject jsonResponse = new JSONObject( stringResponse ); - int expires_in = jsonResponse.getInt("expires_in"); + int expires_in = jsonResponse.getInt(FIELD_TOKEN_EXPIRES_IN); if (expires_in < KAssumeStaleTokenSec) { throw new IOException("Auth token soon expiring."); } - jsonResponse.put(KAccess_Token, authToken); - jsonResponse.put(KTokenExpires, expires_in + (System.currentTimeMillis()/1000)); + jsonResponse.put(FIELD_ACCESS_TOKEN, authToken); + jsonResponse.put(FIELD_TOKEN_EXPIRES, expires_in + (System.currentTimeMillis()/1000)); return jsonResponse; } + + public static String fromStream(InputStream is) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + StringBuilder sb = new StringBuilder(); + String line = null; + while ((line = reader.readLine()) != null) { + sb.append(line).append("\n"); + } + reader.close(); + return sb.toString(); + } }