From cf0190e2bf713784e9392819d93a4425b6e6e4fa Mon Sep 17 00:00:00 2001 From: Jami Couch Date: Thu, 21 Jul 2022 16:21:47 -0500 Subject: [PATCH 1/5] [force-code-for-refresh-token-platform-implementations] Platform implementations for forceCodeForRefreshToken --- .../google_sign_in_android/AUTHORS | 1 + .../google_sign_in_android/CHANGELOG.md | 4 + .../googlesignin/GoogleSignInPlugin.java | 87 ++++++++++++++----- .../googlesignin/GoogleSignInTest.java | 74 ++++++++++++++++ .../lib/google_sign_in_android.dart | 19 +++- .../google_sign_in_android/pubspec.yaml | 2 +- .../test/google_sign_in_android_test.dart | 6 +- .../google_sign_in/google_sign_in_ios/AUTHORS | 1 + .../google_sign_in_ios/CHANGELOG.md | 4 + .../lib/google_sign_in_ios.dart | 18 +++- .../google_sign_in_ios/pubspec.yaml | 2 +- .../test/google_sign_in_ios_test.dart | 4 +- .../google_sign_in/google_sign_in_web/AUTHORS | 1 + .../google_sign_in_web/CHANGELOG.md | 4 + .../google_sign_in_web/pubspec.yaml | 2 +- 15 files changed, 193 insertions(+), 36 deletions(-) diff --git a/packages/google_sign_in/google_sign_in_android/AUTHORS b/packages/google_sign_in/google_sign_in_android/AUTHORS index 493a0b4ef9c2..35d24a5ae0b5 100644 --- a/packages/google_sign_in/google_sign_in_android/AUTHORS +++ b/packages/google_sign_in/google_sign_in_android/AUTHORS @@ -64,3 +64,4 @@ Aleksandr Yurkovskiy Anton Borries Alex Li Rahul Raj <64.rahulraj@gmail.com> +Twin Sun, LLC diff --git a/packages/google_sign_in/google_sign_in_android/CHANGELOG.md b/packages/google_sign_in/google_sign_in_android/CHANGELOG.md index 9852a1f733ae..d2b59c025d79 100644 --- a/packages/google_sign_in/google_sign_in_android/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 6.0.2 + +* Adds override for `GoogleSignIn.initWithParams` to handle new `forceCodeForRefreshToken` parameter. + ## 6.0.1 * Updates gradle version to 7.2.1 on Android. diff --git a/packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index 21640233f210..7de700c774e9 100644 --- a/packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -82,6 +82,16 @@ public void setUpRegistrar(PluginRegistry.Registrar registrar) { delegate.setUpRegistrar(registrar); } + @VisibleForTesting + public void setOptionsBuilderFactory(OptionsBuilderFactory factory) { + delegate.setOptionsBuilderFactory(factory); + } + + @VisibleForTesting + public void setClientIdIdentifierOverride(int clientIdIdentifier) { + delegate.setClientIdIdentifierOverride(clientIdIdentifier); + } + private void dispose() { delegate = null; channel.setMethodCallHandler(null); @@ -140,8 +150,15 @@ public void onMethodCall(MethodCall call, Result result) { String hostedDomain = call.argument("hostedDomain"); String clientId = call.argument("clientId"); String serverClientId = call.argument("serverClientId"); + boolean forceCodeForRefreshToken = call.argument("forceCodeForRefreshToken"); delegate.init( - result, signInOption, requestedScopes, hostedDomain, clientId, serverClientId); + result, + signInOption, + requestedScopes, + hostedDomain, + clientId, + serverClientId, + forceCodeForRefreshToken); break; case METHOD_SIGN_IN_SILENTLY: @@ -198,7 +215,8 @@ public void init( List requestedScopes, String hostedDomain, String clientId, - String serverClientId); + String serverClientId, + boolean forceCodeForRefreshToken); /** * Returns the account information for the user who is signed in to this app. If no user is @@ -243,6 +261,29 @@ public void init( public void requestScopes(final Result result, final List scopes); } + /** + * Factory class that generates the GoogleSignInOptions.Builder. This is exposed so that tests can + * inject a mock instance of the GoogleSignInOptions.Builder. + */ + public static class OptionsBuilderFactory { + public static final String DEFAULT_SIGN_IN = "SignInOption.standard"; + public static final String DEFAULT_GAMES_SIGN_IN = "SignInOption.games"; + + /** Returns an instance of GoogleSignInOptions.Builder with the passed signInOption. */ + public GoogleSignInOptions.Builder get(String signInOption) { + switch (signInOption) { + case DEFAULT_GAMES_SIGN_IN: + return new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN); + + case DEFAULT_SIGN_IN: + return new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestEmail(); + default: + throw new IllegalStateException("Unknown signInOption"); + } + } + } + /** * Delegate class that does the work for the Google sign-in plugin. This is exposed as a dedicated * class for use in other plugins that wrap basic sign-in functionality. @@ -267,9 +308,6 @@ public static class Delegate implements IDelegate, PluginRegistry.ActivityResult private static final String ERROR_FAILURE_TO_RECOVER_AUTH = "failed_to_recover_auth"; private static final String ERROR_USER_RECOVERABLE_AUTH = "user_recoverable_auth"; - private static final String DEFAULT_SIGN_IN = "SignInOption.standard"; - private static final String DEFAULT_GAMES_SIGN_IN = "SignInOption.games"; - private final Context context; // Only set registrar for v1 embedder. @SuppressWarnings("deprecation") @@ -282,6 +320,8 @@ public static class Delegate implements IDelegate, PluginRegistry.ActivityResult private GoogleSignInClient signInClient; private List requestedScopes; private PendingOperation pendingOperation; + private OptionsBuilderFactory optionsBuilderFactory = new OptionsBuilderFactory(); + private int clientIdIdentifierOverride = -1; public Delegate(Context context, GoogleSignInWrapper googleSignInWrapper) { this.context = context; @@ -294,6 +334,14 @@ public void setUpRegistrar(PluginRegistry.Registrar registrar) { registrar.addActivityResultListener(this); } + public void setOptionsBuilderFactory(OptionsBuilderFactory factory) { + this.optionsBuilderFactory = factory; + } + + public void setClientIdIdentifierOverride(int clientIdIdentifier) { + this.clientIdIdentifierOverride = clientIdIdentifier; + } + public void setActivity(Activity activity) { this.activity = activity; } @@ -315,6 +363,15 @@ private void checkAndSetPendingOperation(String method, Result result, Object da pendingOperation = new PendingOperation(method, result, data); } + private int getClientIdIdentifier() { + if (clientIdIdentifierOverride != -1) { + return clientIdIdentifierOverride; + } + return context + .getResources() + .getIdentifier("default_web_client_id", "string", context.getPackageName()); + } + /** * Initializes this delegate so that it is ready to perform other operations. The Dart code * guarantees that this will be called and completed before any other methods are invoked. @@ -326,22 +383,10 @@ public void init( List requestedScopes, String hostedDomain, String clientId, - String serverClientId) { + String serverClientId, + boolean forceCodeForRefreshToken) { try { - GoogleSignInOptions.Builder optionsBuilder; - - switch (signInOption) { - case DEFAULT_GAMES_SIGN_IN: - optionsBuilder = - new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN); - break; - case DEFAULT_SIGN_IN: - optionsBuilder = - new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).requestEmail(); - break; - default: - throw new IllegalStateException("Unknown signInOption"); - } + GoogleSignInOptions.Builder optionsBuilder = optionsBuilderFactory.get(signInOption); // The clientId parameter is not supported on Android. // Android apps are identified by their package name and the SHA-1 of their signing key. @@ -374,7 +419,7 @@ public void init( } if (!Strings.isNullOrEmpty(serverClientId)) { optionsBuilder.requestIdToken(serverClientId); - optionsBuilder.requestServerAuthCode(serverClientId); + optionsBuilder.requestServerAuthCode(serverClientId, forceCodeForRefreshToken); } for (String scope : requestedScopes) { optionsBuilder.requestScopes(new Scope(scope)); diff --git a/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java b/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java index 11f8cda2e9b1..cc8945a8443f 100644 --- a/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java +++ b/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java @@ -42,6 +42,8 @@ public class GoogleSignInTest { @Spy MethodChannel.Result result; @Mock GoogleSignInWrapper mockGoogleSignIn; @Mock GoogleSignInAccount account; + @Mock GoogleSignInPlugin.OptionsBuilderFactory optionsBuilderFactory; + @Mock GoogleSignInOptions.Builder optionsBuilder; @Mock GoogleSignInClient mockClient; private GoogleSignInPlugin plugin; @@ -51,10 +53,82 @@ public void setUp() { when(mockRegistrar.messenger()).thenReturn(mockMessenger); when(mockRegistrar.context()).thenReturn(mockContext); when(mockRegistrar.activity()).thenReturn(mockActivity); + when(optionsBuilderFactory.get(GoogleSignInPlugin.OptionsBuilderFactory.DEFAULT_SIGN_IN)) + .thenReturn(optionsBuilder); + when(optionsBuilderFactory.get(GoogleSignInPlugin.OptionsBuilderFactory.DEFAULT_GAMES_SIGN_IN)) + .thenReturn(optionsBuilder); when(mockContext.getResources()).thenReturn(mockResources); plugin = new GoogleSignInPlugin(); plugin.initInstance(mockRegistrar.messenger(), mockRegistrar.context(), mockGoogleSignIn); plugin.setUpRegistrar(mockRegistrar); + plugin.setOptionsBuilderFactory(optionsBuilderFactory); + plugin.setClientIdIdentifierOverride(0); + } + + @Test + public void init_PassesForceCodeForRefreshTokenFalseWithClientIdParameter() { + HashMap arguments = new HashMap<>(); + arguments.put("signInOption", GoogleSignInPlugin.OptionsBuilderFactory.DEFAULT_SIGN_IN); + arguments.put("requestedScopes", Collections.singletonList("requestedScope")); + arguments.put("hostedDomain", null); + arguments.put("clientId", "mockClientId"); + arguments.put("forceCodeForRefreshToken", false); + + MethodCall methodCall = new MethodCall("init", arguments); + + plugin.onMethodCall(methodCall, result); + + verify(optionsBuilder, times(1)).requestServerAuthCode("mockClientId", false); + } + + @Test + public void init_PassesForceCodeForRefreshTokenTrueWithClientIdParameter() { + HashMap arguments = new HashMap<>(); + arguments.put("signInOption", GoogleSignInPlugin.OptionsBuilderFactory.DEFAULT_SIGN_IN); + arguments.put("requestedScopes", Collections.singletonList("requestedScope")); + arguments.put("hostedDomain", null); + arguments.put("clientId", "mockClientId"); + arguments.put("forceCodeForRefreshToken", true); + + MethodCall methodCall = new MethodCall("init", arguments); + + plugin.onMethodCall(methodCall, result); + + verify(optionsBuilder, times(1)).requestServerAuthCode("mockClientId", true); + } + + @Test + public void init_PassesForceCodeForRefreshTokenFalseWithClientIdFromResources() { + plugin.setClientIdIdentifierOverride(1); + when(mockContext.getString(1)).thenReturn("mockClientId"); + HashMap arguments = new HashMap<>(); + arguments.put("signInOption", GoogleSignInPlugin.OptionsBuilderFactory.DEFAULT_SIGN_IN); + arguments.put("requestedScopes", Collections.singletonList("requestedScope")); + arguments.put("hostedDomain", null); + arguments.put("forceCodeForRefreshToken", false); + + MethodCall methodCall = new MethodCall("init", arguments); + + plugin.onMethodCall(methodCall, result); + + verify(optionsBuilder, times(1)).requestServerAuthCode("mockClientId", false); + } + + @Test + public void init_PassesForceCodeForRefreshTokenTrueWithClientIdFromResources() { + plugin.setClientIdIdentifierOverride(1); + when(mockContext.getString(1)).thenReturn("mockClientId"); + HashMap arguments = new HashMap<>(); + arguments.put("signInOption", GoogleSignInPlugin.OptionsBuilderFactory.DEFAULT_SIGN_IN); + arguments.put("requestedScopes", Collections.singletonList("requestedScope")); + arguments.put("hostedDomain", null); + arguments.put("forceCodeForRefreshToken", true); + + MethodCall methodCall = new MethodCall("init", arguments); + + plugin.onMethodCall(methodCall, result); + + verify(optionsBuilder, times(1)).requestServerAuthCode("mockClientId", true); } @Test diff --git a/packages/google_sign_in/google_sign_in_android/lib/google_sign_in_android.dart b/packages/google_sign_in/google_sign_in_android/lib/google_sign_in_android.dart index d96328de695a..731da3968b3f 100644 --- a/packages/google_sign_in/google_sign_in_android/lib/google_sign_in_android.dart +++ b/packages/google_sign_in/google_sign_in_android/lib/google_sign_in_android.dart @@ -30,11 +30,22 @@ class GoogleSignInAndroid extends GoogleSignInPlatform { String? hostedDomain, String? clientId, }) { + return initWithParams(SignInInitParameters( + signInOption: signInOption, + scopes: scopes, + hostedDomain: hostedDomain, + clientId: clientId, + )); + } + + @override + Future initWithParams(SignInInitParameters params) { return channel.invokeMethod('init', { - 'signInOption': signInOption.toString(), - 'scopes': scopes, - 'hostedDomain': hostedDomain, - 'clientId': clientId, + 'signInOption': params.signInOption.toString(), + 'scopes': params.scopes, + 'hostedDomain': params.hostedDomain, + 'clientId': params.clientId, + 'forceCodeForRefreshToken': params.forceCodeForRefreshToken, }); } diff --git a/packages/google_sign_in/google_sign_in_android/pubspec.yaml b/packages/google_sign_in/google_sign_in_android/pubspec.yaml index 0a863dce1714..ba223b62389c 100644 --- a/packages/google_sign_in/google_sign_in_android/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_android/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in_android description: Android implementation of the google_sign_in plugin. repository: https://github.com/flutter/plugins/tree/main/packages/google_sign_in/google_sign_in_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22 -version: 6.0.1 +version: 6.0.2 environment: sdk: ">=2.14.0 <3.0.0" diff --git a/packages/google_sign_in/google_sign_in_android/test/google_sign_in_android_test.dart b/packages/google_sign_in/google_sign_in_android/test/google_sign_in_android_test.dart index 7d39ae5f0232..df110f2daed4 100644 --- a/packages/google_sign_in/google_sign_in_android/test/google_sign_in_android_test.dart +++ b/packages/google_sign_in/google_sign_in_android/test/google_sign_in_android_test.dart @@ -101,16 +101,18 @@ void main() { test('Other functions pass through arguments to the channel', () async { final Map tests = { () { - googleSignIn.init( + googleSignIn.initWithParams(const SignInInitParameters( hostedDomain: 'example.com', scopes: ['two', 'scopes'], signInOption: SignInOption.games, - clientId: 'fakeClientId'); + clientId: 'fakeClientId', + forceCodeForRefreshToken: true)); }: isMethodCall('init', arguments: { 'hostedDomain': 'example.com', 'scopes': ['two', 'scopes'], 'signInOption': 'SignInOption.games', 'clientId': 'fakeClientId', + 'forceCodeForRefreshToken': true, }), () { googleSignIn.getTokens( diff --git a/packages/google_sign_in/google_sign_in_ios/AUTHORS b/packages/google_sign_in/google_sign_in_ios/AUTHORS index 493a0b4ef9c2..35d24a5ae0b5 100644 --- a/packages/google_sign_in/google_sign_in_ios/AUTHORS +++ b/packages/google_sign_in/google_sign_in_ios/AUTHORS @@ -64,3 +64,4 @@ Aleksandr Yurkovskiy Anton Borries Alex Li Rahul Raj <64.rahulraj@gmail.com> +Twin Sun, LLC diff --git a/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md b/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md index 5ed38de5cb74..32e841818492 100644 --- a/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.4.1 + +* Adds override for `GoogleSignInPlatform.initWithParams`. + ## 5.4.0 * Adds support for `serverClientId` configuration option. diff --git a/packages/google_sign_in/google_sign_in_ios/lib/google_sign_in_ios.dart b/packages/google_sign_in/google_sign_in_ios/lib/google_sign_in_ios.dart index ce8865664507..07407eaf5236 100644 --- a/packages/google_sign_in/google_sign_in_ios/lib/google_sign_in_ios.dart +++ b/packages/google_sign_in/google_sign_in_ios/lib/google_sign_in_ios.dart @@ -30,15 +30,25 @@ class GoogleSignInIOS extends GoogleSignInPlatform { String? hostedDomain, String? clientId, }) { - if (signInOption == SignInOption.games) { + return initWithParams(SignInInitParameters( + signInOption: signInOption, + scopes: scopes, + hostedDomain: hostedDomain, + clientId: clientId, + )); + } + + @override + Future initWithParams(SignInInitParameters params) { + if (params.signInOption == SignInOption.games) { throw PlatformException( code: 'unsupported-options', message: 'Games sign in is not supported on iOS'); } return channel.invokeMethod('init', { - 'scopes': scopes, - 'hostedDomain': hostedDomain, - 'clientId': clientId, + 'scopes': params.scopes, + 'hostedDomain': params.hostedDomain, + 'clientId': params.clientId, }); } diff --git a/packages/google_sign_in/google_sign_in_ios/pubspec.yaml b/packages/google_sign_in/google_sign_in_ios/pubspec.yaml index 65c8928c1402..9760e84443a8 100644 --- a/packages/google_sign_in/google_sign_in_ios/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_ios/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in_ios description: iOS implementation of the google_sign_in plugin. repository: https://github.com/flutter/plugins/tree/main/packages/google_sign_in/google_sign_in_ios issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22 -version: 5.4.0 +version: 5.4.1 environment: sdk: ">=2.14.0 <3.0.0" diff --git a/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart b/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart index 92637e938fd9..3013b8d41d2a 100644 --- a/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart +++ b/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart @@ -116,10 +116,10 @@ void main() { test('Other functions pass through arguments to the channel', () async { final Map tests = { () { - googleSignIn.init( + googleSignIn.initWithParams(const SignInInitParameters( hostedDomain: 'example.com', scopes: ['two', 'scopes'], - clientId: 'fakeClientId'); + clientId: 'fakeClientId')); }: isMethodCall('init', arguments: { 'hostedDomain': 'example.com', 'scopes': ['two', 'scopes'], diff --git a/packages/google_sign_in/google_sign_in_web/AUTHORS b/packages/google_sign_in/google_sign_in_web/AUTHORS index 493a0b4ef9c2..35d24a5ae0b5 100644 --- a/packages/google_sign_in/google_sign_in_web/AUTHORS +++ b/packages/google_sign_in/google_sign_in_web/AUTHORS @@ -64,3 +64,4 @@ Aleksandr Yurkovskiy Anton Borries Alex Li Rahul Raj <64.rahulraj@gmail.com> +Twin Sun, LLC diff --git a/packages/google_sign_in/google_sign_in_web/CHANGELOG.md b/packages/google_sign_in/google_sign_in_web/CHANGELOG.md index 12e6d9630f9c..cea12070a14e 100644 --- a/packages/google_sign_in/google_sign_in_web/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.10.3 + +* Adds override for `GoogleSignInPlatform.initWithParams`. + ## 0.10.2 * Migrates to new platform-interface `initWithParams` method. diff --git a/packages/google_sign_in/google_sign_in_web/pubspec.yaml b/packages/google_sign_in/google_sign_in_web/pubspec.yaml index 1dedd6de6666..e2d70bfb0083 100644 --- a/packages/google_sign_in/google_sign_in_web/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_web/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for Google Sign-In, a secure authentication system for signing in with a Google account on Android, iOS and Web. repository: https://github.com/flutter/plugins/tree/main/packages/google_sign_in/google_sign_in_web issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22 -version: 0.10.2 +version: 0.10.3 environment: sdk: ">=2.12.0 <3.0.0" From 61172057600fc0b107615e1b48af02ca982146dc Mon Sep 17 00:00:00 2001 From: Jami Couch Date: Thu, 21 Jul 2022 16:30:53 -0500 Subject: [PATCH 2/5] [force-code-for-refresh-token-platform-implementations] Revert unnecessary changes to google_sign_in_web --- packages/google_sign_in/google_sign_in_web/AUTHORS | 1 - packages/google_sign_in/google_sign_in_web/CHANGELOG.md | 4 ---- packages/google_sign_in/google_sign_in_web/pubspec.yaml | 2 +- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/google_sign_in/google_sign_in_web/AUTHORS b/packages/google_sign_in/google_sign_in_web/AUTHORS index 35d24a5ae0b5..493a0b4ef9c2 100644 --- a/packages/google_sign_in/google_sign_in_web/AUTHORS +++ b/packages/google_sign_in/google_sign_in_web/AUTHORS @@ -64,4 +64,3 @@ Aleksandr Yurkovskiy Anton Borries Alex Li Rahul Raj <64.rahulraj@gmail.com> -Twin Sun, LLC diff --git a/packages/google_sign_in/google_sign_in_web/CHANGELOG.md b/packages/google_sign_in/google_sign_in_web/CHANGELOG.md index cea12070a14e..12e6d9630f9c 100644 --- a/packages/google_sign_in/google_sign_in_web/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_web/CHANGELOG.md @@ -1,7 +1,3 @@ -## 0.10.3 - -* Adds override for `GoogleSignInPlatform.initWithParams`. - ## 0.10.2 * Migrates to new platform-interface `initWithParams` method. diff --git a/packages/google_sign_in/google_sign_in_web/pubspec.yaml b/packages/google_sign_in/google_sign_in_web/pubspec.yaml index e2d70bfb0083..1dedd6de6666 100644 --- a/packages/google_sign_in/google_sign_in_web/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_web/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for Google Sign-In, a secure authentication system for signing in with a Google account on Android, iOS and Web. repository: https://github.com/flutter/plugins/tree/main/packages/google_sign_in/google_sign_in_web issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22 -version: 0.10.3 +version: 0.10.2 environment: sdk: ">=2.12.0 <3.0.0" From 5deb8150d583836be5ebcb3c13331dcab38b8388 Mon Sep 17 00:00:00 2001 From: Jami Couch Date: Tue, 26 Jul 2022 14:57:00 -0500 Subject: [PATCH 3/5] [force-code-for-refresh-token-platform-implementations] Fix breaking tests, remove unnecessary overrides --- .../googlesignin/GoogleSignInPlugin.java | 70 ++------- .../googlesignin/GoogleSignInTest.java | 145 ++++++++---------- 2 files changed, 82 insertions(+), 133 deletions(-) diff --git a/packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java b/packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java index 7de700c774e9..e84d196a6a0d 100644 --- a/packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java +++ b/packages/google_sign_in/google_sign_in_android/android/src/main/java/io/flutter/plugins/googlesignin/GoogleSignInPlugin.java @@ -82,16 +82,6 @@ public void setUpRegistrar(PluginRegistry.Registrar registrar) { delegate.setUpRegistrar(registrar); } - @VisibleForTesting - public void setOptionsBuilderFactory(OptionsBuilderFactory factory) { - delegate.setOptionsBuilderFactory(factory); - } - - @VisibleForTesting - public void setClientIdIdentifierOverride(int clientIdIdentifier) { - delegate.setClientIdIdentifierOverride(clientIdIdentifier); - } - private void dispose() { delegate = null; channel.setMethodCallHandler(null); @@ -261,29 +251,6 @@ public void init( public void requestScopes(final Result result, final List scopes); } - /** - * Factory class that generates the GoogleSignInOptions.Builder. This is exposed so that tests can - * inject a mock instance of the GoogleSignInOptions.Builder. - */ - public static class OptionsBuilderFactory { - public static final String DEFAULT_SIGN_IN = "SignInOption.standard"; - public static final String DEFAULT_GAMES_SIGN_IN = "SignInOption.games"; - - /** Returns an instance of GoogleSignInOptions.Builder with the passed signInOption. */ - public GoogleSignInOptions.Builder get(String signInOption) { - switch (signInOption) { - case DEFAULT_GAMES_SIGN_IN: - return new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN); - - case DEFAULT_SIGN_IN: - return new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) - .requestEmail(); - default: - throw new IllegalStateException("Unknown signInOption"); - } - } - } - /** * Delegate class that does the work for the Google sign-in plugin. This is exposed as a dedicated * class for use in other plugins that wrap basic sign-in functionality. @@ -308,6 +275,9 @@ public static class Delegate implements IDelegate, PluginRegistry.ActivityResult private static final String ERROR_FAILURE_TO_RECOVER_AUTH = "failed_to_recover_auth"; private static final String ERROR_USER_RECOVERABLE_AUTH = "user_recoverable_auth"; + private static final String DEFAULT_SIGN_IN = "SignInOption.standard"; + private static final String DEFAULT_GAMES_SIGN_IN = "SignInOption.games"; + private final Context context; // Only set registrar for v1 embedder. @SuppressWarnings("deprecation") @@ -320,8 +290,6 @@ public static class Delegate implements IDelegate, PluginRegistry.ActivityResult private GoogleSignInClient signInClient; private List requestedScopes; private PendingOperation pendingOperation; - private OptionsBuilderFactory optionsBuilderFactory = new OptionsBuilderFactory(); - private int clientIdIdentifierOverride = -1; public Delegate(Context context, GoogleSignInWrapper googleSignInWrapper) { this.context = context; @@ -334,14 +302,6 @@ public void setUpRegistrar(PluginRegistry.Registrar registrar) { registrar.addActivityResultListener(this); } - public void setOptionsBuilderFactory(OptionsBuilderFactory factory) { - this.optionsBuilderFactory = factory; - } - - public void setClientIdIdentifierOverride(int clientIdIdentifier) { - this.clientIdIdentifierOverride = clientIdIdentifier; - } - public void setActivity(Activity activity) { this.activity = activity; } @@ -363,15 +323,6 @@ private void checkAndSetPendingOperation(String method, Result result, Object da pendingOperation = new PendingOperation(method, result, data); } - private int getClientIdIdentifier() { - if (clientIdIdentifierOverride != -1) { - return clientIdIdentifierOverride; - } - return context - .getResources() - .getIdentifier("default_web_client_id", "string", context.getPackageName()); - } - /** * Initializes this delegate so that it is ready to perform other operations. The Dart code * guarantees that this will be called and completed before any other methods are invoked. @@ -386,7 +337,20 @@ public void init( String serverClientId, boolean forceCodeForRefreshToken) { try { - GoogleSignInOptions.Builder optionsBuilder = optionsBuilderFactory.get(signInOption); + GoogleSignInOptions.Builder optionsBuilder; + + switch (signInOption) { + case DEFAULT_GAMES_SIGN_IN: + optionsBuilder = + new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN); + break; + case DEFAULT_SIGN_IN: + optionsBuilder = + new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).requestEmail(); + break; + default: + throw new IllegalStateException("Unknown signInOption"); + } // The clientId parameter is not supported on Android. // Android apps are identified by their package name and the SHA-1 of their signing key. diff --git a/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java b/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java index cc8945a8443f..709cbd94f13d 100644 --- a/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java +++ b/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java @@ -42,8 +42,6 @@ public class GoogleSignInTest { @Spy MethodChannel.Result result; @Mock GoogleSignInWrapper mockGoogleSignIn; @Mock GoogleSignInAccount account; - @Mock GoogleSignInPlugin.OptionsBuilderFactory optionsBuilderFactory; - @Mock GoogleSignInOptions.Builder optionsBuilder; @Mock GoogleSignInClient mockClient; private GoogleSignInPlugin plugin; @@ -53,82 +51,10 @@ public void setUp() { when(mockRegistrar.messenger()).thenReturn(mockMessenger); when(mockRegistrar.context()).thenReturn(mockContext); when(mockRegistrar.activity()).thenReturn(mockActivity); - when(optionsBuilderFactory.get(GoogleSignInPlugin.OptionsBuilderFactory.DEFAULT_SIGN_IN)) - .thenReturn(optionsBuilder); - when(optionsBuilderFactory.get(GoogleSignInPlugin.OptionsBuilderFactory.DEFAULT_GAMES_SIGN_IN)) - .thenReturn(optionsBuilder); when(mockContext.getResources()).thenReturn(mockResources); plugin = new GoogleSignInPlugin(); plugin.initInstance(mockRegistrar.messenger(), mockRegistrar.context(), mockGoogleSignIn); plugin.setUpRegistrar(mockRegistrar); - plugin.setOptionsBuilderFactory(optionsBuilderFactory); - plugin.setClientIdIdentifierOverride(0); - } - - @Test - public void init_PassesForceCodeForRefreshTokenFalseWithClientIdParameter() { - HashMap arguments = new HashMap<>(); - arguments.put("signInOption", GoogleSignInPlugin.OptionsBuilderFactory.DEFAULT_SIGN_IN); - arguments.put("requestedScopes", Collections.singletonList("requestedScope")); - arguments.put("hostedDomain", null); - arguments.put("clientId", "mockClientId"); - arguments.put("forceCodeForRefreshToken", false); - - MethodCall methodCall = new MethodCall("init", arguments); - - plugin.onMethodCall(methodCall, result); - - verify(optionsBuilder, times(1)).requestServerAuthCode("mockClientId", false); - } - - @Test - public void init_PassesForceCodeForRefreshTokenTrueWithClientIdParameter() { - HashMap arguments = new HashMap<>(); - arguments.put("signInOption", GoogleSignInPlugin.OptionsBuilderFactory.DEFAULT_SIGN_IN); - arguments.put("requestedScopes", Collections.singletonList("requestedScope")); - arguments.put("hostedDomain", null); - arguments.put("clientId", "mockClientId"); - arguments.put("forceCodeForRefreshToken", true); - - MethodCall methodCall = new MethodCall("init", arguments); - - plugin.onMethodCall(methodCall, result); - - verify(optionsBuilder, times(1)).requestServerAuthCode("mockClientId", true); - } - - @Test - public void init_PassesForceCodeForRefreshTokenFalseWithClientIdFromResources() { - plugin.setClientIdIdentifierOverride(1); - when(mockContext.getString(1)).thenReturn("mockClientId"); - HashMap arguments = new HashMap<>(); - arguments.put("signInOption", GoogleSignInPlugin.OptionsBuilderFactory.DEFAULT_SIGN_IN); - arguments.put("requestedScopes", Collections.singletonList("requestedScope")); - arguments.put("hostedDomain", null); - arguments.put("forceCodeForRefreshToken", false); - - MethodCall methodCall = new MethodCall("init", arguments); - - plugin.onMethodCall(methodCall, result); - - verify(optionsBuilder, times(1)).requestServerAuthCode("mockClientId", false); - } - - @Test - public void init_PassesForceCodeForRefreshTokenTrueWithClientIdFromResources() { - plugin.setClientIdIdentifierOverride(1); - when(mockContext.getString(1)).thenReturn("mockClientId"); - HashMap arguments = new HashMap<>(); - arguments.put("signInOption", GoogleSignInPlugin.OptionsBuilderFactory.DEFAULT_SIGN_IN); - arguments.put("requestedScopes", Collections.singletonList("requestedScope")); - arguments.put("hostedDomain", null); - arguments.put("forceCodeForRefreshToken", true); - - MethodCall methodCall = new MethodCall("init", arguments); - - plugin.onMethodCall(methodCall, result); - - verify(optionsBuilder, times(1)).requestServerAuthCode("mockClientId", true); } @Test @@ -188,10 +114,8 @@ public void requestScopes_ReturnsFalseIfPermissionDenied() { when(mockGoogleSignIn.hasPermissions(account, requestedScope)).thenReturn(false); plugin.onMethodCall(methodCall, result); - listener.onActivityResult( - GoogleSignInPlugin.Delegate.REQUEST_CODE_REQUEST_SCOPE, - Activity.RESULT_CANCELED, - new Intent()); + listener.onActivityResult(GoogleSignInPlugin.Delegate.REQUEST_CODE_REQUEST_SCOPE, + Activity.RESULT_CANCELED, new Intent()); verify(result).success(false); } @@ -313,6 +237,48 @@ public void init_IgnoresClientIdIfServerClientIdIsProvided() { initAndAssertServerClientId(methodCall, serverClientId); } + @Test + public void init_PassesForceCodeForRefreshTokenFalseWithServerClientIdParameter() { + MethodCall methodCall = buildInitMethodCall("fakeClientId", "fakeServerClientId", false); + + initAndAssertForceCodeForRefreshToken(methodCall, false); + } + + @Test + public void init_PassesForceCodeForRefreshTokenTrueWithServerClientIdParameter() { + MethodCall methodCall = buildInitMethodCall("fakeClientId", "fakeServerClientId", true); + + initAndAssertForceCodeForRefreshToken(methodCall, true); + } + + @Test + public void init_PassesForceCodeForRefreshTokenFalseWithServerClientIdFromResources() { + final String packageName = "fakePackageName"; + final String serverClientId = "fakeServerClientId"; + final int resourceId = 1; + MethodCall methodCall = buildInitMethodCall(null, null, false); + when(mockContext.getPackageName()).thenReturn(packageName); + when(mockResources.getIdentifier("default_web_client_id", "string", packageName)) + .thenReturn(resourceId); + when(mockContext.getString(resourceId)).thenReturn(serverClientId); + + initAndAssertForceCodeForRefreshToken(methodCall, false); + } + + @Test + public void init_PassesForceCodeForRefreshTokenTrueWithServerClientIdFromResources() { + final String packageName = "fakePackageName"; + final String serverClientId = "fakeServerClientId"; + final int resourceId = 1; + MethodCall methodCall = buildInitMethodCall(null, null, true); + when(mockContext.getPackageName()).thenReturn(packageName); + when(mockResources.getIdentifier("default_web_client_id", "string", packageName)) + .thenReturn(resourceId); + when(mockContext.getString(resourceId)).thenReturn(serverClientId); + + initAndAssertForceCodeForRefreshToken(methodCall, true); + } + public void initAndAssertServerClientId(MethodCall methodCall, String serverClientId) { ArgumentCaptor optionsCaptor = ArgumentCaptor.forClass(GoogleSignInOptions.class); @@ -323,13 +289,31 @@ public void initAndAssertServerClientId(MethodCall methodCall, String serverClie Assert.assertEquals(serverClientId, optionsCaptor.getValue().getServerClientId()); } + public void initAndAssertForceCodeForRefreshToken( + MethodCall methodCall, boolean forceCodeForRefreshToken) { + ArgumentCaptor optionsCaptor = + ArgumentCaptor.forClass(GoogleSignInOptions.class); + when(mockGoogleSignIn.getClient(any(Context.class), optionsCaptor.capture())) + .thenReturn(mockClient); + plugin.onMethodCall(methodCall, result); + verify(result).success(null); + Assert.assertEquals( + forceCodeForRefreshToken, optionsCaptor.getValue().isForceCodeForRefreshToken()); + } + private static MethodCall buildInitMethodCall(String clientId, String serverClientId) { return buildInitMethodCall( - "SignInOption.standard", Collections.emptyList(), clientId, serverClientId); + "SignInOption.standard", Collections.emptyList(), clientId, serverClientId, false); } private static MethodCall buildInitMethodCall( - String signInOption, List scopes, String clientId, String serverClientId) { + String clientId, String serverClientId, boolean forceCodeForRefreshToken) { + return buildInitMethodCall("SignInOption.standard", Collections.emptyList(), clientId, + serverClientId, forceCodeForRefreshToken); + } + + private static MethodCall buildInitMethodCall(String signInOption, List scopes, + String clientId, String serverClientId, boolean forceCodeForRefreshToken) { HashMap arguments = new HashMap<>(); arguments.put("signInOption", signInOption); arguments.put("scopes", scopes); @@ -339,6 +323,7 @@ private static MethodCall buildInitMethodCall( if (serverClientId != null) { arguments.put("serverClientId", serverClientId); } + arguments.put("forceCodeForRefreshToken", forceCodeForRefreshToken); return new MethodCall("init", arguments); } } From bd28b15e29beb0bce6551d47c8bdea10705666f3 Mon Sep 17 00:00:00 2001 From: Jami Couch Date: Tue, 26 Jul 2022 15:05:09 -0500 Subject: [PATCH 4/5] [force-code-for-refresh-token-platform-implementations] Fix format issues --- .../googlesignin/GoogleSignInTest.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java b/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java index 709cbd94f13d..9692417390a5 100644 --- a/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java +++ b/packages/google_sign_in/google_sign_in_android/android/src/test/java/io/flutter/plugins/googlesignin/GoogleSignInTest.java @@ -114,8 +114,10 @@ public void requestScopes_ReturnsFalseIfPermissionDenied() { when(mockGoogleSignIn.hasPermissions(account, requestedScope)).thenReturn(false); plugin.onMethodCall(methodCall, result); - listener.onActivityResult(GoogleSignInPlugin.Delegate.REQUEST_CODE_REQUEST_SCOPE, - Activity.RESULT_CANCELED, new Intent()); + listener.onActivityResult( + GoogleSignInPlugin.Delegate.REQUEST_CODE_REQUEST_SCOPE, + Activity.RESULT_CANCELED, + new Intent()); verify(result).success(false); } @@ -308,12 +310,20 @@ private static MethodCall buildInitMethodCall(String clientId, String serverClie private static MethodCall buildInitMethodCall( String clientId, String serverClientId, boolean forceCodeForRefreshToken) { - return buildInitMethodCall("SignInOption.standard", Collections.emptyList(), clientId, - serverClientId, forceCodeForRefreshToken); + return buildInitMethodCall( + "SignInOption.standard", + Collections.emptyList(), + clientId, + serverClientId, + forceCodeForRefreshToken); } - private static MethodCall buildInitMethodCall(String signInOption, List scopes, - String clientId, String serverClientId, boolean forceCodeForRefreshToken) { + private static MethodCall buildInitMethodCall( + String signInOption, + List scopes, + String clientId, + String serverClientId, + boolean forceCodeForRefreshToken) { HashMap arguments = new HashMap<>(); arguments.put("signInOption", signInOption); arguments.put("scopes", scopes); From bc4a2da35fd3ea0de5491ee74ad022c2e0d5770b Mon Sep 17 00:00:00 2001 From: Jami Couch Date: Wed, 10 Aug 2022 22:06:36 -0500 Subject: [PATCH 5/5] [force-code-for-refresh-token-platform-implementations] Bump minor version instead of bugfix; add new tests instead of modifying existing init tests --- .../google_sign_in_android/CHANGELOG.md | 2 +- .../google_sign_in_android/pubspec.yaml | 2 +- .../test/google_sign_in_android_test.dart | 13 +++++++++++++ .../google_sign_in/google_sign_in_ios/CHANGELOG.md | 2 +- .../google_sign_in/google_sign_in_ios/pubspec.yaml | 2 +- .../test/google_sign_in_ios_test.dart | 10 ++++++++++ 6 files changed, 27 insertions(+), 4 deletions(-) diff --git a/packages/google_sign_in/google_sign_in_android/CHANGELOG.md b/packages/google_sign_in/google_sign_in_android/CHANGELOG.md index d2b59c025d79..5125b22a0963 100644 --- a/packages/google_sign_in/google_sign_in_android/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_android/CHANGELOG.md @@ -1,4 +1,4 @@ -## 6.0.2 +## 6.1.0 * Adds override for `GoogleSignIn.initWithParams` to handle new `forceCodeForRefreshToken` parameter. diff --git a/packages/google_sign_in/google_sign_in_android/pubspec.yaml b/packages/google_sign_in/google_sign_in_android/pubspec.yaml index ba223b62389c..de5e3f0a8470 100644 --- a/packages/google_sign_in/google_sign_in_android/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_android/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in_android description: Android implementation of the google_sign_in plugin. repository: https://github.com/flutter/plugins/tree/main/packages/google_sign_in/google_sign_in_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22 -version: 6.0.2 +version: 6.1.0 environment: sdk: ">=2.14.0 <3.0.0" diff --git a/packages/google_sign_in/google_sign_in_android/test/google_sign_in_android_test.dart b/packages/google_sign_in/google_sign_in_android/test/google_sign_in_android_test.dart index df110f2daed4..948ced3f65bc 100644 --- a/packages/google_sign_in/google_sign_in_android/test/google_sign_in_android_test.dart +++ b/packages/google_sign_in/google_sign_in_android/test/google_sign_in_android_test.dart @@ -100,6 +100,19 @@ void main() { test('Other functions pass through arguments to the channel', () async { final Map tests = { + () { + googleSignIn.init( + hostedDomain: 'example.com', + scopes: ['two', 'scopes'], + signInOption: SignInOption.games, + clientId: 'fakeClientId'); + }: isMethodCall('init', arguments: { + 'hostedDomain': 'example.com', + 'scopes': ['two', 'scopes'], + 'signInOption': 'SignInOption.games', + 'clientId': 'fakeClientId', + 'forceCodeForRefreshToken': false, + }), () { googleSignIn.initWithParams(const SignInInitParameters( hostedDomain: 'example.com', diff --git a/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md b/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md index 32e841818492..2b62f8afa0b8 100644 --- a/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md +++ b/packages/google_sign_in/google_sign_in_ios/CHANGELOG.md @@ -1,4 +1,4 @@ -## 5.4.1 +## 5.5.0 * Adds override for `GoogleSignInPlatform.initWithParams`. diff --git a/packages/google_sign_in/google_sign_in_ios/pubspec.yaml b/packages/google_sign_in/google_sign_in_ios/pubspec.yaml index 9760e84443a8..760e3339e32d 100644 --- a/packages/google_sign_in/google_sign_in_ios/pubspec.yaml +++ b/packages/google_sign_in/google_sign_in_ios/pubspec.yaml @@ -2,7 +2,7 @@ name: google_sign_in_ios description: iOS implementation of the google_sign_in plugin. repository: https://github.com/flutter/plugins/tree/main/packages/google_sign_in/google_sign_in_ios issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_sign_in%22 -version: 5.4.1 +version: 5.5.0 environment: sdk: ">=2.14.0 <3.0.0" diff --git a/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart b/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart index 3013b8d41d2a..ace65092f61d 100644 --- a/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart +++ b/packages/google_sign_in/google_sign_in_ios/test/google_sign_in_ios_test.dart @@ -115,6 +115,16 @@ void main() { test('Other functions pass through arguments to the channel', () async { final Map tests = { + () { + googleSignIn.init( + hostedDomain: 'example.com', + scopes: ['two', 'scopes'], + clientId: 'fakeClientId'); + }: isMethodCall('init', arguments: { + 'hostedDomain': 'example.com', + 'scopes': ['two', 'scopes'], + 'clientId': 'fakeClientId', + }), () { googleSignIn.initWithParams(const SignInInitParameters( hostedDomain: 'example.com',