diff --git a/CHANGELOG.md b/CHANGELOG.md index 93b3cb8..20c98cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,4 +19,8 @@ Downgrade Alamofire version ## 1.0.4 -Support iOS 9.0 and above +Support iOS 9.0 and above + +## 2.0.0 + +Flutter 2 support and null-safety diff --git a/example/lib/main.dart b/example/lib/main.dart index c605fd5..308449e 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -28,14 +28,15 @@ class _MyAppState extends State { } // Platform messages are asynchronous, so we initialize in an async method. - check(String url, String fingerprint, SHA sha, Map headerHttp, int timeout) async { - - List allowedShA1FingerprintList = new List(); + check(String url, String fingerprint, SHA sha, Map headerHttp, + int timeout) async { + List allowedShA1FingerprintList = []; allowedShA1FingerprintList.add(fingerprint); try { // Platform messages may fail, so we use a try/catch PlatformException. - String checkMsg = await HttpCertificatePinning.check(serverURL: url, + String checkMsg = await HttpCertificatePinning.check( + serverURL: url, headerHttp: headerHttp, sha: sha, allowedSHAFingerprints: allowedShA1FingerprintList, @@ -44,8 +45,7 @@ class _MyAppState extends State { // If the widget was removed from the tree while the asynchronous platform // message was in flight, we want to discard the reply rather than calling // setState to update our non-existent appearance. - if (!mounted) - return; + if (!mounted) return; Scaffold.of(scaffoldContext).showSnackBar( new SnackBar( @@ -53,19 +53,16 @@ class _MyAppState extends State { duration: Duration(seconds: 1), backgroundColor: Colors.green, ), - ); - }catch (e){ + } catch (e) { Scaffold.of(scaffoldContext).showSnackBar( new SnackBar( content: new Text(e.toString()), duration: Duration(seconds: 1), backgroundColor: Colors.red, ), - ); } - } void submit() { @@ -73,7 +70,8 @@ class _MyAppState extends State { if (_formKey.currentState.validate()) { _formKey.currentState.save(); // Save our form now. - this.check(_data.serverURL, _data.allowedSHAFingerprint, _data.sha, _data.headerHttp, _data.timeout); + this.check(_data.serverURL, _data.allowedSHAFingerprint, _data.sha, + _data.headerHttp, _data.timeout); } } @@ -85,8 +83,7 @@ class _MyAppState extends State { appBar: new AppBar( title: new Text('Ssl Pinning Plugin'), ), - body: - new Builder(builder: (BuildContext context) { + body: new Builder(builder: (BuildContext context) { this.scaffoldContext = context; return Container( padding: EdgeInsets.all(20.0), @@ -98,8 +95,7 @@ class _MyAppState extends State { keyboardType: TextInputType.url, decoration: InputDecoration( hintText: 'https://yourdomain.com', - labelText: 'URL' - ), + labelText: 'URL'), validator: (value) { if (value.isEmpty) { return 'Please enter some url'; @@ -107,13 +103,21 @@ class _MyAppState extends State { }, onSaved: (String value) { this._data.serverURL = value; - } - ), + }), DropdownButton( - items: [DropdownMenuItem(child: Text(SHA.SHA1.toString()), value: SHA.SHA1,), DropdownMenuItem(child: Text(SHA.SHA256.toString()), value: SHA.SHA256,)], + items: [ + DropdownMenuItem( + child: Text(SHA.SHA1.toString()), + value: SHA.SHA1, + ), + DropdownMenuItem( + child: Text(SHA.SHA256.toString()), + value: SHA.SHA256, + ) + ], value: _data.sha, isExpanded: true, - onChanged: (SHA val){ + onChanged: (SHA val) { setState(() { this._data.sha = val; }); @@ -123,8 +127,7 @@ class _MyAppState extends State { keyboardType: TextInputType.text, decoration: InputDecoration( hintText: 'OO OO OO OO OO OO OO OO OO OO', - labelText: 'Fingerprint' - ), + labelText: 'Fingerprint'), validator: (value) { if (value.isEmpty) { return 'Please enter some fingerprint'; @@ -132,15 +135,12 @@ class _MyAppState extends State { }, onSaved: (String value) { this._data.allowedSHAFingerprint = value; - } - ), + }), TextFormField( keyboardType: TextInputType.number, initialValue: '60', decoration: InputDecoration( - hintText: '60', - labelText: 'Timeout' - ), + hintText: '60', labelText: 'Timeout'), validator: (value) { if (value.isEmpty) { return 'Please enter some timeout'; @@ -148,29 +148,22 @@ class _MyAppState extends State { }, onSaved: (String value) { this._data.timeout = int.parse(value); - } - ), + }), Container( child: RaisedButton( child: Text( 'Check', - style: TextStyle( - color: Colors.white - ), + style: TextStyle(color: Colors.white), ), onPressed: () => submit(), color: Colors.blue, ), - margin: EdgeInsets.only( - top: 20.0 - ), + margin: EdgeInsets.only(top: 20.0), ) ], ), - ) - ); - }) - ), + )); + })), ); } } diff --git a/example/pubspec.lock b/example/pubspec.lock index 31b9c55..0041093 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -43,20 +43,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.3" dio: dependency: transitive description: name: dio url: "https://pub.dartlang.org" source: hosted - version: "3.0.10" + version: "4.0.0" fake_async: dependency: transitive description: @@ -80,21 +73,21 @@ packages: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.12.2" + version: "0.13.1" http_certificate_pinning: dependency: "direct dev" description: path: ".." relative: true source: path - version: "1.0.4" + version: "2.0.0" http_parser: dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "3.1.4" + version: "4.0.0" matcher: dependency: transitive description: @@ -185,5 +178,5 @@ packages: source: hosted version: "2.1.0" sdks: - dart: ">=2.12.0-0.0 <3.0.0" + dart: ">=2.12.0 <3.0.0" flutter: ">=1.12.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 399b098..beee9cc 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -9,10 +9,6 @@ dependencies: flutter: sdk: flutter - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.2 - dev_dependencies: flutter_test: sdk: flutter @@ -20,44 +16,5 @@ dev_dependencies: http_certificate_pinning: path: ../ -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter. flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages + uses-material-design: true \ No newline at end of file diff --git a/lib/certificate_pinning_interceptor.dart b/lib/certificate_pinning_interceptor.dart index f2c9e13..6be4200 100644 --- a/lib/certificate_pinning_interceptor.dart +++ b/lib/certificate_pinning_interceptor.dart @@ -1,27 +1,26 @@ +import 'dart:async'; import 'package:dio/dio.dart'; import 'package:http_certificate_pinning/http_certificate_pinning.dart'; -class CertificatePinningInterceptor extends Interceptor{ - +class CertificatePinningInterceptor extends Interceptor { final List _allowedSHAFingerprints; CertificatePinningInterceptor(this._allowedSHAFingerprints); @override - Future onRequest(RequestOptions options) async { - + Future onRequest( + RequestOptions options, RequestInterceptorHandler handler) async { final secure = await HttpCertificatePinning.check( serverURL: options.baseUrl, - headerHttp: options.headers.map((a,b)=> MapEntry(a, b.toString())), + headerHttp: options.headers.map((a, b) => MapEntry(a, b.toString())), sha: SHA.SHA256, - allowedSHAFingerprints:_allowedSHAFingerprints, - timeout : 50 - ); + allowedSHAFingerprints: _allowedSHAFingerprints, + timeout: 50); - if(secure.contains("CONNECTION_SECURE")){ - return super.onRequest(options); - }else{ + if (secure.contains("CONNECTION_SECURE")) { + return super.onRequest(options, handler); + } else { throw Exception("CONNECTION_NOT_SECURE"); } } diff --git a/lib/http_certificate_pinning.dart b/lib/http_certificate_pinning.dart index a3aba57..db3db83 100644 --- a/lib/http_certificate_pinning.dart +++ b/lib/http_certificate_pinning.dart @@ -2,14 +2,14 @@ import 'dart:async'; import 'package:flutter/services.dart'; -enum SHA {SHA1, SHA256} +enum SHA { SHA1, SHA256 } class HttpCertificatePinning { - static const MethodChannel _channel = - const MethodChannel('http_certificate_pinning'); + const MethodChannel('http_certificate_pinning'); - static final HttpCertificatePinning _sslPinning = HttpCertificatePinning._internal(); + static final HttpCertificatePinning _sslPinning = + HttpCertificatePinning._internal(); factory HttpCertificatePinning() => _sslPinning; @@ -17,13 +17,20 @@ class HttpCertificatePinning { _channel.setMethodCallHandler(_platformCallHandler); } - static Future check({ String serverURL, Map headerHttp, SHA sha, List allowedSHAFingerprints, int timeout }) async { + static Future check({ + required String serverURL, + required SHA sha, + required List allowedSHAFingerprints, + Map? headerHttp, + int? timeout, + }) async { final Map params = { - "url" : serverURL, - "headers" : headerHttp, + "url": serverURL, + "headers": headerHttp, "type": sha.toString().split(".").last, - "fingerprints" : allowedSHAFingerprints.map((a) => a.replaceAll(":", "")).toList(), - "timeout" : timeout + "fingerprints": + allowedSHAFingerprints.map((a) => a.replaceAll(":", "")).toList(), + "timeout": timeout }; String resp = await _channel.invokeMethod('check', params); return resp; diff --git a/lib/secure_http_client.dart b/lib/secure_http_client.dart index 87b7fdf..ae2000c 100644 --- a/lib/secure_http_client.dart +++ b/lib/secure_http_client.dart @@ -7,52 +7,47 @@ import 'package:http/io_client.dart'; import 'package:http_certificate_pinning/http_certificate_pinning.dart'; class SecureHttpClient extends http.BaseClient { - List allowedSHAFingerprints; final IOClient _client = IOClient(); - SecureHttpClient._internal({this.allowedSHAFingerprints}); + SecureHttpClient._internal({required this.allowedSHAFingerprints}); - factory SecureHttpClient.build( - List allowedSHAFingerprints - ) { - //Remove any value that is null. - allowedSHAFingerprints?.removeWhere((fingerPrint) => fingerPrint == null); + factory SecureHttpClient.build(List allowedSHAFingerprints) { return SecureHttpClient._internal( - allowedSHAFingerprints: allowedSHAFingerprints - ); + allowedSHAFingerprints: allowedSHAFingerprints); } - Future head(url, {Map headers}) => + Future head(url, {Map? headers}) => _sendUnstreamed("HEAD", url, headers); - Future get(url, {Map headers}) => + Future get(url, {Map? headers}) => _sendUnstreamed("GET", url, headers); Future post(url, - {Map headers, body, Encoding encoding}) => + {Map? headers, body, Encoding? encoding}) => _sendUnstreamed("POST", url, headers, body, encoding); Future put(url, - {Map headers, body, Encoding encoding}) => + {Map? headers, body, Encoding? encoding}) => _sendUnstreamed("PUT", url, headers, body, encoding); Future patch(url, - {Map headers, body, Encoding encoding}) => + {Map? headers, body, Encoding? encoding}) => _sendUnstreamed("PATCH", url, headers, body, encoding); - Future delete(url, {Map headers}) => - _sendUnstreamed("DELETE", url, headers); + Future delete(url, + {Map? headers, body, Encoding? encoding}) => + _sendUnstreamed("DELETE", url, headers, body, encoding); - Future read(url, {Map headers}) { + Future read(url, {Map? headers}) { return get(url, headers: headers).then((response) { _checkResponseSuccess(url, response); return response.body; }); } - Future readBytes(url, {Map headers}) { + Future readBytes(url, {Map? headers}) { return get(url, headers: headers).then((response) { _checkResponseSuccess(url, response); return response.bodyBytes; @@ -63,18 +58,17 @@ class SecureHttpClient extends http.BaseClient { /// Sends a non-streaming [Request] and returns a non-streaming [Response]. Future _sendUnstreamed( - String method, url, Map headers, - [body, Encoding encoding]) async { - - final secure = await HttpCertificatePinning.check( - serverURL: url.toString(), - headerHttp: headers, - sha: SHA.SHA256, - allowedSHAFingerprints: allowedSHAFingerprints, - timeout : 50 - ); - - if(secure.contains("CONNECTION_SECURE")){ + String method, url, Map? headers, + [body, Encoding? encoding]) async { + final secure = await (HttpCertificatePinning.check( + serverURL: url.toString(), + headerHttp: headers, + sha: SHA.SHA256, + allowedSHAFingerprints: allowedSHAFingerprints, + timeout: 50, + )); + + if (secure.contains("CONNECTION_SECURE")) { var request = Request(method, _fromUriOrString(url)); if (headers != null) request.headers.addAll(headers); @@ -92,7 +86,7 @@ class SecureHttpClient extends http.BaseClient { } return Response.fromStream(await send(request)); - }else{ + } else { throw Exception("CONNECTION_NOT_SECURE"); } } diff --git a/pubspec.lock b/pubspec.lock index 8699778..4169733 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -49,7 +49,7 @@ packages: name: dio url: "https://pub.dartlang.org" source: hosted - version: "3.0.10" + version: "4.0.0" fake_async: dependency: transitive description: @@ -73,14 +73,14 @@ packages: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.12.2" + version: "0.13.1" http_parser: dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "3.1.4" + version: "4.0.0" matcher: dependency: transitive description: @@ -171,5 +171,5 @@ packages: source: hosted version: "2.1.0" sdks: - dart: ">=2.12.0-0.0 <3.0.0" + dart: ">=2.12.0 <3.0.0" flutter: ">=1.12.0" diff --git a/pubspec.yaml b/pubspec.yaml index f87e0c7..14f1a80 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,18 +1,18 @@ name: http_certificate_pinning description: Https Certificate pinning for Flutter -version: 1.0.4 +version: 2.0.0 author: Diefferson Santos homepage: https://github.com/diefferson/http_certificate_pinning environment: - sdk: ">=2.1.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' flutter: ">=1.12.0" dependencies: + dio: ^4.0.0 flutter: sdk: flutter - dio: ^3.0.10 - http: ^0.12.0+4 + http: ^0.13.1 dev_dependencies: flutter_test: