From 491cf16024975ae45ba7fd9c1cf5239645e567a0 Mon Sep 17 00:00:00 2001 From: TheNoumanDev Date: Thu, 26 Sep 2024 22:39:05 +0500 Subject: [PATCH] added cookie property in api body --- .../framework/apiproviders/api_provider.dart | 1 + .../apiproviders/http_api_provider.dart | 55 +++++++++++++++++-- .../ensemble/lib/framework/data_context.dart | 3 +- modules/ensemble/pubspec.yaml | 1 + modules/ensemble_ts_interpreter/lib/api.dart | 6 +- 5 files changed, 59 insertions(+), 7 deletions(-) diff --git a/modules/ensemble/lib/framework/apiproviders/api_provider.dart b/modules/ensemble/lib/framework/apiproviders/api_provider.dart index f86978ee4..149a8bd55 100644 --- a/modules/ensemble/lib/framework/apiproviders/api_provider.dart +++ b/modules/ensemble/lib/framework/apiproviders/api_provider.dart @@ -81,6 +81,7 @@ abstract class Response { Map? headers; int? statusCode; String? reasonPhrase; + Map get cookies => {}; updateState({required apiState}) { this.apiState = apiState; } diff --git a/modules/ensemble/lib/framework/apiproviders/http_api_provider.dart b/modules/ensemble/lib/framework/apiproviders/http_api_provider.dart index 6f38940cb..131235da9 100644 --- a/modules/ensemble/lib/framework/apiproviders/http_api_provider.dart +++ b/modules/ensemble/lib/framework/apiproviders/http_api_provider.dart @@ -19,8 +19,10 @@ import 'package:http/io_client.dart'; import 'package:yaml/yaml.dart'; import 'package:http/http.dart' as http; import 'package:flutter/foundation.dart' as foundation; +import 'package:cookie_jar/cookie_jar.dart'; class HTTPAPIProvider extends APIProvider { + final CookieJar _cookieJar = CookieJar(); @override Future invokeApi(BuildContext context, YamlMap api, DataContext eContext, String apiName) async { @@ -126,6 +128,8 @@ class HTTPAPIProvider extends APIProvider { env?['ssl_pinning_enabled']?.toLowerCase() == 'true'; String? sslPinningCertificate = secrets?['ssl_pinning_certificate']; + bool manageCookies = Utils.getBool(api['manageCookies'], fallback: false); + Completer completer = Completer(); http.Response response; @@ -134,6 +138,15 @@ class HTTPAPIProvider extends APIProvider { sslPinningEnabled: sslPinningEnabled, sslPinningCertificate: sslPinningCertificate, ); + + if (!kIsWeb && manageCookies) { + List cookies = await _cookieJar.loadForRequest(Uri.parse(url)); + String cookieString = cookies.map((cookie) => '${cookie.name}=${cookie.value}').join('; '); + if (cookieString.isNotEmpty) { + headers['Cookie'] = cookieString; + } + } + switch (method) { case 'POST': response = @@ -156,16 +169,28 @@ class HTTPAPIProvider extends APIProvider { response = await client.get(Uri.parse(url), headers: headers); break; } + // Store cookies for native apps + if (!kIsWeb && manageCookies) { + _cookieJar.saveFromResponse(Uri.parse(url), _extractCookies(response)); + } final isOkay = response.statusCode >= 200 && response.statusCode <= 299; log('Response: ${response.statusCode}'); return HttpResponse(response, isOkay ? APIState.success : APIState.error, - apiName: apiName); + apiName: apiName, manageCookies: manageCookies); } catch (e) { return _handleError(e, apiName); } } + List _extractCookies(http.Response response) { + List cookies = []; + response.headers['set-cookie']?.split(',').forEach((String cookie) { + cookies.add(Cookie.fromSetCookieValue(cookie)); + }); + return cookies; + } + Future _getHttpClient({ required bool sslPinningEnabled, String? sslPinningCertificate, @@ -301,12 +326,16 @@ class HTTPAPIProvider extends APIProvider { /// a wrapper class around the http Response class HttpResponse extends Response { - HttpResponse.updateState({required apiState}) { + final bool _manageCookies; + late Map _cookies; + + HttpResponse.updateState({required apiState}) : _manageCookies = false { super.updateState(apiState: apiState); } // APIState get apiState => _apiState; HttpResponse.fromBody(dynamic body, - [headers, statusCode, reasonPhrase, apiState = APIState.idle]) { + [headers, statusCode, reasonPhrase, apiState = APIState.idle]) + : _manageCookies = false { super.body = body; super.headers = headers; super.statusCode = statusCode; @@ -315,7 +344,8 @@ class HttpResponse extends Response { } HttpResponse(http.Response response, APIState apiState, - {String apiName = ''}) { + {String apiName = '', bool manageCookies = false}) + : _manageCookies = manageCookies { try { body = json.decode(response.body); } on FormatException catch (_, e) { @@ -326,7 +356,24 @@ class HttpResponse extends Response { statusCode = response.statusCode; reasonPhrase = response.reasonPhrase; apiName = apiName; + _cookies = _parseCookies(response); + } + + Map _parseCookies(http.Response response) { + Map cookies = {}; + if (_manageCookies) { + response.headers['set-cookie']?.split(',').forEach((String rawCookie) { + List cookieParts = rawCookie.split(';')[0].split('='); + if (cookieParts.length == 2) { + cookies[cookieParts[0].trim()] = cookieParts[1].trim(); + } + }); + } + return cookies; } + + Map get cookies => _cookies; + @override bool get isOkay => statusCode != null && statusCode! >= 200 && statusCode! <= 299; diff --git a/modules/ensemble/lib/framework/data_context.dart b/modules/ensemble/lib/framework/data_context.dart index 45d73fa1b..ec0f3ab89 100644 --- a/modules/ensemble/lib/framework/data_context.dart +++ b/modules/ensemble/lib/framework/data_context.dart @@ -1151,7 +1151,8 @@ class APIResponse with Invokable { 'body': () => _response?.body, 'headers': () => _response?.headers, 'statusCode': () => _response?.statusCode, - 'reasonPhrase': () => _response?.reasonPhrase + 'reasonPhrase': () => _response?.reasonPhrase, + 'cookies': () => _response?.cookies, }; } diff --git a/modules/ensemble/pubspec.yaml b/modules/ensemble/pubspec.yaml index a619cd464..3ef4ef656 100644 --- a/modules/ensemble/pubspec.yaml +++ b/modules/ensemble/pubspec.yaml @@ -79,6 +79,7 @@ dependencies: fluttertoast: 8.2.2 video_player: ^2.6.1 lottie: ^3.0.0 + cookie_jar: ^4.0.8 js_widget: git: url: https://github.com/EnsembleUI/ensemble.git diff --git a/modules/ensemble_ts_interpreter/lib/api.dart b/modules/ensemble_ts_interpreter/lib/api.dart index 12a85d3da..9497cab8b 100644 --- a/modules/ensemble_ts_interpreter/lib/api.dart +++ b/modules/ensemble_ts_interpreter/lib/api.dart @@ -7,7 +7,8 @@ class API { String name, uri; Map? params; String method = 'get'; - API(this.name, this.uri, this.params); + bool manageCookies = false; + API(this.name, this.uri, this.params, {this.manageCookies = false}); Future call(Map? paramValues) async { Map m = HashMap(); if (params != null) { @@ -38,7 +39,8 @@ class API { params[k.toString()] = v.toString(); }); } - return API(name, uri, params); + bool manageCookies = map['manageCookies'] == true; + return API(name, uri, params, manageCookies: manageCookies); } }