Skip to content

Commit

Permalink
[flutter_appauth_platform_interface][flutter_appauth] migrate to null…
Browse files Browse the repository at this point in the history
… safety (#187)

* migrate platform interface to null safety

* update cirrus script

* migrate plugin to null safety

* address warnings in example app

* updated constraints for plugin_platform_interface dependency

* make clientId and redirectUrl non-nullable

* updated plugin_platform_interface version requirement

* update flutter_appauth_platform_interface for stable release

* switch cirrus script to build on stable

* make ios build task upgrade from stable

* bump version for stable release
  • Loading branch information
MaikuB authored Mar 20, 2021
1 parent 8d266d8 commit b0d390f
Show file tree
Hide file tree
Showing 21 changed files with 130 additions and 121 deletions.
2 changes: 2 additions & 0 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@ task:
pub_cache:
folder: ~/.pub-cache
build_script:
- flutter channel stable
- flutter upgrade
- cd flutter_appauth/example
- flutter build ios --no-codesign
4 changes: 4 additions & 0 deletions flutter_appauth/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 1.0.0

* Migrated to null safety

## 0.9.2+6

* [Android] community has reported that there seem to be instances where the plugin encounters a null intent on some devices upon processing a authorisation request. This resulted in a crash before but will now throw a `PlatformException`. Thanks to the PR from [Leon Havenga](https://github.com/li0nza)
Expand Down
52 changes: 26 additions & 26 deletions flutter_appauth/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ class MyApp extends StatefulWidget {
class _MyAppState extends State<MyApp> {
bool _isBusy = false;
final FlutterAppAuth _appAuth = FlutterAppAuth();
String _codeVerifier;
String _authorizationCode;
String _refreshToken;
String _accessToken;
String? _codeVerifier;
String? _authorizationCode;
String? _refreshToken;
String? _accessToken;
final TextEditingController _authorizationCodeTextController =
TextEditingController();
final TextEditingController _accessTokenTextController =
Expand Down Expand Up @@ -44,7 +44,7 @@ class _MyAppState extends State<MyApp> {
];

final AuthorizationServiceConfiguration _serviceConfiguration =
AuthorizationServiceConfiguration(
const AuthorizationServiceConfiguration(
'https://demo.identityserver.io/connect/authorize',
'https://demo.identityserver.io/connect/token');

Expand All @@ -67,22 +67,22 @@ class _MyAppState extends State<MyApp> {
visible: _isBusy,
child: const LinearProgressIndicator(),
),
RaisedButton(
ElevatedButton(
child: const Text('Sign in with no code exchange'),
onPressed: _signInWithNoCodeExchange,
),
RaisedButton(
ElevatedButton(
child: const Text('Exchange code'),
onPressed: _authorizationCode != null ? _exchangeCode : null,
),
RaisedButton(
ElevatedButton(
child: const Text('Sign in with auto code exchange'),
onPressed: () => _signInWithAutoCodeExchange(),
),
if (Platform.isIOS)
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
child: ElevatedButton(
child: const Text(
'Sign in with auto code exchange using ephemeral session (iOS only)',
textAlign: TextAlign.center,
Expand All @@ -91,7 +91,7 @@ class _MyAppState extends State<MyApp> {
preferEphemeralSession: true),
),
),
RaisedButton(
ElevatedButton(
child: const Text('Refresh token'),
onPressed: _refreshToken != null ? _refresh : null,
),
Expand Down Expand Up @@ -127,7 +127,7 @@ class _MyAppState extends State<MyApp> {
Future<void> _refresh() async {
try {
_setBusyState();
final TokenResponse result = await _appAuth.token(TokenRequest(
final TokenResponse? result = await _appAuth.token(TokenRequest(
_clientId, _redirectUrl,
refreshToken: _refreshToken,
discoveryUrl: _discoveryUrl,
Expand All @@ -142,7 +142,7 @@ class _MyAppState extends State<MyApp> {
Future<void> _exchangeCode() async {
try {
_setBusyState();
final TokenResponse result = await _appAuth.token(TokenRequest(
final TokenResponse? result = await _appAuth.token(TokenRequest(
_clientId, _redirectUrl,
authorizationCode: _authorizationCode,
discoveryUrl: _discoveryUrl,
Expand All @@ -159,7 +159,7 @@ class _MyAppState extends State<MyApp> {
try {
_setBusyState();
// use the discovery endpoint to find the configuration
final AuthorizationResponse result = await _appAuth.authorize(
final AuthorizationResponse? result = await _appAuth.authorize(
AuthorizationRequest(_clientId, _redirectUrl,
discoveryUrl: _discoveryUrl, scopes: _scopes, loginHint: 'bob'),
);
Expand Down Expand Up @@ -187,7 +187,7 @@ class _MyAppState extends State<MyApp> {
_setBusyState();

// show that we can also explicitly specify the endpoints rather than getting from the details from the discovery document
final AuthorizationTokenResponse result =
final AuthorizationTokenResponse? result =
await _appAuth.authorizeAndExchangeCode(
AuthorizationTokenRequest(
_clientId,
Expand Down Expand Up @@ -229,11 +229,11 @@ class _MyAppState extends State<MyApp> {

void _processAuthTokenResponse(AuthorizationTokenResponse response) {
setState(() {
_accessToken = _accessTokenTextController.text = response.accessToken;
_idTokenTextController.text = response.idToken;
_refreshToken = _refreshTokenTextController.text = response.refreshToken;
_accessToken = _accessTokenTextController.text = response.accessToken!;
_idTokenTextController.text = response.idToken!;
_refreshToken = _refreshTokenTextController.text = response.refreshToken!;
_accessTokenExpirationTextController.text =
response.accessTokenExpirationDateTime?.toIso8601String();
response.accessTokenExpirationDateTime!.toIso8601String();
});
}

Expand All @@ -242,24 +242,24 @@ class _MyAppState extends State<MyApp> {
// save the code verifier as it must be used when exchanging the token
_codeVerifier = response.codeVerifier;
_authorizationCode =
_authorizationCodeTextController.text = response.authorizationCode;
_authorizationCodeTextController.text = response.authorizationCode!;
_isBusy = false;
});
}

void _processTokenResponse(TokenResponse response) {
void _processTokenResponse(TokenResponse? response) {
setState(() {
_accessToken = _accessTokenTextController.text = response.accessToken;
_idTokenTextController.text = response.idToken;
_refreshToken = _refreshTokenTextController.text = response.refreshToken;
_accessToken = _accessTokenTextController.text = response!.accessToken!;
_idTokenTextController.text = response.idToken!;
_refreshToken = _refreshTokenTextController.text = response.refreshToken!;
_accessTokenExpirationTextController.text =
response.accessTokenExpirationDateTime?.toIso8601String();
response.accessTokenExpirationDateTime!.toIso8601String();
});
}

Future<void> _testApi(TokenResponse response) async {
Future<void> _testApi(TokenResponse? response) async {
final http.Response httpResponse = await http.get(
'https://demo.identityserver.io/api/test',
Uri.parse('https://demo.identityserver.io/api/test'),
headers: <String, String>{'Authorization': 'Bearer $_accessToken'});
setState(() {
_userInfo = httpResponse.statusCode == 200 ? httpResponse.body : '';
Expand Down
7 changes: 3 additions & 4 deletions flutter_appauth/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ version: 1.0.0+1
publish_to: 'none'

environment:
sdk: ">=2.6.0 <3.0.0"
sdk: '>=2.12.0-0 <3.0.0'

dependencies:
cupertino_icons: ^1.0.2
flutter:
sdk: flutter

cupertino_icons: ^0.1.2
http: ^0.12.0+1
flutter_appauth:
path: ../
http: ^0.13.0

dev_dependencies:
flutter_test:
Expand Down
6 changes: 3 additions & 3 deletions flutter_appauth/lib/src/flutter_appauth.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import 'package:flutter_appauth_platform_interface/flutter_appauth_platform_inte

class FlutterAppAuth {
/// Convenience method for authorizing and then exchanges code
Future<AuthorizationTokenResponse> authorizeAndExchangeCode(
Future<AuthorizationTokenResponse?> authorizeAndExchangeCode(
AuthorizationTokenRequest request) {
return FlutterAppAuthPlatform.instance.authorizeAndExchangeCode(request);
}

/// Sends an authorization request
Future<AuthorizationResponse> authorize(AuthorizationRequest request) {
Future<AuthorizationResponse?> authorize(AuthorizationRequest request) {
return FlutterAppAuthPlatform.instance.authorize(request);
}

/// For exchanging tokens
Future<TokenResponse> token(TokenRequest request) {
Future<TokenResponse?> token(TokenRequest request) {
return FlutterAppAuthPlatform.instance.token(request);
}
}
6 changes: 3 additions & 3 deletions flutter_appauth/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
name: flutter_appauth
description: This plugin provides an abstraction around the Android and iOS AppAuth SDKs so it can be used to communicate with OAuth 2.0 and OpenID Connect providers
version: 0.9.2+6
version: 1.0.0
homepage: https://github.com/MaikuB/flutter_appauth/tree/master/flutter_appauth

environment:
sdk: '>=2.6.0 <3.0.0'
sdk: '>=2.12.0-0 <3.0.0'
flutter: '>=1.12.13+hotfix.5'

dependencies:
flutter:
sdk: flutter
flutter_appauth_platform_interface: ^2.0.0
flutter_appauth_platform_interface: ^3.0.0

flutter:
plugin:
Expand Down
7 changes: 6 additions & 1 deletion flutter_appauth_platform_interface/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
## [3.0.0]

* Migrated to null safety
* `AuthorizationServiceConfiguration` and `AuthorizationResponse` now have `const` constructors

## [2.0.0]

* **BREAKING CHANGE** Removed the `toMap` methods so that it's not part of the public API surface. This was done as these methods were for internal use. Currently `flutter_appauth` (version 0.8.3) is constrained to depend on versions >= 1.0.2 and < 2.0.0. As it's possible that plugin consumers were calling the methods via the plugin, where the platform interface is a transitive dependency, the platform interface has been bumped to version 2.0.0 instead of 1.1.0 to be safe.
* **Breaking change** Removed the `toMap` methods so that it's not part of the public API surface. This was done as these methods were for internal use. Currently `flutter_appauth` (version 0.8.3) is constrained to depend on versions >= 1.0.2 and < 2.0.0. As it's possible that plugin consumers were calling the methods via the plugin, where the platform interface is a transitive dependency, the platform interface has been bumped to version 2.0.0 instead of 1.1.0 to be safe.
* Added `preferEphemeralSession` to `AuthorizationRequest` and `AuthorizationTokenRequest` classes. Thanks to the PR from [Matthew Smith](https://github.com/matthewtsmith).

## [1.0.2]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
mixin AuthorizationParameters {
/// Hint to the Authorization Server about the login identifier the End-User might use to log in.
String loginHint;
String? loginHint;

/// List of ASCII string values that specifies whether the Authorization Server prompts the End-User for reauthentication and consent.
List<String> promptValues;
List<String>? promptValues;

/// Whether to use an ephemeral session that prevents cookies and other browser data being shared with the user's normal browser session.
///
/// This property is only applicable to iOS versions 13 and above.
bool preferEphemeralSession;
bool? preferEphemeralSession;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ class AuthorizationRequest extends CommonRequestDetails
AuthorizationRequest(
String clientId,
String redirectUrl, {
String loginHint,
List<String> scopes,
AuthorizationServiceConfiguration serviceConfiguration,
Map<String, String> additionalParameters,
String issuer,
String discoveryUrl,
List<String> promptValues,
String? loginHint,
List<String>? scopes,
AuthorizationServiceConfiguration? serviceConfiguration,
Map<String, String>? additionalParameters,
String? issuer,
String? discoveryUrl,
List<String>? promptValues,
bool allowInsecureConnections = false,
bool preferEphemeralSession = false,
}) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
/// Contains the response from making an authorization request.
class AuthorizationResponse {
AuthorizationResponse(
const AuthorizationResponse(
this.authorizationCode,
this.codeVerifier,
this.authorizationAdditionalParameters,
);

/// The authorization code.
final String authorizationCode;
final String? authorizationCode;

/// The code verifier generated by AppAuth when issue the authorization request. Use this when exchanging the [authorizationCode] for a token.
final String codeVerifier;
final String? codeVerifier;

/// Additional parameters included in the response.
final Map<String, dynamic> authorizationAdditionalParameters;
final Map<String, dynamic>? authorizationAdditionalParameters;
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
class AuthorizationServiceConfiguration {
AuthorizationServiceConfiguration(
const AuthorizationServiceConfiguration(
this.authorizationEndpoint,
this.tokenEndpoint,
) : assert(tokenEndpoint != null && authorizationEndpoint != null,
'Must specify both the authorization and token endpoints');
);

final String authorizationEndpoint;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ class AuthorizationTokenRequest extends TokenRequest
AuthorizationTokenRequest(
String clientId,
String redirectUrl, {
String loginHint,
String clientSecret,
List<String> scopes,
AuthorizationServiceConfiguration serviceConfiguration,
Map<String, String> additionalParameters,
String issuer,
String discoveryUrl,
List<String> promptValues,
String? loginHint,
String? clientSecret,
List<String>? scopes,
AuthorizationServiceConfiguration? serviceConfiguration,
Map<String, String>? additionalParameters,
String? issuer,
String? discoveryUrl,
List<String>? promptValues,
bool allowInsecureConnections = false,
bool preferEphemeralSession = false,
}) : super(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ import 'token_response.dart';
/// The details from making a successful combined authorization and token exchange request.
class AuthorizationTokenResponse extends TokenResponse {
AuthorizationTokenResponse(
String accessToken,
String refreshToken,
DateTime accessTokenExpirationDateTime,
String idToken,
String tokenType,
String? accessToken,
String? refreshToken,
DateTime? accessTokenExpirationDateTime,
String? idToken,
String? tokenType,
this.authorizationAdditionalParameters,
Map<String, dynamic> tokenAdditionalParameters,
Map<String, dynamic>? tokenAdditionalParameters,
) : super(accessToken, refreshToken, accessTokenExpirationDateTime, idToken,
tokenType, tokenAdditionalParameters);

/// Contains additional parameters returned by the authorization server from making the authorization request.
final Map<String, dynamic> authorizationAdditionalParameters;
final Map<String, dynamic>? authorizationAdditionalParameters;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@ import 'authorization_service_configuration.dart';

class CommonRequestDetails {
/// The client id.
String clientId;
late String clientId;

/// The issuer.
String issuer;
String? issuer;

/// The URL of where the discovery document can be found.
String discoveryUrl;
String? discoveryUrl;

/// The redirect URL.
String redirectUrl;
late String redirectUrl;

/// The request scopes.
List<String> scopes;
List<String>? scopes;

/// The details of the OAuth 2.0 endpoints that can be explicitly when discovery isn't used or not possible.
AuthorizationServiceConfiguration serviceConfiguration;
AuthorizationServiceConfiguration? serviceConfiguration;

/// Additional parameters to include in the request.
Map<String, String> additionalParameters;
Map<String, String>? additionalParameters;

/// Whether to allow non-HTTPS endpoints.
///
/// This property is only applicable to Android.
bool allowInsecureConnections;
bool? allowInsecureConnections;
}
Loading

0 comments on commit b0d390f

Please sign in to comment.