From 6f43c9357d1b5c96c39e7b0ee8f2a8a0038569ed Mon Sep 17 00:00:00 2001 From: benimautner Date: Mon, 18 Jul 2022 23:25:47 +0200 Subject: [PATCH] switched to HttpClient so CertificateErrors can be ignored added option to ignore CertificateErrors --- ios/Flutter/Flutter.podspec | 18 ------- lib/api/client.dart | 80 ++++++++++++++++++++++---------- lib/api/task_implementation.dart | 1 + lib/global.dart | 4 ++ lib/pages/list/task_edit.dart | 7 +-- lib/pages/settings.dart | 12 ++++- lib/service/services.dart | 24 ++++++++++ 7 files changed, 100 insertions(+), 46 deletions(-) delete mode 100644 ios/Flutter/Flutter.podspec diff --git a/ios/Flutter/Flutter.podspec b/ios/Flutter/Flutter.podspec deleted file mode 100644 index 5ca3041..0000000 --- a/ios/Flutter/Flutter.podspec +++ /dev/null @@ -1,18 +0,0 @@ -# -# NOTE: This podspec is NOT to be published. It is only used as a local source! -# - -Pod::Spec.new do |s| - s.name = 'Flutter' - s.version = '1.0.0' - s.summary = 'High-performance, high-fidelity mobile apps.' - s.description = <<-DESC -Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS. - DESC - s.homepage = 'https://flutter.io' - s.license = { :type => 'MIT' } - s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } - s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } - s.ios.deployment_target = '8.0' - s.vendored_frameworks = 'Flutter.framework' -end diff --git a/lib/api/client.dart b/lib/api/client.dart index 657c344..4aafd1e 100644 --- a/lib/api/client.dart +++ b/lib/api/client.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:core'; import 'dart:developer'; +import 'dart:io'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:vikunja_app/api/response.dart'; @@ -15,19 +16,24 @@ class Client { String _token; String _base; bool authenticated; + bool ignoreCertificates = false; String get base => _base; String get token => _token; - //Client(this._token, String base, {this.authenticated = true}) - // : _base = base.endsWith('/api/v1') ? base : '$base/api/v1'; + String post_body; + + HttpClient client = new HttpClient(); bool operator ==(dynamic otherClient) { return otherClient._token == _token; } Client(this.global, {String token, String base, bool authenticated = false}) - { configure(token: token, base: base, authenticated: authenticated);} + { + configure(token: token, base: base, authenticated: authenticated); + client.badCertificateCallback = (_,__,___) => ignoreCertificates; + } get _headers => { 'Authorization': _token != null ? 'Bearer $_token' : '', @@ -46,6 +52,8 @@ class Client { this.authenticated = authenticated; } + + void reset() { _token = _base = null; authenticated = false; @@ -66,37 +74,34 @@ class Client { queryParameters: queryParameters, // Because dart takes a Map here, it is only possible to sort by one parameter while the api supports n parameters. fragment: uri.fragment); - return http.get(newUri, headers: _headers) - .then(_handleResponse, onError: _handleError); + return client.getUrl(newUri) + .then(_handleResponseF, onError: _handleError); } Future delete(String url) { - return http - .delete( + return client + .deleteUrl( '${this.base}$url'.toUri(), - headers: _headers, ) - .then(_handleResponse, onError: _handleError); + .then(_handleResponseF, onError: _handleError); } Future post(String url, {dynamic body}) { - return http - .post( + post_body = _encoder.convert(body); + return client + .postUrl( '${this.base}$url'.toUri(), - headers: _headers, - body: _encoder.convert(body), ) - .then(_handleResponse, onError: _handleError); + .then(_handleResponseF, onError: _handleError); } Future put(String url, {dynamic body}) { - return http - .put( + post_body = _encoder.convert(body); + return client + .putUrl( '${this.base}$url'.toUri(), - headers: _headers, - body: _encoder.convert(body), ) - .then(_handleResponse, onError: _handleError); + .then(_handleResponseF, onError: _handleError); } void _handleError(dynamic e) { @@ -105,7 +110,36 @@ class Client { global.currentState?.showSnackBar(snackBar); } - Response _handleResponse(http.Response response) { + Map headersToMap(HttpHeaders headers) { + Map map = {}; + headers.forEach((name, values) {map[name] = values[0].toString();}); + return map; + } + + Future _handleResponseF(HttpClientRequest request) { + _headers.forEach((k, v) => request.headers.set(k, v)); + if(post_body != "") { + request.write(post_body); + post_body = ""; + } + + return request.close().then((response) { + final completer = Completer(); + final contents = StringBuffer(); + response.transform(utf8.decoder).listen((data) { + contents.write(data); + }, onDone: () => completer.complete(contents.toString())); + return completer.future.then((body) { + + Response res = Response(json.decode(body), response.statusCode, headersToMap(response.headers)); + _handleResponseErrors(res); + return res; + }); + }); + //return Response(body, statusCode, headers) + } + + void _handleResponseErrors(Response response) { if (response.statusCode < 200 || response.statusCode >= 400 || json == null) { @@ -113,7 +147,7 @@ class Client { if (response.statusCode ~/ 100 == 4) { throw new InvalidRequestApiException( response.statusCode, - response.request.url.toString(), + "", error["message"] ?? "Unknown Error"); } final SnackBar snackBar = SnackBar( @@ -132,10 +166,8 @@ class Client { ); global.currentState?.showSnackBar(snackBar); throw new ApiException( - response.statusCode, response.request.url.toString()); + response.statusCode, ""); } - return Response( - _decoder.convert(response.body), response.statusCode, response.headers); } } diff --git a/lib/api/task_implementation.dart b/lib/api/task_implementation.dart index 7a0862b..ff055de 100644 --- a/lib/api/task_implementation.dart +++ b/lib/api/task_implementation.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:developer'; import 'package:vikunja_app/api/client.dart'; import 'package:vikunja_app/api/response.dart'; diff --git a/lib/global.dart b/lib/global.dart index 4b70422..ee0f392 100644 --- a/lib/global.dart +++ b/lib/global.dart @@ -61,6 +61,8 @@ class VikunjaGlobalState extends State { ServerService get serverService => new ServerAPIService(client); + SettingsManager get settingsManager => new SettingsManager(_storage); + NamespaceService get namespaceService => new NamespaceAPIService(client); TaskService get taskService => new TaskAPIService(client); @@ -108,6 +110,7 @@ class VikunjaGlobalState extends State { void initState() { super.initState(); _client = Client(snackbarKey); + settingsManager.getIgnoreCertificates().then((value) => value == "1" ? client.ignoreCertificates = true : client.ignoreCertificates = false); _newUserService = UserAPIService(client); _loadCurrentUser(); tz.initializeTimeZones(); @@ -117,6 +120,7 @@ class VikunjaGlobalState extends State { platformChannelSpecificsReminders = notifs.NotificationDetails( android: androidSpecificsReminders, iOS: iOSSpecifics); notificationInitializer(); + } void changeUser(User newUser, {String token, String base}) async { diff --git a/lib/pages/list/task_edit.dart b/lib/pages/list/task_edit.dart index ab25d14..907a1c4 100644 --- a/lib/pages/list/task_edit.dart +++ b/lib/pages/list/task_edit.dart @@ -262,7 +262,8 @@ class _TaskEditPageState extends State { InputDecoration(labelText: 'Add a new label')), suggestionsCallback: (pattern) => _searchLabel(pattern), itemBuilder: (context, suggestion) { - return Text(suggestion); + print(suggestion); + return new ListTile(title: Text(suggestion)); }, transitionBuilder: (context, suggestionsBox, controller) { return suggestionsBox; @@ -364,11 +365,11 @@ class _TaskEditPageState extends State { .labelService .getAll(query: query) .then((labels) { - log("searched"); // Only show those labels which aren't already added to the task labels.removeWhere((labelToRemove) => _labels.contains(labelToRemove)); _suggestedLabels = labels; - return labels.map((label) => label.title).toList(); + List labelText = labels.map((label) => label.title).toList(); + return labelText; }); } diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart index 75575bf..bcecff2 100644 --- a/lib/pages/settings.dart +++ b/lib/pages/settings.dart @@ -12,6 +12,7 @@ class SettingsPage extends StatefulWidget { class SettingsPageState extends State { List taskListList; int defaultList; + bool ignoreCertificates; @override Widget build(BuildContext context) { @@ -19,6 +20,9 @@ class SettingsPageState extends State { VikunjaGlobal.of(context).listService.getAll().then((value) => setState(() => taskListList = value)); if(defaultList == null) VikunjaGlobal.of(context).listService.getDefaultList().then((value) => setState(() => defaultList = value == null ? null : int.tryParse(value))); + + VikunjaGlobal.of(context).settingsManager.getIgnoreCertificates().then((value) => setState(() => ignoreCertificates = value == "1" ? true:false)); + return new Scaffold( appBar: AppBar(title: Text("Settings"),), body: Column( @@ -33,7 +37,13 @@ class SettingsPageState extends State { setState(() => defaultList = value); VikunjaGlobal.of(context).listService.setDefaultList(value); }, - ),) : ListTile(title: Text("..."),) + ),) : ListTile(title: Text("..."),), + ignoreCertificates != null ? + CheckboxListTile(title: Text("Ignore Certificates"), value: ignoreCertificates, onChanged: (value) { + setState(() => ignoreCertificates = value); + VikunjaGlobal.of(context).settingsManager.setIgnoreCertificates(value); + VikunjaGlobal.of(context).client.ignoreCertificates = value; + }) : ListTile(title: Text("...")) ], ), ); diff --git a/lib/service/services.dart b/lib/service/services.dart index 0b48372..8b52def 100644 --- a/lib/service/services.dart +++ b/lib/service/services.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:developer'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:vikunja_app/api/response.dart'; import 'package:vikunja_app/models/label.dart'; import 'package:vikunja_app/models/labelTask.dart'; @@ -138,4 +139,27 @@ abstract class LabelTaskBulkService { abstract class ServerService { Future getInfo(); +} + +class SettingsManager { + final FlutterSecureStorage _storage; + + Map defaults = { + "ignore-certificates" : "0" + }; + + SettingsManager(this._storage) { + defaults.forEach((key, value) { + _storage.containsKey(key: key).then((is_created) { + if (!is_created) + _storage.write(key: key, value: value); + });});} + + Future getIgnoreCertificates() { + return _storage.read(key: "ignore-certificates"); + } + + void setIgnoreCertificates(bool value) { + _storage.write(key: "ignore-certificates", value: value ? "1" : "0"); + } } \ No newline at end of file