From 171a118d38abf65852de2c55447baf27d3921067 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sat, 7 Jun 2025 15:30:20 +0530 Subject: [PATCH 01/70] feat: add authentication support with APIAuthType and APIAuthModel - Introduced APIAuthType enum for various authentication methods. - Created APIAuthModel with basic authentication fields. - Updated RequestModel to include authType and authData. - Implemented EditAuthType widget for selecting and managing authentication. - Enhanced CollectionStateNotifier to handle authentication updates. :wq --- lib/consts.dart | 1 + lib/models/request_model.dart | 2 + lib/models/request_model.freezed.dart | 89 +++- lib/models/request_model.g.dart | 19 + lib/providers/collection_providers.dart | 4 + .../request_pane/request_auth.dart | 106 +++++ .../request_pane/request_pane_rest.dart | 16 +- packages/apidash_core/lib/consts.dart | 23 ++ .../lib/models/api_auth_model.dart | 17 + .../lib/models/api_auth_model.freezed.dart | 386 ++++++++++++++++++ .../lib/models/api_auth_model.g.dart | 30 ++ packages/apidash_core/lib/models/models.dart | 3 + .../json_field_editor/example/pubspec.lock | 16 +- .../example/pubspec.lock | 16 +- pubspec.lock | 20 +- 15 files changed, 700 insertions(+), 48 deletions(-) create mode 100644 lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart create mode 100644 packages/apidash_core/lib/models/api_auth_model.dart create mode 100644 packages/apidash_core/lib/models/api_auth_model.freezed.dart create mode 100644 packages/apidash_core/lib/models/api_auth_model.g.dart diff --git a/lib/consts.dart b/lib/consts.dart index 3e9dcacd4..88084406b 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -448,6 +448,7 @@ const kLabelURLParams = "Params"; const kLabelHeaders = "Headers"; const kLabelBody = "Body"; const kLabelScripts = "Scripts"; +const kLabelAuth = "Authorization"; const kLabelQuery = "Query"; const kNameCheckbox = "Checkbox"; const kNameURLParam = "URL Parameter"; diff --git a/lib/models/request_model.dart b/lib/models/request_model.dart index 4d63c2adc..fa647f30f 100644 --- a/lib/models/request_model.dart +++ b/lib/models/request_model.dart @@ -15,6 +15,8 @@ class RequestModel with _$RequestModel { @Default(APIType.rest) APIType apiType, @Default("") String name, @Default("") String description, + @Default(APIAuthType.none) APIAuthType authType, + APIAuthModel? authData, @JsonKey(includeToJson: false) @Default(0) requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, diff --git a/lib/models/request_model.freezed.dart b/lib/models/request_model.freezed.dart index 72f607bd5..affd554e5 100644 --- a/lib/models/request_model.freezed.dart +++ b/lib/models/request_model.freezed.dart @@ -24,6 +24,8 @@ mixin _$RequestModel { APIType get apiType => throw _privateConstructorUsedError; String get name => throw _privateConstructorUsedError; String get description => throw _privateConstructorUsedError; + APIAuthType get authType => throw _privateConstructorUsedError; + APIAuthModel? get authData => throw _privateConstructorUsedError; @JsonKey(includeToJson: false) dynamic get requestTabIndex => throw _privateConstructorUsedError; HttpRequestModel? get httpRequestModel => throw _privateConstructorUsedError; @@ -59,6 +61,8 @@ abstract class $RequestModelCopyWith<$Res> { APIType apiType, String name, String description, + APIAuthType authType, + APIAuthModel? authData, @JsonKey(includeToJson: false) dynamic requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, @@ -69,6 +73,7 @@ abstract class $RequestModelCopyWith<$Res> { String? preRequestScript, String? postRequestScript}); + $APIAuthModelCopyWith<$Res>? get authData; $HttpRequestModelCopyWith<$Res>? get httpRequestModel; $HttpResponseModelCopyWith<$Res>? get httpResponseModel; } @@ -92,6 +97,8 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> Object? apiType = null, Object? name = null, Object? description = null, + Object? authType = null, + Object? authData = freezed, Object? requestTabIndex = freezed, Object? httpRequestModel = freezed, Object? responseStatus = freezed, @@ -119,6 +126,14 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> ? _value.description : description // ignore: cast_nullable_to_non_nullable as String, + authType: null == authType + ? _value.authType + : authType // ignore: cast_nullable_to_non_nullable + as APIAuthType, + authData: freezed == authData + ? _value.authData + : authData // ignore: cast_nullable_to_non_nullable + as APIAuthModel?, requestTabIndex: freezed == requestTabIndex ? _value.requestTabIndex : requestTabIndex // ignore: cast_nullable_to_non_nullable @@ -158,6 +173,20 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> ) as $Val); } + /// Create a copy of RequestModel + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $APIAuthModelCopyWith<$Res>? get authData { + if (_value.authData == null) { + return null; + } + + return $APIAuthModelCopyWith<$Res>(_value.authData!, (value) { + return _then(_value.copyWith(authData: value) as $Val); + }); + } + /// Create a copy of RequestModel /// with the given fields replaced by the non-null parameter values. @override @@ -200,6 +229,8 @@ abstract class _$$RequestModelImplCopyWith<$Res> APIType apiType, String name, String description, + APIAuthType authType, + APIAuthModel? authData, @JsonKey(includeToJson: false) dynamic requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, @@ -210,6 +241,8 @@ abstract class _$$RequestModelImplCopyWith<$Res> String? preRequestScript, String? postRequestScript}); + @override + $APIAuthModelCopyWith<$Res>? get authData; @override $HttpRequestModelCopyWith<$Res>? get httpRequestModel; @override @@ -233,6 +266,8 @@ class __$$RequestModelImplCopyWithImpl<$Res> Object? apiType = null, Object? name = null, Object? description = null, + Object? authType = null, + Object? authData = freezed, Object? requestTabIndex = freezed, Object? httpRequestModel = freezed, Object? responseStatus = freezed, @@ -260,6 +295,14 @@ class __$$RequestModelImplCopyWithImpl<$Res> ? _value.description : description // ignore: cast_nullable_to_non_nullable as String, + authType: null == authType + ? _value.authType + : authType // ignore: cast_nullable_to_non_nullable + as APIAuthType, + authData: freezed == authData + ? _value.authData + : authData // ignore: cast_nullable_to_non_nullable + as APIAuthModel?, requestTabIndex: freezed == requestTabIndex ? _value.requestTabIndex! : requestTabIndex, @@ -308,6 +351,8 @@ class _$RequestModelImpl implements _RequestModel { this.apiType = APIType.rest, this.name = "", this.description = "", + this.authType = APIAuthType.none, + this.authData, @JsonKey(includeToJson: false) this.requestTabIndex = 0, this.httpRequestModel, this.responseStatus, @@ -333,6 +378,11 @@ class _$RequestModelImpl implements _RequestModel { @JsonKey() final String description; @override + @JsonKey() + final APIAuthType authType; + @override + final APIAuthModel? authData; + @override @JsonKey(includeToJson: false) final dynamic requestTabIndex; @override @@ -356,7 +406,7 @@ class _$RequestModelImpl implements _RequestModel { @override String toString() { - return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime, preRequestScript: $preRequestScript, postRequestScript: $postRequestScript)'; + return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, authType: $authType, authData: $authData, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime)'; } @override @@ -369,6 +419,10 @@ class _$RequestModelImpl implements _RequestModel { (identical(other.name, name) || other.name == name) && (identical(other.description, description) || other.description == description) && + (identical(other.authType, authType) || + other.authType == authType) && + (identical(other.authData, authData) || + other.authData == authData) && const DeepCollectionEquality() .equals(other.requestTabIndex, requestTabIndex) && (identical(other.httpRequestModel, httpRequestModel) || @@ -396,6 +450,8 @@ class _$RequestModelImpl implements _RequestModel { apiType, name, description, + authType, + authData, const DeepCollectionEquality().hash(requestTabIndex), httpRequestModel, responseStatus, @@ -424,19 +480,20 @@ class _$RequestModelImpl implements _RequestModel { abstract class _RequestModel implements RequestModel { const factory _RequestModel( - {required final String id, - final APIType apiType, - final String name, - final String description, - @JsonKey(includeToJson: false) final dynamic requestTabIndex, - final HttpRequestModel? httpRequestModel, - final int? responseStatus, - final String? message, - final HttpResponseModel? httpResponseModel, - @JsonKey(includeToJson: false) final bool isWorking, - @JsonKey(includeToJson: false) final DateTime? sendingTime, - final String? preRequestScript, - final String? postRequestScript}) = _$RequestModelImpl; + {required final String id, + final APIType apiType, + final String name, + final String description, + final APIAuthType authType, + final APIAuthModel? authData, + @JsonKey(includeToJson: false) final dynamic requestTabIndex, + final HttpRequestModel? httpRequestModel, + final int? responseStatus, + final String? message, + final HttpResponseModel? httpResponseModel, + @JsonKey(includeToJson: false) final bool isWorking, + @JsonKey(includeToJson: false) final DateTime? sendingTime}) = + _$RequestModelImpl; factory _RequestModel.fromJson(Map json) = _$RequestModelImpl.fromJson; @@ -450,6 +507,10 @@ abstract class _RequestModel implements RequestModel { @override String get description; @override + APIAuthType get authType; + @override + APIAuthModel? get authData; + @override @JsonKey(includeToJson: false) dynamic get requestTabIndex; @override diff --git a/lib/models/request_model.g.dart b/lib/models/request_model.g.dart index d4f6ec206..d684118c3 100644 --- a/lib/models/request_model.g.dart +++ b/lib/models/request_model.g.dart @@ -12,6 +12,12 @@ _$RequestModelImpl _$$RequestModelImplFromJson(Map json) => _$RequestModelImpl( APIType.rest, name: json['name'] as String? ?? "", description: json['description'] as String? ?? "", + authType: $enumDecodeNullable(_$APIAuthTypeEnumMap, json['authType']) ?? + APIAuthType.none, + authData: json['authData'] == null + ? null + : APIAuthModel.fromJson( + Map.from(json['authData'] as Map)), requestTabIndex: json['requestTabIndex'] ?? 0, httpRequestModel: json['httpRequestModel'] == null ? null @@ -37,6 +43,8 @@ Map _$$RequestModelImplToJson(_$RequestModelImpl instance) => 'apiType': _$APITypeEnumMap[instance.apiType]!, 'name': instance.name, 'description': instance.description, + 'authType': _$APIAuthTypeEnumMap[instance.authType]!, + 'authData': instance.authData?.toJson(), 'httpRequestModel': instance.httpRequestModel?.toJson(), 'responseStatus': instance.responseStatus, 'message': instance.message, @@ -49,3 +57,14 @@ const _$APITypeEnumMap = { APIType.rest: 'rest', APIType.graphql: 'graphql', }; + +const _$APIAuthTypeEnumMap = { + APIAuthType.none: 'none', + APIAuthType.basic: 'basic', + APIAuthType.apiKey: 'apiKey', + APIAuthType.bearerToken: 'bearerToken', + APIAuthType.jwtBearer: 'jwtBearer', + APIAuthType.digest: 'digest', + APIAuthType.oauth1: 'oauth1', + APIAuthType.oauth2: 'oauth2', +}; diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 1bb9fba2e..e46820a6a 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -207,6 +207,8 @@ class CollectionStateNotifier String? id, HTTPVerb? method, APIType? apiType, + APIAuthType? authType, + APIAuthModel? authData, String? url, String? name, String? description, @@ -234,6 +236,8 @@ class CollectionStateNotifier var currentHttpRequestModel = currentModel.httpRequestModel; final newModel = currentModel.copyWith( apiType: apiType ?? currentModel.apiType, + authType: authType ?? currentModel.authType, + authData: authData ?? currentModel.authData, name: name ?? currentModel.name, description: description ?? currentModel.description, requestTabIndex: requestTabIndex ?? currentModel.requestTabIndex, diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart new file mode 100644 index 000000000..946705807 --- /dev/null +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -0,0 +1,106 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash/providers/providers.dart'; + +class EditAuthType extends ConsumerWidget { + const EditAuthType({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final selectedRequest = ref.watch(selectedRequestModelProvider); + + if (selectedRequest == null) { + return const SizedBox.shrink(); + } + + final currentAuthType = selectedRequest.authType; + final currentAuthData = selectedRequest.authData; + + return Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Auth Type Dropdown + DropdownButtonFormField( + value: currentAuthType, + decoration: const InputDecoration( + labelText: 'Authentication Type', + border: OutlineInputBorder(), + ), + items: APIAuthType.values.map((type) { + return DropdownMenuItem( + value: type, + child: Text(type.name), + ); + }).toList(), + onChanged: (APIAuthType? newType) { + if (newType != null) { + ref.read(collectionStateNotifierProvider.notifier).update( + authType: newType, + authData: null, // reset when auth type changes + ); + } + }, + ), + const SizedBox(height: 16), + + // Dynamic Auth Input Fields + _buildAuthFields(ref, currentAuthType, currentAuthData), + ], + ), + ); + } + + Widget _buildAuthFields( + WidgetRef ref, + APIAuthType authType, + APIAuthModel? authData, + ) { + final controllerMap = {}; + + void updateAuth(APIAuthModel model) { + ref.read(collectionStateNotifierProvider.notifier).update( + authData: model, + ); + } + + switch (authType) { + case APIAuthType.basic: + final usernameController = TextEditingController( + text: (authData is BasicAuth) ? authData.username : '', + ); + final passwordController = TextEditingController( + text: (authData is BasicAuth) ? authData.password : '', + ); + return Column( + children: [ + TextField( + controller: usernameController, + decoration: const InputDecoration(labelText: 'Username'), + onChanged: (value) => updateAuth(BasicAuth( + username: value, password: passwordController.text)), + ), + const SizedBox(height: 8), + TextField( + controller: passwordController, + decoration: const InputDecoration(labelText: 'Password'), + obscureText: true, + onChanged: (value) => updateAuth(BasicAuth( + username: usernameController.text, password: value)), + ), + ], + ); + + // + + case APIAuthType.none: + return const Text("No authentication selected."); + + // TODO: Implement digest, oauth1, oauth2 later + default: + return const Text("This auth type is not implemented yet."); + } + } +} diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart index 27d675676..ab0c21844 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart @@ -1,4 +1,6 @@ import 'package:apidash/consts.dart'; +import 'package:apidash/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart'; +import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/providers/providers.dart'; @@ -28,11 +30,9 @@ class EditRestRequestPane extends ConsumerWidget { .select((value) => value?.httpRequestModel?.hasBody)) ?? false; - final scriptsLength = ref.watch(selectedRequestModelProvider - .select((value) => value?.preRequestScript?.length)) ?? - ref.watch(selectedRequestModelProvider - .select((value) => value?.postRequestScript?.length)) ?? - 0; + final hasAuth = ref.watch( + selectedRequestModelProvider.select((value) => value?.authType != APIAuthType.none)); + false; return RequestPane( selectedId: selectedId, @@ -51,19 +51,19 @@ class EditRestRequestPane extends ConsumerWidget { paramLength > 0, headerLength > 0, hasBody, - scriptsLength > 0, + hasAuth ], tabLabels: const [ kLabelURLParams, kLabelHeaders, kLabelBody, - kLabelScripts, + kLabelAuth, ], children: const [ EditRequestURLParams(), EditRequestHeaders(), EditRequestBody(), - EditRequestScripts(), + EditAuthType(), ], ); } diff --git a/packages/apidash_core/lib/consts.dart b/packages/apidash_core/lib/consts.dart index 3d5d19c86..99a86c9f5 100644 --- a/packages/apidash_core/lib/consts.dart +++ b/packages/apidash_core/lib/consts.dart @@ -1 +1,24 @@ +import 'dart:convert'; + +enum APIType { + rest("HTTP", "HTTP"), + graphql("GraphQL", "GQL"); + + const APIType(this.label, this.abbr); + final String label; + final String abbr; +} + +enum APIAuthType { + none, + basic, + apiKey, + bearerToken, + jwtBearer, + digest, + oauth1, + oauth2, +} + + enum EnvironmentVariableType { variable, secret } diff --git a/packages/apidash_core/lib/models/api_auth_model.dart b/packages/apidash_core/lib/models/api_auth_model.dart new file mode 100644 index 000000000..6a3449a1e --- /dev/null +++ b/packages/apidash_core/lib/models/api_auth_model.dart @@ -0,0 +1,17 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'api_auth_model.g.dart'; +part 'api_auth_model.freezed.dart'; + +@freezed +class APIAuthModel with _$APIAuthModel { + const factory APIAuthModel.none() = None; + + const factory APIAuthModel.basic({ + required String username, + required String password, + }) = BasicAuth; + + factory APIAuthModel.fromJson(Map json) => + _$APIAuthModelFromJson(json); +} diff --git a/packages/apidash_core/lib/models/api_auth_model.freezed.dart b/packages/apidash_core/lib/models/api_auth_model.freezed.dart new file mode 100644 index 000000000..c7cc47e63 --- /dev/null +++ b/packages/apidash_core/lib/models/api_auth_model.freezed.dart @@ -0,0 +1,386 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'api_auth_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +APIAuthModel _$APIAuthModelFromJson(Map json) { + switch (json['runtimeType']) { + case 'none': + return None.fromJson(json); + case 'basic': + return BasicAuth.fromJson(json); + + default: + throw CheckedFromJsonException(json, 'runtimeType', 'APIAuthModel', + 'Invalid union type "${json['runtimeType']}"!'); + } +} + +/// @nodoc +mixin _$APIAuthModel { + @optionalTypeArgs + TResult when({ + required TResult Function() none, + required TResult Function(String username, String password) basic, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? none, + TResult? Function(String username, String password)? basic, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? none, + TResult Function(String username, String password)? basic, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(None value) none, + required TResult Function(BasicAuth value) basic, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(None value)? none, + TResult? Function(BasicAuth value)? basic, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(None value)? none, + TResult Function(BasicAuth value)? basic, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + + /// Serializes this APIAuthModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $APIAuthModelCopyWith<$Res> { + factory $APIAuthModelCopyWith( + APIAuthModel value, $Res Function(APIAuthModel) then) = + _$APIAuthModelCopyWithImpl<$Res, APIAuthModel>; +} + +/// @nodoc +class _$APIAuthModelCopyWithImpl<$Res, $Val extends APIAuthModel> + implements $APIAuthModelCopyWith<$Res> { + _$APIAuthModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of APIAuthModel + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc +abstract class _$$NoneImplCopyWith<$Res> { + factory _$$NoneImplCopyWith( + _$NoneImpl value, $Res Function(_$NoneImpl) then) = + __$$NoneImplCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$NoneImplCopyWithImpl<$Res> + extends _$APIAuthModelCopyWithImpl<$Res, _$NoneImpl> + implements _$$NoneImplCopyWith<$Res> { + __$$NoneImplCopyWithImpl(_$NoneImpl _value, $Res Function(_$NoneImpl) _then) + : super(_value, _then); + + /// Create a copy of APIAuthModel + /// with the given fields replaced by the non-null parameter values. +} + +/// @nodoc +@JsonSerializable() +class _$NoneImpl implements None { + const _$NoneImpl({final String? $type}) : $type = $type ?? 'none'; + + factory _$NoneImpl.fromJson(Map json) => + _$$NoneImplFromJson(json); + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'APIAuthModel.none()'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$NoneImpl); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() none, + required TResult Function(String username, String password) basic, + }) { + return none(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? none, + TResult? Function(String username, String password)? basic, + }) { + return none?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? none, + TResult Function(String username, String password)? basic, + required TResult orElse(), + }) { + if (none != null) { + return none(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(None value) none, + required TResult Function(BasicAuth value) basic, + }) { + return none(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(None value)? none, + TResult? Function(BasicAuth value)? basic, + }) { + return none?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(None value)? none, + TResult Function(BasicAuth value)? basic, + required TResult orElse(), + }) { + if (none != null) { + return none(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$NoneImplToJson( + this, + ); + } +} + +abstract class None implements APIAuthModel { + const factory None() = _$NoneImpl; + + factory None.fromJson(Map json) = _$NoneImpl.fromJson; +} + +/// @nodoc +abstract class _$$BasicAuthImplCopyWith<$Res> { + factory _$$BasicAuthImplCopyWith( + _$BasicAuthImpl value, $Res Function(_$BasicAuthImpl) then) = + __$$BasicAuthImplCopyWithImpl<$Res>; + @useResult + $Res call({String username, String password}); +} + +/// @nodoc +class __$$BasicAuthImplCopyWithImpl<$Res> + extends _$APIAuthModelCopyWithImpl<$Res, _$BasicAuthImpl> + implements _$$BasicAuthImplCopyWith<$Res> { + __$$BasicAuthImplCopyWithImpl( + _$BasicAuthImpl _value, $Res Function(_$BasicAuthImpl) _then) + : super(_value, _then); + + /// Create a copy of APIAuthModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? username = null, + Object? password = null, + }) { + return _then(_$BasicAuthImpl( + username: null == username + ? _value.username + : username // ignore: cast_nullable_to_non_nullable + as String, + password: null == password + ? _value.password + : password // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$BasicAuthImpl implements BasicAuth { + const _$BasicAuthImpl( + {required this.username, required this.password, final String? $type}) + : $type = $type ?? 'basic'; + + factory _$BasicAuthImpl.fromJson(Map json) => + _$$BasicAuthImplFromJson(json); + + @override + final String username; + @override + final String password; + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'APIAuthModel.basic(username: $username, password: $password)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$BasicAuthImpl && + (identical(other.username, username) || + other.username == username) && + (identical(other.password, password) || + other.password == password)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, username, password); + + /// Create a copy of APIAuthModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$BasicAuthImplCopyWith<_$BasicAuthImpl> get copyWith => + __$$BasicAuthImplCopyWithImpl<_$BasicAuthImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() none, + required TResult Function(String username, String password) basic, + }) { + return basic(username, password); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? none, + TResult? Function(String username, String password)? basic, + }) { + return basic?.call(username, password); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? none, + TResult Function(String username, String password)? basic, + required TResult orElse(), + }) { + if (basic != null) { + return basic(username, password); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(None value) none, + required TResult Function(BasicAuth value) basic, + }) { + return basic(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(None value)? none, + TResult? Function(BasicAuth value)? basic, + }) { + return basic?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(None value)? none, + TResult Function(BasicAuth value)? basic, + required TResult orElse(), + }) { + if (basic != null) { + return basic(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$BasicAuthImplToJson( + this, + ); + } +} + +abstract class BasicAuth implements APIAuthModel { + const factory BasicAuth( + {required final String username, + required final String password}) = _$BasicAuthImpl; + + factory BasicAuth.fromJson(Map json) = + _$BasicAuthImpl.fromJson; + + String get username; + String get password; + + /// Create a copy of APIAuthModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$BasicAuthImplCopyWith<_$BasicAuthImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/packages/apidash_core/lib/models/api_auth_model.g.dart b/packages/apidash_core/lib/models/api_auth_model.g.dart new file mode 100644 index 000000000..83a5b8685 --- /dev/null +++ b/packages/apidash_core/lib/models/api_auth_model.g.dart @@ -0,0 +1,30 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'api_auth_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$NoneImpl _$$NoneImplFromJson(Map json) => _$NoneImpl( + $type: json['runtimeType'] as String?, + ); + +Map _$$NoneImplToJson(_$NoneImpl instance) => + { + 'runtimeType': instance.$type, + }; + +_$BasicAuthImpl _$$BasicAuthImplFromJson(Map json) => + _$BasicAuthImpl( + username: json['username'] as String, + password: json['password'] as String, + $type: json['runtimeType'] as String?, + ); + +Map _$$BasicAuthImplToJson(_$BasicAuthImpl instance) => + { + 'username': instance.username, + 'password': instance.password, + 'runtimeType': instance.$type, + }; diff --git a/packages/apidash_core/lib/models/models.dart b/packages/apidash_core/lib/models/models.dart index c3206fd90..0fd9acef3 100644 --- a/packages/apidash_core/lib/models/models.dart +++ b/packages/apidash_core/lib/models/models.dart @@ -1 +1,4 @@ export 'environment_model.dart'; +export 'http_request_model.dart'; +export 'http_response_model.dart'; +export 'api_auth_model.dart'; \ No newline at end of file diff --git a/packages/json_field_editor/example/pubspec.lock b/packages/json_field_editor/example/pubspec.lock index 49c1a06a0..19d456fd7 100644 --- a/packages/json_field_editor/example/pubspec.lock +++ b/packages/json_field_editor/example/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.13.0" + version: "2.12.0" boolean_selector: dependency: transitive description: @@ -69,10 +69,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.3" + version: "1.3.2" flutter: dependency: "direct main" description: flutter @@ -102,10 +102,10 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: @@ -227,10 +227,10 @@ packages: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "15.0.0" + version: "14.3.1" sdks: dart: ">=3.7.0-0 <4.0.0" flutter: ">=3.24.0" diff --git a/packages/multi_trigger_autocomplete_plus/example/pubspec.lock b/packages/multi_trigger_autocomplete_plus/example/pubspec.lock index 7f847cdd1..5bfc05a8b 100644 --- a/packages/multi_trigger_autocomplete_plus/example/pubspec.lock +++ b/packages/multi_trigger_autocomplete_plus/example/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.13.0" + version: "2.12.0" boolean_selector: dependency: transitive description: @@ -61,10 +61,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.3" + version: "1.3.2" ffi: dependency: transitive description: @@ -135,10 +135,10 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: @@ -339,10 +339,10 @@ packages: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "15.0.0" + version: "14.3.1" web: dependency: transitive description: diff --git a/pubspec.lock b/pubspec.lock index 590e147c6..69e0c77d2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -67,10 +67,10 @@ packages: dependency: transitive description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.13.0" + version: "2.12.0" audio_session: dependency: transitive description: @@ -409,10 +409,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.3" + version: "1.3.2" fetch_api: dependency: transitive description: @@ -947,10 +947,10 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: @@ -1878,10 +1878,10 @@ packages: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "15.0.0" + version: "14.3.1" watcher: dependency: transitive description: @@ -1918,10 +1918,10 @@ packages: dependency: transitive description: name: webdriver - sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" + sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.0.4" webkit_inspection_protocol: dependency: transitive description: From 417706523b2a4c44d6451c40cabfc4cd1aa82cf2 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sat, 7 Jun 2025 17:08:09 +0530 Subject: [PATCH 02/70] feat: improve authentication model with BearerToken, APIKey, and JWTBearer support --- .../request_pane/request_auth.dart | 265 +++++++- .../lib/models/api_auth_model.dart | 14 + .../lib/models/api_auth_model.freezed.dart | 620 ++++++++++++++++++ .../lib/models/api_auth_model.g.dart | 42 ++ 4 files changed, 923 insertions(+), 18 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index 946705807..8a5e8534f 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -22,44 +22,51 @@ class EditAuthType extends ConsumerWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // Auth Type Dropdown + Text( + "Authentication Type", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + height: 8, + ), DropdownButtonFormField( value: currentAuthType, - decoration: const InputDecoration( - labelText: 'Authentication Type', - border: OutlineInputBorder(), + elevation: 4, + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(9), + ), ), items: APIAuthType.values.map((type) { return DropdownMenuItem( value: type, - child: Text(type.name), + child: Text(type.name.capitalize()), ); }).toList(), onChanged: (APIAuthType? newType) { if (newType != null) { ref.read(collectionStateNotifierProvider.notifier).update( authType: newType, - authData: null, // reset when auth type changes + authData: null, ); } }, ), - const SizedBox(height: 16), - - // Dynamic Auth Input Fields - _buildAuthFields(ref, currentAuthType, currentAuthData), + const SizedBox(height: 48), + _buildAuthFields(context, ref, currentAuthType, currentAuthData), ], ), ); } Widget _buildAuthFields( + BuildContext context, WidgetRef ref, APIAuthType authType, APIAuthModel? authData, ) { - final controllerMap = {}; - void updateAuth(APIAuthModel model) { ref.read(collectionStateNotifierProvider.notifier).update( authData: model, @@ -75,17 +82,59 @@ class EditAuthType extends ConsumerWidget { text: (authData is BasicAuth) ? authData.password : '', ); return Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text( + "Username", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + height: 4, + ), TextField( controller: usernameController, - decoration: const InputDecoration(labelText: 'Username'), - onChanged: (value) => updateAuth(BasicAuth( - username: value, password: passwordController.text)), + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + hintText: "Username", + hintStyle: Theme.of(context).textTheme.bodyMedium, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onChanged: (value) => updateAuth( + BasicAuth(username: value, password: passwordController.text), + ), + ), + SizedBox( + height: 16, + ), + Text( + "Password", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + height: 4, ), - const SizedBox(height: 8), TextField( controller: passwordController, - decoration: const InputDecoration(labelText: 'Password'), + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + hintText: "Password", + hintStyle: Theme.of(context).textTheme.bodyMedium, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), obscureText: true, onChanged: (value) => updateAuth(BasicAuth( username: usernameController.text, password: value)), @@ -93,7 +142,187 @@ class EditAuthType extends ConsumerWidget { ], ); - // + case APIAuthType.bearerToken: + final tokenController = TextEditingController( + text: (authData is BearerTokenAuth) ? authData.token : '', + ); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Token", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + height: 4, + ), + TextField( + controller: tokenController, + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + hintText: "Token", + hintStyle: Theme.of(context).textTheme.bodyMedium, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onChanged: (value) => updateAuth(BearerTokenAuth(token: value)), + ), + ], + ); + + case APIAuthType.apiKey: + final keyController = TextEditingController( + text: (authData is APIKeyAuth) ? authData.key : '', + ); + final nameController = TextEditingController( + text: (authData is APIKeyAuth) ? authData.name : 'x-api-key', + ); + final currentLocation = + (authData is APIKeyAuth) ? authData.location : 'header'; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Add to", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + height: 4, + ), + DropdownButtonFormField( + value: currentLocation, + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + items: [ + DropdownMenuItem( + value: 'header', + child: Text('Header'), + ), + DropdownMenuItem( + value: 'query', + child: Text('Query Params'), + ), + ], + onChanged: (String? newLocation) { + if (newLocation != null) { + updateAuth(APIKeyAuth( + key: keyController.text, + name: nameController.text, + location: newLocation, + )); + } + }, + ), + const SizedBox(height: 16), + Text( + "Header/Query Param Name", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + height: 4, + ), + TextField( + controller: nameController, + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + hintText: "Header/Query Param Name", + hintStyle: Theme.of(context).textTheme.bodyMedium, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onChanged: (value) => updateAuth(APIKeyAuth( + key: keyController.text, + name: value, + location: currentLocation, + )), + ), + const SizedBox(height: 16), + Text( + "API Key", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + height: 4, + ), + TextField( + controller: keyController, + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + hintText: "API Key", + hintStyle: Theme.of(context).textTheme.bodyMedium, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onChanged: (value) => updateAuth(APIKeyAuth( + key: value, + name: nameController.text, + location: currentLocation, + )), + ), + ], + ); + + case APIAuthType.jwtBearer: + final jwtController = TextEditingController( + text: (authData is JWTBearerAuth) ? authData.jwt : '', + ); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "JWT Token", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + height: 4, + ), + TextField( + controller: jwtController, + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + hintText: "JWT Token", + hintStyle: Theme.of(context).textTheme.bodyMedium, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onChanged: (value) => updateAuth(JWTBearerAuth(jwt: value)), + ), + ], + ); case APIAuthType.none: return const Text("No authentication selected."); diff --git a/packages/apidash_core/lib/models/api_auth_model.dart b/packages/apidash_core/lib/models/api_auth_model.dart index 6a3449a1e..3765939ee 100644 --- a/packages/apidash_core/lib/models/api_auth_model.dart +++ b/packages/apidash_core/lib/models/api_auth_model.dart @@ -14,4 +14,18 @@ class APIAuthModel with _$APIAuthModel { factory APIAuthModel.fromJson(Map json) => _$APIAuthModelFromJson(json); + + const factory APIAuthModel.bearerToken({ + required String token, + }) = BearerTokenAuth; + + const factory APIAuthModel.apiKey({ + required String key, + @Default('header') String location, // or 'query' + @Default('x-api-key') String name, + }) = APIKeyAuth; + + const factory APIAuthModel.jwtBearer({ + required String jwt, + }) = JWTBearerAuth; } diff --git a/packages/apidash_core/lib/models/api_auth_model.freezed.dart b/packages/apidash_core/lib/models/api_auth_model.freezed.dart index c7cc47e63..68b24d489 100644 --- a/packages/apidash_core/lib/models/api_auth_model.freezed.dart +++ b/packages/apidash_core/lib/models/api_auth_model.freezed.dart @@ -20,6 +20,12 @@ APIAuthModel _$APIAuthModelFromJson(Map json) { return None.fromJson(json); case 'basic': return BasicAuth.fromJson(json); + case 'bearerToken': + return BearerTokenAuth.fromJson(json); + case 'apiKey': + return APIKeyAuth.fromJson(json); + case 'jwtBearer': + return JWTBearerAuth.fromJson(json); default: throw CheckedFromJsonException(json, 'runtimeType', 'APIAuthModel', @@ -33,18 +39,27 @@ mixin _$APIAuthModel { TResult when({ required TResult Function() none, required TResult Function(String username, String password) basic, + required TResult Function(String token) bearerToken, + required TResult Function(String key, String location, String name) apiKey, + required TResult Function(String jwt) jwtBearer, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ TResult? Function()? none, TResult? Function(String username, String password)? basic, + TResult? Function(String token)? bearerToken, + TResult? Function(String key, String location, String name)? apiKey, + TResult? Function(String jwt)? jwtBearer, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ TResult Function()? none, TResult Function(String username, String password)? basic, + TResult Function(String token)? bearerToken, + TResult Function(String key, String location, String name)? apiKey, + TResult Function(String jwt)? jwtBearer, required TResult orElse(), }) => throw _privateConstructorUsedError; @@ -52,18 +67,27 @@ mixin _$APIAuthModel { TResult map({ required TResult Function(None value) none, required TResult Function(BasicAuth value) basic, + required TResult Function(BearerTokenAuth value) bearerToken, + required TResult Function(APIKeyAuth value) apiKey, + required TResult Function(JWTBearerAuth value) jwtBearer, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? mapOrNull({ TResult? Function(None value)? none, TResult? Function(BasicAuth value)? basic, + TResult? Function(BearerTokenAuth value)? bearerToken, + TResult? Function(APIKeyAuth value)? apiKey, + TResult? Function(JWTBearerAuth value)? jwtBearer, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeMap({ TResult Function(None value)? none, TResult Function(BasicAuth value)? basic, + TResult Function(BearerTokenAuth value)? bearerToken, + TResult Function(APIKeyAuth value)? apiKey, + TResult Function(JWTBearerAuth value)? jwtBearer, required TResult orElse(), }) => throw _privateConstructorUsedError; @@ -142,6 +166,9 @@ class _$NoneImpl implements None { TResult when({ required TResult Function() none, required TResult Function(String username, String password) basic, + required TResult Function(String token) bearerToken, + required TResult Function(String key, String location, String name) apiKey, + required TResult Function(String jwt) jwtBearer, }) { return none(); } @@ -151,6 +178,9 @@ class _$NoneImpl implements None { TResult? whenOrNull({ TResult? Function()? none, TResult? Function(String username, String password)? basic, + TResult? Function(String token)? bearerToken, + TResult? Function(String key, String location, String name)? apiKey, + TResult? Function(String jwt)? jwtBearer, }) { return none?.call(); } @@ -160,6 +190,9 @@ class _$NoneImpl implements None { TResult maybeWhen({ TResult Function()? none, TResult Function(String username, String password)? basic, + TResult Function(String token)? bearerToken, + TResult Function(String key, String location, String name)? apiKey, + TResult Function(String jwt)? jwtBearer, required TResult orElse(), }) { if (none != null) { @@ -173,6 +206,9 @@ class _$NoneImpl implements None { TResult map({ required TResult Function(None value) none, required TResult Function(BasicAuth value) basic, + required TResult Function(BearerTokenAuth value) bearerToken, + required TResult Function(APIKeyAuth value) apiKey, + required TResult Function(JWTBearerAuth value) jwtBearer, }) { return none(this); } @@ -182,6 +218,9 @@ class _$NoneImpl implements None { TResult? mapOrNull({ TResult? Function(None value)? none, TResult? Function(BasicAuth value)? basic, + TResult? Function(BearerTokenAuth value)? bearerToken, + TResult? Function(APIKeyAuth value)? apiKey, + TResult? Function(JWTBearerAuth value)? jwtBearer, }) { return none?.call(this); } @@ -191,6 +230,9 @@ class _$NoneImpl implements None { TResult maybeMap({ TResult Function(None value)? none, TResult Function(BasicAuth value)? basic, + TResult Function(BearerTokenAuth value)? bearerToken, + TResult Function(APIKeyAuth value)? apiKey, + TResult Function(JWTBearerAuth value)? jwtBearer, required TResult orElse(), }) { if (none != null) { @@ -302,6 +344,9 @@ class _$BasicAuthImpl implements BasicAuth { TResult when({ required TResult Function() none, required TResult Function(String username, String password) basic, + required TResult Function(String token) bearerToken, + required TResult Function(String key, String location, String name) apiKey, + required TResult Function(String jwt) jwtBearer, }) { return basic(username, password); } @@ -311,6 +356,9 @@ class _$BasicAuthImpl implements BasicAuth { TResult? whenOrNull({ TResult? Function()? none, TResult? Function(String username, String password)? basic, + TResult? Function(String token)? bearerToken, + TResult? Function(String key, String location, String name)? apiKey, + TResult? Function(String jwt)? jwtBearer, }) { return basic?.call(username, password); } @@ -320,6 +368,9 @@ class _$BasicAuthImpl implements BasicAuth { TResult maybeWhen({ TResult Function()? none, TResult Function(String username, String password)? basic, + TResult Function(String token)? bearerToken, + TResult Function(String key, String location, String name)? apiKey, + TResult Function(String jwt)? jwtBearer, required TResult orElse(), }) { if (basic != null) { @@ -333,6 +384,9 @@ class _$BasicAuthImpl implements BasicAuth { TResult map({ required TResult Function(None value) none, required TResult Function(BasicAuth value) basic, + required TResult Function(BearerTokenAuth value) bearerToken, + required TResult Function(APIKeyAuth value) apiKey, + required TResult Function(JWTBearerAuth value) jwtBearer, }) { return basic(this); } @@ -342,6 +396,9 @@ class _$BasicAuthImpl implements BasicAuth { TResult? mapOrNull({ TResult? Function(None value)? none, TResult? Function(BasicAuth value)? basic, + TResult? Function(BearerTokenAuth value)? bearerToken, + TResult? Function(APIKeyAuth value)? apiKey, + TResult? Function(JWTBearerAuth value)? jwtBearer, }) { return basic?.call(this); } @@ -351,6 +408,9 @@ class _$BasicAuthImpl implements BasicAuth { TResult maybeMap({ TResult Function(None value)? none, TResult Function(BasicAuth value)? basic, + TResult Function(BearerTokenAuth value)? bearerToken, + TResult Function(APIKeyAuth value)? apiKey, + TResult Function(JWTBearerAuth value)? jwtBearer, required TResult orElse(), }) { if (basic != null) { @@ -384,3 +444,563 @@ abstract class BasicAuth implements APIAuthModel { _$$BasicAuthImplCopyWith<_$BasicAuthImpl> get copyWith => throw _privateConstructorUsedError; } + +/// @nodoc +abstract class _$$BearerTokenAuthImplCopyWith<$Res> { + factory _$$BearerTokenAuthImplCopyWith(_$BearerTokenAuthImpl value, + $Res Function(_$BearerTokenAuthImpl) then) = + __$$BearerTokenAuthImplCopyWithImpl<$Res>; + @useResult + $Res call({String token}); +} + +/// @nodoc +class __$$BearerTokenAuthImplCopyWithImpl<$Res> + extends _$APIAuthModelCopyWithImpl<$Res, _$BearerTokenAuthImpl> + implements _$$BearerTokenAuthImplCopyWith<$Res> { + __$$BearerTokenAuthImplCopyWithImpl( + _$BearerTokenAuthImpl _value, $Res Function(_$BearerTokenAuthImpl) _then) + : super(_value, _then); + + /// Create a copy of APIAuthModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? token = null, + }) { + return _then(_$BearerTokenAuthImpl( + token: null == token + ? _value.token + : token // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$BearerTokenAuthImpl implements BearerTokenAuth { + const _$BearerTokenAuthImpl({required this.token, final String? $type}) + : $type = $type ?? 'bearerToken'; + + factory _$BearerTokenAuthImpl.fromJson(Map json) => + _$$BearerTokenAuthImplFromJson(json); + + @override + final String token; + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'APIAuthModel.bearerToken(token: $token)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$BearerTokenAuthImpl && + (identical(other.token, token) || other.token == token)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, token); + + /// Create a copy of APIAuthModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$BearerTokenAuthImplCopyWith<_$BearerTokenAuthImpl> get copyWith => + __$$BearerTokenAuthImplCopyWithImpl<_$BearerTokenAuthImpl>( + this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() none, + required TResult Function(String username, String password) basic, + required TResult Function(String token) bearerToken, + required TResult Function(String key, String location, String name) apiKey, + required TResult Function(String jwt) jwtBearer, + }) { + return bearerToken(token); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? none, + TResult? Function(String username, String password)? basic, + TResult? Function(String token)? bearerToken, + TResult? Function(String key, String location, String name)? apiKey, + TResult? Function(String jwt)? jwtBearer, + }) { + return bearerToken?.call(token); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? none, + TResult Function(String username, String password)? basic, + TResult Function(String token)? bearerToken, + TResult Function(String key, String location, String name)? apiKey, + TResult Function(String jwt)? jwtBearer, + required TResult orElse(), + }) { + if (bearerToken != null) { + return bearerToken(token); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(None value) none, + required TResult Function(BasicAuth value) basic, + required TResult Function(BearerTokenAuth value) bearerToken, + required TResult Function(APIKeyAuth value) apiKey, + required TResult Function(JWTBearerAuth value) jwtBearer, + }) { + return bearerToken(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(None value)? none, + TResult? Function(BasicAuth value)? basic, + TResult? Function(BearerTokenAuth value)? bearerToken, + TResult? Function(APIKeyAuth value)? apiKey, + TResult? Function(JWTBearerAuth value)? jwtBearer, + }) { + return bearerToken?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(None value)? none, + TResult Function(BasicAuth value)? basic, + TResult Function(BearerTokenAuth value)? bearerToken, + TResult Function(APIKeyAuth value)? apiKey, + TResult Function(JWTBearerAuth value)? jwtBearer, + required TResult orElse(), + }) { + if (bearerToken != null) { + return bearerToken(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$BearerTokenAuthImplToJson( + this, + ); + } +} + +abstract class BearerTokenAuth implements APIAuthModel { + const factory BearerTokenAuth({required final String token}) = + _$BearerTokenAuthImpl; + + factory BearerTokenAuth.fromJson(Map json) = + _$BearerTokenAuthImpl.fromJson; + + String get token; + + /// Create a copy of APIAuthModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$BearerTokenAuthImplCopyWith<_$BearerTokenAuthImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$APIKeyAuthImplCopyWith<$Res> { + factory _$$APIKeyAuthImplCopyWith( + _$APIKeyAuthImpl value, $Res Function(_$APIKeyAuthImpl) then) = + __$$APIKeyAuthImplCopyWithImpl<$Res>; + @useResult + $Res call({String key, String location, String name}); +} + +/// @nodoc +class __$$APIKeyAuthImplCopyWithImpl<$Res> + extends _$APIAuthModelCopyWithImpl<$Res, _$APIKeyAuthImpl> + implements _$$APIKeyAuthImplCopyWith<$Res> { + __$$APIKeyAuthImplCopyWithImpl( + _$APIKeyAuthImpl _value, $Res Function(_$APIKeyAuthImpl) _then) + : super(_value, _then); + + /// Create a copy of APIAuthModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? key = null, + Object? location = null, + Object? name = null, + }) { + return _then(_$APIKeyAuthImpl( + key: null == key + ? _value.key + : key // ignore: cast_nullable_to_non_nullable + as String, + location: null == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as String, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$APIKeyAuthImpl implements APIKeyAuth { + const _$APIKeyAuthImpl( + {required this.key, + this.location = 'header', + this.name = 'x-api-key', + final String? $type}) + : $type = $type ?? 'apiKey'; + + factory _$APIKeyAuthImpl.fromJson(Map json) => + _$$APIKeyAuthImplFromJson(json); + + @override + final String key; + @override + @JsonKey() + final String location; +// or 'query' + @override + @JsonKey() + final String name; + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'APIAuthModel.apiKey(key: $key, location: $location, name: $name)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$APIKeyAuthImpl && + (identical(other.key, key) || other.key == key) && + (identical(other.location, location) || + other.location == location) && + (identical(other.name, name) || other.name == name)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, key, location, name); + + /// Create a copy of APIAuthModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$APIKeyAuthImplCopyWith<_$APIKeyAuthImpl> get copyWith => + __$$APIKeyAuthImplCopyWithImpl<_$APIKeyAuthImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() none, + required TResult Function(String username, String password) basic, + required TResult Function(String token) bearerToken, + required TResult Function(String key, String location, String name) apiKey, + required TResult Function(String jwt) jwtBearer, + }) { + return apiKey(key, location, name); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? none, + TResult? Function(String username, String password)? basic, + TResult? Function(String token)? bearerToken, + TResult? Function(String key, String location, String name)? apiKey, + TResult? Function(String jwt)? jwtBearer, + }) { + return apiKey?.call(key, location, name); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? none, + TResult Function(String username, String password)? basic, + TResult Function(String token)? bearerToken, + TResult Function(String key, String location, String name)? apiKey, + TResult Function(String jwt)? jwtBearer, + required TResult orElse(), + }) { + if (apiKey != null) { + return apiKey(key, location, name); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(None value) none, + required TResult Function(BasicAuth value) basic, + required TResult Function(BearerTokenAuth value) bearerToken, + required TResult Function(APIKeyAuth value) apiKey, + required TResult Function(JWTBearerAuth value) jwtBearer, + }) { + return apiKey(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(None value)? none, + TResult? Function(BasicAuth value)? basic, + TResult? Function(BearerTokenAuth value)? bearerToken, + TResult? Function(APIKeyAuth value)? apiKey, + TResult? Function(JWTBearerAuth value)? jwtBearer, + }) { + return apiKey?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(None value)? none, + TResult Function(BasicAuth value)? basic, + TResult Function(BearerTokenAuth value)? bearerToken, + TResult Function(APIKeyAuth value)? apiKey, + TResult Function(JWTBearerAuth value)? jwtBearer, + required TResult orElse(), + }) { + if (apiKey != null) { + return apiKey(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$APIKeyAuthImplToJson( + this, + ); + } +} + +abstract class APIKeyAuth implements APIAuthModel { + const factory APIKeyAuth( + {required final String key, + final String location, + final String name}) = _$APIKeyAuthImpl; + + factory APIKeyAuth.fromJson(Map json) = + _$APIKeyAuthImpl.fromJson; + + String get key; + String get location; // or 'query' + String get name; + + /// Create a copy of APIAuthModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$APIKeyAuthImplCopyWith<_$APIKeyAuthImpl> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$JWTBearerAuthImplCopyWith<$Res> { + factory _$$JWTBearerAuthImplCopyWith( + _$JWTBearerAuthImpl value, $Res Function(_$JWTBearerAuthImpl) then) = + __$$JWTBearerAuthImplCopyWithImpl<$Res>; + @useResult + $Res call({String jwt}); +} + +/// @nodoc +class __$$JWTBearerAuthImplCopyWithImpl<$Res> + extends _$APIAuthModelCopyWithImpl<$Res, _$JWTBearerAuthImpl> + implements _$$JWTBearerAuthImplCopyWith<$Res> { + __$$JWTBearerAuthImplCopyWithImpl( + _$JWTBearerAuthImpl _value, $Res Function(_$JWTBearerAuthImpl) _then) + : super(_value, _then); + + /// Create a copy of APIAuthModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? jwt = null, + }) { + return _then(_$JWTBearerAuthImpl( + jwt: null == jwt + ? _value.jwt + : jwt // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$JWTBearerAuthImpl implements JWTBearerAuth { + const _$JWTBearerAuthImpl({required this.jwt, final String? $type}) + : $type = $type ?? 'jwtBearer'; + + factory _$JWTBearerAuthImpl.fromJson(Map json) => + _$$JWTBearerAuthImplFromJson(json); + + @override + final String jwt; + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'APIAuthModel.jwtBearer(jwt: $jwt)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$JWTBearerAuthImpl && + (identical(other.jwt, jwt) || other.jwt == jwt)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, jwt); + + /// Create a copy of APIAuthModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$JWTBearerAuthImplCopyWith<_$JWTBearerAuthImpl> get copyWith => + __$$JWTBearerAuthImplCopyWithImpl<_$JWTBearerAuthImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() none, + required TResult Function(String username, String password) basic, + required TResult Function(String token) bearerToken, + required TResult Function(String key, String location, String name) apiKey, + required TResult Function(String jwt) jwtBearer, + }) { + return jwtBearer(jwt); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? none, + TResult? Function(String username, String password)? basic, + TResult? Function(String token)? bearerToken, + TResult? Function(String key, String location, String name)? apiKey, + TResult? Function(String jwt)? jwtBearer, + }) { + return jwtBearer?.call(jwt); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? none, + TResult Function(String username, String password)? basic, + TResult Function(String token)? bearerToken, + TResult Function(String key, String location, String name)? apiKey, + TResult Function(String jwt)? jwtBearer, + required TResult orElse(), + }) { + if (jwtBearer != null) { + return jwtBearer(jwt); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(None value) none, + required TResult Function(BasicAuth value) basic, + required TResult Function(BearerTokenAuth value) bearerToken, + required TResult Function(APIKeyAuth value) apiKey, + required TResult Function(JWTBearerAuth value) jwtBearer, + }) { + return jwtBearer(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(None value)? none, + TResult? Function(BasicAuth value)? basic, + TResult? Function(BearerTokenAuth value)? bearerToken, + TResult? Function(APIKeyAuth value)? apiKey, + TResult? Function(JWTBearerAuth value)? jwtBearer, + }) { + return jwtBearer?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(None value)? none, + TResult Function(BasicAuth value)? basic, + TResult Function(BearerTokenAuth value)? bearerToken, + TResult Function(APIKeyAuth value)? apiKey, + TResult Function(JWTBearerAuth value)? jwtBearer, + required TResult orElse(), + }) { + if (jwtBearer != null) { + return jwtBearer(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$JWTBearerAuthImplToJson( + this, + ); + } +} + +abstract class JWTBearerAuth implements APIAuthModel { + const factory JWTBearerAuth({required final String jwt}) = + _$JWTBearerAuthImpl; + + factory JWTBearerAuth.fromJson(Map json) = + _$JWTBearerAuthImpl.fromJson; + + String get jwt; + + /// Create a copy of APIAuthModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + _$$JWTBearerAuthImplCopyWith<_$JWTBearerAuthImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/packages/apidash_core/lib/models/api_auth_model.g.dart b/packages/apidash_core/lib/models/api_auth_model.g.dart index 83a5b8685..0c25143b4 100644 --- a/packages/apidash_core/lib/models/api_auth_model.g.dart +++ b/packages/apidash_core/lib/models/api_auth_model.g.dart @@ -28,3 +28,45 @@ Map _$$BasicAuthImplToJson(_$BasicAuthImpl instance) => 'password': instance.password, 'runtimeType': instance.$type, }; + +_$BearerTokenAuthImpl _$$BearerTokenAuthImplFromJson( + Map json) => + _$BearerTokenAuthImpl( + token: json['token'] as String, + $type: json['runtimeType'] as String?, + ); + +Map _$$BearerTokenAuthImplToJson( + _$BearerTokenAuthImpl instance) => + { + 'token': instance.token, + 'runtimeType': instance.$type, + }; + +_$APIKeyAuthImpl _$$APIKeyAuthImplFromJson(Map json) => + _$APIKeyAuthImpl( + key: json['key'] as String, + location: json['location'] as String? ?? 'header', + name: json['name'] as String? ?? 'x-api-key', + $type: json['runtimeType'] as String?, + ); + +Map _$$APIKeyAuthImplToJson(_$APIKeyAuthImpl instance) => + { + 'key': instance.key, + 'location': instance.location, + 'name': instance.name, + 'runtimeType': instance.$type, + }; + +_$JWTBearerAuthImpl _$$JWTBearerAuthImplFromJson(Map json) => + _$JWTBearerAuthImpl( + jwt: json['jwt'] as String, + $type: json['runtimeType'] as String?, + ); + +Map _$$JWTBearerAuthImplToJson(_$JWTBearerAuthImpl instance) => + { + 'jwt': instance.jwt, + 'runtimeType': instance.$type, + }; From 51fe211ef6e0f3860d1d8d3afce68bc7493c5068 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sat, 7 Jun 2025 23:33:52 +0530 Subject: [PATCH 03/70] feat: implement authentication handling in HTTP requests --- lib/providers/collection_providers.dart | 2 + .../apidash_core/lib/utils/handle_auth.dart | 76 +++++++++++++++++++ .../lib/services/http_service.dart | 33 ++++---- 3 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 packages/apidash_core/lib/utils/handle_auth.dart diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index e46820a6a..0fc8d3879 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -318,6 +318,8 @@ class CollectionStateNotifier var responseRec = await sendHttpRequest( requestId, apiType, + requestModel.authData, + requestModel.authType, substitutedHttpRequestModel, defaultUriScheme: defaultUriScheme, noSSL: noSSL, diff --git a/packages/apidash_core/lib/utils/handle_auth.dart b/packages/apidash_core/lib/utils/handle_auth.dart new file mode 100644 index 000000000..f626269b8 --- /dev/null +++ b/packages/apidash_core/lib/utils/handle_auth.dart @@ -0,0 +1,76 @@ +import 'dart:convert'; +import 'package:apidash_core/consts.dart'; +import 'package:apidash_core/models/api_auth_model.dart'; +import 'package:apidash_core/models/http_request_model.dart'; +import 'package:seed/seed.dart'; + +HttpRequestModel handleAuth(HttpRequestModel httpRequestModel, + APIAuthType apiAuthType, APIAuthModel? authData) { + if (authData == null || apiAuthType == APIAuthType.none) { + return httpRequestModel; + } + + List updatedHeaders = List.from(httpRequestModel.headers ?? []); + List updatedParams = List.from(httpRequestModel.params ?? []); + List updatedHeaderEnabledList = List.from(httpRequestModel.isHeaderEnabledList ?? []); + List updatedParamEnabledList = List.from(httpRequestModel.isParamEnabledList ?? []); + + switch (apiAuthType) { + case APIAuthType.basic: + final auth = authData as BasicAuth; + final encoded = + base64Encode(utf8.encode('${auth.username}:${auth.password}')); + updatedHeaders.add(const NameValueModel(name: 'Authorization', value: '')); + updatedHeaders[updatedHeaders.length - 1] = NameValueModel( + name: 'Authorization', + value: 'Basic $encoded' + ); + updatedHeaderEnabledList.add(true); + break; + + case APIAuthType.bearerToken: + final auth = authData as BearerTokenAuth; + updatedHeaders.add(NameValueModel( + name: 'Authorization', + value: 'Bearer ${auth.token}' + )); + updatedHeaderEnabledList.add(true); + break; + + case APIAuthType.jwtBearer: + final auth = authData as JWTBearerAuth; + updatedHeaders.add(NameValueModel( + name: 'Authorization', + value: 'Bearer ${auth.jwt}' + )); + updatedHeaderEnabledList.add(true); + break; + + case APIAuthType.apiKey: + final auth = authData as APIKeyAuth; + if (auth.location == 'header') { + updatedHeaders.add(NameValueModel( + name: auth.name, + value: auth.key + )); + updatedHeaderEnabledList.add(true); + } else if (auth.location == 'query') { + updatedParams.add(NameValueModel( + name: auth.name, + value: auth.key + )); + updatedParamEnabledList.add(true); + } + break; + + default: + break; + } + + return httpRequestModel.copyWith( + headers: updatedHeaders, + params: updatedParams, + isHeaderEnabledList: updatedHeaderEnabledList, + isParamEnabledList: updatedParamEnabledList, + ); +} diff --git a/packages/better_networking/lib/services/http_service.dart b/packages/better_networking/lib/services/http_service.dart index 31c7ef06f..087521dd5 100644 --- a/packages/better_networking/lib/services/http_service.dart +++ b/packages/better_networking/lib/services/http_service.dart @@ -7,6 +7,7 @@ import '../consts.dart'; import '../extensions/extensions.dart'; import '../models/models.dart'; import '../utils/utils.dart'; +import '../utils/handle_auth.dart'; import 'http_client_manager.dart'; typedef HttpResponse = http.Response; @@ -16,6 +17,8 @@ final httpClientManager = HttpClientManager(); Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( String requestId, APIType apiType, + APIAuthModel? authData, + APIAuthType apiAuthType, HttpRequestModel requestModel, { SupportedUriSchemes defaultUriScheme = kDefaultUriScheme, bool noSSL = false, @@ -25,15 +28,19 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( } final client = httpClientManager.createClient(requestId, noSSL: noSSL); + // Handle authentication + final authenticatedRequestModel = + handleAuth(requestModel, apiAuthType, authData); + (Uri?, String?) uriRec = getValidRequestUri( - requestModel.url, - requestModel.enabledParams, + authenticatedRequestModel.url, + authenticatedRequestModel.enabledParams, defaultUriScheme: defaultUriScheme, ); if (uriRec.$1 != null) { Uri requestUrl = uriRec.$1!; - Map headers = requestModel.enabledHeadersMap; + Map headers = authenticatedRequestModel.enabledHeadersMap; bool overrideContentType = false; HttpResponse? response; String? body; @@ -43,26 +50,26 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( var isMultiPartRequest = requestModel.bodyContentType == ContentType.formdata; - if (kMethodsWithBody.contains(requestModel.method)) { - var requestBody = requestModel.body; + if (kMethodsWithBody.contains(authenticatedRequestModel.method)) { + var requestBody = authenticatedRequestModel.body; if (requestBody != null && !isMultiPartRequest && requestBody.isNotEmpty) { body = requestBody; - if (requestModel.hasContentTypeHeader) { + if (authenticatedRequestModel.hasContentTypeHeader) { overrideContentType = true; } else { headers[HttpHeaders.contentTypeHeader] = - requestModel.bodyContentType.header; + authenticatedRequestModel.bodyContentType.header; } } if (isMultiPartRequest) { var multiPartRequest = http.MultipartRequest( - requestModel.method.name.toUpperCase(), + authenticatedRequestModel.method.name.toUpperCase(), requestUrl, ); multiPartRequest.headers.addAll(headers); - for (var formData in requestModel.formDataList) { + for (var formData in authenticatedRequestModel.formDataList) { if (formData.type == FormDataType.text) { multiPartRequest.fields.addAll({formData.name: formData.value}); } else { @@ -84,7 +91,7 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( return (convertedMultiPartResponse, stopwatch.elapsed, null); } } - switch (requestModel.method) { + switch (authenticatedRequestModel.method) { case HTTPVerb.get: response = await client.get(requestUrl, headers: headers); break; @@ -98,7 +105,7 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( case HTTPVerb.options: final request = prepareHttpRequest( url: requestUrl, - method: requestModel.method.name.toUpperCase(), + method: authenticatedRequestModel.method.name.toUpperCase(), headers: headers, body: body, overrideContentType: overrideContentType, @@ -109,13 +116,13 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( } } if (apiType == APIType.graphql) { - var requestBody = getGraphQLBody(requestModel); + var requestBody = getGraphQLBody(authenticatedRequestModel); if (requestBody != null) { var contentLength = utf8.encode(requestBody).length; if (contentLength > 0) { body = requestBody; headers[HttpHeaders.contentLengthHeader] = contentLength.toString(); - if (!requestModel.hasContentTypeHeader) { + if (!authenticatedRequestModel.hasContentTypeHeader) { headers[HttpHeaders.contentTypeHeader] = ContentType.json.header; } } From 6a2d1fd5347ac92275dfd8529403bc3d3beb0799 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Thu, 12 Jun 2025 16:20:29 +0530 Subject: [PATCH 04/70] feat: implement new authentication models --- .../lib/models/api_auth_model.dart | 31 - .../lib/models/api_auth_model.freezed.dart | 1006 ----------------- .../lib/models/api_auth_model.g.dart | 72 -- .../lib/models/auth/api_auth_model.dart | 23 + .../models/auth/api_auth_model.freezed.dart | 310 +++++ .../lib/models/auth/api_auth_model.g.dart | 43 + .../lib/models/auth/auth_api_key_model.dart | 16 + .../auth/auth_api_key_model.freezed.dart | 206 ++++ .../lib/models/auth/auth_api_key_model.g.dart | 23 + .../lib/models/auth/auth_basic_model.dart | 15 + .../models/auth/auth_basic_model.freezed.dart | 186 +++ .../lib/models/auth/auth_basic_model.g.dart | 21 + .../lib/models/auth/auth_bearer_model.dart | 14 + .../auth/auth_bearer_model.freezed.dart | 166 +++ .../lib/models/auth/auth_bearer_model.g.dart | 19 + .../lib/models/auth/auth_jwt_model.dart | 14 + .../models/auth/auth_jwt_model.freezed.dart | 164 +++ .../lib/models/auth/auth_jwt_model.g.dart | 17 + 18 files changed, 1237 insertions(+), 1109 deletions(-) delete mode 100644 packages/apidash_core/lib/models/api_auth_model.dart delete mode 100644 packages/apidash_core/lib/models/api_auth_model.freezed.dart delete mode 100644 packages/apidash_core/lib/models/api_auth_model.g.dart create mode 100644 packages/apidash_core/lib/models/auth/api_auth_model.dart create mode 100644 packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart create mode 100644 packages/apidash_core/lib/models/auth/api_auth_model.g.dart create mode 100644 packages/apidash_core/lib/models/auth/auth_api_key_model.dart create mode 100644 packages/apidash_core/lib/models/auth/auth_api_key_model.freezed.dart create mode 100644 packages/apidash_core/lib/models/auth/auth_api_key_model.g.dart create mode 100644 packages/apidash_core/lib/models/auth/auth_basic_model.dart create mode 100644 packages/apidash_core/lib/models/auth/auth_basic_model.freezed.dart create mode 100644 packages/apidash_core/lib/models/auth/auth_basic_model.g.dart create mode 100644 packages/apidash_core/lib/models/auth/auth_bearer_model.dart create mode 100644 packages/apidash_core/lib/models/auth/auth_bearer_model.freezed.dart create mode 100644 packages/apidash_core/lib/models/auth/auth_bearer_model.g.dart create mode 100644 packages/apidash_core/lib/models/auth/auth_jwt_model.dart create mode 100644 packages/apidash_core/lib/models/auth/auth_jwt_model.freezed.dart create mode 100644 packages/apidash_core/lib/models/auth/auth_jwt_model.g.dart diff --git a/packages/apidash_core/lib/models/api_auth_model.dart b/packages/apidash_core/lib/models/api_auth_model.dart deleted file mode 100644 index 3765939ee..000000000 --- a/packages/apidash_core/lib/models/api_auth_model.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'api_auth_model.g.dart'; -part 'api_auth_model.freezed.dart'; - -@freezed -class APIAuthModel with _$APIAuthModel { - const factory APIAuthModel.none() = None; - - const factory APIAuthModel.basic({ - required String username, - required String password, - }) = BasicAuth; - - factory APIAuthModel.fromJson(Map json) => - _$APIAuthModelFromJson(json); - - const factory APIAuthModel.bearerToken({ - required String token, - }) = BearerTokenAuth; - - const factory APIAuthModel.apiKey({ - required String key, - @Default('header') String location, // or 'query' - @Default('x-api-key') String name, - }) = APIKeyAuth; - - const factory APIAuthModel.jwtBearer({ - required String jwt, - }) = JWTBearerAuth; -} diff --git a/packages/apidash_core/lib/models/api_auth_model.freezed.dart b/packages/apidash_core/lib/models/api_auth_model.freezed.dart deleted file mode 100644 index 68b24d489..000000000 --- a/packages/apidash_core/lib/models/api_auth_model.freezed.dart +++ /dev/null @@ -1,1006 +0,0 @@ -// coverage:ignore-file -// GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint -// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark - -part of 'api_auth_model.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -T _$identity(T value) => value; - -final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); - -APIAuthModel _$APIAuthModelFromJson(Map json) { - switch (json['runtimeType']) { - case 'none': - return None.fromJson(json); - case 'basic': - return BasicAuth.fromJson(json); - case 'bearerToken': - return BearerTokenAuth.fromJson(json); - case 'apiKey': - return APIKeyAuth.fromJson(json); - case 'jwtBearer': - return JWTBearerAuth.fromJson(json); - - default: - throw CheckedFromJsonException(json, 'runtimeType', 'APIAuthModel', - 'Invalid union type "${json['runtimeType']}"!'); - } -} - -/// @nodoc -mixin _$APIAuthModel { - @optionalTypeArgs - TResult when({ - required TResult Function() none, - required TResult Function(String username, String password) basic, - required TResult Function(String token) bearerToken, - required TResult Function(String key, String location, String name) apiKey, - required TResult Function(String jwt) jwtBearer, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? none, - TResult? Function(String username, String password)? basic, - TResult? Function(String token)? bearerToken, - TResult? Function(String key, String location, String name)? apiKey, - TResult? Function(String jwt)? jwtBearer, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? none, - TResult Function(String username, String password)? basic, - TResult Function(String token)? bearerToken, - TResult Function(String key, String location, String name)? apiKey, - TResult Function(String jwt)? jwtBearer, - required TResult orElse(), - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult map({ - required TResult Function(None value) none, - required TResult Function(BasicAuth value) basic, - required TResult Function(BearerTokenAuth value) bearerToken, - required TResult Function(APIKeyAuth value) apiKey, - required TResult Function(JWTBearerAuth value) jwtBearer, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(None value)? none, - TResult? Function(BasicAuth value)? basic, - TResult? Function(BearerTokenAuth value)? bearerToken, - TResult? Function(APIKeyAuth value)? apiKey, - TResult? Function(JWTBearerAuth value)? jwtBearer, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeMap({ - TResult Function(None value)? none, - TResult Function(BasicAuth value)? basic, - TResult Function(BearerTokenAuth value)? bearerToken, - TResult Function(APIKeyAuth value)? apiKey, - TResult Function(JWTBearerAuth value)? jwtBearer, - required TResult orElse(), - }) => - throw _privateConstructorUsedError; - - /// Serializes this APIAuthModel to a JSON map. - Map toJson() => throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $APIAuthModelCopyWith<$Res> { - factory $APIAuthModelCopyWith( - APIAuthModel value, $Res Function(APIAuthModel) then) = - _$APIAuthModelCopyWithImpl<$Res, APIAuthModel>; -} - -/// @nodoc -class _$APIAuthModelCopyWithImpl<$Res, $Val extends APIAuthModel> - implements $APIAuthModelCopyWith<$Res> { - _$APIAuthModelCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of APIAuthModel - /// with the given fields replaced by the non-null parameter values. -} - -/// @nodoc -abstract class _$$NoneImplCopyWith<$Res> { - factory _$$NoneImplCopyWith( - _$NoneImpl value, $Res Function(_$NoneImpl) then) = - __$$NoneImplCopyWithImpl<$Res>; -} - -/// @nodoc -class __$$NoneImplCopyWithImpl<$Res> - extends _$APIAuthModelCopyWithImpl<$Res, _$NoneImpl> - implements _$$NoneImplCopyWith<$Res> { - __$$NoneImplCopyWithImpl(_$NoneImpl _value, $Res Function(_$NoneImpl) _then) - : super(_value, _then); - - /// Create a copy of APIAuthModel - /// with the given fields replaced by the non-null parameter values. -} - -/// @nodoc -@JsonSerializable() -class _$NoneImpl implements None { - const _$NoneImpl({final String? $type}) : $type = $type ?? 'none'; - - factory _$NoneImpl.fromJson(Map json) => - _$$NoneImplFromJson(json); - - @JsonKey(name: 'runtimeType') - final String $type; - - @override - String toString() { - return 'APIAuthModel.none()'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && other is _$NoneImpl); - } - - @JsonKey(includeFromJson: false, includeToJson: false) - @override - int get hashCode => runtimeType.hashCode; - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() none, - required TResult Function(String username, String password) basic, - required TResult Function(String token) bearerToken, - required TResult Function(String key, String location, String name) apiKey, - required TResult Function(String jwt) jwtBearer, - }) { - return none(); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? none, - TResult? Function(String username, String password)? basic, - TResult? Function(String token)? bearerToken, - TResult? Function(String key, String location, String name)? apiKey, - TResult? Function(String jwt)? jwtBearer, - }) { - return none?.call(); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? none, - TResult Function(String username, String password)? basic, - TResult Function(String token)? bearerToken, - TResult Function(String key, String location, String name)? apiKey, - TResult Function(String jwt)? jwtBearer, - required TResult orElse(), - }) { - if (none != null) { - return none(); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(None value) none, - required TResult Function(BasicAuth value) basic, - required TResult Function(BearerTokenAuth value) bearerToken, - required TResult Function(APIKeyAuth value) apiKey, - required TResult Function(JWTBearerAuth value) jwtBearer, - }) { - return none(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(None value)? none, - TResult? Function(BasicAuth value)? basic, - TResult? Function(BearerTokenAuth value)? bearerToken, - TResult? Function(APIKeyAuth value)? apiKey, - TResult? Function(JWTBearerAuth value)? jwtBearer, - }) { - return none?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(None value)? none, - TResult Function(BasicAuth value)? basic, - TResult Function(BearerTokenAuth value)? bearerToken, - TResult Function(APIKeyAuth value)? apiKey, - TResult Function(JWTBearerAuth value)? jwtBearer, - required TResult orElse(), - }) { - if (none != null) { - return none(this); - } - return orElse(); - } - - @override - Map toJson() { - return _$$NoneImplToJson( - this, - ); - } -} - -abstract class None implements APIAuthModel { - const factory None() = _$NoneImpl; - - factory None.fromJson(Map json) = _$NoneImpl.fromJson; -} - -/// @nodoc -abstract class _$$BasicAuthImplCopyWith<$Res> { - factory _$$BasicAuthImplCopyWith( - _$BasicAuthImpl value, $Res Function(_$BasicAuthImpl) then) = - __$$BasicAuthImplCopyWithImpl<$Res>; - @useResult - $Res call({String username, String password}); -} - -/// @nodoc -class __$$BasicAuthImplCopyWithImpl<$Res> - extends _$APIAuthModelCopyWithImpl<$Res, _$BasicAuthImpl> - implements _$$BasicAuthImplCopyWith<$Res> { - __$$BasicAuthImplCopyWithImpl( - _$BasicAuthImpl _value, $Res Function(_$BasicAuthImpl) _then) - : super(_value, _then); - - /// Create a copy of APIAuthModel - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? username = null, - Object? password = null, - }) { - return _then(_$BasicAuthImpl( - username: null == username - ? _value.username - : username // ignore: cast_nullable_to_non_nullable - as String, - password: null == password - ? _value.password - : password // ignore: cast_nullable_to_non_nullable - as String, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$BasicAuthImpl implements BasicAuth { - const _$BasicAuthImpl( - {required this.username, required this.password, final String? $type}) - : $type = $type ?? 'basic'; - - factory _$BasicAuthImpl.fromJson(Map json) => - _$$BasicAuthImplFromJson(json); - - @override - final String username; - @override - final String password; - - @JsonKey(name: 'runtimeType') - final String $type; - - @override - String toString() { - return 'APIAuthModel.basic(username: $username, password: $password)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$BasicAuthImpl && - (identical(other.username, username) || - other.username == username) && - (identical(other.password, password) || - other.password == password)); - } - - @JsonKey(includeFromJson: false, includeToJson: false) - @override - int get hashCode => Object.hash(runtimeType, username, password); - - /// Create a copy of APIAuthModel - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$BasicAuthImplCopyWith<_$BasicAuthImpl> get copyWith => - __$$BasicAuthImplCopyWithImpl<_$BasicAuthImpl>(this, _$identity); - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() none, - required TResult Function(String username, String password) basic, - required TResult Function(String token) bearerToken, - required TResult Function(String key, String location, String name) apiKey, - required TResult Function(String jwt) jwtBearer, - }) { - return basic(username, password); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? none, - TResult? Function(String username, String password)? basic, - TResult? Function(String token)? bearerToken, - TResult? Function(String key, String location, String name)? apiKey, - TResult? Function(String jwt)? jwtBearer, - }) { - return basic?.call(username, password); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? none, - TResult Function(String username, String password)? basic, - TResult Function(String token)? bearerToken, - TResult Function(String key, String location, String name)? apiKey, - TResult Function(String jwt)? jwtBearer, - required TResult orElse(), - }) { - if (basic != null) { - return basic(username, password); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(None value) none, - required TResult Function(BasicAuth value) basic, - required TResult Function(BearerTokenAuth value) bearerToken, - required TResult Function(APIKeyAuth value) apiKey, - required TResult Function(JWTBearerAuth value) jwtBearer, - }) { - return basic(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(None value)? none, - TResult? Function(BasicAuth value)? basic, - TResult? Function(BearerTokenAuth value)? bearerToken, - TResult? Function(APIKeyAuth value)? apiKey, - TResult? Function(JWTBearerAuth value)? jwtBearer, - }) { - return basic?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(None value)? none, - TResult Function(BasicAuth value)? basic, - TResult Function(BearerTokenAuth value)? bearerToken, - TResult Function(APIKeyAuth value)? apiKey, - TResult Function(JWTBearerAuth value)? jwtBearer, - required TResult orElse(), - }) { - if (basic != null) { - return basic(this); - } - return orElse(); - } - - @override - Map toJson() { - return _$$BasicAuthImplToJson( - this, - ); - } -} - -abstract class BasicAuth implements APIAuthModel { - const factory BasicAuth( - {required final String username, - required final String password}) = _$BasicAuthImpl; - - factory BasicAuth.fromJson(Map json) = - _$BasicAuthImpl.fromJson; - - String get username; - String get password; - - /// Create a copy of APIAuthModel - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - _$$BasicAuthImplCopyWith<_$BasicAuthImpl> get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class _$$BearerTokenAuthImplCopyWith<$Res> { - factory _$$BearerTokenAuthImplCopyWith(_$BearerTokenAuthImpl value, - $Res Function(_$BearerTokenAuthImpl) then) = - __$$BearerTokenAuthImplCopyWithImpl<$Res>; - @useResult - $Res call({String token}); -} - -/// @nodoc -class __$$BearerTokenAuthImplCopyWithImpl<$Res> - extends _$APIAuthModelCopyWithImpl<$Res, _$BearerTokenAuthImpl> - implements _$$BearerTokenAuthImplCopyWith<$Res> { - __$$BearerTokenAuthImplCopyWithImpl( - _$BearerTokenAuthImpl _value, $Res Function(_$BearerTokenAuthImpl) _then) - : super(_value, _then); - - /// Create a copy of APIAuthModel - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? token = null, - }) { - return _then(_$BearerTokenAuthImpl( - token: null == token - ? _value.token - : token // ignore: cast_nullable_to_non_nullable - as String, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$BearerTokenAuthImpl implements BearerTokenAuth { - const _$BearerTokenAuthImpl({required this.token, final String? $type}) - : $type = $type ?? 'bearerToken'; - - factory _$BearerTokenAuthImpl.fromJson(Map json) => - _$$BearerTokenAuthImplFromJson(json); - - @override - final String token; - - @JsonKey(name: 'runtimeType') - final String $type; - - @override - String toString() { - return 'APIAuthModel.bearerToken(token: $token)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$BearerTokenAuthImpl && - (identical(other.token, token) || other.token == token)); - } - - @JsonKey(includeFromJson: false, includeToJson: false) - @override - int get hashCode => Object.hash(runtimeType, token); - - /// Create a copy of APIAuthModel - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$BearerTokenAuthImplCopyWith<_$BearerTokenAuthImpl> get copyWith => - __$$BearerTokenAuthImplCopyWithImpl<_$BearerTokenAuthImpl>( - this, _$identity); - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() none, - required TResult Function(String username, String password) basic, - required TResult Function(String token) bearerToken, - required TResult Function(String key, String location, String name) apiKey, - required TResult Function(String jwt) jwtBearer, - }) { - return bearerToken(token); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? none, - TResult? Function(String username, String password)? basic, - TResult? Function(String token)? bearerToken, - TResult? Function(String key, String location, String name)? apiKey, - TResult? Function(String jwt)? jwtBearer, - }) { - return bearerToken?.call(token); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? none, - TResult Function(String username, String password)? basic, - TResult Function(String token)? bearerToken, - TResult Function(String key, String location, String name)? apiKey, - TResult Function(String jwt)? jwtBearer, - required TResult orElse(), - }) { - if (bearerToken != null) { - return bearerToken(token); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(None value) none, - required TResult Function(BasicAuth value) basic, - required TResult Function(BearerTokenAuth value) bearerToken, - required TResult Function(APIKeyAuth value) apiKey, - required TResult Function(JWTBearerAuth value) jwtBearer, - }) { - return bearerToken(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(None value)? none, - TResult? Function(BasicAuth value)? basic, - TResult? Function(BearerTokenAuth value)? bearerToken, - TResult? Function(APIKeyAuth value)? apiKey, - TResult? Function(JWTBearerAuth value)? jwtBearer, - }) { - return bearerToken?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(None value)? none, - TResult Function(BasicAuth value)? basic, - TResult Function(BearerTokenAuth value)? bearerToken, - TResult Function(APIKeyAuth value)? apiKey, - TResult Function(JWTBearerAuth value)? jwtBearer, - required TResult orElse(), - }) { - if (bearerToken != null) { - return bearerToken(this); - } - return orElse(); - } - - @override - Map toJson() { - return _$$BearerTokenAuthImplToJson( - this, - ); - } -} - -abstract class BearerTokenAuth implements APIAuthModel { - const factory BearerTokenAuth({required final String token}) = - _$BearerTokenAuthImpl; - - factory BearerTokenAuth.fromJson(Map json) = - _$BearerTokenAuthImpl.fromJson; - - String get token; - - /// Create a copy of APIAuthModel - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - _$$BearerTokenAuthImplCopyWith<_$BearerTokenAuthImpl> get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class _$$APIKeyAuthImplCopyWith<$Res> { - factory _$$APIKeyAuthImplCopyWith( - _$APIKeyAuthImpl value, $Res Function(_$APIKeyAuthImpl) then) = - __$$APIKeyAuthImplCopyWithImpl<$Res>; - @useResult - $Res call({String key, String location, String name}); -} - -/// @nodoc -class __$$APIKeyAuthImplCopyWithImpl<$Res> - extends _$APIAuthModelCopyWithImpl<$Res, _$APIKeyAuthImpl> - implements _$$APIKeyAuthImplCopyWith<$Res> { - __$$APIKeyAuthImplCopyWithImpl( - _$APIKeyAuthImpl _value, $Res Function(_$APIKeyAuthImpl) _then) - : super(_value, _then); - - /// Create a copy of APIAuthModel - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? key = null, - Object? location = null, - Object? name = null, - }) { - return _then(_$APIKeyAuthImpl( - key: null == key - ? _value.key - : key // ignore: cast_nullable_to_non_nullable - as String, - location: null == location - ? _value.location - : location // ignore: cast_nullable_to_non_nullable - as String, - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$APIKeyAuthImpl implements APIKeyAuth { - const _$APIKeyAuthImpl( - {required this.key, - this.location = 'header', - this.name = 'x-api-key', - final String? $type}) - : $type = $type ?? 'apiKey'; - - factory _$APIKeyAuthImpl.fromJson(Map json) => - _$$APIKeyAuthImplFromJson(json); - - @override - final String key; - @override - @JsonKey() - final String location; -// or 'query' - @override - @JsonKey() - final String name; - - @JsonKey(name: 'runtimeType') - final String $type; - - @override - String toString() { - return 'APIAuthModel.apiKey(key: $key, location: $location, name: $name)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$APIKeyAuthImpl && - (identical(other.key, key) || other.key == key) && - (identical(other.location, location) || - other.location == location) && - (identical(other.name, name) || other.name == name)); - } - - @JsonKey(includeFromJson: false, includeToJson: false) - @override - int get hashCode => Object.hash(runtimeType, key, location, name); - - /// Create a copy of APIAuthModel - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$APIKeyAuthImplCopyWith<_$APIKeyAuthImpl> get copyWith => - __$$APIKeyAuthImplCopyWithImpl<_$APIKeyAuthImpl>(this, _$identity); - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() none, - required TResult Function(String username, String password) basic, - required TResult Function(String token) bearerToken, - required TResult Function(String key, String location, String name) apiKey, - required TResult Function(String jwt) jwtBearer, - }) { - return apiKey(key, location, name); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? none, - TResult? Function(String username, String password)? basic, - TResult? Function(String token)? bearerToken, - TResult? Function(String key, String location, String name)? apiKey, - TResult? Function(String jwt)? jwtBearer, - }) { - return apiKey?.call(key, location, name); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? none, - TResult Function(String username, String password)? basic, - TResult Function(String token)? bearerToken, - TResult Function(String key, String location, String name)? apiKey, - TResult Function(String jwt)? jwtBearer, - required TResult orElse(), - }) { - if (apiKey != null) { - return apiKey(key, location, name); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(None value) none, - required TResult Function(BasicAuth value) basic, - required TResult Function(BearerTokenAuth value) bearerToken, - required TResult Function(APIKeyAuth value) apiKey, - required TResult Function(JWTBearerAuth value) jwtBearer, - }) { - return apiKey(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(None value)? none, - TResult? Function(BasicAuth value)? basic, - TResult? Function(BearerTokenAuth value)? bearerToken, - TResult? Function(APIKeyAuth value)? apiKey, - TResult? Function(JWTBearerAuth value)? jwtBearer, - }) { - return apiKey?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(None value)? none, - TResult Function(BasicAuth value)? basic, - TResult Function(BearerTokenAuth value)? bearerToken, - TResult Function(APIKeyAuth value)? apiKey, - TResult Function(JWTBearerAuth value)? jwtBearer, - required TResult orElse(), - }) { - if (apiKey != null) { - return apiKey(this); - } - return orElse(); - } - - @override - Map toJson() { - return _$$APIKeyAuthImplToJson( - this, - ); - } -} - -abstract class APIKeyAuth implements APIAuthModel { - const factory APIKeyAuth( - {required final String key, - final String location, - final String name}) = _$APIKeyAuthImpl; - - factory APIKeyAuth.fromJson(Map json) = - _$APIKeyAuthImpl.fromJson; - - String get key; - String get location; // or 'query' - String get name; - - /// Create a copy of APIAuthModel - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - _$$APIKeyAuthImplCopyWith<_$APIKeyAuthImpl> get copyWith => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class _$$JWTBearerAuthImplCopyWith<$Res> { - factory _$$JWTBearerAuthImplCopyWith( - _$JWTBearerAuthImpl value, $Res Function(_$JWTBearerAuthImpl) then) = - __$$JWTBearerAuthImplCopyWithImpl<$Res>; - @useResult - $Res call({String jwt}); -} - -/// @nodoc -class __$$JWTBearerAuthImplCopyWithImpl<$Res> - extends _$APIAuthModelCopyWithImpl<$Res, _$JWTBearerAuthImpl> - implements _$$JWTBearerAuthImplCopyWith<$Res> { - __$$JWTBearerAuthImplCopyWithImpl( - _$JWTBearerAuthImpl _value, $Res Function(_$JWTBearerAuthImpl) _then) - : super(_value, _then); - - /// Create a copy of APIAuthModel - /// with the given fields replaced by the non-null parameter values. - @pragma('vm:prefer-inline') - @override - $Res call({ - Object? jwt = null, - }) { - return _then(_$JWTBearerAuthImpl( - jwt: null == jwt - ? _value.jwt - : jwt // ignore: cast_nullable_to_non_nullable - as String, - )); - } -} - -/// @nodoc -@JsonSerializable() -class _$JWTBearerAuthImpl implements JWTBearerAuth { - const _$JWTBearerAuthImpl({required this.jwt, final String? $type}) - : $type = $type ?? 'jwtBearer'; - - factory _$JWTBearerAuthImpl.fromJson(Map json) => - _$$JWTBearerAuthImplFromJson(json); - - @override - final String jwt; - - @JsonKey(name: 'runtimeType') - final String $type; - - @override - String toString() { - return 'APIAuthModel.jwtBearer(jwt: $jwt)'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$JWTBearerAuthImpl && - (identical(other.jwt, jwt) || other.jwt == jwt)); - } - - @JsonKey(includeFromJson: false, includeToJson: false) - @override - int get hashCode => Object.hash(runtimeType, jwt); - - /// Create a copy of APIAuthModel - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - @override - @pragma('vm:prefer-inline') - _$$JWTBearerAuthImplCopyWith<_$JWTBearerAuthImpl> get copyWith => - __$$JWTBearerAuthImplCopyWithImpl<_$JWTBearerAuthImpl>(this, _$identity); - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() none, - required TResult Function(String username, String password) basic, - required TResult Function(String token) bearerToken, - required TResult Function(String key, String location, String name) apiKey, - required TResult Function(String jwt) jwtBearer, - }) { - return jwtBearer(jwt); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? none, - TResult? Function(String username, String password)? basic, - TResult? Function(String token)? bearerToken, - TResult? Function(String key, String location, String name)? apiKey, - TResult? Function(String jwt)? jwtBearer, - }) { - return jwtBearer?.call(jwt); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? none, - TResult Function(String username, String password)? basic, - TResult Function(String token)? bearerToken, - TResult Function(String key, String location, String name)? apiKey, - TResult Function(String jwt)? jwtBearer, - required TResult orElse(), - }) { - if (jwtBearer != null) { - return jwtBearer(jwt); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(None value) none, - required TResult Function(BasicAuth value) basic, - required TResult Function(BearerTokenAuth value) bearerToken, - required TResult Function(APIKeyAuth value) apiKey, - required TResult Function(JWTBearerAuth value) jwtBearer, - }) { - return jwtBearer(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(None value)? none, - TResult? Function(BasicAuth value)? basic, - TResult? Function(BearerTokenAuth value)? bearerToken, - TResult? Function(APIKeyAuth value)? apiKey, - TResult? Function(JWTBearerAuth value)? jwtBearer, - }) { - return jwtBearer?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(None value)? none, - TResult Function(BasicAuth value)? basic, - TResult Function(BearerTokenAuth value)? bearerToken, - TResult Function(APIKeyAuth value)? apiKey, - TResult Function(JWTBearerAuth value)? jwtBearer, - required TResult orElse(), - }) { - if (jwtBearer != null) { - return jwtBearer(this); - } - return orElse(); - } - - @override - Map toJson() { - return _$$JWTBearerAuthImplToJson( - this, - ); - } -} - -abstract class JWTBearerAuth implements APIAuthModel { - const factory JWTBearerAuth({required final String jwt}) = - _$JWTBearerAuthImpl; - - factory JWTBearerAuth.fromJson(Map json) = - _$JWTBearerAuthImpl.fromJson; - - String get jwt; - - /// Create a copy of APIAuthModel - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) - _$$JWTBearerAuthImplCopyWith<_$JWTBearerAuthImpl> get copyWith => - throw _privateConstructorUsedError; -} diff --git a/packages/apidash_core/lib/models/api_auth_model.g.dart b/packages/apidash_core/lib/models/api_auth_model.g.dart deleted file mode 100644 index 0c25143b4..000000000 --- a/packages/apidash_core/lib/models/api_auth_model.g.dart +++ /dev/null @@ -1,72 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'api_auth_model.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -_$NoneImpl _$$NoneImplFromJson(Map json) => _$NoneImpl( - $type: json['runtimeType'] as String?, - ); - -Map _$$NoneImplToJson(_$NoneImpl instance) => - { - 'runtimeType': instance.$type, - }; - -_$BasicAuthImpl _$$BasicAuthImplFromJson(Map json) => - _$BasicAuthImpl( - username: json['username'] as String, - password: json['password'] as String, - $type: json['runtimeType'] as String?, - ); - -Map _$$BasicAuthImplToJson(_$BasicAuthImpl instance) => - { - 'username': instance.username, - 'password': instance.password, - 'runtimeType': instance.$type, - }; - -_$BearerTokenAuthImpl _$$BearerTokenAuthImplFromJson( - Map json) => - _$BearerTokenAuthImpl( - token: json['token'] as String, - $type: json['runtimeType'] as String?, - ); - -Map _$$BearerTokenAuthImplToJson( - _$BearerTokenAuthImpl instance) => - { - 'token': instance.token, - 'runtimeType': instance.$type, - }; - -_$APIKeyAuthImpl _$$APIKeyAuthImplFromJson(Map json) => - _$APIKeyAuthImpl( - key: json['key'] as String, - location: json['location'] as String? ?? 'header', - name: json['name'] as String? ?? 'x-api-key', - $type: json['runtimeType'] as String?, - ); - -Map _$$APIKeyAuthImplToJson(_$APIKeyAuthImpl instance) => - { - 'key': instance.key, - 'location': instance.location, - 'name': instance.name, - 'runtimeType': instance.$type, - }; - -_$JWTBearerAuthImpl _$$JWTBearerAuthImplFromJson(Map json) => - _$JWTBearerAuthImpl( - jwt: json['jwt'] as String, - $type: json['runtimeType'] as String?, - ); - -Map _$$JWTBearerAuthImplToJson(_$JWTBearerAuthImpl instance) => - { - 'jwt': instance.jwt, - 'runtimeType': instance.$type, - }; diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.dart b/packages/apidash_core/lib/models/auth/api_auth_model.dart new file mode 100644 index 000000000..03ea8fc6d --- /dev/null +++ b/packages/apidash_core/lib/models/auth/api_auth_model.dart @@ -0,0 +1,23 @@ +import 'package:apidash_core/models/auth/auth_api_key_model.dart'; +import 'package:apidash_core/models/auth/auth_basic_model.dart'; +import 'package:apidash_core/models/auth/auth_bearer_model.dart'; +import 'package:apidash_core/models/auth/auth_jwt_model.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import '../../consts.dart'; + +part 'api_auth_model.g.dart'; +part 'api_auth_model.freezed.dart'; + + +@freezed +class Auth with _$Auth { + const factory Auth({ + required APIAuthType type, + AuthApiKeyModel? apikey, + AuthBearerModel? bearer, + AuthBasicAuthModel? basic, + AuthJwtModel? jwt, + }) = _Auth; + + factory Auth.fromJson(Map json) => _$AuthFromJson(json); +} diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart b/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart new file mode 100644 index 000000000..877eb36e9 --- /dev/null +++ b/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart @@ -0,0 +1,310 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'api_auth_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +Auth _$AuthFromJson(Map json) { + return _Auth.fromJson(json); +} + +/// @nodoc +mixin _$Auth { + APIAuthType get type => throw _privateConstructorUsedError; + AuthApiKeyModel? get apikey => throw _privateConstructorUsedError; + AuthBearerModel? get bearer => throw _privateConstructorUsedError; + AuthBasicAuthModel? get basic => throw _privateConstructorUsedError; + AuthJwtModel? get jwt => throw _privateConstructorUsedError; + + /// Serializes this Auth to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of Auth + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $AuthCopyWith get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AuthCopyWith<$Res> { + factory $AuthCopyWith(Auth value, $Res Function(Auth) then) = + _$AuthCopyWithImpl<$Res, Auth>; + @useResult + $Res call( + {APIAuthType type, + AuthApiKeyModel? apikey, + AuthBearerModel? bearer, + AuthBasicAuthModel? basic, + AuthJwtModel? jwt}); + + $AuthApiKeyModelCopyWith<$Res>? get apikey; + $AuthBearerModelCopyWith<$Res>? get bearer; + $AuthBasicAuthModelCopyWith<$Res>? get basic; + $AuthJwtModelCopyWith<$Res>? get jwt; +} + +/// @nodoc +class _$AuthCopyWithImpl<$Res, $Val extends Auth> + implements $AuthCopyWith<$Res> { + _$AuthCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of Auth + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? type = null, + Object? apikey = freezed, + Object? bearer = freezed, + Object? basic = freezed, + Object? jwt = freezed, + }) { + return _then(_value.copyWith( + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as APIAuthType, + apikey: freezed == apikey + ? _value.apikey + : apikey // ignore: cast_nullable_to_non_nullable + as AuthApiKeyModel?, + bearer: freezed == bearer + ? _value.bearer + : bearer // ignore: cast_nullable_to_non_nullable + as AuthBearerModel?, + basic: freezed == basic + ? _value.basic + : basic // ignore: cast_nullable_to_non_nullable + as AuthBasicAuthModel?, + jwt: freezed == jwt + ? _value.jwt + : jwt // ignore: cast_nullable_to_non_nullable + as AuthJwtModel?, + ) as $Val); + } + + /// Create a copy of Auth + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $AuthApiKeyModelCopyWith<$Res>? get apikey { + if (_value.apikey == null) { + return null; + } + + return $AuthApiKeyModelCopyWith<$Res>(_value.apikey!, (value) { + return _then(_value.copyWith(apikey: value) as $Val); + }); + } + + /// Create a copy of Auth + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $AuthBearerModelCopyWith<$Res>? get bearer { + if (_value.bearer == null) { + return null; + } + + return $AuthBearerModelCopyWith<$Res>(_value.bearer!, (value) { + return _then(_value.copyWith(bearer: value) as $Val); + }); + } + + /// Create a copy of Auth + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $AuthBasicAuthModelCopyWith<$Res>? get basic { + if (_value.basic == null) { + return null; + } + + return $AuthBasicAuthModelCopyWith<$Res>(_value.basic!, (value) { + return _then(_value.copyWith(basic: value) as $Val); + }); + } + + /// Create a copy of Auth + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $AuthJwtModelCopyWith<$Res>? get jwt { + if (_value.jwt == null) { + return null; + } + + return $AuthJwtModelCopyWith<$Res>(_value.jwt!, (value) { + return _then(_value.copyWith(jwt: value) as $Val); + }); + } +} + +/// @nodoc +abstract class _$$AuthImplCopyWith<$Res> implements $AuthCopyWith<$Res> { + factory _$$AuthImplCopyWith( + _$AuthImpl value, $Res Function(_$AuthImpl) then) = + __$$AuthImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {APIAuthType type, + AuthApiKeyModel? apikey, + AuthBearerModel? bearer, + AuthBasicAuthModel? basic, + AuthJwtModel? jwt}); + + @override + $AuthApiKeyModelCopyWith<$Res>? get apikey; + @override + $AuthBearerModelCopyWith<$Res>? get bearer; + @override + $AuthBasicAuthModelCopyWith<$Res>? get basic; + @override + $AuthJwtModelCopyWith<$Res>? get jwt; +} + +/// @nodoc +class __$$AuthImplCopyWithImpl<$Res> + extends _$AuthCopyWithImpl<$Res, _$AuthImpl> + implements _$$AuthImplCopyWith<$Res> { + __$$AuthImplCopyWithImpl(_$AuthImpl _value, $Res Function(_$AuthImpl) _then) + : super(_value, _then); + + /// Create a copy of Auth + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? type = null, + Object? apikey = freezed, + Object? bearer = freezed, + Object? basic = freezed, + Object? jwt = freezed, + }) { + return _then(_$AuthImpl( + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as APIAuthType, + apikey: freezed == apikey + ? _value.apikey + : apikey // ignore: cast_nullable_to_non_nullable + as AuthApiKeyModel?, + bearer: freezed == bearer + ? _value.bearer + : bearer // ignore: cast_nullable_to_non_nullable + as AuthBearerModel?, + basic: freezed == basic + ? _value.basic + : basic // ignore: cast_nullable_to_non_nullable + as AuthBasicAuthModel?, + jwt: freezed == jwt + ? _value.jwt + : jwt // ignore: cast_nullable_to_non_nullable + as AuthJwtModel?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$AuthImpl implements _Auth { + const _$AuthImpl( + {required this.type, this.apikey, this.bearer, this.basic, this.jwt}); + + factory _$AuthImpl.fromJson(Map json) => + _$$AuthImplFromJson(json); + + @override + final APIAuthType type; + @override + final AuthApiKeyModel? apikey; + @override + final AuthBearerModel? bearer; + @override + final AuthBasicAuthModel? basic; + @override + final AuthJwtModel? jwt; + + @override + String toString() { + return 'Auth(type: $type, apikey: $apikey, bearer: $bearer, basic: $basic, jwt: $jwt)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AuthImpl && + (identical(other.type, type) || other.type == type) && + (identical(other.apikey, apikey) || other.apikey == apikey) && + (identical(other.bearer, bearer) || other.bearer == bearer) && + (identical(other.basic, basic) || other.basic == basic) && + (identical(other.jwt, jwt) || other.jwt == jwt)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => + Object.hash(runtimeType, type, apikey, bearer, basic, jwt); + + /// Create a copy of Auth + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$AuthImplCopyWith<_$AuthImpl> get copyWith => + __$$AuthImplCopyWithImpl<_$AuthImpl>(this, _$identity); + + @override + Map toJson() { + return _$$AuthImplToJson( + this, + ); + } +} + +abstract class _Auth implements Auth { + const factory _Auth( + {required final APIAuthType type, + final AuthApiKeyModel? apikey, + final AuthBearerModel? bearer, + final AuthBasicAuthModel? basic, + final AuthJwtModel? jwt}) = _$AuthImpl; + + factory _Auth.fromJson(Map json) = _$AuthImpl.fromJson; + + @override + APIAuthType get type; + @override + AuthApiKeyModel? get apikey; + @override + AuthBearerModel? get bearer; + @override + AuthBasicAuthModel? get basic; + @override + AuthJwtModel? get jwt; + + /// Create a copy of Auth + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$AuthImplCopyWith<_$AuthImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.g.dart b/packages/apidash_core/lib/models/auth/api_auth_model.g.dart new file mode 100644 index 000000000..f50bbfe38 --- /dev/null +++ b/packages/apidash_core/lib/models/auth/api_auth_model.g.dart @@ -0,0 +1,43 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'api_auth_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$AuthImpl _$$AuthImplFromJson(Map json) => _$AuthImpl( + type: $enumDecode(_$APIAuthTypeEnumMap, json['type']), + apikey: json['apikey'] == null + ? null + : AuthApiKeyModel.fromJson(json['apikey'] as Map), + bearer: json['bearer'] == null + ? null + : AuthBearerModel.fromJson(json['bearer'] as Map), + basic: json['basic'] == null + ? null + : AuthBasicAuthModel.fromJson(json['basic'] as Map), + jwt: json['jwt'] == null + ? null + : AuthJwtModel.fromJson(json['jwt'] as Map), + ); + +Map _$$AuthImplToJson(_$AuthImpl instance) => + { + 'type': _$APIAuthTypeEnumMap[instance.type]!, + 'apikey': instance.apikey, + 'bearer': instance.bearer, + 'basic': instance.basic, + 'jwt': instance.jwt, + }; + +const _$APIAuthTypeEnumMap = { + APIAuthType.none: 'none', + APIAuthType.basic: 'basic', + APIAuthType.apiKey: 'apiKey', + APIAuthType.bearerToken: 'bearerToken', + APIAuthType.jwtBearer: 'jwtBearer', + APIAuthType.digest: 'digest', + APIAuthType.oauth1: 'oauth1', + APIAuthType.oauth2: 'oauth2', +}; diff --git a/packages/apidash_core/lib/models/auth/auth_api_key_model.dart b/packages/apidash_core/lib/models/auth/auth_api_key_model.dart new file mode 100644 index 000000000..c65837a8b --- /dev/null +++ b/packages/apidash_core/lib/models/auth/auth_api_key_model.dart @@ -0,0 +1,16 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'auth_api_key_model.g.dart'; +part 'auth_api_key_model.freezed.dart'; + +@freezed +class AuthApiKeyModel with _$AuthApiKeyModel { + const factory AuthApiKeyModel({ + required String key, + @Default('header') String location, // 'header' or 'query' + @Default('x-api-key') String name, + }) = _AuthApiKeyModel; + + factory AuthApiKeyModel.fromJson(Map json) => + _$AuthApiKeyModelFromJson(json); +} diff --git a/packages/apidash_core/lib/models/auth/auth_api_key_model.freezed.dart b/packages/apidash_core/lib/models/auth/auth_api_key_model.freezed.dart new file mode 100644 index 000000000..3b9b272f2 --- /dev/null +++ b/packages/apidash_core/lib/models/auth/auth_api_key_model.freezed.dart @@ -0,0 +1,206 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'auth_api_key_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +AuthApiKeyModel _$AuthApiKeyModelFromJson(Map json) { + return _AuthApiKeyModel.fromJson(json); +} + +/// @nodoc +mixin _$AuthApiKeyModel { + String get key => throw _privateConstructorUsedError; + String get location => + throw _privateConstructorUsedError; // 'header' or 'query' + String get name => throw _privateConstructorUsedError; + + /// Serializes this AuthApiKeyModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of AuthApiKeyModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $AuthApiKeyModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AuthApiKeyModelCopyWith<$Res> { + factory $AuthApiKeyModelCopyWith( + AuthApiKeyModel value, $Res Function(AuthApiKeyModel) then) = + _$AuthApiKeyModelCopyWithImpl<$Res, AuthApiKeyModel>; + @useResult + $Res call({String key, String location, String name}); +} + +/// @nodoc +class _$AuthApiKeyModelCopyWithImpl<$Res, $Val extends AuthApiKeyModel> + implements $AuthApiKeyModelCopyWith<$Res> { + _$AuthApiKeyModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of AuthApiKeyModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? key = null, + Object? location = null, + Object? name = null, + }) { + return _then(_value.copyWith( + key: null == key + ? _value.key + : key // ignore: cast_nullable_to_non_nullable + as String, + location: null == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as String, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$AuthApiKeyModelImplCopyWith<$Res> + implements $AuthApiKeyModelCopyWith<$Res> { + factory _$$AuthApiKeyModelImplCopyWith(_$AuthApiKeyModelImpl value, + $Res Function(_$AuthApiKeyModelImpl) then) = + __$$AuthApiKeyModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String key, String location, String name}); +} + +/// @nodoc +class __$$AuthApiKeyModelImplCopyWithImpl<$Res> + extends _$AuthApiKeyModelCopyWithImpl<$Res, _$AuthApiKeyModelImpl> + implements _$$AuthApiKeyModelImplCopyWith<$Res> { + __$$AuthApiKeyModelImplCopyWithImpl( + _$AuthApiKeyModelImpl _value, $Res Function(_$AuthApiKeyModelImpl) _then) + : super(_value, _then); + + /// Create a copy of AuthApiKeyModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? key = null, + Object? location = null, + Object? name = null, + }) { + return _then(_$AuthApiKeyModelImpl( + key: null == key + ? _value.key + : key // ignore: cast_nullable_to_non_nullable + as String, + location: null == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as String, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$AuthApiKeyModelImpl implements _AuthApiKeyModel { + const _$AuthApiKeyModelImpl( + {required this.key, this.location = 'header', this.name = 'x-api-key'}); + + factory _$AuthApiKeyModelImpl.fromJson(Map json) => + _$$AuthApiKeyModelImplFromJson(json); + + @override + final String key; + @override + @JsonKey() + final String location; +// 'header' or 'query' + @override + @JsonKey() + final String name; + + @override + String toString() { + return 'AuthApiKeyModel(key: $key, location: $location, name: $name)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AuthApiKeyModelImpl && + (identical(other.key, key) || other.key == key) && + (identical(other.location, location) || + other.location == location) && + (identical(other.name, name) || other.name == name)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, key, location, name); + + /// Create a copy of AuthApiKeyModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$AuthApiKeyModelImplCopyWith<_$AuthApiKeyModelImpl> get copyWith => + __$$AuthApiKeyModelImplCopyWithImpl<_$AuthApiKeyModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$AuthApiKeyModelImplToJson( + this, + ); + } +} + +abstract class _AuthApiKeyModel implements AuthApiKeyModel { + const factory _AuthApiKeyModel( + {required final String key, + final String location, + final String name}) = _$AuthApiKeyModelImpl; + + factory _AuthApiKeyModel.fromJson(Map json) = + _$AuthApiKeyModelImpl.fromJson; + + @override + String get key; + @override + String get location; // 'header' or 'query' + @override + String get name; + + /// Create a copy of AuthApiKeyModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$AuthApiKeyModelImplCopyWith<_$AuthApiKeyModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/packages/apidash_core/lib/models/auth/auth_api_key_model.g.dart b/packages/apidash_core/lib/models/auth/auth_api_key_model.g.dart new file mode 100644 index 000000000..f04e5c84b --- /dev/null +++ b/packages/apidash_core/lib/models/auth/auth_api_key_model.g.dart @@ -0,0 +1,23 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'auth_api_key_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$AuthApiKeyModelImpl _$$AuthApiKeyModelImplFromJson( + Map json) => + _$AuthApiKeyModelImpl( + key: json['key'] as String, + location: json['location'] as String? ?? 'header', + name: json['name'] as String? ?? 'x-api-key', + ); + +Map _$$AuthApiKeyModelImplToJson( + _$AuthApiKeyModelImpl instance) => + { + 'key': instance.key, + 'location': instance.location, + 'name': instance.name, + }; diff --git a/packages/apidash_core/lib/models/auth/auth_basic_model.dart b/packages/apidash_core/lib/models/auth/auth_basic_model.dart new file mode 100644 index 000000000..5030652cc --- /dev/null +++ b/packages/apidash_core/lib/models/auth/auth_basic_model.dart @@ -0,0 +1,15 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'auth_basic_model.g.dart'; +part 'auth_basic_model.freezed.dart'; + +@freezed +class AuthBasicAuthModel with _$AuthBasicAuthModel { + const factory AuthBasicAuthModel({ + required String username, + required String password, + }) = _AuthBasicAuthModel; + + factory AuthBasicAuthModel.fromJson(Map json) => + _$AuthBasicAuthModelFromJson(json); +} diff --git a/packages/apidash_core/lib/models/auth/auth_basic_model.freezed.dart b/packages/apidash_core/lib/models/auth/auth_basic_model.freezed.dart new file mode 100644 index 000000000..d5c1a07f2 --- /dev/null +++ b/packages/apidash_core/lib/models/auth/auth_basic_model.freezed.dart @@ -0,0 +1,186 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'auth_basic_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +AuthBasicAuthModel _$AuthBasicAuthModelFromJson(Map json) { + return _AuthBasicAuthModel.fromJson(json); +} + +/// @nodoc +mixin _$AuthBasicAuthModel { + String get username => throw _privateConstructorUsedError; + String get password => throw _privateConstructorUsedError; + + /// Serializes this AuthBasicAuthModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of AuthBasicAuthModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $AuthBasicAuthModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AuthBasicAuthModelCopyWith<$Res> { + factory $AuthBasicAuthModelCopyWith( + AuthBasicAuthModel value, $Res Function(AuthBasicAuthModel) then) = + _$AuthBasicAuthModelCopyWithImpl<$Res, AuthBasicAuthModel>; + @useResult + $Res call({String username, String password}); +} + +/// @nodoc +class _$AuthBasicAuthModelCopyWithImpl<$Res, $Val extends AuthBasicAuthModel> + implements $AuthBasicAuthModelCopyWith<$Res> { + _$AuthBasicAuthModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of AuthBasicAuthModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? username = null, + Object? password = null, + }) { + return _then(_value.copyWith( + username: null == username + ? _value.username + : username // ignore: cast_nullable_to_non_nullable + as String, + password: null == password + ? _value.password + : password // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$AuthBasicAuthModelImplCopyWith<$Res> + implements $AuthBasicAuthModelCopyWith<$Res> { + factory _$$AuthBasicAuthModelImplCopyWith(_$AuthBasicAuthModelImpl value, + $Res Function(_$AuthBasicAuthModelImpl) then) = + __$$AuthBasicAuthModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String username, String password}); +} + +/// @nodoc +class __$$AuthBasicAuthModelImplCopyWithImpl<$Res> + extends _$AuthBasicAuthModelCopyWithImpl<$Res, _$AuthBasicAuthModelImpl> + implements _$$AuthBasicAuthModelImplCopyWith<$Res> { + __$$AuthBasicAuthModelImplCopyWithImpl(_$AuthBasicAuthModelImpl _value, + $Res Function(_$AuthBasicAuthModelImpl) _then) + : super(_value, _then); + + /// Create a copy of AuthBasicAuthModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? username = null, + Object? password = null, + }) { + return _then(_$AuthBasicAuthModelImpl( + username: null == username + ? _value.username + : username // ignore: cast_nullable_to_non_nullable + as String, + password: null == password + ? _value.password + : password // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$AuthBasicAuthModelImpl implements _AuthBasicAuthModel { + const _$AuthBasicAuthModelImpl( + {required this.username, required this.password}); + + factory _$AuthBasicAuthModelImpl.fromJson(Map json) => + _$$AuthBasicAuthModelImplFromJson(json); + + @override + final String username; + @override + final String password; + + @override + String toString() { + return 'AuthBasicAuthModel(username: $username, password: $password)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AuthBasicAuthModelImpl && + (identical(other.username, username) || + other.username == username) && + (identical(other.password, password) || + other.password == password)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, username, password); + + /// Create a copy of AuthBasicAuthModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$AuthBasicAuthModelImplCopyWith<_$AuthBasicAuthModelImpl> get copyWith => + __$$AuthBasicAuthModelImplCopyWithImpl<_$AuthBasicAuthModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$AuthBasicAuthModelImplToJson( + this, + ); + } +} + +abstract class _AuthBasicAuthModel implements AuthBasicAuthModel { + const factory _AuthBasicAuthModel( + {required final String username, + required final String password}) = _$AuthBasicAuthModelImpl; + + factory _AuthBasicAuthModel.fromJson(Map json) = + _$AuthBasicAuthModelImpl.fromJson; + + @override + String get username; + @override + String get password; + + /// Create a copy of AuthBasicAuthModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$AuthBasicAuthModelImplCopyWith<_$AuthBasicAuthModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/packages/apidash_core/lib/models/auth/auth_basic_model.g.dart b/packages/apidash_core/lib/models/auth/auth_basic_model.g.dart new file mode 100644 index 000000000..d093c2fe4 --- /dev/null +++ b/packages/apidash_core/lib/models/auth/auth_basic_model.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'auth_basic_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$AuthBasicAuthModelImpl _$$AuthBasicAuthModelImplFromJson( + Map json) => + _$AuthBasicAuthModelImpl( + username: json['username'] as String, + password: json['password'] as String, + ); + +Map _$$AuthBasicAuthModelImplToJson( + _$AuthBasicAuthModelImpl instance) => + { + 'username': instance.username, + 'password': instance.password, + }; diff --git a/packages/apidash_core/lib/models/auth/auth_bearer_model.dart b/packages/apidash_core/lib/models/auth/auth_bearer_model.dart new file mode 100644 index 000000000..ab4002acb --- /dev/null +++ b/packages/apidash_core/lib/models/auth/auth_bearer_model.dart @@ -0,0 +1,14 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'auth_bearer_model.g.dart'; +part 'auth_bearer_model.freezed.dart'; + +@freezed +class AuthBearerModel with _$AuthBearerModel { + const factory AuthBearerModel({ + required String token, + }) = _AuthBearerModel; + + factory AuthBearerModel.fromJson(Map json) => + _$AuthBearerModelFromJson(json); +} diff --git a/packages/apidash_core/lib/models/auth/auth_bearer_model.freezed.dart b/packages/apidash_core/lib/models/auth/auth_bearer_model.freezed.dart new file mode 100644 index 000000000..b94aa4132 --- /dev/null +++ b/packages/apidash_core/lib/models/auth/auth_bearer_model.freezed.dart @@ -0,0 +1,166 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'auth_bearer_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +AuthBearerModel _$AuthBearerModelFromJson(Map json) { + return _AuthBearerModel.fromJson(json); +} + +/// @nodoc +mixin _$AuthBearerModel { + String get token => throw _privateConstructorUsedError; + + /// Serializes this AuthBearerModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of AuthBearerModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $AuthBearerModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AuthBearerModelCopyWith<$Res> { + factory $AuthBearerModelCopyWith( + AuthBearerModel value, $Res Function(AuthBearerModel) then) = + _$AuthBearerModelCopyWithImpl<$Res, AuthBearerModel>; + @useResult + $Res call({String token}); +} + +/// @nodoc +class _$AuthBearerModelCopyWithImpl<$Res, $Val extends AuthBearerModel> + implements $AuthBearerModelCopyWith<$Res> { + _$AuthBearerModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of AuthBearerModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? token = null, + }) { + return _then(_value.copyWith( + token: null == token + ? _value.token + : token // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$AuthBearerModelImplCopyWith<$Res> + implements $AuthBearerModelCopyWith<$Res> { + factory _$$AuthBearerModelImplCopyWith(_$AuthBearerModelImpl value, + $Res Function(_$AuthBearerModelImpl) then) = + __$$AuthBearerModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String token}); +} + +/// @nodoc +class __$$AuthBearerModelImplCopyWithImpl<$Res> + extends _$AuthBearerModelCopyWithImpl<$Res, _$AuthBearerModelImpl> + implements _$$AuthBearerModelImplCopyWith<$Res> { + __$$AuthBearerModelImplCopyWithImpl( + _$AuthBearerModelImpl _value, $Res Function(_$AuthBearerModelImpl) _then) + : super(_value, _then); + + /// Create a copy of AuthBearerModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? token = null, + }) { + return _then(_$AuthBearerModelImpl( + token: null == token + ? _value.token + : token // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$AuthBearerModelImpl implements _AuthBearerModel { + const _$AuthBearerModelImpl({required this.token}); + + factory _$AuthBearerModelImpl.fromJson(Map json) => + _$$AuthBearerModelImplFromJson(json); + + @override + final String token; + + @override + String toString() { + return 'AuthBearerModel(token: $token)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AuthBearerModelImpl && + (identical(other.token, token) || other.token == token)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, token); + + /// Create a copy of AuthBearerModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$AuthBearerModelImplCopyWith<_$AuthBearerModelImpl> get copyWith => + __$$AuthBearerModelImplCopyWithImpl<_$AuthBearerModelImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$AuthBearerModelImplToJson( + this, + ); + } +} + +abstract class _AuthBearerModel implements AuthBearerModel { + const factory _AuthBearerModel({required final String token}) = + _$AuthBearerModelImpl; + + factory _AuthBearerModel.fromJson(Map json) = + _$AuthBearerModelImpl.fromJson; + + @override + String get token; + + /// Create a copy of AuthBearerModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$AuthBearerModelImplCopyWith<_$AuthBearerModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/packages/apidash_core/lib/models/auth/auth_bearer_model.g.dart b/packages/apidash_core/lib/models/auth/auth_bearer_model.g.dart new file mode 100644 index 000000000..a986b911e --- /dev/null +++ b/packages/apidash_core/lib/models/auth/auth_bearer_model.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'auth_bearer_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$AuthBearerModelImpl _$$AuthBearerModelImplFromJson( + Map json) => + _$AuthBearerModelImpl( + token: json['token'] as String, + ); + +Map _$$AuthBearerModelImplToJson( + _$AuthBearerModelImpl instance) => + { + 'token': instance.token, + }; diff --git a/packages/apidash_core/lib/models/auth/auth_jwt_model.dart b/packages/apidash_core/lib/models/auth/auth_jwt_model.dart new file mode 100644 index 000000000..4551b370f --- /dev/null +++ b/packages/apidash_core/lib/models/auth/auth_jwt_model.dart @@ -0,0 +1,14 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'auth_jwt_model.g.dart'; +part 'auth_jwt_model.freezed.dart'; + +@freezed +class AuthJwtModel with _$AuthJwtModel { + const factory AuthJwtModel({ + required String jwt, + }) = _AuthJwtModel; + + factory AuthJwtModel.fromJson(Map json) => + _$AuthJwtModelFromJson(json); +} diff --git a/packages/apidash_core/lib/models/auth/auth_jwt_model.freezed.dart b/packages/apidash_core/lib/models/auth/auth_jwt_model.freezed.dart new file mode 100644 index 000000000..c96881852 --- /dev/null +++ b/packages/apidash_core/lib/models/auth/auth_jwt_model.freezed.dart @@ -0,0 +1,164 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'auth_jwt_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +AuthJwtModel _$AuthJwtModelFromJson(Map json) { + return _AuthJwtModel.fromJson(json); +} + +/// @nodoc +mixin _$AuthJwtModel { + String get jwt => throw _privateConstructorUsedError; + + /// Serializes this AuthJwtModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of AuthJwtModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $AuthJwtModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AuthJwtModelCopyWith<$Res> { + factory $AuthJwtModelCopyWith( + AuthJwtModel value, $Res Function(AuthJwtModel) then) = + _$AuthJwtModelCopyWithImpl<$Res, AuthJwtModel>; + @useResult + $Res call({String jwt}); +} + +/// @nodoc +class _$AuthJwtModelCopyWithImpl<$Res, $Val extends AuthJwtModel> + implements $AuthJwtModelCopyWith<$Res> { + _$AuthJwtModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of AuthJwtModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? jwt = null, + }) { + return _then(_value.copyWith( + jwt: null == jwt + ? _value.jwt + : jwt // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$AuthJwtModelImplCopyWith<$Res> + implements $AuthJwtModelCopyWith<$Res> { + factory _$$AuthJwtModelImplCopyWith( + _$AuthJwtModelImpl value, $Res Function(_$AuthJwtModelImpl) then) = + __$$AuthJwtModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({String jwt}); +} + +/// @nodoc +class __$$AuthJwtModelImplCopyWithImpl<$Res> + extends _$AuthJwtModelCopyWithImpl<$Res, _$AuthJwtModelImpl> + implements _$$AuthJwtModelImplCopyWith<$Res> { + __$$AuthJwtModelImplCopyWithImpl( + _$AuthJwtModelImpl _value, $Res Function(_$AuthJwtModelImpl) _then) + : super(_value, _then); + + /// Create a copy of AuthJwtModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? jwt = null, + }) { + return _then(_$AuthJwtModelImpl( + jwt: null == jwt + ? _value.jwt + : jwt // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$AuthJwtModelImpl implements _AuthJwtModel { + const _$AuthJwtModelImpl({required this.jwt}); + + factory _$AuthJwtModelImpl.fromJson(Map json) => + _$$AuthJwtModelImplFromJson(json); + + @override + final String jwt; + + @override + String toString() { + return 'AuthJwtModel(jwt: $jwt)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AuthJwtModelImpl && + (identical(other.jwt, jwt) || other.jwt == jwt)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash(runtimeType, jwt); + + /// Create a copy of AuthJwtModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$AuthJwtModelImplCopyWith<_$AuthJwtModelImpl> get copyWith => + __$$AuthJwtModelImplCopyWithImpl<_$AuthJwtModelImpl>(this, _$identity); + + @override + Map toJson() { + return _$$AuthJwtModelImplToJson( + this, + ); + } +} + +abstract class _AuthJwtModel implements AuthJwtModel { + const factory _AuthJwtModel({required final String jwt}) = _$AuthJwtModelImpl; + + factory _AuthJwtModel.fromJson(Map json) = + _$AuthJwtModelImpl.fromJson; + + @override + String get jwt; + + /// Create a copy of AuthJwtModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$AuthJwtModelImplCopyWith<_$AuthJwtModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/packages/apidash_core/lib/models/auth/auth_jwt_model.g.dart b/packages/apidash_core/lib/models/auth/auth_jwt_model.g.dart new file mode 100644 index 000000000..73bc26152 --- /dev/null +++ b/packages/apidash_core/lib/models/auth/auth_jwt_model.g.dart @@ -0,0 +1,17 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'auth_jwt_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$AuthJwtModelImpl _$$AuthJwtModelImplFromJson(Map json) => + _$AuthJwtModelImpl( + jwt: json['jwt'] as String, + ); + +Map _$$AuthJwtModelImplToJson(_$AuthJwtModelImpl instance) => + { + 'jwt': instance.jwt, + }; From 449e32521e3268f9305dbc56e8f4667d42a0dbe8 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Thu, 12 Jun 2025 18:18:37 +0530 Subject: [PATCH 05/70] feat: refactor authentication handling to use new ApiAuthModel and update related components --- lib/models/request_model.dart | 4 +- lib/models/request_model.freezed.dart | 50 +++------ lib/models/request_model.g.dart | 18 +-- lib/providers/collection_providers.dart | 5 +- .../request_pane/request_auth.dart | 106 ++++++++++++------ .../request_pane/request_pane_rest.dart | 11 +- packages/apidash_core/lib/consts.dart | 5 +- .../lib/models/auth/api_auth_model.dart | 10 +- .../models/auth/api_auth_model.freezed.dart | 91 ++++++++------- .../lib/models/auth/api_auth_model.g.dart | 9 +- packages/apidash_core/lib/models/models.dart | 2 +- .../apidash_core/lib/utils/handle_auth.dart | 98 ++++++++-------- .../lib/services/http_service.dart | 6 +- 13 files changed, 208 insertions(+), 207 deletions(-) diff --git a/lib/models/request_model.dart b/lib/models/request_model.dart index fa647f30f..2702a5467 100644 --- a/lib/models/request_model.dart +++ b/lib/models/request_model.dart @@ -1,4 +1,5 @@ import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash_core/models/auth/api_auth_model.dart'; part 'request_model.freezed.dart'; @@ -15,8 +16,7 @@ class RequestModel with _$RequestModel { @Default(APIType.rest) APIType apiType, @Default("") String name, @Default("") String description, - @Default(APIAuthType.none) APIAuthType authType, - APIAuthModel? authData, + @Default(ApiAuthModel(type: APIAuthType.none)) ApiAuthModel? authData, @JsonKey(includeToJson: false) @Default(0) requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, diff --git a/lib/models/request_model.freezed.dart b/lib/models/request_model.freezed.dart index affd554e5..da973b64c 100644 --- a/lib/models/request_model.freezed.dart +++ b/lib/models/request_model.freezed.dart @@ -24,8 +24,7 @@ mixin _$RequestModel { APIType get apiType => throw _privateConstructorUsedError; String get name => throw _privateConstructorUsedError; String get description => throw _privateConstructorUsedError; - APIAuthType get authType => throw _privateConstructorUsedError; - APIAuthModel? get authData => throw _privateConstructorUsedError; + ApiAuthModel? get authData => throw _privateConstructorUsedError; @JsonKey(includeToJson: false) dynamic get requestTabIndex => throw _privateConstructorUsedError; HttpRequestModel? get httpRequestModel => throw _privateConstructorUsedError; @@ -61,8 +60,7 @@ abstract class $RequestModelCopyWith<$Res> { APIType apiType, String name, String description, - APIAuthType authType, - APIAuthModel? authData, + ApiAuthModel? authData, @JsonKey(includeToJson: false) dynamic requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, @@ -73,7 +71,7 @@ abstract class $RequestModelCopyWith<$Res> { String? preRequestScript, String? postRequestScript}); - $APIAuthModelCopyWith<$Res>? get authData; + $ApiAuthModelCopyWith<$Res>? get authData; $HttpRequestModelCopyWith<$Res>? get httpRequestModel; $HttpResponseModelCopyWith<$Res>? get httpResponseModel; } @@ -97,7 +95,6 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> Object? apiType = null, Object? name = null, Object? description = null, - Object? authType = null, Object? authData = freezed, Object? requestTabIndex = freezed, Object? httpRequestModel = freezed, @@ -126,14 +123,10 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> ? _value.description : description // ignore: cast_nullable_to_non_nullable as String, - authType: null == authType - ? _value.authType - : authType // ignore: cast_nullable_to_non_nullable - as APIAuthType, authData: freezed == authData ? _value.authData : authData // ignore: cast_nullable_to_non_nullable - as APIAuthModel?, + as ApiAuthModel?, requestTabIndex: freezed == requestTabIndex ? _value.requestTabIndex : requestTabIndex // ignore: cast_nullable_to_non_nullable @@ -177,12 +170,12 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') - $APIAuthModelCopyWith<$Res>? get authData { + $ApiAuthModelCopyWith<$Res>? get authData { if (_value.authData == null) { return null; } - return $APIAuthModelCopyWith<$Res>(_value.authData!, (value) { + return $ApiAuthModelCopyWith<$Res>(_value.authData!, (value) { return _then(_value.copyWith(authData: value) as $Val); }); } @@ -229,8 +222,7 @@ abstract class _$$RequestModelImplCopyWith<$Res> APIType apiType, String name, String description, - APIAuthType authType, - APIAuthModel? authData, + ApiAuthModel? authData, @JsonKey(includeToJson: false) dynamic requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, @@ -242,7 +234,7 @@ abstract class _$$RequestModelImplCopyWith<$Res> String? postRequestScript}); @override - $APIAuthModelCopyWith<$Res>? get authData; + $ApiAuthModelCopyWith<$Res>? get authData; @override $HttpRequestModelCopyWith<$Res>? get httpRequestModel; @override @@ -266,7 +258,6 @@ class __$$RequestModelImplCopyWithImpl<$Res> Object? apiType = null, Object? name = null, Object? description = null, - Object? authType = null, Object? authData = freezed, Object? requestTabIndex = freezed, Object? httpRequestModel = freezed, @@ -295,14 +286,10 @@ class __$$RequestModelImplCopyWithImpl<$Res> ? _value.description : description // ignore: cast_nullable_to_non_nullable as String, - authType: null == authType - ? _value.authType - : authType // ignore: cast_nullable_to_non_nullable - as APIAuthType, authData: freezed == authData ? _value.authData : authData // ignore: cast_nullable_to_non_nullable - as APIAuthModel?, + as ApiAuthModel?, requestTabIndex: freezed == requestTabIndex ? _value.requestTabIndex! : requestTabIndex, @@ -351,8 +338,7 @@ class _$RequestModelImpl implements _RequestModel { this.apiType = APIType.rest, this.name = "", this.description = "", - this.authType = APIAuthType.none, - this.authData, + this.authData = const ApiAuthModel(type: APIAuthType.none), @JsonKey(includeToJson: false) this.requestTabIndex = 0, this.httpRequestModel, this.responseStatus, @@ -379,9 +365,7 @@ class _$RequestModelImpl implements _RequestModel { final String description; @override @JsonKey() - final APIAuthType authType; - @override - final APIAuthModel? authData; + final ApiAuthModel? authData; @override @JsonKey(includeToJson: false) final dynamic requestTabIndex; @@ -406,7 +390,7 @@ class _$RequestModelImpl implements _RequestModel { @override String toString() { - return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, authType: $authType, authData: $authData, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime)'; + return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, authData: $authData, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime)'; } @override @@ -419,8 +403,6 @@ class _$RequestModelImpl implements _RequestModel { (identical(other.name, name) || other.name == name) && (identical(other.description, description) || other.description == description) && - (identical(other.authType, authType) || - other.authType == authType) && (identical(other.authData, authData) || other.authData == authData) && const DeepCollectionEquality() @@ -450,7 +432,6 @@ class _$RequestModelImpl implements _RequestModel { apiType, name, description, - authType, authData, const DeepCollectionEquality().hash(requestTabIndex), httpRequestModel, @@ -484,8 +465,7 @@ abstract class _RequestModel implements RequestModel { final APIType apiType, final String name, final String description, - final APIAuthType authType, - final APIAuthModel? authData, + final ApiAuthModel? authData, @JsonKey(includeToJson: false) final dynamic requestTabIndex, final HttpRequestModel? httpRequestModel, final int? responseStatus, @@ -507,9 +487,7 @@ abstract class _RequestModel implements RequestModel { @override String get description; @override - APIAuthType get authType; - @override - APIAuthModel? get authData; + ApiAuthModel? get authData; @override @JsonKey(includeToJson: false) dynamic get requestTabIndex; diff --git a/lib/models/request_model.g.dart b/lib/models/request_model.g.dart index d684118c3..6b01848a0 100644 --- a/lib/models/request_model.g.dart +++ b/lib/models/request_model.g.dart @@ -12,11 +12,9 @@ _$RequestModelImpl _$$RequestModelImplFromJson(Map json) => _$RequestModelImpl( APIType.rest, name: json['name'] as String? ?? "", description: json['description'] as String? ?? "", - authType: $enumDecodeNullable(_$APIAuthTypeEnumMap, json['authType']) ?? - APIAuthType.none, authData: json['authData'] == null - ? null - : APIAuthModel.fromJson( + ? const ApiAuthModel(type: APIAuthType.none) + : ApiAuthModel.fromJson( Map.from(json['authData'] as Map)), requestTabIndex: json['requestTabIndex'] ?? 0, httpRequestModel: json['httpRequestModel'] == null @@ -43,7 +41,6 @@ Map _$$RequestModelImplToJson(_$RequestModelImpl instance) => 'apiType': _$APITypeEnumMap[instance.apiType]!, 'name': instance.name, 'description': instance.description, - 'authType': _$APIAuthTypeEnumMap[instance.authType]!, 'authData': instance.authData?.toJson(), 'httpRequestModel': instance.httpRequestModel?.toJson(), 'responseStatus': instance.responseStatus, @@ -57,14 +54,3 @@ const _$APITypeEnumMap = { APIType.rest: 'rest', APIType.graphql: 'graphql', }; - -const _$APIAuthTypeEnumMap = { - APIAuthType.none: 'none', - APIAuthType.basic: 'basic', - APIAuthType.apiKey: 'apiKey', - APIAuthType.bearerToken: 'bearerToken', - APIAuthType.jwtBearer: 'jwtBearer', - APIAuthType.digest: 'digest', - APIAuthType.oauth1: 'oauth1', - APIAuthType.oauth2: 'oauth2', -}; diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 0fc8d3879..a701e85f4 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -207,8 +207,7 @@ class CollectionStateNotifier String? id, HTTPVerb? method, APIType? apiType, - APIAuthType? authType, - APIAuthModel? authData, + ApiAuthModel? authData, String? url, String? name, String? description, @@ -236,7 +235,6 @@ class CollectionStateNotifier var currentHttpRequestModel = currentModel.httpRequestModel; final newModel = currentModel.copyWith( apiType: apiType ?? currentModel.apiType, - authType: authType ?? currentModel.authType, authData: authData ?? currentModel.authData, name: name ?? currentModel.name, description: description ?? currentModel.description, @@ -319,7 +317,6 @@ class CollectionStateNotifier requestId, apiType, requestModel.authData, - requestModel.authType, substitutedHttpRequestModel, defaultUriScheme: defaultUriScheme, noSSL: noSSL, diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index 8a5e8534f..04548b0c4 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -1,3 +1,7 @@ +import 'package:apidash_core/models/auth/auth_api_key_model.dart'; +import 'package:apidash_core/models/auth/auth_basic_model.dart'; +import 'package:apidash_core/models/auth/auth_bearer_model.dart'; +import 'package:apidash_core/models/auth/auth_jwt_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash_core/apidash_core.dart'; @@ -14,7 +18,7 @@ class EditAuthType extends ConsumerWidget { return const SizedBox.shrink(); } - final currentAuthType = selectedRequest.authType; + final currentAuthType = selectedRequest.authData?.type ?? APIAuthType.none; final currentAuthData = selectedRequest.authData; return Padding( @@ -48,14 +52,14 @@ class EditAuthType extends ConsumerWidget { onChanged: (APIAuthType? newType) { if (newType != null) { ref.read(collectionStateNotifierProvider.notifier).update( - authType: newType, - authData: null, + authData: currentAuthData?.copyWith(type: newType) ?? + ApiAuthModel(type: newType), ); } }, ), const SizedBox(height: 48), - _buildAuthFields(context, ref, currentAuthType, currentAuthData), + _buildAuthFields(context, ref, currentAuthData), ], ), ); @@ -64,22 +68,21 @@ class EditAuthType extends ConsumerWidget { Widget _buildAuthFields( BuildContext context, WidgetRef ref, - APIAuthType authType, - APIAuthModel? authData, + ApiAuthModel? authData, ) { - void updateAuth(APIAuthModel model) { + void updateAuth(ApiAuthModel model) { ref.read(collectionStateNotifierProvider.notifier).update( authData: model, ); } - switch (authType) { + switch (authData?.type) { case APIAuthType.basic: final usernameController = TextEditingController( - text: (authData is BasicAuth) ? authData.username : '', + text: authData?.basic?.username ?? '', ); final passwordController = TextEditingController( - text: (authData is BasicAuth) ? authData.password : '', + text: authData?.basic?.password ?? '', ); return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -107,7 +110,13 @@ class EditAuthType extends ConsumerWidget { ), ), onChanged: (value) => updateAuth( - BasicAuth(username: value, password: passwordController.text), + ApiAuthModel( + type: APIAuthType.basic, + basic: AuthBasicAuthModel( + username: usernameController.text, + password: value, + ), + ), ), ), SizedBox( @@ -136,15 +145,22 @@ class EditAuthType extends ConsumerWidget { ), ), obscureText: true, - onChanged: (value) => updateAuth(BasicAuth( - username: usernameController.text, password: value)), + onChanged: (value) => updateAuth( + ApiAuthModel( + type: APIAuthType.basic, + basic: AuthBasicAuthModel( + username: usernameController.text, + password: value, + ), + ), + ), ), ], ); - case APIAuthType.bearerToken: + case APIAuthType.bearer: final tokenController = TextEditingController( - text: (authData is BearerTokenAuth) ? authData.token : '', + text: authData?.bearer?.token ?? '', ); return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -171,20 +187,24 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onChanged: (value) => updateAuth(BearerTokenAuth(token: value)), + onChanged: (value) => updateAuth( + ApiAuthModel( + type: APIAuthType.bearer, + bearer: AuthBearerModel(token: value), + ), + ), ), ], ); case APIAuthType.apiKey: final keyController = TextEditingController( - text: (authData is APIKeyAuth) ? authData.key : '', + text: authData?.apikey?.key ?? '', ); final nameController = TextEditingController( - text: (authData is APIKeyAuth) ? authData.name : 'x-api-key', + text: authData?.apikey?.key ?? 'x-api-key', ); - final currentLocation = - (authData is APIKeyAuth) ? authData.location : 'header'; + final currentLocation = authData?.apikey?.location ?? 'header'; return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -221,10 +241,13 @@ class EditAuthType extends ConsumerWidget { ], onChanged: (String? newLocation) { if (newLocation != null) { - updateAuth(APIKeyAuth( - key: keyController.text, - name: nameController.text, - location: newLocation, + updateAuth(ApiAuthModel( + type: APIAuthType.apiKey, + apikey: AuthApiKeyModel( + key: keyController.text, + name: nameController.text, + location: newLocation, + ), )); } }, @@ -252,11 +275,16 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onChanged: (value) => updateAuth(APIKeyAuth( - key: keyController.text, - name: value, - location: currentLocation, - )), + onChanged: (value) => updateAuth( + ApiAuthModel( + type: APIAuthType.apiKey, + apikey: AuthApiKeyModel( + key: keyController.text, + name: value, + location: currentLocation, + ), + ), + ), ), const SizedBox(height: 16), Text( @@ -281,18 +309,21 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onChanged: (value) => updateAuth(APIKeyAuth( - key: value, - name: nameController.text, - location: currentLocation, + onChanged: (value) => updateAuth(ApiAuthModel( + type: APIAuthType.apiKey, + apikey: AuthApiKeyModel( + key: value, + name: nameController.text, + location: currentLocation, + ), )), ), ], ); - case APIAuthType.jwtBearer: + case APIAuthType.jwt: final jwtController = TextEditingController( - text: (authData is JWTBearerAuth) ? authData.jwt : '', + text: authData?.jwt?.jwt ?? '', ); return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -319,7 +350,10 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onChanged: (value) => updateAuth(JWTBearerAuth(jwt: value)), + onChanged: (value) => updateAuth(ApiAuthModel( + type: APIAuthType.jwt, + jwt: AuthJwtModel(jwt: value), + )), ), ], ); diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart index ab0c21844..343850b2f 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart @@ -30,8 +30,8 @@ class EditRestRequestPane extends ConsumerWidget { .select((value) => value?.httpRequestModel?.hasBody)) ?? false; - final hasAuth = ref.watch( - selectedRequestModelProvider.select((value) => value?.authType != APIAuthType.none)); + final hasAuth = ref.watch(selectedRequestModelProvider + .select((value) => value?.authData?.type != APIAuthType.none)); false; return RequestPane( @@ -47,12 +47,7 @@ class EditRestRequestPane extends ConsumerWidget { .read(collectionStateNotifierProvider.notifier) .update(requestTabIndex: index); }, - showIndicators: [ - paramLength > 0, - headerLength > 0, - hasBody, - hasAuth - ], + showIndicators: [paramLength > 0, headerLength > 0, hasBody, hasAuth], tabLabels: const [ kLabelURLParams, kLabelHeaders, diff --git a/packages/apidash_core/lib/consts.dart b/packages/apidash_core/lib/consts.dart index 99a86c9f5..747fb89fc 100644 --- a/packages/apidash_core/lib/consts.dart +++ b/packages/apidash_core/lib/consts.dart @@ -13,12 +13,11 @@ enum APIAuthType { none, basic, apiKey, - bearerToken, - jwtBearer, + bearer, + jwt, digest, oauth1, oauth2, } - enum EnvironmentVariableType { variable, secret } diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.dart b/packages/apidash_core/lib/models/auth/api_auth_model.dart index 03ea8fc6d..c1ddb01c9 100644 --- a/packages/apidash_core/lib/models/auth/api_auth_model.dart +++ b/packages/apidash_core/lib/models/auth/api_auth_model.dart @@ -8,16 +8,16 @@ import '../../consts.dart'; part 'api_auth_model.g.dart'; part 'api_auth_model.freezed.dart'; - @freezed -class Auth with _$Auth { - const factory Auth({ +class ApiAuthModel with _$ApiAuthModel { + const factory ApiAuthModel({ required APIAuthType type, AuthApiKeyModel? apikey, AuthBearerModel? bearer, AuthBasicAuthModel? basic, AuthJwtModel? jwt, - }) = _Auth; + }) = _ApiAuthModel; - factory Auth.fromJson(Map json) => _$AuthFromJson(json); + factory ApiAuthModel.fromJson(Map json) => + _$ApiAuthModelFromJson(json); } diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart b/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart index 877eb36e9..b1bf48304 100644 --- a/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart +++ b/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart @@ -14,31 +14,33 @@ T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); -Auth _$AuthFromJson(Map json) { - return _Auth.fromJson(json); +ApiAuthModel _$ApiAuthModelFromJson(Map json) { + return _ApiAuthModel.fromJson(json); } /// @nodoc -mixin _$Auth { +mixin _$ApiAuthModel { APIAuthType get type => throw _privateConstructorUsedError; AuthApiKeyModel? get apikey => throw _privateConstructorUsedError; AuthBearerModel? get bearer => throw _privateConstructorUsedError; AuthBasicAuthModel? get basic => throw _privateConstructorUsedError; AuthJwtModel? get jwt => throw _privateConstructorUsedError; - /// Serializes this Auth to a JSON map. + /// Serializes this ApiAuthModel to a JSON map. Map toJson() => throw _privateConstructorUsedError; - /// Create a copy of Auth + /// Create a copy of ApiAuthModel /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) - $AuthCopyWith get copyWith => throw _privateConstructorUsedError; + $ApiAuthModelCopyWith get copyWith => + throw _privateConstructorUsedError; } /// @nodoc -abstract class $AuthCopyWith<$Res> { - factory $AuthCopyWith(Auth value, $Res Function(Auth) then) = - _$AuthCopyWithImpl<$Res, Auth>; +abstract class $ApiAuthModelCopyWith<$Res> { + factory $ApiAuthModelCopyWith( + ApiAuthModel value, $Res Function(ApiAuthModel) then) = + _$ApiAuthModelCopyWithImpl<$Res, ApiAuthModel>; @useResult $Res call( {APIAuthType type, @@ -54,16 +56,16 @@ abstract class $AuthCopyWith<$Res> { } /// @nodoc -class _$AuthCopyWithImpl<$Res, $Val extends Auth> - implements $AuthCopyWith<$Res> { - _$AuthCopyWithImpl(this._value, this._then); +class _$ApiAuthModelCopyWithImpl<$Res, $Val extends ApiAuthModel> + implements $ApiAuthModelCopyWith<$Res> { + _$ApiAuthModelCopyWithImpl(this._value, this._then); // ignore: unused_field final $Val _value; // ignore: unused_field final $Res Function($Val) _then; - /// Create a copy of Auth + /// Create a copy of ApiAuthModel /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override @@ -98,7 +100,7 @@ class _$AuthCopyWithImpl<$Res, $Val extends Auth> ) as $Val); } - /// Create a copy of Auth + /// Create a copy of ApiAuthModel /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') @@ -112,7 +114,7 @@ class _$AuthCopyWithImpl<$Res, $Val extends Auth> }); } - /// Create a copy of Auth + /// Create a copy of ApiAuthModel /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') @@ -126,7 +128,7 @@ class _$AuthCopyWithImpl<$Res, $Val extends Auth> }); } - /// Create a copy of Auth + /// Create a copy of ApiAuthModel /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') @@ -140,7 +142,7 @@ class _$AuthCopyWithImpl<$Res, $Val extends Auth> }); } - /// Create a copy of Auth + /// Create a copy of ApiAuthModel /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') @@ -156,10 +158,11 @@ class _$AuthCopyWithImpl<$Res, $Val extends Auth> } /// @nodoc -abstract class _$$AuthImplCopyWith<$Res> implements $AuthCopyWith<$Res> { - factory _$$AuthImplCopyWith( - _$AuthImpl value, $Res Function(_$AuthImpl) then) = - __$$AuthImplCopyWithImpl<$Res>; +abstract class _$$ApiAuthModelImplCopyWith<$Res> + implements $ApiAuthModelCopyWith<$Res> { + factory _$$ApiAuthModelImplCopyWith( + _$ApiAuthModelImpl value, $Res Function(_$ApiAuthModelImpl) then) = + __$$ApiAuthModelImplCopyWithImpl<$Res>; @override @useResult $Res call( @@ -180,13 +183,14 @@ abstract class _$$AuthImplCopyWith<$Res> implements $AuthCopyWith<$Res> { } /// @nodoc -class __$$AuthImplCopyWithImpl<$Res> - extends _$AuthCopyWithImpl<$Res, _$AuthImpl> - implements _$$AuthImplCopyWith<$Res> { - __$$AuthImplCopyWithImpl(_$AuthImpl _value, $Res Function(_$AuthImpl) _then) +class __$$ApiAuthModelImplCopyWithImpl<$Res> + extends _$ApiAuthModelCopyWithImpl<$Res, _$ApiAuthModelImpl> + implements _$$ApiAuthModelImplCopyWith<$Res> { + __$$ApiAuthModelImplCopyWithImpl( + _$ApiAuthModelImpl _value, $Res Function(_$ApiAuthModelImpl) _then) : super(_value, _then); - /// Create a copy of Auth + /// Create a copy of ApiAuthModel /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override @@ -197,7 +201,7 @@ class __$$AuthImplCopyWithImpl<$Res> Object? basic = freezed, Object? jwt = freezed, }) { - return _then(_$AuthImpl( + return _then(_$ApiAuthModelImpl( type: null == type ? _value.type : type // ignore: cast_nullable_to_non_nullable @@ -224,12 +228,12 @@ class __$$AuthImplCopyWithImpl<$Res> /// @nodoc @JsonSerializable() -class _$AuthImpl implements _Auth { - const _$AuthImpl( +class _$ApiAuthModelImpl implements _ApiAuthModel { + const _$ApiAuthModelImpl( {required this.type, this.apikey, this.bearer, this.basic, this.jwt}); - factory _$AuthImpl.fromJson(Map json) => - _$$AuthImplFromJson(json); + factory _$ApiAuthModelImpl.fromJson(Map json) => + _$$ApiAuthModelImplFromJson(json); @override final APIAuthType type; @@ -244,14 +248,14 @@ class _$AuthImpl implements _Auth { @override String toString() { - return 'Auth(type: $type, apikey: $apikey, bearer: $bearer, basic: $basic, jwt: $jwt)'; + return 'ApiAuthModel(type: $type, apikey: $apikey, bearer: $bearer, basic: $basic, jwt: $jwt)'; } @override bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && - other is _$AuthImpl && + other is _$ApiAuthModelImpl && (identical(other.type, type) || other.type == type) && (identical(other.apikey, apikey) || other.apikey == apikey) && (identical(other.bearer, bearer) || other.bearer == bearer) && @@ -264,31 +268,32 @@ class _$AuthImpl implements _Auth { int get hashCode => Object.hash(runtimeType, type, apikey, bearer, basic, jwt); - /// Create a copy of Auth + /// Create a copy of ApiAuthModel /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') - _$$AuthImplCopyWith<_$AuthImpl> get copyWith => - __$$AuthImplCopyWithImpl<_$AuthImpl>(this, _$identity); + _$$ApiAuthModelImplCopyWith<_$ApiAuthModelImpl> get copyWith => + __$$ApiAuthModelImplCopyWithImpl<_$ApiAuthModelImpl>(this, _$identity); @override Map toJson() { - return _$$AuthImplToJson( + return _$$ApiAuthModelImplToJson( this, ); } } -abstract class _Auth implements Auth { - const factory _Auth( +abstract class _ApiAuthModel implements ApiAuthModel { + const factory _ApiAuthModel( {required final APIAuthType type, final AuthApiKeyModel? apikey, final AuthBearerModel? bearer, final AuthBasicAuthModel? basic, - final AuthJwtModel? jwt}) = _$AuthImpl; + final AuthJwtModel? jwt}) = _$ApiAuthModelImpl; - factory _Auth.fromJson(Map json) = _$AuthImpl.fromJson; + factory _ApiAuthModel.fromJson(Map json) = + _$ApiAuthModelImpl.fromJson; @override APIAuthType get type; @@ -301,10 +306,10 @@ abstract class _Auth implements Auth { @override AuthJwtModel? get jwt; - /// Create a copy of Auth + /// Create a copy of ApiAuthModel /// with the given fields replaced by the non-null parameter values. @override @JsonKey(includeFromJson: false, includeToJson: false) - _$$AuthImplCopyWith<_$AuthImpl> get copyWith => + _$$ApiAuthModelImplCopyWith<_$ApiAuthModelImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.g.dart b/packages/apidash_core/lib/models/auth/api_auth_model.g.dart index f50bbfe38..96b37d895 100644 --- a/packages/apidash_core/lib/models/auth/api_auth_model.g.dart +++ b/packages/apidash_core/lib/models/auth/api_auth_model.g.dart @@ -6,7 +6,8 @@ part of 'api_auth_model.dart'; // JsonSerializableGenerator // ************************************************************************** -_$AuthImpl _$$AuthImplFromJson(Map json) => _$AuthImpl( +_$ApiAuthModelImpl _$$ApiAuthModelImplFromJson(Map json) => + _$ApiAuthModelImpl( type: $enumDecode(_$APIAuthTypeEnumMap, json['type']), apikey: json['apikey'] == null ? null @@ -22,7 +23,7 @@ _$AuthImpl _$$AuthImplFromJson(Map json) => _$AuthImpl( : AuthJwtModel.fromJson(json['jwt'] as Map), ); -Map _$$AuthImplToJson(_$AuthImpl instance) => +Map _$$ApiAuthModelImplToJson(_$ApiAuthModelImpl instance) => { 'type': _$APIAuthTypeEnumMap[instance.type]!, 'apikey': instance.apikey, @@ -35,8 +36,8 @@ const _$APIAuthTypeEnumMap = { APIAuthType.none: 'none', APIAuthType.basic: 'basic', APIAuthType.apiKey: 'apiKey', - APIAuthType.bearerToken: 'bearerToken', - APIAuthType.jwtBearer: 'jwtBearer', + APIAuthType.bearer: 'bearer', + APIAuthType.jwt: 'jwt', APIAuthType.digest: 'digest', APIAuthType.oauth1: 'oauth1', APIAuthType.oauth2: 'oauth2', diff --git a/packages/apidash_core/lib/models/models.dart b/packages/apidash_core/lib/models/models.dart index 0fd9acef3..86ef78da9 100644 --- a/packages/apidash_core/lib/models/models.dart +++ b/packages/apidash_core/lib/models/models.dart @@ -1,4 +1,4 @@ export 'environment_model.dart'; export 'http_request_model.dart'; export 'http_response_model.dart'; -export 'api_auth_model.dart'; \ No newline at end of file +export 'auth/api_auth_model.dart'; diff --git a/packages/apidash_core/lib/utils/handle_auth.dart b/packages/apidash_core/lib/utils/handle_auth.dart index f626269b8..9b4ec0baa 100644 --- a/packages/apidash_core/lib/utils/handle_auth.dart +++ b/packages/apidash_core/lib/utils/handle_auth.dart @@ -1,70 +1,78 @@ import 'dart:convert'; import 'package:apidash_core/consts.dart'; -import 'package:apidash_core/models/api_auth_model.dart'; +import 'package:apidash_core/models/auth/api_auth_model.dart'; import 'package:apidash_core/models/http_request_model.dart'; import 'package:seed/seed.dart'; -HttpRequestModel handleAuth(HttpRequestModel httpRequestModel, - APIAuthType apiAuthType, APIAuthModel? authData) { - if (authData == null || apiAuthType == APIAuthType.none) { +HttpRequestModel handleAuth(HttpRequestModel httpRequestModel, ApiAuthModel? auth) { + if (auth == null || auth.type == APIAuthType.none) { return httpRequestModel; } - List updatedHeaders = List.from(httpRequestModel.headers ?? []); + List updatedHeaders = + List.from(httpRequestModel.headers ?? []); List updatedParams = List.from(httpRequestModel.params ?? []); - List updatedHeaderEnabledList = List.from(httpRequestModel.isHeaderEnabledList ?? []); - List updatedParamEnabledList = List.from(httpRequestModel.isParamEnabledList ?? []); + List updatedHeaderEnabledList = + List.from(httpRequestModel.isHeaderEnabledList ?? []); + List updatedParamEnabledList = + List.from(httpRequestModel.isParamEnabledList ?? []); - switch (apiAuthType) { + switch (auth.type) { case APIAuthType.basic: - final auth = authData as BasicAuth; - final encoded = - base64Encode(utf8.encode('${auth.username}:${auth.password}')); - updatedHeaders.add(const NameValueModel(name: 'Authorization', value: '')); - updatedHeaders[updatedHeaders.length - 1] = NameValueModel( - name: 'Authorization', - value: 'Basic $encoded' - ); - updatedHeaderEnabledList.add(true); + if (auth.basic != null) { + final basicAuth = auth.basic!; + final encoded = base64Encode( + utf8.encode('${basicAuth.username}:${basicAuth.password}')); + updatedHeaders.add( + NameValueModel(name: 'Authorization', value: 'Basic $encoded')); + updatedHeaderEnabledList.add(true); + } break; - case APIAuthType.bearerToken: - final auth = authData as BearerTokenAuth; - updatedHeaders.add(NameValueModel( - name: 'Authorization', - value: 'Bearer ${auth.token}' - )); - updatedHeaderEnabledList.add(true); + case APIAuthType.bearer: + if (auth.bearer != null) { + final bearerAuth = auth.bearer!; + updatedHeaders.add(NameValueModel( + name: 'Authorization', value: 'Bearer ${bearerAuth.token}')); + updatedHeaderEnabledList.add(true); + } break; - case APIAuthType.jwtBearer: - final auth = authData as JWTBearerAuth; - updatedHeaders.add(NameValueModel( - name: 'Authorization', - value: 'Bearer ${auth.jwt}' - )); - updatedHeaderEnabledList.add(true); + case APIAuthType.jwt: + if (auth.jwt != null) { + final jwtAuth = auth.jwt!; + updatedHeaders.add(NameValueModel( + name: 'Authorization', value: 'Bearer ${jwtAuth.jwt}')); + updatedHeaderEnabledList.add(true); + } break; case APIAuthType.apiKey: - final auth = authData as APIKeyAuth; - if (auth.location == 'header') { - updatedHeaders.add(NameValueModel( - name: auth.name, - value: auth.key - )); - updatedHeaderEnabledList.add(true); - } else if (auth.location == 'query') { - updatedParams.add(NameValueModel( - name: auth.name, - value: auth.key - )); - updatedParamEnabledList.add(true); + if (auth.apikey != null) { + final apiKeyAuth = auth.apikey!; + if (apiKeyAuth.location == 'header') { + updatedHeaders.add( + NameValueModel(name: apiKeyAuth.name, value: apiKeyAuth.key)); + updatedHeaderEnabledList.add(true); + } else if (apiKeyAuth.location == 'query') { + updatedParams.add( + NameValueModel(name: apiKeyAuth.name, value: apiKeyAuth.key)); + updatedParamEnabledList.add(true); + } } break; - default: + case APIAuthType.none: break; + case APIAuthType.digest: + // TODO: Handle this case. + throw UnimplementedError(); + case APIAuthType.oauth1: + // TODO: Handle this case. + throw UnimplementedError(); + case APIAuthType.oauth2: + // TODO: Handle this case. + throw UnimplementedError(); } return httpRequestModel.copyWith( diff --git a/packages/better_networking/lib/services/http_service.dart b/packages/better_networking/lib/services/http_service.dart index 087521dd5..b069ae0dd 100644 --- a/packages/better_networking/lib/services/http_service.dart +++ b/packages/better_networking/lib/services/http_service.dart @@ -17,8 +17,7 @@ final httpClientManager = HttpClientManager(); Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( String requestId, APIType apiType, - APIAuthModel? authData, - APIAuthType apiAuthType, + ApiAuthModel? authData, HttpRequestModel requestModel, { SupportedUriSchemes defaultUriScheme = kDefaultUriScheme, bool noSSL = false, @@ -29,8 +28,7 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( final client = httpClientManager.createClient(requestId, noSSL: noSSL); // Handle authentication - final authenticatedRequestModel = - handleAuth(requestModel, apiAuthType, authData); + final authenticatedRequestModel = handleAuth(requestModel, authData); (Uri?, String?) uriRec = getValidRequestUri( authenticatedRequestModel.url, From efaebd09eb84a3d6a8551bd661a3595b7e438c68 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Thu, 12 Jun 2025 18:30:09 +0530 Subject: [PATCH 06/70] fix: input text field error --- .../request_pane/request_auth.dart | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index 04548b0c4..68f524240 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -109,12 +109,12 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onChanged: (value) => updateAuth( + onEditingComplete: () => updateAuth( ApiAuthModel( type: APIAuthType.basic, basic: AuthBasicAuthModel( - username: usernameController.text, - password: value, + username: usernameController.text.trim(), + password: passwordController.text.trim(), ), ), ), @@ -145,12 +145,12 @@ class EditAuthType extends ConsumerWidget { ), ), obscureText: true, - onChanged: (value) => updateAuth( + onEditingComplete: () => updateAuth( ApiAuthModel( type: APIAuthType.basic, basic: AuthBasicAuthModel( - username: usernameController.text, - password: value, + username: usernameController.text.trim(), + password: passwordController.text.trim(), ), ), ), @@ -187,10 +187,10 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onChanged: (value) => updateAuth( + onEditingComplete: () => updateAuth( ApiAuthModel( type: APIAuthType.bearer, - bearer: AuthBearerModel(token: value), + bearer: AuthBearerModel(token: tokenController.text.trim()), ), ), ), @@ -202,7 +202,7 @@ class EditAuthType extends ConsumerWidget { text: authData?.apikey?.key ?? '', ); final nameController = TextEditingController( - text: authData?.apikey?.key ?? 'x-api-key', + text: authData?.apikey?.name ?? 'x-api-key', ); final currentLocation = authData?.apikey?.location ?? 'header'; @@ -275,12 +275,12 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onChanged: (value) => updateAuth( + onEditingComplete: () => updateAuth( ApiAuthModel( type: APIAuthType.apiKey, apikey: AuthApiKeyModel( key: keyController.text, - name: value, + name: nameController.text.trim(), location: currentLocation, ), ), @@ -309,10 +309,10 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onChanged: (value) => updateAuth(ApiAuthModel( + onEditingComplete: () => updateAuth(ApiAuthModel( type: APIAuthType.apiKey, apikey: AuthApiKeyModel( - key: value, + key: keyController.text.trim(), name: nameController.text, location: currentLocation, ), @@ -350,9 +350,9 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onChanged: (value) => updateAuth(ApiAuthModel( + onEditingComplete: () => updateAuth(ApiAuthModel( type: APIAuthType.jwt, - jwt: AuthJwtModel(jwt: value), + jwt: AuthJwtModel(jwt: jwtController.text.trim()), )), ), ], From 1540d84de5c2e44fb080f31d92cd01cf0ff263ed Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Fri, 13 Jun 2025 13:30:18 +0530 Subject: [PATCH 07/70] fix:prevent text field rebuild on watch --- .../request_pane/request_auth.dart | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index 68f524240..00080c631 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -12,13 +12,16 @@ class EditAuthType extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final selectedRequest = ref.watch(selectedRequestModelProvider); + final selectedRequest = ref.read(selectedRequestModelProvider); if (selectedRequest == null) { return const SizedBox.shrink(); } - final currentAuthType = selectedRequest.authData?.type ?? APIAuthType.none; + final currentAuthType = ref.watch( + selectedRequestModelProvider + .select((request) => request?.authData?.type ?? APIAuthType.none), + ); final currentAuthData = selectedRequest.authData; return Padding( @@ -109,7 +112,7 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onEditingComplete: () => updateAuth( + onChanged: (value) => updateAuth( ApiAuthModel( type: APIAuthType.basic, basic: AuthBasicAuthModel( @@ -145,7 +148,7 @@ class EditAuthType extends ConsumerWidget { ), ), obscureText: true, - onEditingComplete: () => updateAuth( + onChanged: (value) => updateAuth( ApiAuthModel( type: APIAuthType.basic, basic: AuthBasicAuthModel( @@ -187,7 +190,7 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onEditingComplete: () => updateAuth( + onChanged: (value) => updateAuth( ApiAuthModel( type: APIAuthType.bearer, bearer: AuthBearerModel(token: tokenController.text.trim()), @@ -275,7 +278,7 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onEditingComplete: () => updateAuth( + onChanged: (value) => updateAuth( ApiAuthModel( type: APIAuthType.apiKey, apikey: AuthApiKeyModel( @@ -309,7 +312,7 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onEditingComplete: () => updateAuth(ApiAuthModel( + onChanged: (value) => updateAuth(ApiAuthModel( type: APIAuthType.apiKey, apikey: AuthApiKeyModel( key: keyController.text.trim(), @@ -350,7 +353,7 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onEditingComplete: () => updateAuth(ApiAuthModel( + onChanged: (value) => updateAuth(ApiAuthModel( type: APIAuthType.jwt, jwt: AuthJwtModel(jwt: jwtController.text.trim()), )), From 52a1feb0eec8c8266404979ebc063f2639bb81cb Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Fri, 13 Jun 2025 14:47:51 +0530 Subject: [PATCH 08/70] feat: enhance JWT authentication handling with new fields and JWT generation utility --- .../request_pane/request_auth.dart | 387 ++++++++++++++++-- .../lib/models/auth/auth_jwt_model.dart | 11 +- .../models/auth/auth_jwt_model.freezed.dart | 186 ++++++++- .../lib/models/auth/auth_jwt_model.g.dart | 18 +- .../apidash_core/lib/utils/auth_utils.dart | 95 +++++ .../apidash_core/lib/utils/handle_auth.dart | 27 +- packages/apidash_core/pubspec.yaml | 1 + 7 files changed, 654 insertions(+), 71 deletions(-) create mode 100644 packages/apidash_core/lib/utils/auth_utils.dart diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index 00080c631..b43e28f1f 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -24,46 +24,48 @@ class EditAuthType extends ConsumerWidget { ); final currentAuthData = selectedRequest.authData; - return Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Authentication Type", - style: TextStyle( - fontWeight: FontWeight.bold, + return SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Authentication Type", + style: TextStyle( + fontWeight: FontWeight.bold, + ), ), - ), - SizedBox( - height: 8, - ), - DropdownButtonFormField( - value: currentAuthType, - elevation: 4, - decoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(9), + SizedBox( + height: 8, + ), + DropdownButtonFormField( + value: currentAuthType, + elevation: 4, + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(9), + ), ), + items: APIAuthType.values.map((type) { + return DropdownMenuItem( + value: type, + child: Text(type.name.capitalize()), + ); + }).toList(), + onChanged: (APIAuthType? newType) { + if (newType != null) { + ref.read(collectionStateNotifierProvider.notifier).update( + authData: currentAuthData?.copyWith(type: newType) ?? + ApiAuthModel(type: newType), + ); + } + }, ), - items: APIAuthType.values.map((type) { - return DropdownMenuItem( - value: type, - child: Text(type.name.capitalize()), - ); - }).toList(), - onChanged: (APIAuthType? newType) { - if (newType != null) { - ref.read(collectionStateNotifierProvider.notifier).update( - authData: currentAuthData?.copyWith(type: newType) ?? - ApiAuthModel(type: newType), - ); - } - }, - ), - const SizedBox(height: 48), - _buildAuthFields(context, ref, currentAuthData), - ], + const SizedBox(height: 48), + _buildAuthFields(context, ref, currentAuthData), + ], + ), ), ); } @@ -325,29 +327,139 @@ class EditAuthType extends ConsumerWidget { ); case APIAuthType.jwt: - final jwtController = TextEditingController( - text: authData?.jwt?.jwt ?? '', + final jwtSecretController = TextEditingController( + text: authData?.jwt?.secret ?? '', + ); + final jwtPayloadController = TextEditingController( + text: authData?.jwt?.payload ?? '', + ); + final jwtHeaderPrefixController = TextEditingController( + text: authData?.jwt?.headerPrefix ?? 'Bearer', + ); + final jwtQueryParamKeyController = TextEditingController( + text: authData?.jwt?.queryParamKey ?? 'token', ); + final jwtHeaderController = TextEditingController( + text: authData?.jwt?.header ?? '', + ); + + final currentAddTokenTo = authData?.jwt?.addTokenTo ?? 'header'; + final currentAlgorithm = authData?.jwt?.algorithm ?? 'HS256'; + final isSecretBase64Encoded = + authData?.jwt?.isSecretBase64Encoded ?? false; + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "JWT Token", + "Add JWT token to", style: TextStyle( fontWeight: FontWeight.bold, ), ), - SizedBox( - height: 4, + SizedBox(height: 4), + DropdownButtonFormField( + value: currentAddTokenTo, + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + items: [ + DropdownMenuItem( + value: 'header', + child: Text('Request Header'), + ), + DropdownMenuItem( + value: 'query', + child: Text('Query Parameters'), + ), + ], + onChanged: (String? newAddTokenTo) { + if (newAddTokenTo != null) { + updateAuth(ApiAuthModel( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: jwtSecretController.text.trim(), + payload: jwtPayloadController.text.trim(), + addTokenTo: newAddTokenTo, + algorithm: currentAlgorithm, + isSecretBase64Encoded: isSecretBase64Encoded, + headerPrefix: jwtHeaderPrefixController.text.trim(), + queryParamKey: jwtQueryParamKeyController.text.trim(), + header: jwtHeaderController.text.trim(), + ), + )); + } + }, ), + const SizedBox(height: 16), + Text( + "Algorithm", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 4), + DropdownButtonFormField( + value: currentAlgorithm, + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + items: [ + 'HS256', + 'HS384', + 'HS512', + ].map((algorithm) { + return DropdownMenuItem( + value: algorithm, + child: Text(algorithm), + ); + }).toList(), + onChanged: (String? newAlgorithm) { + if (newAlgorithm != null) { + updateAuth(ApiAuthModel( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: jwtSecretController.text.trim(), + payload: jwtPayloadController.text.trim(), + addTokenTo: currentAddTokenTo, + algorithm: newAlgorithm, + isSecretBase64Encoded: isSecretBase64Encoded, + headerPrefix: jwtHeaderPrefixController.text.trim(), + queryParamKey: jwtQueryParamKeyController.text.trim(), + header: jwtHeaderController.text.trim(), + ), + )); + } + }, + ), + const SizedBox(height: 16), + Text( + "Secret", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 4), TextField( - controller: jwtController, + controller: jwtSecretController, decoration: InputDecoration( constraints: BoxConstraints( maxWidth: MediaQuery.sizeOf(context).width - 100, ), contentPadding: const EdgeInsets.all(18), - hintText: "JWT Token", + hintText: "Secret key", hintStyle: Theme.of(context).textTheme.bodyMedium, border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -355,9 +467,194 @@ class EditAuthType extends ConsumerWidget { ), onChanged: (value) => updateAuth(ApiAuthModel( type: APIAuthType.jwt, - jwt: AuthJwtModel(jwt: jwtController.text.trim()), + jwt: AuthJwtModel( + secret: jwtSecretController.text.trim(), + payload: jwtPayloadController.text.trim(), + addTokenTo: currentAddTokenTo, + algorithm: currentAlgorithm, + isSecretBase64Encoded: isSecretBase64Encoded, + headerPrefix: jwtHeaderPrefixController.text.trim(), + queryParamKey: jwtQueryParamKeyController.text.trim(), + header: jwtHeaderController.text.trim(), + ), + )), + ), + const SizedBox(height: 16), + CheckboxListTile( + title: Text( + "Secret is Base64 encoded", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + value: isSecretBase64Encoded, + contentPadding: EdgeInsets.zero, + controlAffinity: ListTileControlAffinity.leading, + onChanged: (bool? value) { + updateAuth(ApiAuthModel( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: jwtSecretController.text.trim(), + payload: jwtPayloadController.text.trim(), + addTokenTo: currentAddTokenTo, + algorithm: currentAlgorithm, + isSecretBase64Encoded: value ?? false, + headerPrefix: jwtHeaderPrefixController.text.trim(), + queryParamKey: jwtQueryParamKeyController.text.trim(), + header: jwtHeaderController.text.trim(), + ), + )); + }, + ), + const SizedBox(height: 16), + Text( + "Payload (JSON format)", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 4), + TextField( + controller: jwtPayloadController, + maxLines: 4, + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + hintText: + '{"sub": "1234567890", "name": "John Doe", "iat": 1516239022}', + hintStyle: Theme.of(context).textTheme.bodyMedium, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onChanged: (value) => updateAuth(ApiAuthModel( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: jwtSecretController.text.trim(), + payload: jwtPayloadController.text.trim(), + addTokenTo: currentAddTokenTo, + algorithm: currentAlgorithm, + isSecretBase64Encoded: isSecretBase64Encoded, + headerPrefix: jwtHeaderPrefixController.text.trim(), + queryParamKey: jwtQueryParamKeyController.text.trim(), + header: jwtHeaderController.text.trim(), + ), )), ), + // const SizedBox(height: 16), + // if (currentAddTokenTo == 'header') ...[ + // Text( + // "Header Prefix", + // style: TextStyle( + // fontWeight: FontWeight.bold, + // ), + // ), + // SizedBox(height: 4), + // TextField( + // controller: jwtHeaderPrefixController, + // decoration: InputDecoration( + // constraints: BoxConstraints( + // maxWidth: MediaQuery.sizeOf(context).width - 100, + // ), + // contentPadding: const EdgeInsets.all(18), + // hintText: "Bearer", + // hintStyle: Theme.of(context).textTheme.bodyMedium, + // border: OutlineInputBorder( + // borderRadius: BorderRadius.circular(8), + // ), + // ), + // onChanged: (value) => updateAuth(ApiAuthModel( + // type: APIAuthType.jwt, + // jwt: AuthJwtModel( + // secret: jwtSecretController.text.trim(), + // payload: jwtPayloadController.text.trim(), + // addTokenTo: currentAddTokenTo, + // algorithm: currentAlgorithm, + // isSecretBase64Encoded: isSecretBase64Encoded, + // headerPrefix: jwtHeaderPrefixController.text.trim(), + // queryParamKey: jwtQueryParamKeyController.text.trim(), + // header: jwtHeaderController.text.trim(), + // ), + // )), + // ), + // const SizedBox(height: 16), + // ], + // if (currentAddTokenTo == 'query') ...[ + // Text( + // "Query Parameter Key", + // style: TextStyle( + // fontWeight: FontWeight.bold, + // ), + // ), + // SizedBox(height: 4), + // TextField( + // controller: jwtQueryParamKeyController, + // decoration: InputDecoration( + // constraints: BoxConstraints( + // maxWidth: MediaQuery.sizeOf(context).width - 100, + // ), + // contentPadding: const EdgeInsets.all(18), + // hintText: "token", + // hintStyle: Theme.of(context).textTheme.bodyMedium, + // border: OutlineInputBorder( + // borderRadius: BorderRadius.circular(8), + // ), + // ), + // onChanged: (value) => updateAuth(ApiAuthModel( + // type: APIAuthType.jwt, + // jwt: AuthJwtModel( + // secret: jwtSecretController.text.trim(), + // payload: jwtPayloadController.text.trim(), + // addTokenTo: currentAddTokenTo, + // algorithm: currentAlgorithm, + // isSecretBase64Encoded: isSecretBase64Encoded, + // headerPrefix: jwtHeaderPrefixController.text.trim(), + // queryParamKey: jwtQueryParamKeyController.text.trim(), + // header: jwtHeaderController.text.trim(), + // ), + // )), + // ), + // const SizedBox(height: 16), + // ], + // Text( + // "JWT Headers (JSON format)", + // style: TextStyle( + // fontWeight: FontWeight.bold, + // ), + // ), + // SizedBox(height: 4), + // TextField( + // controller: jwtHeaderController, + // maxLines: 3, + // decoration: InputDecoration( + // constraints: BoxConstraints( + // maxWidth: MediaQuery.sizeOf(context).width - 100, + // ), + // contentPadding: const EdgeInsets.all(18), + // hintText: '{"typ": "JWT", "alg": "HS256"}', + // hintStyle: Theme.of(context).textTheme.bodyMedium, + // border: OutlineInputBorder( + // borderRadius: BorderRadius.circular(8), + // ), + // ), + // onChanged: (value) => updateAuth( + // ApiAuthModel( + // type: APIAuthType.jwt, + // jwt: AuthJwtModel( + // secret: jwtSecretController.text.trim(), + // payload: jwtPayloadController.text.trim(), + // addTokenTo: currentAddTokenTo, + // algorithm: currentAlgorithm, + // isSecretBase64Encoded: isSecretBase64Encoded, + // headerPrefix: jwtHeaderPrefixController.text.trim(), + // queryParamKey: jwtQueryParamKeyController.text.trim(), + // header: jwtHeaderController.text.trim(), + // ), + // ), + // ), + // ), ], ); diff --git a/packages/apidash_core/lib/models/auth/auth_jwt_model.dart b/packages/apidash_core/lib/models/auth/auth_jwt_model.dart index 4551b370f..61b165a57 100644 --- a/packages/apidash_core/lib/models/auth/auth_jwt_model.dart +++ b/packages/apidash_core/lib/models/auth/auth_jwt_model.dart @@ -1,12 +1,19 @@ import 'package:freezed_annotation/freezed_annotation.dart'; -part 'auth_jwt_model.g.dart'; part 'auth_jwt_model.freezed.dart'; +part 'auth_jwt_model.g.dart'; @freezed class AuthJwtModel with _$AuthJwtModel { const factory AuthJwtModel({ - required String jwt, + required String secret, + required String payload, + required String addTokenTo, + required String algorithm, + required bool isSecretBase64Encoded, + required String headerPrefix, + required String queryParamKey, + required String header, }) = _AuthJwtModel; factory AuthJwtModel.fromJson(Map json) => diff --git a/packages/apidash_core/lib/models/auth/auth_jwt_model.freezed.dart b/packages/apidash_core/lib/models/auth/auth_jwt_model.freezed.dart index c96881852..cf35ed41e 100644 --- a/packages/apidash_core/lib/models/auth/auth_jwt_model.freezed.dart +++ b/packages/apidash_core/lib/models/auth/auth_jwt_model.freezed.dart @@ -20,7 +20,14 @@ AuthJwtModel _$AuthJwtModelFromJson(Map json) { /// @nodoc mixin _$AuthJwtModel { - String get jwt => throw _privateConstructorUsedError; + String get secret => throw _privateConstructorUsedError; + String get payload => throw _privateConstructorUsedError; + String get addTokenTo => throw _privateConstructorUsedError; + String get algorithm => throw _privateConstructorUsedError; + bool get isSecretBase64Encoded => throw _privateConstructorUsedError; + String get headerPrefix => throw _privateConstructorUsedError; + String get queryParamKey => throw _privateConstructorUsedError; + String get header => throw _privateConstructorUsedError; /// Serializes this AuthJwtModel to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -38,7 +45,15 @@ abstract class $AuthJwtModelCopyWith<$Res> { AuthJwtModel value, $Res Function(AuthJwtModel) then) = _$AuthJwtModelCopyWithImpl<$Res, AuthJwtModel>; @useResult - $Res call({String jwt}); + $Res call( + {String secret, + String payload, + String addTokenTo, + String algorithm, + bool isSecretBase64Encoded, + String headerPrefix, + String queryParamKey, + String header}); } /// @nodoc @@ -56,12 +71,47 @@ class _$AuthJwtModelCopyWithImpl<$Res, $Val extends AuthJwtModel> @pragma('vm:prefer-inline') @override $Res call({ - Object? jwt = null, + Object? secret = null, + Object? payload = null, + Object? addTokenTo = null, + Object? algorithm = null, + Object? isSecretBase64Encoded = null, + Object? headerPrefix = null, + Object? queryParamKey = null, + Object? header = null, }) { return _then(_value.copyWith( - jwt: null == jwt - ? _value.jwt - : jwt // ignore: cast_nullable_to_non_nullable + secret: null == secret + ? _value.secret + : secret // ignore: cast_nullable_to_non_nullable + as String, + payload: null == payload + ? _value.payload + : payload // ignore: cast_nullable_to_non_nullable + as String, + addTokenTo: null == addTokenTo + ? _value.addTokenTo + : addTokenTo // ignore: cast_nullable_to_non_nullable + as String, + algorithm: null == algorithm + ? _value.algorithm + : algorithm // ignore: cast_nullable_to_non_nullable + as String, + isSecretBase64Encoded: null == isSecretBase64Encoded + ? _value.isSecretBase64Encoded + : isSecretBase64Encoded // ignore: cast_nullable_to_non_nullable + as bool, + headerPrefix: null == headerPrefix + ? _value.headerPrefix + : headerPrefix // ignore: cast_nullable_to_non_nullable + as String, + queryParamKey: null == queryParamKey + ? _value.queryParamKey + : queryParamKey // ignore: cast_nullable_to_non_nullable + as String, + header: null == header + ? _value.header + : header // ignore: cast_nullable_to_non_nullable as String, ) as $Val); } @@ -75,7 +125,15 @@ abstract class _$$AuthJwtModelImplCopyWith<$Res> __$$AuthJwtModelImplCopyWithImpl<$Res>; @override @useResult - $Res call({String jwt}); + $Res call( + {String secret, + String payload, + String addTokenTo, + String algorithm, + bool isSecretBase64Encoded, + String headerPrefix, + String queryParamKey, + String header}); } /// @nodoc @@ -91,12 +149,47 @@ class __$$AuthJwtModelImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? jwt = null, + Object? secret = null, + Object? payload = null, + Object? addTokenTo = null, + Object? algorithm = null, + Object? isSecretBase64Encoded = null, + Object? headerPrefix = null, + Object? queryParamKey = null, + Object? header = null, }) { return _then(_$AuthJwtModelImpl( - jwt: null == jwt - ? _value.jwt - : jwt // ignore: cast_nullable_to_non_nullable + secret: null == secret + ? _value.secret + : secret // ignore: cast_nullable_to_non_nullable + as String, + payload: null == payload + ? _value.payload + : payload // ignore: cast_nullable_to_non_nullable + as String, + addTokenTo: null == addTokenTo + ? _value.addTokenTo + : addTokenTo // ignore: cast_nullable_to_non_nullable + as String, + algorithm: null == algorithm + ? _value.algorithm + : algorithm // ignore: cast_nullable_to_non_nullable + as String, + isSecretBase64Encoded: null == isSecretBase64Encoded + ? _value.isSecretBase64Encoded + : isSecretBase64Encoded // ignore: cast_nullable_to_non_nullable + as bool, + headerPrefix: null == headerPrefix + ? _value.headerPrefix + : headerPrefix // ignore: cast_nullable_to_non_nullable + as String, + queryParamKey: null == queryParamKey + ? _value.queryParamKey + : queryParamKey // ignore: cast_nullable_to_non_nullable + as String, + header: null == header + ? _value.header + : header // ignore: cast_nullable_to_non_nullable as String, )); } @@ -105,17 +198,39 @@ class __$$AuthJwtModelImplCopyWithImpl<$Res> /// @nodoc @JsonSerializable() class _$AuthJwtModelImpl implements _AuthJwtModel { - const _$AuthJwtModelImpl({required this.jwt}); + const _$AuthJwtModelImpl( + {required this.secret, + required this.payload, + required this.addTokenTo, + required this.algorithm, + required this.isSecretBase64Encoded, + required this.headerPrefix, + required this.queryParamKey, + required this.header}); factory _$AuthJwtModelImpl.fromJson(Map json) => _$$AuthJwtModelImplFromJson(json); @override - final String jwt; + final String secret; + @override + final String payload; + @override + final String addTokenTo; + @override + final String algorithm; + @override + final bool isSecretBase64Encoded; + @override + final String headerPrefix; + @override + final String queryParamKey; + @override + final String header; @override String toString() { - return 'AuthJwtModel(jwt: $jwt)'; + return 'AuthJwtModel(secret: $secret, payload: $payload, addTokenTo: $addTokenTo, algorithm: $algorithm, isSecretBase64Encoded: $isSecretBase64Encoded, headerPrefix: $headerPrefix, queryParamKey: $queryParamKey, header: $header)'; } @override @@ -123,12 +238,25 @@ class _$AuthJwtModelImpl implements _AuthJwtModel { return identical(this, other) || (other.runtimeType == runtimeType && other is _$AuthJwtModelImpl && - (identical(other.jwt, jwt) || other.jwt == jwt)); + (identical(other.secret, secret) || other.secret == secret) && + (identical(other.payload, payload) || other.payload == payload) && + (identical(other.addTokenTo, addTokenTo) || + other.addTokenTo == addTokenTo) && + (identical(other.algorithm, algorithm) || + other.algorithm == algorithm) && + (identical(other.isSecretBase64Encoded, isSecretBase64Encoded) || + other.isSecretBase64Encoded == isSecretBase64Encoded) && + (identical(other.headerPrefix, headerPrefix) || + other.headerPrefix == headerPrefix) && + (identical(other.queryParamKey, queryParamKey) || + other.queryParamKey == queryParamKey) && + (identical(other.header, header) || other.header == header)); } @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => Object.hash(runtimeType, jwt); + int get hashCode => Object.hash(runtimeType, secret, payload, addTokenTo, + algorithm, isSecretBase64Encoded, headerPrefix, queryParamKey, header); /// Create a copy of AuthJwtModel /// with the given fields replaced by the non-null parameter values. @@ -147,13 +275,35 @@ class _$AuthJwtModelImpl implements _AuthJwtModel { } abstract class _AuthJwtModel implements AuthJwtModel { - const factory _AuthJwtModel({required final String jwt}) = _$AuthJwtModelImpl; + const factory _AuthJwtModel( + {required final String secret, + required final String payload, + required final String addTokenTo, + required final String algorithm, + required final bool isSecretBase64Encoded, + required final String headerPrefix, + required final String queryParamKey, + required final String header}) = _$AuthJwtModelImpl; factory _AuthJwtModel.fromJson(Map json) = _$AuthJwtModelImpl.fromJson; @override - String get jwt; + String get secret; + @override + String get payload; + @override + String get addTokenTo; + @override + String get algorithm; + @override + bool get isSecretBase64Encoded; + @override + String get headerPrefix; + @override + String get queryParamKey; + @override + String get header; /// Create a copy of AuthJwtModel /// with the given fields replaced by the non-null parameter values. diff --git a/packages/apidash_core/lib/models/auth/auth_jwt_model.g.dart b/packages/apidash_core/lib/models/auth/auth_jwt_model.g.dart index 73bc26152..4e415d108 100644 --- a/packages/apidash_core/lib/models/auth/auth_jwt_model.g.dart +++ b/packages/apidash_core/lib/models/auth/auth_jwt_model.g.dart @@ -8,10 +8,24 @@ part of 'auth_jwt_model.dart'; _$AuthJwtModelImpl _$$AuthJwtModelImplFromJson(Map json) => _$AuthJwtModelImpl( - jwt: json['jwt'] as String, + secret: json['secret'] as String, + payload: json['payload'] as String, + addTokenTo: json['addTokenTo'] as String, + algorithm: json['algorithm'] as String, + isSecretBase64Encoded: json['isSecretBase64Encoded'] as bool, + headerPrefix: json['headerPrefix'] as String, + queryParamKey: json['queryParamKey'] as String, + header: json['header'] as String, ); Map _$$AuthJwtModelImplToJson(_$AuthJwtModelImpl instance) => { - 'jwt': instance.jwt, + 'secret': instance.secret, + 'payload': instance.payload, + 'addTokenTo': instance.addTokenTo, + 'algorithm': instance.algorithm, + 'isSecretBase64Encoded': instance.isSecretBase64Encoded, + 'headerPrefix': instance.headerPrefix, + 'queryParamKey': instance.queryParamKey, + 'header': instance.header, }; diff --git a/packages/apidash_core/lib/utils/auth_utils.dart b/packages/apidash_core/lib/utils/auth_utils.dart new file mode 100644 index 000000000..4e03b1440 --- /dev/null +++ b/packages/apidash_core/lib/utils/auth_utils.dart @@ -0,0 +1,95 @@ +import 'dart:convert'; +import 'dart:typed_data'; +import 'package:apidash_core/models/auth/auth_jwt_model.dart'; +import 'package:crypto/crypto.dart'; + +String generateJWT(AuthJwtModel jwtAuth) { + try { + Map header; + if (jwtAuth.header.isNotEmpty) { + try { + header = json.decode(jwtAuth.header) as Map; + } catch (e) { + header = {}; + } + } else { + header = {}; + } + header['typ'] = header['typ'] ?? 'JWT'; + header['alg'] = jwtAuth.algorithm; + Map payload; + if (jwtAuth.payload.isNotEmpty) { + try { + payload = json.decode(jwtAuth.payload) as Map; + } catch (e) { + payload = {}; + } + } else { + payload = {}; + } + if (!payload.containsKey('iat')) { + payload['iat'] = DateTime.now().millisecondsSinceEpoch ~/ 1000; + } + + // Encode header and payload + final encodedHeader = _base64UrlEncode(utf8.encode(json.encode(header))); + final encodedPayload = _base64UrlEncode(utf8.encode(json.encode(payload))); + + // Create signature + final signature = _createSignature( + '$encodedHeader.$encodedPayload', + jwtAuth.secret, + jwtAuth.algorithm, + jwtAuth.isSecretBase64Encoded, + ); + + return '$encodedHeader.$encodedPayload.$signature'; + } catch (e) { + // Return a basic JWT if generation fails + return 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; + } +} + +String _createSignature( + String data, String secret, String algorithm, bool isSecretBase64Encoded) { + try { + Uint8List secretBytes; + if (isSecretBase64Encoded) { + secretBytes = base64.decode(secret); + } else { + secretBytes = utf8.encode(secret); + } + + final dataBytes = utf8.encode(data); + + switch (algorithm) { + case 'HS256': + final hmac = Hmac(sha256, secretBytes); + final digest = hmac.convert(dataBytes); + return _base64UrlEncode(digest.bytes); + + case 'HS384': + final hmac = Hmac(sha384, secretBytes); + final digest = hmac.convert(dataBytes); + return _base64UrlEncode(digest.bytes); + + case 'HS512': + final hmac = Hmac(sha512, secretBytes); + final digest = hmac.convert(dataBytes); + return _base64UrlEncode(digest.bytes); + + default: + // Default to HS256 + final hmac = Hmac(sha256, secretBytes); + final digest = hmac.convert(dataBytes); + return _base64UrlEncode(digest.bytes); + } + } catch (e) { + // Return placeholder signature if creation fails + return _base64UrlEncode(utf8.encode('signature_generation_failed')); + } +} + +String _base64UrlEncode(List bytes) { + return base64Url.encode(bytes).replaceAll('=', ''); +} diff --git a/packages/apidash_core/lib/utils/handle_auth.dart b/packages/apidash_core/lib/utils/handle_auth.dart index 9b4ec0baa..bad494f9d 100644 --- a/packages/apidash_core/lib/utils/handle_auth.dart +++ b/packages/apidash_core/lib/utils/handle_auth.dart @@ -2,9 +2,11 @@ import 'dart:convert'; import 'package:apidash_core/consts.dart'; import 'package:apidash_core/models/auth/api_auth_model.dart'; import 'package:apidash_core/models/http_request_model.dart'; +import 'package:apidash_core/utils/auth_utils.dart'; import 'package:seed/seed.dart'; -HttpRequestModel handleAuth(HttpRequestModel httpRequestModel, ApiAuthModel? auth) { +HttpRequestModel handleAuth( + HttpRequestModel httpRequestModel, ApiAuthModel? auth) { if (auth == null || auth.type == APIAuthType.none) { return httpRequestModel; } @@ -41,9 +43,26 @@ HttpRequestModel handleAuth(HttpRequestModel httpRequestModel, ApiAuthModel? aut case APIAuthType.jwt: if (auth.jwt != null) { final jwtAuth = auth.jwt!; - updatedHeaders.add(NameValueModel( - name: 'Authorization', value: 'Bearer ${jwtAuth.jwt}')); - updatedHeaderEnabledList.add(true); + + // Generate JWT token + final jwtToken = generateJWT(jwtAuth); + + if (jwtAuth.addTokenTo == 'header') { + // Add to request header with prefix + final headerValue = jwtAuth.headerPrefix.isNotEmpty + ? '${jwtAuth.headerPrefix} $jwtToken' + : jwtToken; + updatedHeaders + .add(NameValueModel(name: 'Authorization', value: headerValue)); + updatedHeaderEnabledList.add(true); + } else if (jwtAuth.addTokenTo == 'query') { + // Add to query parameters(if selected) + final paramKey = jwtAuth.queryParamKey.isNotEmpty + ? jwtAuth.queryParamKey + : 'token'; + updatedParams.add(NameValueModel(name: paramKey, value: jwtToken)); + updatedParamEnabledList.add(true); + } } break; diff --git a/packages/apidash_core/pubspec.yaml b/packages/apidash_core/pubspec.yaml index 2c010a07a..ca73b2796 100644 --- a/packages/apidash_core/pubspec.yaml +++ b/packages/apidash_core/pubspec.yaml @@ -23,6 +23,7 @@ dependencies: postman: path: ../postman xml: ^6.3.0 + crypto: ^3.0.6 dev_dependencies: flutter_test: From a48d05942282bff15a52e53d29189306e9c28394 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sat, 14 Jun 2025 10:47:17 +0530 Subject: [PATCH 09/70] fix: state persistance upon api type switch --- .../request_pane/request_auth.dart | 188 ++++++++++-------- 1 file changed, 101 insertions(+), 87 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index b43e28f1f..8cb15f655 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -54,9 +54,11 @@ class EditAuthType extends ConsumerWidget { ); }).toList(), onChanged: (APIAuthType? newType) { + final selectedRequest = ref.read(selectedRequestModelProvider); if (newType != null) { ref.read(collectionStateNotifierProvider.notifier).update( - authData: currentAuthData?.copyWith(type: newType) ?? + authData: selectedRequest?.authData + ?.copyWith(type: newType) ?? ApiAuthModel(type: newType), ); } @@ -75,7 +77,7 @@ class EditAuthType extends ConsumerWidget { WidgetRef ref, ApiAuthModel? authData, ) { - void updateAuth(ApiAuthModel model) { + void updateAuth(ApiAuthModel? model) { ref.read(collectionStateNotifierProvider.notifier).update( authData: model, ); @@ -114,15 +116,13 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onChanged: (value) => updateAuth( - ApiAuthModel( - type: APIAuthType.basic, - basic: AuthBasicAuthModel( - username: usernameController.text.trim(), - password: passwordController.text.trim(), - ), + onChanged: (value) => updateAuth(authData?.copyWith( + type: APIAuthType.basic, + basic: AuthBasicAuthModel( + username: usernameController.text.trim(), + password: passwordController.text.trim(), ), - ), + )), ), SizedBox( height: 16, @@ -151,7 +151,7 @@ class EditAuthType extends ConsumerWidget { ), obscureText: true, onChanged: (value) => updateAuth( - ApiAuthModel( + authData?.copyWith( type: APIAuthType.basic, basic: AuthBasicAuthModel( username: usernameController.text.trim(), @@ -193,7 +193,7 @@ class EditAuthType extends ConsumerWidget { ), ), onChanged: (value) => updateAuth( - ApiAuthModel( + authData?.copyWith( type: APIAuthType.bearer, bearer: AuthBearerModel(token: tokenController.text.trim()), ), @@ -246,14 +246,16 @@ class EditAuthType extends ConsumerWidget { ], onChanged: (String? newLocation) { if (newLocation != null) { - updateAuth(ApiAuthModel( - type: APIAuthType.apiKey, - apikey: AuthApiKeyModel( - key: keyController.text, - name: nameController.text, - location: newLocation, + updateAuth( + authData?.copyWith( + type: APIAuthType.apiKey, + apikey: AuthApiKeyModel( + key: keyController.text, + name: nameController.text, + location: newLocation, + ), ), - )); + ); } }, ), @@ -281,7 +283,7 @@ class EditAuthType extends ConsumerWidget { ), ), onChanged: (value) => updateAuth( - ApiAuthModel( + authData?.copyWith( type: APIAuthType.apiKey, apikey: AuthApiKeyModel( key: keyController.text, @@ -314,14 +316,16 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onChanged: (value) => updateAuth(ApiAuthModel( - type: APIAuthType.apiKey, - apikey: AuthApiKeyModel( - key: keyController.text.trim(), - name: nameController.text, - location: currentLocation, + onChanged: (value) => updateAuth( + authData?.copyWith( + type: APIAuthType.apiKey, + apikey: AuthApiKeyModel( + key: keyController.text.trim(), + name: nameController.text, + location: currentLocation, + ), ), - )), + ), ), ], ); @@ -381,19 +385,21 @@ class EditAuthType extends ConsumerWidget { ], onChanged: (String? newAddTokenTo) { if (newAddTokenTo != null) { - updateAuth(ApiAuthModel( - type: APIAuthType.jwt, - jwt: AuthJwtModel( - secret: jwtSecretController.text.trim(), - payload: jwtPayloadController.text.trim(), - addTokenTo: newAddTokenTo, - algorithm: currentAlgorithm, - isSecretBase64Encoded: isSecretBase64Encoded, - headerPrefix: jwtHeaderPrefixController.text.trim(), - queryParamKey: jwtQueryParamKeyController.text.trim(), - header: jwtHeaderController.text.trim(), + updateAuth( + authData?.copyWith( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: jwtSecretController.text.trim(), + payload: jwtPayloadController.text.trim(), + addTokenTo: newAddTokenTo, + algorithm: currentAlgorithm, + isSecretBase64Encoded: isSecretBase64Encoded, + headerPrefix: jwtHeaderPrefixController.text.trim(), + queryParamKey: jwtQueryParamKeyController.text.trim(), + header: jwtHeaderController.text.trim(), + ), ), - )); + ); } }, ), @@ -428,19 +434,21 @@ class EditAuthType extends ConsumerWidget { }).toList(), onChanged: (String? newAlgorithm) { if (newAlgorithm != null) { - updateAuth(ApiAuthModel( - type: APIAuthType.jwt, - jwt: AuthJwtModel( - secret: jwtSecretController.text.trim(), - payload: jwtPayloadController.text.trim(), - addTokenTo: currentAddTokenTo, - algorithm: newAlgorithm, - isSecretBase64Encoded: isSecretBase64Encoded, - headerPrefix: jwtHeaderPrefixController.text.trim(), - queryParamKey: jwtQueryParamKeyController.text.trim(), - header: jwtHeaderController.text.trim(), + updateAuth( + authData?.copyWith( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: jwtSecretController.text.trim(), + payload: jwtPayloadController.text.trim(), + addTokenTo: currentAddTokenTo, + algorithm: newAlgorithm, + isSecretBase64Encoded: isSecretBase64Encoded, + headerPrefix: jwtHeaderPrefixController.text.trim(), + queryParamKey: jwtQueryParamKeyController.text.trim(), + header: jwtHeaderController.text.trim(), + ), ), - )); + ); } }, ), @@ -465,19 +473,21 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onChanged: (value) => updateAuth(ApiAuthModel( - type: APIAuthType.jwt, - jwt: AuthJwtModel( - secret: jwtSecretController.text.trim(), - payload: jwtPayloadController.text.trim(), - addTokenTo: currentAddTokenTo, - algorithm: currentAlgorithm, - isSecretBase64Encoded: isSecretBase64Encoded, - headerPrefix: jwtHeaderPrefixController.text.trim(), - queryParamKey: jwtQueryParamKeyController.text.trim(), - header: jwtHeaderController.text.trim(), + onChanged: (value) => updateAuth( + authData?.copyWith( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: jwtSecretController.text.trim(), + payload: jwtPayloadController.text.trim(), + addTokenTo: currentAddTokenTo, + algorithm: currentAlgorithm, + isSecretBase64Encoded: isSecretBase64Encoded, + headerPrefix: jwtHeaderPrefixController.text.trim(), + queryParamKey: jwtQueryParamKeyController.text.trim(), + header: jwtHeaderController.text.trim(), + ), ), - )), + ), ), const SizedBox(height: 16), CheckboxListTile( @@ -491,19 +501,21 @@ class EditAuthType extends ConsumerWidget { contentPadding: EdgeInsets.zero, controlAffinity: ListTileControlAffinity.leading, onChanged: (bool? value) { - updateAuth(ApiAuthModel( - type: APIAuthType.jwt, - jwt: AuthJwtModel( - secret: jwtSecretController.text.trim(), - payload: jwtPayloadController.text.trim(), - addTokenTo: currentAddTokenTo, - algorithm: currentAlgorithm, - isSecretBase64Encoded: value ?? false, - headerPrefix: jwtHeaderPrefixController.text.trim(), - queryParamKey: jwtQueryParamKeyController.text.trim(), - header: jwtHeaderController.text.trim(), + updateAuth( + authData?.copyWith( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: jwtSecretController.text.trim(), + payload: jwtPayloadController.text.trim(), + addTokenTo: currentAddTokenTo, + algorithm: currentAlgorithm, + isSecretBase64Encoded: value ?? false, + headerPrefix: jwtHeaderPrefixController.text.trim(), + queryParamKey: jwtQueryParamKeyController.text.trim(), + header: jwtHeaderController.text.trim(), + ), ), - )); + ); }, ), const SizedBox(height: 16), @@ -529,19 +541,21 @@ class EditAuthType extends ConsumerWidget { borderRadius: BorderRadius.circular(8), ), ), - onChanged: (value) => updateAuth(ApiAuthModel( - type: APIAuthType.jwt, - jwt: AuthJwtModel( - secret: jwtSecretController.text.trim(), - payload: jwtPayloadController.text.trim(), - addTokenTo: currentAddTokenTo, - algorithm: currentAlgorithm, - isSecretBase64Encoded: isSecretBase64Encoded, - headerPrefix: jwtHeaderPrefixController.text.trim(), - queryParamKey: jwtQueryParamKeyController.text.trim(), - header: jwtHeaderController.text.trim(), + onChanged: (value) => updateAuth( + authData?.copyWith( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: jwtSecretController.text.trim(), + payload: jwtPayloadController.text.trim(), + addTokenTo: currentAddTokenTo, + algorithm: currentAlgorithm, + isSecretBase64Encoded: isSecretBase64Encoded, + headerPrefix: jwtHeaderPrefixController.text.trim(), + queryParamKey: jwtQueryParamKeyController.text.trim(), + header: jwtHeaderController.text.trim(), + ), ), - )), + ), ), // const SizedBox(height: 16), // if (currentAddTokenTo == 'header') ...[ From 88017a96b0b8f6d9c99a396f9a7d8c0ef74e8db1 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sun, 15 Jun 2025 16:51:50 +0530 Subject: [PATCH 10/70] chore: generate lock files --- .../json_field_editor/example/pubspec.lock | 24 +- .../example/pubspec.lock | 40 +-- pubspec.lock | 240 +++++++++--------- 3 files changed, 152 insertions(+), 152 deletions(-) diff --git a/packages/json_field_editor/example/pubspec.lock b/packages/json_field_editor/example/pubspec.lock index 19d456fd7..ccfa627cd 100644 --- a/packages/json_field_editor/example/pubspec.lock +++ b/packages/json_field_editor/example/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.13.0" boolean_selector: dependency: transitive description: @@ -45,10 +45,10 @@ packages: dependency: "direct main" description: name: cupertino_icons - sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 url: "https://pub.dev" source: hosted - version: "1.0.6" + version: "1.0.8" extended_text_field: dependency: transitive description: @@ -61,18 +61,18 @@ packages: dependency: transitive description: name: extended_text_library - sha256: "55d09098ec56fab0d9a8a68950ca0bbf2efa1327937f7cec6af6dfa066234829" + sha256: "13d99f8a10ead472d5e2cf4770d3d047203fe5054b152e9eb5dc692a71befbba" url: "https://pub.dev" source: hosted - version: "12.0.0" + version: "12.0.1" fake_async: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.3" flutter: dependency: "direct main" description: flutter @@ -102,10 +102,10 @@ packages: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "10.0.9" leak_tracker_flutter_testing: dependency: transitive description: @@ -227,10 +227,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "15.0.0" sdks: dart: ">=3.7.0-0 <4.0.0" flutter: ">=3.24.0" diff --git a/packages/multi_trigger_autocomplete_plus/example/pubspec.lock b/packages/multi_trigger_autocomplete_plus/example/pubspec.lock index 5bfc05a8b..c3af53252 100644 --- a/packages/multi_trigger_autocomplete_plus/example/pubspec.lock +++ b/packages/multi_trigger_autocomplete_plus/example/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.13.0" boolean_selector: dependency: transitive description: @@ -61,18 +61,18 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.3" ffi: dependency: transitive description: name: ffi - sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" flutter: dependency: "direct main" description: flutter @@ -119,26 +119,26 @@ packages: dependency: transitive description: name: http - sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f + sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" http_parser: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "10.0.9" leak_tracker_flutter_testing: dependency: transitive description: @@ -214,10 +214,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2" + sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 url: "https://pub.dev" source: hosted - version: "2.2.15" + version: "2.2.17" path_provider_foundation: dependency: transitive description: @@ -339,18 +339,18 @@ packages: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "15.0.0" web: dependency: transitive description: name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" xdg_directories: dependency: transitive description: @@ -360,5 +360,5 @@ packages: source: hosted version: "1.1.0" sdks: - dart: ">=3.7.0-0 <4.0.0" - flutter: ">=3.24.0" + dart: ">=3.7.0 <4.0.0" + flutter: ">=3.27.0" diff --git a/pubspec.lock b/pubspec.lock index 69e0c77d2..66394a8de 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: dc27559385e905ad30838356c5f5d574014ba39872d732111cd07ac0beff4c57 + sha256: e55636ed79578b9abca5fecf9437947798f5ef7456308b5cb85720b793eac92f url: "https://pub.dev" source: hosted - version: "80.0.0" + version: "82.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "192d1c5b944e7e53b24b5586db760db934b177d4147c42fbca8c8c5f1eb8d11e" + sha256: "904ae5bb474d32c38fb9482e2d925d5454cda04ddd0e55d2e6826bc72f6ba8c0" url: "https://pub.dev" source: hosted - version: "7.3.0" + version: "7.4.5" ansi_styles: dependency: transitive description: @@ -51,26 +51,26 @@ packages: dependency: transitive description: name: archive - sha256: "528579c7e4579719f04b21eeeeddfd73a18b31dabc22766893b7d1be7f49b967" + sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" url: "https://pub.dev" source: hosted - version: "4.0.3" + version: "4.0.7" args: dependency: transitive description: name: args - sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.7.0" async: dependency: transitive description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.13.0" audio_session: dependency: transitive description: @@ -106,10 +106,10 @@ packages: dependency: transitive description: name: bidi - sha256: "9a712c7ddf708f7c41b1923aa83648a3ed44cfd75b04f72d598c45e5be287f9d" + sha256: "77f475165e94b261745cf1032c751e2032b8ed92ccb2bf5716036db79320637d" url: "https://pub.dev" source: hosted - version: "2.0.12" + version: "2.0.13" binary_codec: dependency: transitive description: @@ -186,18 +186,18 @@ packages: dependency: transitive description: name: built_value - sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61" + sha256: "082001b5c3dc495d4a42f1d5789990505df20d8547d42507c29050af6933ee27" url: "https://pub.dev" source: hosted - version: "8.9.4" + version: "8.10.1" carousel_slider: dependency: "direct main" description: name: carousel_slider - sha256: "7b006ec356205054af5beaef62e2221160ea36b90fb70a35e4deacd49d0349ae" + sha256: bcc61735345c9ab5cb81073896579e735f81e35fd588907a393143ea986be8ff url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "5.1.1" characters: dependency: transitive description: @@ -218,10 +218,10 @@ packages: dependency: transitive description: name: checked_yaml - sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.0.4" checks: dependency: transitive description: @@ -238,6 +238,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.0" + cli_config: + dependency: transitive + description: + name: cli_config + sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec + url: "https://pub.dev" + source: hosted + version: "0.2.0" cli_launcher: dependency: transitive description: @@ -282,10 +290,10 @@ packages: dependency: transitive description: name: conventional_commit - sha256: dec15ad1118f029c618651a4359eb9135d8b88f761aa24e4016d061cd45948f2 + sha256: c40b1b449ce2a63fa2ce852f35e3890b1e182f5951819934c0e4a66254bc0dc3 url: "https://pub.dev" source: hosted - version: "0.6.0+1" + version: "0.6.1+1" convert: dependency: transitive description: @@ -298,10 +306,10 @@ packages: dependency: transitive description: name: coverage - sha256: e3493833ea012784c740e341952298f1cc77f1f01b1bbc3eb4eecf6984fb7f43 + sha256: aa07dbe5f2294c827b7edb9a87bba44a9c15a3cc81bc8da2ca19b37322d30080 url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.14.1" cross_file: dependency: transitive description: @@ -345,10 +353,10 @@ packages: dependency: "direct main" description: name: dart_style - sha256: "27eb0ae77836989a3bc541ce55595e8ceee0992807f14511552a898ddd0d88ac" + sha256: "5b236382b47ee411741447c1f1e111459c941ea1b3f2b540dde54c210a3662af" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.1.0" dartx: dependency: transitive description: @@ -409,26 +417,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.2" - fetch_api: - dependency: transitive - description: - name: fetch_api - sha256: "97f46c25b480aad74f7cc2ad7ccba2c5c6f08d008e68f95c1077286ce243d0e6" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - fetch_client: - dependency: transitive - description: - name: fetch_client - sha256: "9666ee14536778474072245ed5cba07db81ae8eb5de3b7bf4a2d1e2c49696092" - url: "https://pub.dev" - source: hosted - version: "1.1.2" + version: "1.3.3" ffi: dependency: transitive description: @@ -457,10 +449,10 @@ packages: dependency: transitive description: name: file_selector_android - sha256: "98ac58e878b05ea2fdb204e7f4fc4978d90406c9881874f901428e01d3b18fbc" + sha256: "6bba3d590ee9462758879741abc132a19133600dd31832f55627442f1ebd7b54" url: "https://pub.dev" source: hosted - version: "0.5.1+12" + version: "0.5.1+14" file_selector_ios: dependency: transitive description: @@ -481,10 +473,10 @@ packages: dependency: transitive description: name: file_selector_macos - sha256: "271ab9986df0c135d45c3cdb6bd0faa5db6f4976d3e4b437cf7d0f258d941bfc" + sha256: "8c9250b2bd2d8d4268e39c82543bacbaca0fda7d29e0728c3c4bbb7c820fd711" url: "https://pub.dev" source: hosted - version: "0.9.4+2" + version: "0.9.4+3" file_selector_platform_interface: dependency: transitive description: @@ -587,10 +579,10 @@ packages: dependency: "direct dev" description: name: flutter_launcher_icons - sha256: bfa04787c85d80ecb3f8777bde5fc10c3de809240c48fa061a2c2bf15ea5211c + sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7" url: "https://pub.dev" source: hosted - version: "0.14.3" + version: "0.14.4" flutter_lints: dependency: "direct dev" description: @@ -603,18 +595,18 @@ packages: dependency: "direct main" description: name: flutter_markdown - sha256: e7bbc718adc9476aa14cfddc1ef048d2e21e4e8f18311aaac723266db9f9e7b5 + sha256: "08fb8315236099ff8e90cb87bb2b935e0a724a3af1623000a9cec930468e0f27" url: "https://pub.dev" source: hosted - version: "0.7.6+2" + version: "0.7.7+1" flutter_native_splash: dependency: "direct dev" description: name: flutter_native_splash - sha256: edb09c35ee9230c4b03f13dd45bb3a276d0801865f0a4650b7e2a3bba61a803a + sha256: "8321a6d11a8d13977fa780c89de8d257cce3d841eecfb7a4cadffcc4f12d82dc" url: "https://pub.dev" source: hosted - version: "2.4.5" + version: "2.4.6" flutter_portal: dependency: "direct main" description: @@ -635,10 +627,10 @@ packages: dependency: "direct main" description: name: flutter_svg - sha256: c200fd79c918a40c5cd50ea0877fa13f81bdaf6f0a5d3dbcc2a13e3285d6aa1b + sha256: d44bf546b13025ec7353091516f6881f1d4c633993cb109c3916c3a0159dadf1 url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.1.0" flutter_test: dependency: "direct dev" description: flutter @@ -769,10 +761,10 @@ packages: dependency: transitive description: name: html - sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" + sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" url: "https://pub.dev" source: hosted - version: "0.15.5" + version: "0.15.6" html_unescape: dependency: transitive description: @@ -785,10 +777,10 @@ packages: dependency: transitive description: name: http - sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f + sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" http_multi_server: dependency: transitive description: @@ -809,10 +801,10 @@ packages: dependency: transitive description: name: image - sha256: "13d3349ace88f12f4a0d175eb5c12dcdd39d35c4c109a8a13dfeb6d0bd9e31c3" + sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928" url: "https://pub.dev" source: hosted - version: "4.5.3" + version: "4.5.4" insomnia_collection: dependency: transitive description: @@ -853,10 +845,10 @@ packages: dependency: "direct main" description: name: jinja - sha256: "157a05d22c1b60aaf21e3e9f0b26ec27315cd2892f7ac9571e9478eb0d5d62f9" + sha256: e0e14bb04cde45f944d61140612ee9368cfcd890e3ca65573316b7c6ce51c635 url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.6.2" js: dependency: transitive description: @@ -899,10 +891,10 @@ packages: dependency: "direct dev" description: name: json_serializable - sha256: "81f04dee10969f89f604e1249382d46b97a1ccad53872875369622b5bfc9e58a" + sha256: c50ef5fc083d5b5e12eef489503ba3bf5ccc899e487d691584699b4bdefeea8c url: "https://pub.dev" source: hosted - version: "6.9.4" + version: "6.9.5" just_audio: dependency: "direct main" description: @@ -923,18 +915,18 @@ packages: dependency: transitive description: name: just_audio_platform_interface - sha256: "271b93b484c6f494ecd72a107fffbdb26b425f170c665b9777a0a24a726f2f24" + sha256: "4cd94536af0219fa306205a58e78d67e02b0555283c1c094ee41e402a14a5c4a" url: "https://pub.dev" source: hosted - version: "4.4.0" + version: "4.5.0" just_audio_web: dependency: transitive description: name: just_audio_web - sha256: "58915be64509a7683c44bf11cd1a23c15a48de104927bee116e3c63c8eeea0d4" + sha256: "6ba8a2a7e87d57d32f0f7b42856ade3d6a9fbe0f1a11fabae0a4f00bb73f0663" url: "https://pub.dev" source: hosted - version: "0.4.14" + version: "0.4.16" just_audio_windows: dependency: "direct main" description: @@ -947,10 +939,10 @@ packages: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "10.0.9" leak_tracker_flutter_testing: dependency: transitive description: @@ -1027,10 +1019,10 @@ packages: dependency: "direct dev" description: name: melos - sha256: "3f3ab3f902843d1e5a1b1a4dd39a4aca8ba1056f2d32fd8995210fa2843f646f" + sha256: "4280dc46bd5b741887cce1e67e5c1a6aaf3c22310035cf5bd33dceeeda62ed22" url: "https://pub.dev" source: hosted - version: "6.3.2" + version: "6.3.3" meta: dependency: transitive description: @@ -1122,18 +1114,18 @@ packages: dependency: "direct main" description: name: ollama_dart - sha256: "4e40bc499b6fe46ba54a004d2da601c40bd73d66e3f18cf7b03225ccf3d481a6" + sha256: c5c8656aa42e109b5a3e58a9b92661adc8204a5a1c312644c4b448ac2d413b95 url: "https://pub.dev" source: hosted - version: "0.2.2+1" + version: "0.2.3" package_config: dependency: transitive description: name: package_config - sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67" + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.2.0" package_info_plus: dependency: "direct main" description: @@ -1178,10 +1170,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2" + sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 url: "https://pub.dev" source: hosted - version: "2.2.15" + version: "2.2.17" path_provider_foundation: dependency: transitive description: @@ -1266,10 +1258,10 @@ packages: dependency: transitive description: name: posix - sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a + sha256: f0d7856b6ca1887cfa6d1d394056a296ae33489db914e365e2044fdada449e62 url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "6.0.2" postman: dependency: transitive description: @@ -1305,26 +1297,26 @@ packages: dependency: "direct main" description: name: provider - sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" url: "https://pub.dev" source: hosted - version: "6.1.2" + version: "6.1.5" pub_semver: dependency: "direct main" description: name: pub_semver - sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.2.0" pub_updater: dependency: transitive description: name: pub_updater - sha256: "54e8dc865349059ebe7f163d6acce7c89eb958b8047e6d6e80ce93b13d7c9e60" + sha256: "739a0161d73a6974c0675b864fb0cf5147305f7b077b7f03a58fa7a9ab3e7e7d" url: "https://pub.dev" source: hosted - version: "0.4.0" + version: "0.5.0" pubspec_parse: dependency: transitive description: @@ -1433,18 +1425,18 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a" + sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" url: "https://pub.dev" source: hosted - version: "2.5.2" + version: "2.5.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22 + sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac" url: "https://pub.dev" source: hosted - version: "2.4.6" + version: "2.4.10" shared_preferences_foundation: dependency: transitive description: @@ -1650,6 +1642,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.1" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "0669c70faae6270521ee4f05bffd2919892d42d1276e6c495be80174b6bc0ef6" + url: "https://pub.dev" + source: hosted + version: "3.3.1" term_glyph: dependency: transitive description: @@ -1742,18 +1742,18 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193" + sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79" url: "https://pub.dev" source: hosted - version: "6.3.14" + version: "6.3.16" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626" + sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" url: "https://pub.dev" source: hosted - version: "6.3.2" + version: "6.3.3" url_launcher_linux: dependency: transitive description: @@ -1782,10 +1782,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9" + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" url_launcher_windows: dependency: transitive description: @@ -1806,10 +1806,10 @@ packages: dependency: transitive description: name: vector_graphics - sha256: "44cc7104ff32563122a929e4620cf3efd584194eec6d1d913eb5ba593dbcf6de" + sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 url: "https://pub.dev" source: hosted - version: "1.1.18" + version: "1.1.19" vector_graphics_codec: dependency: transitive description: @@ -1822,10 +1822,10 @@ packages: dependency: "direct main" description: name: vector_graphics_compiler - sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad" + sha256: "557a315b7d2a6dbb0aaaff84d857967ce6bdc96a63dc6ee2a57ce5a6ee5d3331" url: "https://pub.dev" source: hosted - version: "1.1.16" + version: "1.1.17" vector_math: dependency: transitive description: @@ -1838,26 +1838,26 @@ packages: dependency: "direct main" description: name: video_player - sha256: "48941c8b05732f9582116b1c01850b74dbee1d8520cd7e34ad4609d6df666845" + sha256: "0d55b1f1a31e5ad4c4967bfaa8ade0240b07d20ee4af1dfef5f531056512961a" url: "https://pub.dev" source: hosted - version: "2.9.3" + version: "2.10.0" video_player_android: dependency: transitive description: name: video_player_android - sha256: "7018dbcb395e2bca0b9a898e73989e67c0c4a5db269528e1b036ca38bcca0d0b" + sha256: "4a5135754a62dbc827a64a42ef1f8ed72c962e191c97e2d48744225c2b9ebb73" url: "https://pub.dev" source: hosted - version: "2.7.17" + version: "2.8.7" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - sha256: "84b4752745eeccb6e75865c9aab39b3d28eb27ba5726d352d45db8297fbd75bc" + sha256: "9ee764e5cd2fc1e10911ae8ad588e1a19db3b6aa9a6eb53c127c42d3a3c3f22f" url: "https://pub.dev" source: hosted - version: "2.7.0" + version: "2.7.1" video_player_platform_interface: dependency: "direct main" description: @@ -1870,26 +1870,26 @@ packages: dependency: transitive description: name: video_player_web - sha256: "3ef40ea6d72434edbfdba4624b90fd3a80a0740d260667d91e7ecd2d79e13476" + sha256: e8bba2e5d1e159d5048c9a491bb2a7b29c535c612bb7d10c1e21107f5bd365ba url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.5" vm_service: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "15.0.0" watcher: dependency: transitive description: name: watcher - sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" + sha256: "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" web: dependency: "direct overridden" description: @@ -1902,26 +1902,26 @@ packages: dependency: transitive description: name: web_socket - sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" url: "https://pub.dev" source: hosted - version: "0.1.6" + version: "1.0.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5" + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" webdriver: dependency: transitive description: name: webdriver - sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.1.0" webkit_inspection_protocol: dependency: transitive description: @@ -1934,10 +1934,10 @@ packages: dependency: transitive description: name: win32 - sha256: b89e6e24d1454e149ab20fbb225af58660f0c0bf4475544650700d8e2da54aef + sha256: "66814138c3562338d05613a6e368ed8cfb237ad6d64a9e9334be3f309acfca03" url: "https://pub.dev" source: hosted - version: "5.11.0" + version: "5.14.0" window_manager: dependency: "direct main" description: From 0d7f1a9d5bf8ff4ee1bad1fccfd4c5cda43969af Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sun, 15 Jun 2025 17:18:57 +0530 Subject: [PATCH 11/70] fix: update authorization label and reorder request pane --- lib/consts.dart | 2 +- .../details_card/request_pane/request_pane_rest.dart | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/consts.dart b/lib/consts.dart index 88084406b..c5a829d09 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -448,7 +448,7 @@ const kLabelURLParams = "Params"; const kLabelHeaders = "Headers"; const kLabelBody = "Body"; const kLabelScripts = "Scripts"; -const kLabelAuth = "Authorization"; +const kLabelAuth = "Auth"; const kLabelQuery = "Query"; const kNameCheckbox = "Checkbox"; const kNameURLParam = "URL Parameter"; diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart index 343850b2f..22d9275fa 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart @@ -47,18 +47,23 @@ class EditRestRequestPane extends ConsumerWidget { .read(collectionStateNotifierProvider.notifier) .update(requestTabIndex: index); }, - showIndicators: [paramLength > 0, headerLength > 0, hasBody, hasAuth], + showIndicators: [ + paramLength > 0, + hasAuth, + headerLength > 0, + hasBody, + ], tabLabels: const [ kLabelURLParams, + kLabelAuth, kLabelHeaders, kLabelBody, - kLabelAuth, ], children: const [ EditRequestURLParams(), + EditAuthType(), EditRequestHeaders(), EditRequestBody(), - EditAuthType(), ], ); } From fd92206ccb7320874aaeab79c10d603c69fade85 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sun, 15 Jun 2025 22:01:36 +0530 Subject: [PATCH 12/70] refactor: reorganize import statements --- .../details_card/request_pane/request_auth.dart | 4 ---- .../details_card/request_pane/request_pane_rest.dart | 3 +-- packages/apidash_core/lib/models/auth/api_auth_model.dart | 8 ++++---- packages/apidash_core/lib/models/models.dart | 4 ++++ 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index 8cb15f655..5b73b8ca6 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -1,7 +1,3 @@ -import 'package:apidash_core/models/auth/auth_api_key_model.dart'; -import 'package:apidash_core/models/auth/auth_basic_model.dart'; -import 'package:apidash_core/models/auth/auth_bearer_model.dart'; -import 'package:apidash_core/models/auth/auth_jwt_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash_core/apidash_core.dart'; diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart index 22d9275fa..0dc8b2178 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart @@ -1,5 +1,4 @@ import 'package:apidash/consts.dart'; -import 'package:apidash/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -8,7 +7,7 @@ import 'package:apidash/widgets/widgets.dart'; import 'request_headers.dart'; import 'request_params.dart'; import 'request_body.dart'; -import 'request_scripts.dart'; +import 'request_auth.dart'; class EditRestRequestPane extends ConsumerWidget { const EditRestRequestPane({super.key}); diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.dart b/packages/apidash_core/lib/models/auth/api_auth_model.dart index c1ddb01c9..580e3122f 100644 --- a/packages/apidash_core/lib/models/auth/api_auth_model.dart +++ b/packages/apidash_core/lib/models/auth/api_auth_model.dart @@ -1,9 +1,9 @@ -import 'package:apidash_core/models/auth/auth_api_key_model.dart'; -import 'package:apidash_core/models/auth/auth_basic_model.dart'; -import 'package:apidash_core/models/auth/auth_bearer_model.dart'; -import 'package:apidash_core/models/auth/auth_jwt_model.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import '../../consts.dart'; +import 'auth_api_key_model.dart'; +import 'auth_basic_model.dart'; +import 'auth_bearer_model.dart'; +import 'auth_jwt_model.dart'; part 'api_auth_model.g.dart'; part 'api_auth_model.freezed.dart'; diff --git a/packages/apidash_core/lib/models/models.dart b/packages/apidash_core/lib/models/models.dart index 86ef78da9..4b84832f7 100644 --- a/packages/apidash_core/lib/models/models.dart +++ b/packages/apidash_core/lib/models/models.dart @@ -2,3 +2,7 @@ export 'environment_model.dart'; export 'http_request_model.dart'; export 'http_response_model.dart'; export 'auth/api_auth_model.dart'; +export 'auth/auth_api_key_model.dart'; +export 'auth/auth_basic_model.dart'; +export 'auth/auth_bearer_model.dart'; +export 'auth/auth_jwt_model.dart'; From d046d50273fc51d5a5ac9aa6abfd6ae53fd88e1b Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sun, 15 Jun 2025 22:10:38 +0530 Subject: [PATCH 13/70] refactor: rename ApiAuthModel to AuthModel and authData to authModel --- lib/models/request_model.dart | 3 +- lib/models/request_model.freezed.dart | 54 +++++------ lib/models/request_model.g.dart | 10 +- .../request_pane/request_auth.dart | 12 +-- .../request_pane/request_pane_rest.dart | 2 +- .../lib/models/auth/api_auth_model.dart | 10 +- .../models/auth/api_auth_model.freezed.dart | 93 +++++++++---------- .../lib/models/auth/api_auth_model.g.dart | 6 +- .../apidash_core/lib/utils/handle_auth.dart | 2 +- .../lib/services/http_service.dart | 2 +- 10 files changed, 96 insertions(+), 98 deletions(-) diff --git a/lib/models/request_model.dart b/lib/models/request_model.dart index 2702a5467..a3eda0ba6 100644 --- a/lib/models/request_model.dart +++ b/lib/models/request_model.dart @@ -1,5 +1,4 @@ import 'package:apidash_core/apidash_core.dart'; -import 'package:apidash_core/models/auth/api_auth_model.dart'; part 'request_model.freezed.dart'; @@ -16,7 +15,7 @@ class RequestModel with _$RequestModel { @Default(APIType.rest) APIType apiType, @Default("") String name, @Default("") String description, - @Default(ApiAuthModel(type: APIAuthType.none)) ApiAuthModel? authData, + @Default(AuthModel(type: APIAuthType.none)) AuthModel? authModel, @JsonKey(includeToJson: false) @Default(0) requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, diff --git a/lib/models/request_model.freezed.dart b/lib/models/request_model.freezed.dart index da973b64c..392c34f8a 100644 --- a/lib/models/request_model.freezed.dart +++ b/lib/models/request_model.freezed.dart @@ -24,7 +24,7 @@ mixin _$RequestModel { APIType get apiType => throw _privateConstructorUsedError; String get name => throw _privateConstructorUsedError; String get description => throw _privateConstructorUsedError; - ApiAuthModel? get authData => throw _privateConstructorUsedError; + AuthModel? get authModel => throw _privateConstructorUsedError; @JsonKey(includeToJson: false) dynamic get requestTabIndex => throw _privateConstructorUsedError; HttpRequestModel? get httpRequestModel => throw _privateConstructorUsedError; @@ -60,7 +60,7 @@ abstract class $RequestModelCopyWith<$Res> { APIType apiType, String name, String description, - ApiAuthModel? authData, + AuthModel? authModel, @JsonKey(includeToJson: false) dynamic requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, @@ -71,7 +71,7 @@ abstract class $RequestModelCopyWith<$Res> { String? preRequestScript, String? postRequestScript}); - $ApiAuthModelCopyWith<$Res>? get authData; + $AuthModelCopyWith<$Res>? get authModel; $HttpRequestModelCopyWith<$Res>? get httpRequestModel; $HttpResponseModelCopyWith<$Res>? get httpResponseModel; } @@ -95,7 +95,7 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> Object? apiType = null, Object? name = null, Object? description = null, - Object? authData = freezed, + Object? authModel = freezed, Object? requestTabIndex = freezed, Object? httpRequestModel = freezed, Object? responseStatus = freezed, @@ -123,10 +123,10 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> ? _value.description : description // ignore: cast_nullable_to_non_nullable as String, - authData: freezed == authData - ? _value.authData - : authData // ignore: cast_nullable_to_non_nullable - as ApiAuthModel?, + authModel: freezed == authModel + ? _value.authModel + : authModel // ignore: cast_nullable_to_non_nullable + as AuthModel?, requestTabIndex: freezed == requestTabIndex ? _value.requestTabIndex : requestTabIndex // ignore: cast_nullable_to_non_nullable @@ -170,13 +170,13 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') - $ApiAuthModelCopyWith<$Res>? get authData { - if (_value.authData == null) { + $AuthModelCopyWith<$Res>? get authModel { + if (_value.authModel == null) { return null; } - return $ApiAuthModelCopyWith<$Res>(_value.authData!, (value) { - return _then(_value.copyWith(authData: value) as $Val); + return $AuthModelCopyWith<$Res>(_value.authModel!, (value) { + return _then(_value.copyWith(authModel: value) as $Val); }); } @@ -222,7 +222,7 @@ abstract class _$$RequestModelImplCopyWith<$Res> APIType apiType, String name, String description, - ApiAuthModel? authData, + AuthModel? authModel, @JsonKey(includeToJson: false) dynamic requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, @@ -234,7 +234,7 @@ abstract class _$$RequestModelImplCopyWith<$Res> String? postRequestScript}); @override - $ApiAuthModelCopyWith<$Res>? get authData; + $AuthModelCopyWith<$Res>? get authModel; @override $HttpRequestModelCopyWith<$Res>? get httpRequestModel; @override @@ -258,7 +258,7 @@ class __$$RequestModelImplCopyWithImpl<$Res> Object? apiType = null, Object? name = null, Object? description = null, - Object? authData = freezed, + Object? authModel = freezed, Object? requestTabIndex = freezed, Object? httpRequestModel = freezed, Object? responseStatus = freezed, @@ -286,10 +286,10 @@ class __$$RequestModelImplCopyWithImpl<$Res> ? _value.description : description // ignore: cast_nullable_to_non_nullable as String, - authData: freezed == authData - ? _value.authData - : authData // ignore: cast_nullable_to_non_nullable - as ApiAuthModel?, + authModel: freezed == authModel + ? _value.authModel + : authModel // ignore: cast_nullable_to_non_nullable + as AuthModel?, requestTabIndex: freezed == requestTabIndex ? _value.requestTabIndex! : requestTabIndex, @@ -338,7 +338,7 @@ class _$RequestModelImpl implements _RequestModel { this.apiType = APIType.rest, this.name = "", this.description = "", - this.authData = const ApiAuthModel(type: APIAuthType.none), + this.authModel = const AuthModel(type: APIAuthType.none), @JsonKey(includeToJson: false) this.requestTabIndex = 0, this.httpRequestModel, this.responseStatus, @@ -365,7 +365,7 @@ class _$RequestModelImpl implements _RequestModel { final String description; @override @JsonKey() - final ApiAuthModel? authData; + final AuthModel? authModel; @override @JsonKey(includeToJson: false) final dynamic requestTabIndex; @@ -390,7 +390,7 @@ class _$RequestModelImpl implements _RequestModel { @override String toString() { - return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, authData: $authData, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime)'; + return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, authModel: $authModel, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime)'; } @override @@ -403,8 +403,8 @@ class _$RequestModelImpl implements _RequestModel { (identical(other.name, name) || other.name == name) && (identical(other.description, description) || other.description == description) && - (identical(other.authData, authData) || - other.authData == authData) && + (identical(other.authModel, authModel) || + other.authModel == authModel) && const DeepCollectionEquality() .equals(other.requestTabIndex, requestTabIndex) && (identical(other.httpRequestModel, httpRequestModel) || @@ -432,7 +432,7 @@ class _$RequestModelImpl implements _RequestModel { apiType, name, description, - authData, + authModel, const DeepCollectionEquality().hash(requestTabIndex), httpRequestModel, responseStatus, @@ -465,7 +465,7 @@ abstract class _RequestModel implements RequestModel { final APIType apiType, final String name, final String description, - final ApiAuthModel? authData, + final AuthModel? authModel, @JsonKey(includeToJson: false) final dynamic requestTabIndex, final HttpRequestModel? httpRequestModel, final int? responseStatus, @@ -487,7 +487,7 @@ abstract class _RequestModel implements RequestModel { @override String get description; @override - ApiAuthModel? get authData; + AuthModel? get authModel; @override @JsonKey(includeToJson: false) dynamic get requestTabIndex; diff --git a/lib/models/request_model.g.dart b/lib/models/request_model.g.dart index 6b01848a0..6c6337262 100644 --- a/lib/models/request_model.g.dart +++ b/lib/models/request_model.g.dart @@ -12,10 +12,10 @@ _$RequestModelImpl _$$RequestModelImplFromJson(Map json) => _$RequestModelImpl( APIType.rest, name: json['name'] as String? ?? "", description: json['description'] as String? ?? "", - authData: json['authData'] == null - ? const ApiAuthModel(type: APIAuthType.none) - : ApiAuthModel.fromJson( - Map.from(json['authData'] as Map)), + authModel: json['authModel'] == null + ? const AuthModel(type: APIAuthType.none) + : AuthModel.fromJson( + Map.from(json['authModel'] as Map)), requestTabIndex: json['requestTabIndex'] ?? 0, httpRequestModel: json['httpRequestModel'] == null ? null @@ -41,7 +41,7 @@ Map _$$RequestModelImplToJson(_$RequestModelImpl instance) => 'apiType': _$APITypeEnumMap[instance.apiType]!, 'name': instance.name, 'description': instance.description, - 'authData': instance.authData?.toJson(), + 'authModel': instance.authModel?.toJson(), 'httpRequestModel': instance.httpRequestModel?.toJson(), 'responseStatus': instance.responseStatus, 'message': instance.message, diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index 5b73b8ca6..644c7b740 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -16,9 +16,9 @@ class EditAuthType extends ConsumerWidget { final currentAuthType = ref.watch( selectedRequestModelProvider - .select((request) => request?.authData?.type ?? APIAuthType.none), + .select((request) => request?.authModel?.type ?? APIAuthType.none), ); - final currentAuthData = selectedRequest.authData; + final currentAuthData = selectedRequest.authModel; return SingleChildScrollView( child: Padding( @@ -53,9 +53,9 @@ class EditAuthType extends ConsumerWidget { final selectedRequest = ref.read(selectedRequestModelProvider); if (newType != null) { ref.read(collectionStateNotifierProvider.notifier).update( - authData: selectedRequest?.authData + authData: selectedRequest?.authModel ?.copyWith(type: newType) ?? - ApiAuthModel(type: newType), + AuthModel(type: newType), ); } }, @@ -71,9 +71,9 @@ class EditAuthType extends ConsumerWidget { Widget _buildAuthFields( BuildContext context, WidgetRef ref, - ApiAuthModel? authData, + AuthModel? authData, ) { - void updateAuth(ApiAuthModel? model) { + void updateAuth(AuthModel? model) { ref.read(collectionStateNotifierProvider.notifier).update( authData: model, ); diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart index 0dc8b2178..c3177e8ba 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart @@ -30,7 +30,7 @@ class EditRestRequestPane extends ConsumerWidget { false; final hasAuth = ref.watch(selectedRequestModelProvider - .select((value) => value?.authData?.type != APIAuthType.none)); + .select((value) => value?.authModel?.type != APIAuthType.none)); false; return RequestPane( diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.dart b/packages/apidash_core/lib/models/auth/api_auth_model.dart index 580e3122f..fc7d89252 100644 --- a/packages/apidash_core/lib/models/auth/api_auth_model.dart +++ b/packages/apidash_core/lib/models/auth/api_auth_model.dart @@ -9,15 +9,15 @@ part 'api_auth_model.g.dart'; part 'api_auth_model.freezed.dart'; @freezed -class ApiAuthModel with _$ApiAuthModel { - const factory ApiAuthModel({ +class AuthModel with _$AuthModel { + const factory AuthModel({ required APIAuthType type, AuthApiKeyModel? apikey, AuthBearerModel? bearer, AuthBasicAuthModel? basic, AuthJwtModel? jwt, - }) = _ApiAuthModel; + }) = _AuthModel; - factory ApiAuthModel.fromJson(Map json) => - _$ApiAuthModelFromJson(json); + factory AuthModel.fromJson(Map json) => + _$AuthModelFromJson(json); } diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart b/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart index b1bf48304..60e4872ef 100644 --- a/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart +++ b/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart @@ -14,33 +14,32 @@ T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); -ApiAuthModel _$ApiAuthModelFromJson(Map json) { - return _ApiAuthModel.fromJson(json); +AuthModel _$AuthModelFromJson(Map json) { + return _AuthModel.fromJson(json); } /// @nodoc -mixin _$ApiAuthModel { +mixin _$AuthModel { APIAuthType get type => throw _privateConstructorUsedError; AuthApiKeyModel? get apikey => throw _privateConstructorUsedError; AuthBearerModel? get bearer => throw _privateConstructorUsedError; AuthBasicAuthModel? get basic => throw _privateConstructorUsedError; AuthJwtModel? get jwt => throw _privateConstructorUsedError; - /// Serializes this ApiAuthModel to a JSON map. + /// Serializes this AuthModel to a JSON map. Map toJson() => throw _privateConstructorUsedError; - /// Create a copy of ApiAuthModel + /// Create a copy of AuthModel /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) - $ApiAuthModelCopyWith get copyWith => + $AuthModelCopyWith get copyWith => throw _privateConstructorUsedError; } /// @nodoc -abstract class $ApiAuthModelCopyWith<$Res> { - factory $ApiAuthModelCopyWith( - ApiAuthModel value, $Res Function(ApiAuthModel) then) = - _$ApiAuthModelCopyWithImpl<$Res, ApiAuthModel>; +abstract class $AuthModelCopyWith<$Res> { + factory $AuthModelCopyWith(AuthModel value, $Res Function(AuthModel) then) = + _$AuthModelCopyWithImpl<$Res, AuthModel>; @useResult $Res call( {APIAuthType type, @@ -56,16 +55,16 @@ abstract class $ApiAuthModelCopyWith<$Res> { } /// @nodoc -class _$ApiAuthModelCopyWithImpl<$Res, $Val extends ApiAuthModel> - implements $ApiAuthModelCopyWith<$Res> { - _$ApiAuthModelCopyWithImpl(this._value, this._then); +class _$AuthModelCopyWithImpl<$Res, $Val extends AuthModel> + implements $AuthModelCopyWith<$Res> { + _$AuthModelCopyWithImpl(this._value, this._then); // ignore: unused_field final $Val _value; // ignore: unused_field final $Res Function($Val) _then; - /// Create a copy of ApiAuthModel + /// Create a copy of AuthModel /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override @@ -100,7 +99,7 @@ class _$ApiAuthModelCopyWithImpl<$Res, $Val extends ApiAuthModel> ) as $Val); } - /// Create a copy of ApiAuthModel + /// Create a copy of AuthModel /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') @@ -114,7 +113,7 @@ class _$ApiAuthModelCopyWithImpl<$Res, $Val extends ApiAuthModel> }); } - /// Create a copy of ApiAuthModel + /// Create a copy of AuthModel /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') @@ -128,7 +127,7 @@ class _$ApiAuthModelCopyWithImpl<$Res, $Val extends ApiAuthModel> }); } - /// Create a copy of ApiAuthModel + /// Create a copy of AuthModel /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') @@ -142,7 +141,7 @@ class _$ApiAuthModelCopyWithImpl<$Res, $Val extends ApiAuthModel> }); } - /// Create a copy of ApiAuthModel + /// Create a copy of AuthModel /// with the given fields replaced by the non-null parameter values. @override @pragma('vm:prefer-inline') @@ -158,11 +157,11 @@ class _$ApiAuthModelCopyWithImpl<$Res, $Val extends ApiAuthModel> } /// @nodoc -abstract class _$$ApiAuthModelImplCopyWith<$Res> - implements $ApiAuthModelCopyWith<$Res> { - factory _$$ApiAuthModelImplCopyWith( - _$ApiAuthModelImpl value, $Res Function(_$ApiAuthModelImpl) then) = - __$$ApiAuthModelImplCopyWithImpl<$Res>; +abstract class _$$AuthModelImplCopyWith<$Res> + implements $AuthModelCopyWith<$Res> { + factory _$$AuthModelImplCopyWith( + _$AuthModelImpl value, $Res Function(_$AuthModelImpl) then) = + __$$AuthModelImplCopyWithImpl<$Res>; @override @useResult $Res call( @@ -183,14 +182,14 @@ abstract class _$$ApiAuthModelImplCopyWith<$Res> } /// @nodoc -class __$$ApiAuthModelImplCopyWithImpl<$Res> - extends _$ApiAuthModelCopyWithImpl<$Res, _$ApiAuthModelImpl> - implements _$$ApiAuthModelImplCopyWith<$Res> { - __$$ApiAuthModelImplCopyWithImpl( - _$ApiAuthModelImpl _value, $Res Function(_$ApiAuthModelImpl) _then) +class __$$AuthModelImplCopyWithImpl<$Res> + extends _$AuthModelCopyWithImpl<$Res, _$AuthModelImpl> + implements _$$AuthModelImplCopyWith<$Res> { + __$$AuthModelImplCopyWithImpl( + _$AuthModelImpl _value, $Res Function(_$AuthModelImpl) _then) : super(_value, _then); - /// Create a copy of ApiAuthModel + /// Create a copy of AuthModel /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override @@ -201,7 +200,7 @@ class __$$ApiAuthModelImplCopyWithImpl<$Res> Object? basic = freezed, Object? jwt = freezed, }) { - return _then(_$ApiAuthModelImpl( + return _then(_$AuthModelImpl( type: null == type ? _value.type : type // ignore: cast_nullable_to_non_nullable @@ -228,12 +227,12 @@ class __$$ApiAuthModelImplCopyWithImpl<$Res> /// @nodoc @JsonSerializable() -class _$ApiAuthModelImpl implements _ApiAuthModel { - const _$ApiAuthModelImpl( +class _$AuthModelImpl implements _AuthModel { + const _$AuthModelImpl( {required this.type, this.apikey, this.bearer, this.basic, this.jwt}); - factory _$ApiAuthModelImpl.fromJson(Map json) => - _$$ApiAuthModelImplFromJson(json); + factory _$AuthModelImpl.fromJson(Map json) => + _$$AuthModelImplFromJson(json); @override final APIAuthType type; @@ -248,14 +247,14 @@ class _$ApiAuthModelImpl implements _ApiAuthModel { @override String toString() { - return 'ApiAuthModel(type: $type, apikey: $apikey, bearer: $bearer, basic: $basic, jwt: $jwt)'; + return 'AuthModel(type: $type, apikey: $apikey, bearer: $bearer, basic: $basic, jwt: $jwt)'; } @override bool operator ==(Object other) { return identical(this, other) || (other.runtimeType == runtimeType && - other is _$ApiAuthModelImpl && + other is _$AuthModelImpl && (identical(other.type, type) || other.type == type) && (identical(other.apikey, apikey) || other.apikey == apikey) && (identical(other.bearer, bearer) || other.bearer == bearer) && @@ -268,32 +267,32 @@ class _$ApiAuthModelImpl implements _ApiAuthModel { int get hashCode => Object.hash(runtimeType, type, apikey, bearer, basic, jwt); - /// Create a copy of ApiAuthModel + /// Create a copy of AuthModel /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') - _$$ApiAuthModelImplCopyWith<_$ApiAuthModelImpl> get copyWith => - __$$ApiAuthModelImplCopyWithImpl<_$ApiAuthModelImpl>(this, _$identity); + _$$AuthModelImplCopyWith<_$AuthModelImpl> get copyWith => + __$$AuthModelImplCopyWithImpl<_$AuthModelImpl>(this, _$identity); @override Map toJson() { - return _$$ApiAuthModelImplToJson( + return _$$AuthModelImplToJson( this, ); } } -abstract class _ApiAuthModel implements ApiAuthModel { - const factory _ApiAuthModel( +abstract class _AuthModel implements AuthModel { + const factory _AuthModel( {required final APIAuthType type, final AuthApiKeyModel? apikey, final AuthBearerModel? bearer, final AuthBasicAuthModel? basic, - final AuthJwtModel? jwt}) = _$ApiAuthModelImpl; + final AuthJwtModel? jwt}) = _$AuthModelImpl; - factory _ApiAuthModel.fromJson(Map json) = - _$ApiAuthModelImpl.fromJson; + factory _AuthModel.fromJson(Map json) = + _$AuthModelImpl.fromJson; @override APIAuthType get type; @@ -306,10 +305,10 @@ abstract class _ApiAuthModel implements ApiAuthModel { @override AuthJwtModel? get jwt; - /// Create a copy of ApiAuthModel + /// Create a copy of AuthModel /// with the given fields replaced by the non-null parameter values. @override @JsonKey(includeFromJson: false, includeToJson: false) - _$$ApiAuthModelImplCopyWith<_$ApiAuthModelImpl> get copyWith => + _$$AuthModelImplCopyWith<_$AuthModelImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.g.dart b/packages/apidash_core/lib/models/auth/api_auth_model.g.dart index 96b37d895..96b5f69f7 100644 --- a/packages/apidash_core/lib/models/auth/api_auth_model.g.dart +++ b/packages/apidash_core/lib/models/auth/api_auth_model.g.dart @@ -6,8 +6,8 @@ part of 'api_auth_model.dart'; // JsonSerializableGenerator // ************************************************************************** -_$ApiAuthModelImpl _$$ApiAuthModelImplFromJson(Map json) => - _$ApiAuthModelImpl( +_$AuthModelImpl _$$AuthModelImplFromJson(Map json) => + _$AuthModelImpl( type: $enumDecode(_$APIAuthTypeEnumMap, json['type']), apikey: json['apikey'] == null ? null @@ -23,7 +23,7 @@ _$ApiAuthModelImpl _$$ApiAuthModelImplFromJson(Map json) => : AuthJwtModel.fromJson(json['jwt'] as Map), ); -Map _$$ApiAuthModelImplToJson(_$ApiAuthModelImpl instance) => +Map _$$AuthModelImplToJson(_$AuthModelImpl instance) => { 'type': _$APIAuthTypeEnumMap[instance.type]!, 'apikey': instance.apikey, diff --git a/packages/apidash_core/lib/utils/handle_auth.dart b/packages/apidash_core/lib/utils/handle_auth.dart index bad494f9d..f46c5db81 100644 --- a/packages/apidash_core/lib/utils/handle_auth.dart +++ b/packages/apidash_core/lib/utils/handle_auth.dart @@ -6,7 +6,7 @@ import 'package:apidash_core/utils/auth_utils.dart'; import 'package:seed/seed.dart'; HttpRequestModel handleAuth( - HttpRequestModel httpRequestModel, ApiAuthModel? auth) { + HttpRequestModel httpRequestModel, AuthModel? auth) { if (auth == null || auth.type == APIAuthType.none) { return httpRequestModel; } diff --git a/packages/better_networking/lib/services/http_service.dart b/packages/better_networking/lib/services/http_service.dart index b069ae0dd..eee305a25 100644 --- a/packages/better_networking/lib/services/http_service.dart +++ b/packages/better_networking/lib/services/http_service.dart @@ -17,7 +17,7 @@ final httpClientManager = HttpClientManager(); Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( String requestId, APIType apiType, - ApiAuthModel? authData, + AuthModel? authData, HttpRequestModel requestModel, { SupportedUriSchemes defaultUriScheme = kDefaultUriScheme, bool noSSL = false, From 74c09592bb17f87d242a052f94e41b5a98b27841 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sun, 15 Jun 2025 22:29:02 +0530 Subject: [PATCH 14/70] refactor: rename authData to authModel and update related tests --- lib/providers/collection_providers.dart | 6 ++-- .../lib/services/http_service.dart | 4 +-- test/models/request_models.dart | 36 +++++++++++++++++++ test/models/response_model_test.dart | 8 +++++ 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index a701e85f4..98e5ddeba 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -207,7 +207,7 @@ class CollectionStateNotifier String? id, HTTPVerb? method, APIType? apiType, - ApiAuthModel? authData, + AuthModel? authData, String? url, String? name, String? description, @@ -235,7 +235,7 @@ class CollectionStateNotifier var currentHttpRequestModel = currentModel.httpRequestModel; final newModel = currentModel.copyWith( apiType: apiType ?? currentModel.apiType, - authData: authData ?? currentModel.authData, + authModel: authData ?? currentModel.authModel, name: name ?? currentModel.name, description: description ?? currentModel.description, requestTabIndex: requestTabIndex ?? currentModel.requestTabIndex, @@ -316,7 +316,7 @@ class CollectionStateNotifier var responseRec = await sendHttpRequest( requestId, apiType, - requestModel.authData, + requestModel.authModel, substitutedHttpRequestModel, defaultUriScheme: defaultUriScheme, noSSL: noSSL, diff --git a/packages/better_networking/lib/services/http_service.dart b/packages/better_networking/lib/services/http_service.dart index eee305a25..62478b71d 100644 --- a/packages/better_networking/lib/services/http_service.dart +++ b/packages/better_networking/lib/services/http_service.dart @@ -17,7 +17,7 @@ final httpClientManager = HttpClientManager(); Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( String requestId, APIType apiType, - AuthModel? authData, + AuthModel? authModel, HttpRequestModel requestModel, { SupportedUriSchemes defaultUriScheme = kDefaultUriScheme, bool noSSL = false, @@ -28,7 +28,7 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( final client = httpClientManager.createClient(requestId, noSSL: noSSL); // Handle authentication - final authenticatedRequestModel = handleAuth(requestModel, authData); + final authenticatedRequestModel = handleAuth(requestModel, authModel); (Uri?, String?) uriRec = getValidRequestUri( authenticatedRequestModel.url, diff --git a/test/models/request_models.dart b/test/models/request_models.dart index 1762706cc..9c89bc19c 100644 --- a/test/models/request_models.dart +++ b/test/models/request_models.dart @@ -7,6 +7,7 @@ import 'http_response_models.dart'; const requestModelGet1 = RequestModel( id: 'get1', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet1, ); @@ -14,6 +15,7 @@ const requestModelGet1 = RequestModel( const requestModelGet2 = RequestModel( id: 'get2', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet2, ); @@ -21,6 +23,7 @@ const requestModelGet2 = RequestModel( const requestModelGet3 = RequestModel( id: 'get3', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet3, ); @@ -28,6 +31,7 @@ const requestModelGet3 = RequestModel( const requestModelGet4 = RequestModel( id: 'get4', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet4, ); @@ -35,6 +39,7 @@ const requestModelGet4 = RequestModel( const requestModelGet5 = RequestModel( id: 'get5', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet5, ); @@ -42,6 +47,7 @@ const requestModelGet5 = RequestModel( const requestModelGet6 = RequestModel( id: 'get6', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet6, ); @@ -49,6 +55,7 @@ const requestModelGet6 = RequestModel( const requestModelGet7 = RequestModel( id: 'get7', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet7, ); @@ -56,6 +63,7 @@ const requestModelGet7 = RequestModel( const requestModelGet8 = RequestModel( id: 'get8', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet8, ); @@ -63,6 +71,7 @@ const requestModelGet8 = RequestModel( const requestModelGet9 = RequestModel( id: 'get9', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet9, ); @@ -70,6 +79,7 @@ const requestModelGet9 = RequestModel( const requestModelGet10 = RequestModel( id: 'get10', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet10, ); @@ -77,6 +87,7 @@ const requestModelGet10 = RequestModel( const requestModelGet11 = RequestModel( id: 'get11', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet11, ); @@ -84,6 +95,7 @@ const requestModelGet11 = RequestModel( const requestModelGet12 = RequestModel( id: 'get12', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet12, ); @@ -91,6 +103,7 @@ const requestModelGet12 = RequestModel( const requestModelHead1 = RequestModel( id: 'head1', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelHead1, ); @@ -98,6 +111,7 @@ const requestModelHead1 = RequestModel( const requestModelHead2 = RequestModel( id: 'head2', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelHead2, ); @@ -105,6 +119,7 @@ const requestModelHead2 = RequestModel( const requestModelPost1 = RequestModel( id: 'post1', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost1, ); @@ -112,6 +127,7 @@ const requestModelPost1 = RequestModel( const requestModelPost2 = RequestModel( id: 'post2', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost2, ); @@ -119,6 +135,7 @@ const requestModelPost2 = RequestModel( const requestModelPost3 = RequestModel( id: 'post3', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost3, ); @@ -126,6 +143,7 @@ const requestModelPost3 = RequestModel( const requestModelPost4 = RequestModel( id: 'post4', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost4, ); @@ -133,6 +151,7 @@ const requestModelPost4 = RequestModel( const requestModelPost5 = RequestModel( id: 'post5', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost5, ); @@ -140,6 +159,7 @@ const requestModelPost5 = RequestModel( const requestModelPost6 = RequestModel( id: 'post6', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost6, ); @@ -147,6 +167,7 @@ const requestModelPost6 = RequestModel( const requestModelPost7 = RequestModel( id: 'post7', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost7, ); @@ -154,6 +175,7 @@ const requestModelPost7 = RequestModel( const requestModelPost8 = RequestModel( id: 'post8', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost8, ); @@ -161,12 +183,14 @@ const requestModelPost8 = RequestModel( const requestModelPost9 = RequestModel( id: 'post9', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost9, ); const requestModelPost10 = RequestModel( id: 'post9', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost10, ); @@ -174,6 +198,7 @@ const requestModelPost10 = RequestModel( const requestModelPut1 = RequestModel( id: 'put1', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPut1, ); @@ -181,6 +206,7 @@ const requestModelPut1 = RequestModel( const requestModelPatch1 = RequestModel( id: 'patch1', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPatch1, ); @@ -188,6 +214,7 @@ const requestModelPatch1 = RequestModel( const requestModelDelete1 = RequestModel( id: 'delete1', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelDelete1, ); @@ -195,6 +222,7 @@ const requestModelDelete1 = RequestModel( const requestModelDelete2 = RequestModel( id: 'delete2', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelDelete2, ); @@ -202,6 +230,7 @@ const requestModelDelete2 = RequestModel( RequestModel testRequestModel = RequestModel( id: '1', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost10, responseStatus: 200, httpResponseModel: responseModel, @@ -212,6 +241,7 @@ Map requestModelJson = { 'id': '1', 'apiType': 'rest', 'name': '', + 'authModel': '', 'description': '', 'httpRequestModel': httpRequestModelPost10Json, 'responseStatus': 200, @@ -225,6 +255,7 @@ Map requestModelJson = { const requestModelGet13 = RequestModel( id: 'get13', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet13, ); @@ -232,6 +263,7 @@ const requestModelGet13 = RequestModel( const requestModelGetBadSSL = RequestModel( id: 'badSSL', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGetBadSSL, ); @@ -239,6 +271,7 @@ const requestModelGetBadSSL = RequestModel( const requestModelPost11 = RequestModel( id: 'post11', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost11, ); @@ -246,6 +279,7 @@ const requestModelPost11 = RequestModel( const requestModelPost12 = RequestModel( id: 'post12', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost12, ); @@ -253,11 +287,13 @@ const requestModelPost12 = RequestModel( const requestModelPost13 = RequestModel( id: 'post13', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost13, ); const requestModelOptions1 = RequestModel( id: 'options1', apiType: APIType.rest, + authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelOptions1, ); diff --git a/test/models/response_model_test.dart b/test/models/response_model_test.dart index 74872cdb4..bef5eff8f 100644 --- a/test/models/response_model_test.dart +++ b/test/models/response_model_test.dart @@ -17,6 +17,7 @@ void main() { var responseRec = await sendHttpRequest( requestModelGet1.id, requestModelGet1.apiType, + requestModelGet1.authModel, requestModelGet1.httpRequestModel!, defaultUriScheme: kDefaultUriScheme, noSSL: false, @@ -35,6 +36,7 @@ void main() { var responseRec = await sendHttpRequest( requestModelGet13.id, requestModelGet13.apiType, + requestModelGet13.authModel, requestModelGet13.httpRequestModel!, defaultUriScheme: kDefaultUriScheme, noSSL: false, @@ -52,6 +54,7 @@ void main() { var responseRec = await sendHttpRequest( requestModelPost11.id, requestModelPost11.apiType, + requestModelPost11.authModel, requestModelPost11.httpRequestModel!, ); @@ -66,6 +69,7 @@ void main() { var responseRec = await sendHttpRequest( requestModelPost12.id, requestModelPost12.apiType, + requestModelPost12.authModel, requestModelPost12.httpRequestModel!, ); @@ -79,6 +83,7 @@ void main() { var responseRec = await sendHttpRequest( requestModelPost13.id, requestModelPost13.apiType, + requestModelPost13.authModel, requestModelPost13.httpRequestModel!, ); @@ -92,6 +97,7 @@ void main() { var responseRec = await sendHttpRequest( requestModelGetBadSSL.id, requestModelGetBadSSL.apiType, + requestModelGetBadSSL.authModel, requestModelGetBadSSL.httpRequestModel!, defaultUriScheme: kDefaultUriScheme, noSSL: false, @@ -104,6 +110,7 @@ void main() { var responseRec = await sendHttpRequest( requestModelGetBadSSL.id, requestModelGetBadSSL.apiType, + requestModelGetBadSSL.authModel, requestModelGetBadSSL.httpRequestModel!, defaultUriScheme: kDefaultUriScheme, noSSL: true, @@ -124,6 +131,7 @@ void main() { var responseRec = await sendHttpRequest( requestModelOptions1.id, requestModelOptions1.apiType, + requestModelOptions1.authModel, requestModelOptions1.httpRequestModel!, defaultUriScheme: kDefaultUriScheme, noSSL: false, From bb10ad655d56fabd6a855f2199fc95afc48d7609 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Tue, 17 Jun 2025 23:15:25 +0530 Subject: [PATCH 15/70] feat: split authentication related fields into seperate files --- .../auth/api_key_auth_fields.dart | 141 +++++ .../auth/basic_auth_fields.dart | 84 +++ .../auth/bearer_auth_fields.dart | 71 +++ .../common_widgets/auth/jwt_auth_fields.dart | 307 +++++++++ .../request_pane/request_auth.dart | 598 +----------------- pubspec.lock | 4 +- pubspec.yaml | 3 +- 7 files changed, 622 insertions(+), 586 deletions(-) create mode 100644 lib/screens/common_widgets/auth/api_key_auth_fields.dart create mode 100644 lib/screens/common_widgets/auth/basic_auth_fields.dart create mode 100644 lib/screens/common_widgets/auth/bearer_auth_fields.dart create mode 100644 lib/screens/common_widgets/auth/jwt_auth_fields.dart diff --git a/lib/screens/common_widgets/auth/api_key_auth_fields.dart b/lib/screens/common_widgets/auth/api_key_auth_fields.dart new file mode 100644 index 000000000..ab4370bed --- /dev/null +++ b/lib/screens/common_widgets/auth/api_key_auth_fields.dart @@ -0,0 +1,141 @@ +import 'package:apidash_core/consts.dart'; +import 'package:apidash_core/models/auth/api_auth_model.dart'; +import 'package:apidash_core/models/auth/auth_api_key_model.dart'; +import 'package:flutter/material.dart'; + +class ApiKeyAuthFields extends StatefulWidget { + final AuthModel? authData; + final Function(AuthModel?) updateAuth; + + const ApiKeyAuthFields({ + super.key, + required this.authData, + required this.updateAuth, + }); + + @override + State createState() => _ApiKeyAuthFieldsState(); +} + +class _ApiKeyAuthFieldsState extends State { + late TextEditingController _keyController; + late TextEditingController _nameController; + late String _addKeyTo; + + @override + void initState() { + super.initState(); + final apiAuth = widget.authData?.apikey; + _keyController = TextEditingController(text: apiAuth?.key ?? ''); + _nameController = TextEditingController(text: apiAuth?.name ?? ''); + _addKeyTo = apiAuth?.location ?? 'header'; + } + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Add to", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + height: 4, + ), + DropdownButtonFormField( + value: _addKeyTo, + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + items: [ + DropdownMenuItem( + value: 'header', + child: Text('Header'), + ), + DropdownMenuItem( + value: 'query', + child: Text('Query Params'), + ), + ], + onChanged: (String? newLocation) { + if (newLocation != null) { + _updateApiKeyAuth(); + } + }, + ), + const SizedBox(height: 16), + Text( + "Header/Query Param Name", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + height: 4, + ), + TextField( + controller: _nameController, + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + hintText: "Header/Query Param Name", + hintStyle: Theme.of(context).textTheme.bodyMedium, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onChanged: (value) => _updateApiKeyAuth(), + ), + const SizedBox(height: 16), + Text( + "API Key", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + height: 4, + ), + TextField( + controller: _keyController, + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + hintText: "API Key", + hintStyle: Theme.of(context).textTheme.bodyMedium, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onChanged: (value) => _updateApiKeyAuth(), + ), + ], + ); + } + + void _updateApiKeyAuth() { + widget.updateAuth( + widget.authData?.copyWith( + type: APIAuthType.apiKey, + apikey: AuthApiKeyModel( + key: _keyController.text.trim(), + name: _nameController.text.trim(), + location: _addKeyTo, + ), + ), + ); + } +} diff --git a/lib/screens/common_widgets/auth/basic_auth_fields.dart b/lib/screens/common_widgets/auth/basic_auth_fields.dart new file mode 100644 index 000000000..0ac0b6c6e --- /dev/null +++ b/lib/screens/common_widgets/auth/basic_auth_fields.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:apidash_core/apidash_core.dart'; + +class BasicAuthFields extends StatelessWidget { + final AuthModel? authData; + final Function(AuthModel?) updateAuth; + + const BasicAuthFields({ + super.key, + required this.authData, + required this.updateAuth, + }); + + @override + Widget build(BuildContext context) { + final usernameController = TextEditingController( + text: authData?.basic?.username ?? '', + ); + final passwordController = TextEditingController( + text: authData?.basic?.password ?? '', + ); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Username", + style: TextStyle(fontWeight: FontWeight.bold), + ), + const SizedBox(height: 4), + TextField( + controller: usernameController, + decoration: _inputDecoration(context, "Username"), + onChanged: (_) => _updateBasicAuth( + usernameController, + passwordController, + ), + ), + const SizedBox(height: 16), + Text( + "Password", + style: TextStyle(fontWeight: FontWeight.bold), + ), + const SizedBox(height: 4), + TextField( + controller: passwordController, + decoration: _inputDecoration(context, "Password"), + obscureText: true, + onChanged: (_) => _updateBasicAuth( + usernameController, + passwordController, + ), + ), + ], + ); + } + + InputDecoration _inputDecoration(BuildContext context, String hint) { + return InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + hintText: hint, + hintStyle: Theme.of(context).textTheme.bodyMedium, + border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), + ); + } + + void _updateBasicAuth( + TextEditingController usernameController, + TextEditingController passwordController, + ) { + updateAuth( + authData?.copyWith( + type: APIAuthType.basic, + basic: AuthBasicAuthModel( + username: usernameController.text.trim(), + password: passwordController.text.trim(), + ), + ), + ); + } +} diff --git a/lib/screens/common_widgets/auth/bearer_auth_fields.dart b/lib/screens/common_widgets/auth/bearer_auth_fields.dart new file mode 100644 index 000000000..47b4f7387 --- /dev/null +++ b/lib/screens/common_widgets/auth/bearer_auth_fields.dart @@ -0,0 +1,71 @@ +import 'package:apidash_core/apidash_core.dart'; +import 'package:flutter/material.dart'; + +class BearerAuthFields extends StatefulWidget { + final AuthModel? authData; + final Function(AuthModel?) updateAuth; + + const BearerAuthFields({ + super.key, + required this.authData, + required this.updateAuth, + }); + + @override + State createState() => _BearerAuthFieldsState(); +} + +class _BearerAuthFieldsState extends State { + late TextEditingController _tokenController; + + @override + void initState() { + super.initState(); + final bearerAuth = widget.authData?.bearer; + _tokenController = TextEditingController(text: bearerAuth?.token ?? ''); + } + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Token", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + height: 4, + ), + TextField( + controller: _tokenController, + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + hintText: "Token", + hintStyle: Theme.of(context).textTheme.bodyMedium, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onChanged: (value) => _updateBearerAuth(), + ), + ], + ); + } + + void _updateBearerAuth() { + widget.updateAuth( + widget.authData?.copyWith( + type: APIAuthType.bearer, + bearer: AuthBearerModel( + token: _tokenController.text.trim(), + ), + ), + ); + } +} diff --git a/lib/screens/common_widgets/auth/jwt_auth_fields.dart b/lib/screens/common_widgets/auth/jwt_auth_fields.dart new file mode 100644 index 000000000..a64d9820d --- /dev/null +++ b/lib/screens/common_widgets/auth/jwt_auth_fields.dart @@ -0,0 +1,307 @@ +import 'package:flutter/material.dart'; +import 'package:apidash_core/apidash_core.dart'; + +class JwtAuthFields extends StatefulWidget { + final AuthModel? authData; + final Function(AuthModel?) updateAuth; + + const JwtAuthFields({ + super.key, + required this.authData, + required this.updateAuth, + }); + + @override + State createState() => _JwtAuthFieldsState(); +} + +class _JwtAuthFieldsState extends State { + late TextEditingController _secretController; + late TextEditingController _payloadController; + late String _addTokenTo; + late String _algorithm; + late bool _isSecretBase64Encoded; + + @override + void initState() { + super.initState(); + final jwt = widget.authData?.jwt; + _secretController = TextEditingController(text: jwt?.secret ?? ''); + _payloadController = TextEditingController(text: jwt?.payload ?? ''); + _addTokenTo = jwt?.addTokenTo ?? 'header'; + _algorithm = jwt?.algorithm ?? 'HS256'; + _isSecretBase64Encoded = jwt?.isSecretBase64Encoded ?? false; + } + + @override + Widget build(BuildContext context) { + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Add JWT token to", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 4), + DropdownButtonFormField( + value: _addTokenTo, + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + items: [ + DropdownMenuItem( + value: 'header', + child: Text('Request Header'), + ), + DropdownMenuItem( + value: 'query', + child: Text('Query Parameters'), + ), + ], + onChanged: (String? newAddTokenTo) { + if (newAddTokenTo != null) { + _updateJwtAuth(); + } + }, + ), + const SizedBox(height: 16), + Text( + "Algorithm", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 4), + DropdownButtonFormField( + value: _algorithm, + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + items: [ + 'HS256', + 'HS384', + 'HS512', + ].map((algorithm) { + return DropdownMenuItem( + value: algorithm, + child: Text(algorithm), + ); + }).toList(), + onChanged: (String? newAlgorithm) { + if (newAlgorithm != null) { + _updateJwtAuth(); + } + }, + ), + const SizedBox(height: 16), + Text( + "Secret", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 4), + TextField( + controller: _secretController, + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + hintText: "Secret key", + hintStyle: Theme.of(context).textTheme.bodyMedium, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onChanged: (value) => _updateJwtAuth(), + ), + const SizedBox(height: 16), + CheckboxListTile( + title: Text( + "Secret is Base64 encoded", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + value: _isSecretBase64Encoded, + contentPadding: EdgeInsets.zero, + controlAffinity: ListTileControlAffinity.leading, + onChanged: (bool? value) { + _updateJwtAuth(); + }, + ), + const SizedBox(height: 16), + Text( + "Payload (JSON format)", + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 4), + TextField( + controller: _payloadController, + maxLines: 4, + decoration: InputDecoration( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + hintText: + '{"sub": "1234567890", "name": "John Doe", "iat": 1516239022}', + hintStyle: Theme.of(context).textTheme.bodyMedium, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onChanged: (value) => _updateJwtAuth(), + ), + // const SizedBox(height: 16), + // if (currentAddTokenTo == 'header') ...[ + // Text( + // "Header Prefix", + // style: TextStyle( + // fontWeight: FontWeight.bold, + // ), + // ), + // SizedBox(height: 4), + // TextField( + // controller: jwtHeaderPrefixController, + // decoration: InputDecoration( + // constraints: BoxConstraints( + // maxWidth: MediaQuery.sizeOf(context).width - 100, + // ), + // contentPadding: const EdgeInsets.all(18), + // hintText: "Bearer", + // hintStyle: Theme.of(context).textTheme.bodyMedium, + // border: OutlineInputBorder( + // borderRadius: BorderRadius.circular(8), + // ), + // ), + // onChanged: (value) => updateAuth(ApiAuthModel( + // type: APIAuthType.jwt, + // jwt: AuthJwtModel( + // secret: jwtSecretController.text.trim(), + // payload: jwtPayloadController.text.trim(), + // addTokenTo: currentAddTokenTo, + // algorithm: currentAlgorithm, + // isSecretBase64Encoded: isSecretBase64Encoded, + // headerPrefix: jwtHeaderPrefixController.text.trim(), + // queryParamKey: jwtQueryParamKeyController.text.trim(), + // header: jwtHeaderController.text.trim(), + // ), + // )), + // ), + // const SizedBox(height: 16), + // ], + // if (currentAddTokenTo == 'query') ...[ + // Text( + // "Query Parameter Key", + // style: TextStyle( + // fontWeight: FontWeight.bold, + // ), + // ), + // SizedBox(height: 4), + // TextField( + // controller: jwtQueryParamKeyController, + // decoration: InputDecoration( + // constraints: BoxConstraints( + // maxWidth: MediaQuery.sizeOf(context).width - 100, + // ), + // contentPadding: const EdgeInsets.all(18), + // hintText: "token", + // hintStyle: Theme.of(context).textTheme.bodyMedium, + // border: OutlineInputBorder( + // borderRadius: BorderRadius.circular(8), + // ), + // ), + // onChanged: (value) => updateAuth(ApiAuthModel( + // type: APIAuthType.jwt, + // jwt: AuthJwtModel( + // secret: jwtSecretController.text.trim(), + // payload: jwtPayloadController.text.trim(), + // addTokenTo: currentAddTokenTo, + // algorithm: currentAlgorithm, + // isSecretBase64Encoded: isSecretBase64Encoded, + // headerPrefix: jwtHeaderPrefixController.text.trim(), + // queryParamKey: jwtQueryParamKeyController.text.trim(), + // header: jwtHeaderController.text.trim(), + // ), + // )), + // ), + // const SizedBox(height: 16), + // ], + // Text( + // "JWT Headers (JSON format)", + // style: TextStyle( + // fontWeight: FontWeight.bold, + // ), + // ), + // SizedBox(height: 4), + // TextField( + // controller: jwtHeaderController, + // maxLines: 3, + // decoration: InputDecoration( + // constraints: BoxConstraints( + // maxWidth: MediaQuery.sizeOf(context).width - 100, + // ), + // contentPadding: const EdgeInsets.all(18), + // hintText: '{"typ": "JWT", "alg": "HS256"}', + // hintStyle: Theme.of(context).textTheme.bodyMedium, + // border: OutlineInputBorder( + // borderRadius: BorderRadius.circular(8), + // ), + // ), + // onChanged: (value) => updateAuth( + // ApiAuthModel( + // type: APIAuthType.jwt, + // jwt: AuthJwtModel( + // secret: jwtSecretController.text.trim(), + // payload: jwtPayloadController.text.trim(), + // addTokenTo: currentAddTokenTo, + // algorithm: currentAlgorithm, + // isSecretBase64Encoded: isSecretBase64Encoded, + // headerPrefix: jwtHeaderPrefixController.text.trim(), + // queryParamKey: jwtQueryParamKeyController.text.trim(), + // header: jwtHeaderController.text.trim(), + // ), + // ), + // ), + // ), + ], + ); + } + + void _updateJwtAuth() { + widget.updateAuth( + widget.authData?.copyWith( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: _secretController.text.trim(), + payload: _payloadController.text.trim(), + addTokenTo: _addTokenTo, + algorithm: _algorithm, + isSecretBase64Encoded: _isSecretBase64Encoded, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: '', + ), + ), + ); + } +} diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index 644c7b740..6d401ea7a 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -1,3 +1,7 @@ +import 'package:apidash/screens/common_widgets/auth/api_key_auth_fields.dart'; +import 'package:apidash/screens/common_widgets/auth/basic_auth_fields.dart'; +import 'package:apidash/screens/common_widgets/auth/bearer_auth_fields.dart'; +import 'package:apidash/screens/common_widgets/auth/jwt_auth_fields.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash_core/apidash_core.dart'; @@ -81,597 +85,27 @@ class EditAuthType extends ConsumerWidget { switch (authData?.type) { case APIAuthType.basic: - final usernameController = TextEditingController( - text: authData?.basic?.username ?? '', + return BasicAuthFields( + authData: authData, + updateAuth: updateAuth, ); - final passwordController = TextEditingController( - text: authData?.basic?.password ?? '', - ); - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Username", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - SizedBox( - height: 4, - ), - TextField( - controller: usernameController, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - hintText: "Username", - hintStyle: Theme.of(context).textTheme.bodyMedium, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - onChanged: (value) => updateAuth(authData?.copyWith( - type: APIAuthType.basic, - basic: AuthBasicAuthModel( - username: usernameController.text.trim(), - password: passwordController.text.trim(), - ), - )), - ), - SizedBox( - height: 16, - ), - Text( - "Password", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - SizedBox( - height: 4, - ), - TextField( - controller: passwordController, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - hintText: "Password", - hintStyle: Theme.of(context).textTheme.bodyMedium, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - obscureText: true, - onChanged: (value) => updateAuth( - authData?.copyWith( - type: APIAuthType.basic, - basic: AuthBasicAuthModel( - username: usernameController.text.trim(), - password: passwordController.text.trim(), - ), - ), - ), - ), - ], - ); - case APIAuthType.bearer: - final tokenController = TextEditingController( - text: authData?.bearer?.token ?? '', + return BearerAuthFields( + authData: authData, + updateAuth: updateAuth, ); - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Token", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - SizedBox( - height: 4, - ), - TextField( - controller: tokenController, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - hintText: "Token", - hintStyle: Theme.of(context).textTheme.bodyMedium, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - onChanged: (value) => updateAuth( - authData?.copyWith( - type: APIAuthType.bearer, - bearer: AuthBearerModel(token: tokenController.text.trim()), - ), - ), - ), - ], - ); - case APIAuthType.apiKey: - final keyController = TextEditingController( - text: authData?.apikey?.key ?? '', - ); - final nameController = TextEditingController( - text: authData?.apikey?.name ?? 'x-api-key', + return ApiKeyAuthFields( + authData: authData, + updateAuth: updateAuth, ); - final currentLocation = authData?.apikey?.location ?? 'header'; - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Add to", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - SizedBox( - height: 4, - ), - DropdownButtonFormField( - value: currentLocation, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - items: [ - DropdownMenuItem( - value: 'header', - child: Text('Header'), - ), - DropdownMenuItem( - value: 'query', - child: Text('Query Params'), - ), - ], - onChanged: (String? newLocation) { - if (newLocation != null) { - updateAuth( - authData?.copyWith( - type: APIAuthType.apiKey, - apikey: AuthApiKeyModel( - key: keyController.text, - name: nameController.text, - location: newLocation, - ), - ), - ); - } - }, - ), - const SizedBox(height: 16), - Text( - "Header/Query Param Name", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - SizedBox( - height: 4, - ), - TextField( - controller: nameController, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - hintText: "Header/Query Param Name", - hintStyle: Theme.of(context).textTheme.bodyMedium, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - onChanged: (value) => updateAuth( - authData?.copyWith( - type: APIAuthType.apiKey, - apikey: AuthApiKeyModel( - key: keyController.text, - name: nameController.text.trim(), - location: currentLocation, - ), - ), - ), - ), - const SizedBox(height: 16), - Text( - "API Key", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - SizedBox( - height: 4, - ), - TextField( - controller: keyController, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - hintText: "API Key", - hintStyle: Theme.of(context).textTheme.bodyMedium, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - onChanged: (value) => updateAuth( - authData?.copyWith( - type: APIAuthType.apiKey, - apikey: AuthApiKeyModel( - key: keyController.text.trim(), - name: nameController.text, - location: currentLocation, - ), - ), - ), - ), - ], - ); - case APIAuthType.jwt: - final jwtSecretController = TextEditingController( - text: authData?.jwt?.secret ?? '', - ); - final jwtPayloadController = TextEditingController( - text: authData?.jwt?.payload ?? '', - ); - final jwtHeaderPrefixController = TextEditingController( - text: authData?.jwt?.headerPrefix ?? 'Bearer', - ); - final jwtQueryParamKeyController = TextEditingController( - text: authData?.jwt?.queryParamKey ?? 'token', - ); - final jwtHeaderController = TextEditingController( - text: authData?.jwt?.header ?? '', - ); - - final currentAddTokenTo = authData?.jwt?.addTokenTo ?? 'header'; - final currentAlgorithm = authData?.jwt?.algorithm ?? 'HS256'; - final isSecretBase64Encoded = - authData?.jwt?.isSecretBase64Encoded ?? false; - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Add JWT token to", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - SizedBox(height: 4), - DropdownButtonFormField( - value: currentAddTokenTo, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - items: [ - DropdownMenuItem( - value: 'header', - child: Text('Request Header'), - ), - DropdownMenuItem( - value: 'query', - child: Text('Query Parameters'), - ), - ], - onChanged: (String? newAddTokenTo) { - if (newAddTokenTo != null) { - updateAuth( - authData?.copyWith( - type: APIAuthType.jwt, - jwt: AuthJwtModel( - secret: jwtSecretController.text.trim(), - payload: jwtPayloadController.text.trim(), - addTokenTo: newAddTokenTo, - algorithm: currentAlgorithm, - isSecretBase64Encoded: isSecretBase64Encoded, - headerPrefix: jwtHeaderPrefixController.text.trim(), - queryParamKey: jwtQueryParamKeyController.text.trim(), - header: jwtHeaderController.text.trim(), - ), - ), - ); - } - }, - ), - const SizedBox(height: 16), - Text( - "Algorithm", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - SizedBox(height: 4), - DropdownButtonFormField( - value: currentAlgorithm, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - items: [ - 'HS256', - 'HS384', - 'HS512', - ].map((algorithm) { - return DropdownMenuItem( - value: algorithm, - child: Text(algorithm), - ); - }).toList(), - onChanged: (String? newAlgorithm) { - if (newAlgorithm != null) { - updateAuth( - authData?.copyWith( - type: APIAuthType.jwt, - jwt: AuthJwtModel( - secret: jwtSecretController.text.trim(), - payload: jwtPayloadController.text.trim(), - addTokenTo: currentAddTokenTo, - algorithm: newAlgorithm, - isSecretBase64Encoded: isSecretBase64Encoded, - headerPrefix: jwtHeaderPrefixController.text.trim(), - queryParamKey: jwtQueryParamKeyController.text.trim(), - header: jwtHeaderController.text.trim(), - ), - ), - ); - } - }, - ), - const SizedBox(height: 16), - Text( - "Secret", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - SizedBox(height: 4), - TextField( - controller: jwtSecretController, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - hintText: "Secret key", - hintStyle: Theme.of(context).textTheme.bodyMedium, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - onChanged: (value) => updateAuth( - authData?.copyWith( - type: APIAuthType.jwt, - jwt: AuthJwtModel( - secret: jwtSecretController.text.trim(), - payload: jwtPayloadController.text.trim(), - addTokenTo: currentAddTokenTo, - algorithm: currentAlgorithm, - isSecretBase64Encoded: isSecretBase64Encoded, - headerPrefix: jwtHeaderPrefixController.text.trim(), - queryParamKey: jwtQueryParamKeyController.text.trim(), - header: jwtHeaderController.text.trim(), - ), - ), - ), - ), - const SizedBox(height: 16), - CheckboxListTile( - title: Text( - "Secret is Base64 encoded", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - value: isSecretBase64Encoded, - contentPadding: EdgeInsets.zero, - controlAffinity: ListTileControlAffinity.leading, - onChanged: (bool? value) { - updateAuth( - authData?.copyWith( - type: APIAuthType.jwt, - jwt: AuthJwtModel( - secret: jwtSecretController.text.trim(), - payload: jwtPayloadController.text.trim(), - addTokenTo: currentAddTokenTo, - algorithm: currentAlgorithm, - isSecretBase64Encoded: value ?? false, - headerPrefix: jwtHeaderPrefixController.text.trim(), - queryParamKey: jwtQueryParamKeyController.text.trim(), - header: jwtHeaderController.text.trim(), - ), - ), - ); - }, - ), - const SizedBox(height: 16), - Text( - "Payload (JSON format)", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - SizedBox(height: 4), - TextField( - controller: jwtPayloadController, - maxLines: 4, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - hintText: - '{"sub": "1234567890", "name": "John Doe", "iat": 1516239022}', - hintStyle: Theme.of(context).textTheme.bodyMedium, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - onChanged: (value) => updateAuth( - authData?.copyWith( - type: APIAuthType.jwt, - jwt: AuthJwtModel( - secret: jwtSecretController.text.trim(), - payload: jwtPayloadController.text.trim(), - addTokenTo: currentAddTokenTo, - algorithm: currentAlgorithm, - isSecretBase64Encoded: isSecretBase64Encoded, - headerPrefix: jwtHeaderPrefixController.text.trim(), - queryParamKey: jwtQueryParamKeyController.text.trim(), - header: jwtHeaderController.text.trim(), - ), - ), - ), - ), - // const SizedBox(height: 16), - // if (currentAddTokenTo == 'header') ...[ - // Text( - // "Header Prefix", - // style: TextStyle( - // fontWeight: FontWeight.bold, - // ), - // ), - // SizedBox(height: 4), - // TextField( - // controller: jwtHeaderPrefixController, - // decoration: InputDecoration( - // constraints: BoxConstraints( - // maxWidth: MediaQuery.sizeOf(context).width - 100, - // ), - // contentPadding: const EdgeInsets.all(18), - // hintText: "Bearer", - // hintStyle: Theme.of(context).textTheme.bodyMedium, - // border: OutlineInputBorder( - // borderRadius: BorderRadius.circular(8), - // ), - // ), - // onChanged: (value) => updateAuth(ApiAuthModel( - // type: APIAuthType.jwt, - // jwt: AuthJwtModel( - // secret: jwtSecretController.text.trim(), - // payload: jwtPayloadController.text.trim(), - // addTokenTo: currentAddTokenTo, - // algorithm: currentAlgorithm, - // isSecretBase64Encoded: isSecretBase64Encoded, - // headerPrefix: jwtHeaderPrefixController.text.trim(), - // queryParamKey: jwtQueryParamKeyController.text.trim(), - // header: jwtHeaderController.text.trim(), - // ), - // )), - // ), - // const SizedBox(height: 16), - // ], - // if (currentAddTokenTo == 'query') ...[ - // Text( - // "Query Parameter Key", - // style: TextStyle( - // fontWeight: FontWeight.bold, - // ), - // ), - // SizedBox(height: 4), - // TextField( - // controller: jwtQueryParamKeyController, - // decoration: InputDecoration( - // constraints: BoxConstraints( - // maxWidth: MediaQuery.sizeOf(context).width - 100, - // ), - // contentPadding: const EdgeInsets.all(18), - // hintText: "token", - // hintStyle: Theme.of(context).textTheme.bodyMedium, - // border: OutlineInputBorder( - // borderRadius: BorderRadius.circular(8), - // ), - // ), - // onChanged: (value) => updateAuth(ApiAuthModel( - // type: APIAuthType.jwt, - // jwt: AuthJwtModel( - // secret: jwtSecretController.text.trim(), - // payload: jwtPayloadController.text.trim(), - // addTokenTo: currentAddTokenTo, - // algorithm: currentAlgorithm, - // isSecretBase64Encoded: isSecretBase64Encoded, - // headerPrefix: jwtHeaderPrefixController.text.trim(), - // queryParamKey: jwtQueryParamKeyController.text.trim(), - // header: jwtHeaderController.text.trim(), - // ), - // )), - // ), - // const SizedBox(height: 16), - // ], - // Text( - // "JWT Headers (JSON format)", - // style: TextStyle( - // fontWeight: FontWeight.bold, - // ), - // ), - // SizedBox(height: 4), - // TextField( - // controller: jwtHeaderController, - // maxLines: 3, - // decoration: InputDecoration( - // constraints: BoxConstraints( - // maxWidth: MediaQuery.sizeOf(context).width - 100, - // ), - // contentPadding: const EdgeInsets.all(18), - // hintText: '{"typ": "JWT", "alg": "HS256"}', - // hintStyle: Theme.of(context).textTheme.bodyMedium, - // border: OutlineInputBorder( - // borderRadius: BorderRadius.circular(8), - // ), - // ), - // onChanged: (value) => updateAuth( - // ApiAuthModel( - // type: APIAuthType.jwt, - // jwt: AuthJwtModel( - // secret: jwtSecretController.text.trim(), - // payload: jwtPayloadController.text.trim(), - // addTokenTo: currentAddTokenTo, - // algorithm: currentAlgorithm, - // isSecretBase64Encoded: isSecretBase64Encoded, - // headerPrefix: jwtHeaderPrefixController.text.trim(), - // queryParamKey: jwtQueryParamKeyController.text.trim(), - // header: jwtHeaderController.text.trim(), - // ), - // ), - // ), - // ), - ], + return JwtAuthFields( + authData: authData, + updateAuth: updateAuth, ); - case APIAuthType.none: return const Text("No authentication selected."); - - // TODO: Implement digest, oauth1, oauth2 later default: return const Text("This auth type is not implemented yet."); } diff --git a/pubspec.lock b/pubspec.lock index 66394a8de..97ee48710 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -674,10 +674,10 @@ packages: dependency: "direct main" description: name: fvp - sha256: f5012756985f7c8c19caaea2d65baf8a6cf5fee9fe520e1fabb8bc61e1d5f468 + sha256: a2b6f305a5e559abc21b1be06ca0ffb5bb6b5b523d6d45eb8e78d53f3b89e9a2 url: "https://pub.dev" source: hosted - version: "0.30.0" + version: "0.32.1" glob: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f34e23bac..cf1e4cc5e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -32,8 +32,7 @@ dependencies: flutter_portal: ^1.1.4 flutter_riverpod: ^2.5.1 flutter_svg: ^2.0.17 - fvp: ^0.30.0 - highlight: ^0.7.0 + fvp: ^0.32.1 highlighter: ^0.1.1 hive_flutter: ^1.1.0 hooks_riverpod: ^2.5.2 From ff2341316438acbdb087737914c601a839c2b60a Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Wed, 18 Jun 2025 09:07:50 +0530 Subject: [PATCH 16/70] feat: change text field design --- .../auth/api_key_auth_fields.dart | 48 ++------- .../auth/basic_auth_fields.dart | 33 ++----- .../auth/bearer_auth_fields.dart | 34 ++----- .../common_widgets/auth/jwt_auth_fields.dart | 40 ++++---- .../common_widgets/auth_textfield.dart | 99 +++++++++++++++++++ 5 files changed, 137 insertions(+), 117 deletions(-) create mode 100644 lib/screens/common_widgets/auth_textfield.dart diff --git a/lib/screens/common_widgets/auth/api_key_auth_fields.dart b/lib/screens/common_widgets/auth/api_key_auth_fields.dart index ab4370bed..6b4998749 100644 --- a/lib/screens/common_widgets/auth/api_key_auth_fields.dart +++ b/lib/screens/common_widgets/auth/api_key_auth_fields.dart @@ -1,3 +1,4 @@ +import 'package:apidash/screens/common_widgets/auth_textfield.dart'; import 'package:apidash_core/consts.dart'; import 'package:apidash_core/models/auth/api_auth_model.dart'; import 'package:apidash_core/models/auth/auth_api_key_model.dart'; @@ -73,53 +74,16 @@ class _ApiKeyAuthFieldsState extends State { }, ), const SizedBox(height: 16), - Text( - "Header/Query Param Name", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - SizedBox( - height: 4, - ), - TextField( + AuthTextField( controller: _nameController, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - hintText: "Header/Query Param Name", - hintStyle: Theme.of(context).textTheme.bodyMedium, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), + hintText: "Header/Query Param Name", onChanged: (value) => _updateApiKeyAuth(), ), const SizedBox(height: 16), - Text( - "API Key", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - SizedBox( - height: 4, - ), - TextField( + AuthTextField( controller: _keyController, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - hintText: "API Key", - hintStyle: Theme.of(context).textTheme.bodyMedium, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), + hintText: "API KeyName", + isObscureText: true, onChanged: (value) => _updateApiKeyAuth(), ), ], diff --git a/lib/screens/common_widgets/auth/basic_auth_fields.dart b/lib/screens/common_widgets/auth/basic_auth_fields.dart index 0ac0b6c6e..887f68abd 100644 --- a/lib/screens/common_widgets/auth/basic_auth_fields.dart +++ b/lib/screens/common_widgets/auth/basic_auth_fields.dart @@ -1,3 +1,4 @@ +import 'package:apidash/screens/common_widgets/auth_textfield.dart'; import 'package:flutter/material.dart'; import 'package:apidash_core/apidash_core.dart'; @@ -23,29 +24,19 @@ class BasicAuthFields extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - "Username", - style: TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(height: 4), - TextField( + AuthTextField( + hintText: "Username", controller: usernameController, - decoration: _inputDecoration(context, "Username"), onChanged: (_) => _updateBasicAuth( usernameController, passwordController, ), ), const SizedBox(height: 16), - Text( - "Password", - style: TextStyle(fontWeight: FontWeight.bold), - ), - const SizedBox(height: 4), - TextField( + AuthTextField( + hintText: "Password", + isObscureText: true, controller: passwordController, - decoration: _inputDecoration(context, "Password"), - obscureText: true, onChanged: (_) => _updateBasicAuth( usernameController, passwordController, @@ -55,18 +46,6 @@ class BasicAuthFields extends StatelessWidget { ); } - InputDecoration _inputDecoration(BuildContext context, String hint) { - return InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - hintText: hint, - hintStyle: Theme.of(context).textTheme.bodyMedium, - border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), - ); - } - void _updateBasicAuth( TextEditingController usernameController, TextEditingController passwordController, diff --git a/lib/screens/common_widgets/auth/bearer_auth_fields.dart b/lib/screens/common_widgets/auth/bearer_auth_fields.dart index 47b4f7387..da7de3c91 100644 --- a/lib/screens/common_widgets/auth/bearer_auth_fields.dart +++ b/lib/screens/common_widgets/auth/bearer_auth_fields.dart @@ -1,3 +1,4 @@ +import 'package:apidash/screens/common_widgets/auth_textfield.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; @@ -27,34 +28,11 @@ class _BearerAuthFieldsState extends State { @override Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Token", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - SizedBox( - height: 4, - ), - TextField( - controller: _tokenController, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - hintText: "Token", - hintStyle: Theme.of(context).textTheme.bodyMedium, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - onChanged: (value) => _updateBearerAuth(), - ), - ], + return AuthTextField( + controller: _tokenController, + hintText: "Token", + isObscureText: true, + onChanged: (value) => _updateBearerAuth(), ); } diff --git a/lib/screens/common_widgets/auth/jwt_auth_fields.dart b/lib/screens/common_widgets/auth/jwt_auth_fields.dart index a64d9820d..4a478aabf 100644 --- a/lib/screens/common_widgets/auth/jwt_auth_fields.dart +++ b/lib/screens/common_widgets/auth/jwt_auth_fields.dart @@ -1,3 +1,4 @@ +import 'package:apidash/screens/common_widgets/auth_textfield.dart'; import 'package:flutter/material.dart'; import 'package:apidash_core/apidash_core.dart'; @@ -35,7 +36,6 @@ class _JwtAuthFieldsState extends State { @override Widget build(BuildContext context) { - return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -109,26 +109,10 @@ class _JwtAuthFieldsState extends State { }, ), const SizedBox(height: 16), - Text( - "Secret", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - SizedBox(height: 4), - TextField( + AuthTextField( controller: _secretController, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - hintText: "Secret key", - hintStyle: Theme.of(context).textTheme.bodyMedium, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), + isObscureText: true, + hintText: "Secret key", onChanged: (value) => _updateJwtAuth(), ), const SizedBox(height: 16), @@ -143,6 +127,10 @@ class _JwtAuthFieldsState extends State { contentPadding: EdgeInsets.zero, controlAffinity: ListTileControlAffinity.leading, onChanged: (bool? value) { + setState(() { + _isSecretBase64Encoded = value ?? false; + }); + _updateJwtAuth(); }, ), @@ -158,6 +146,8 @@ class _JwtAuthFieldsState extends State { controller: _payloadController, maxLines: 4, decoration: InputDecoration( + filled: true, + fillColor: Theme.of(context).colorScheme.surfaceContainerLowest, constraints: BoxConstraints( maxWidth: MediaQuery.sizeOf(context).width - 100, ), @@ -168,6 +158,16 @@ class _JwtAuthFieldsState extends State { border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.outline, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.surfaceContainerHighest, + ), + ), ), onChanged: (value) => _updateJwtAuth(), ), diff --git a/lib/screens/common_widgets/auth_textfield.dart b/lib/screens/common_widgets/auth_textfield.dart new file mode 100644 index 000000000..0dd03c6e1 --- /dev/null +++ b/lib/screens/common_widgets/auth_textfield.dart @@ -0,0 +1,99 @@ +import 'package:apidash_design_system/tokens/measurements.dart'; +import 'package:apidash_design_system/tokens/typography.dart'; +import 'package:flutter/material.dart'; + +class AuthTextField extends StatefulWidget { + final String hintText; + final TextEditingController controller; + final bool isObscureText; + final Function(String)? onChanged; + + const AuthTextField({ + super.key, + required this.hintText, + required this.controller, + required this.onChanged, + this.isObscureText = false, + }); + + @override + State createState() => _AuthFieldState(); +} + +class _AuthFieldState extends State { + late bool _obscureText; + + @override + void initState() { + super.initState(); + _obscureText = widget.isObscureText; + } + + void _toggleVisibility() { + setState(() { + _obscureText = !_obscureText; + }); + } + + @override + Widget build(BuildContext context) { + return AutofillGroup( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.hintText, + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 6), + TextFormField( + controller: widget.controller, + style: kCodeStyle.copyWith( + color: Theme.of(context).colorScheme.onSurface, + fontSize: Theme.of(context).textTheme.bodyMedium?.fontSize, + ), + decoration: InputDecoration( + filled: true, + fillColor: Theme.of(context).colorScheme.surfaceContainerLowest, + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 80), + contentPadding: kP10, + hintText: widget.hintText, + hintStyle: Theme.of(context).textTheme.bodySmall, + suffixIcon: widget.isObscureText + ? IconButton( + icon: Icon( + _obscureText ? Icons.visibility_off : Icons.visibility, + size: 20, + ), + onPressed: _toggleVisibility, + ) + : null, + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.outline, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.surfaceContainerHighest, + ), + ), + ), + validator: (value) { + if (value!.isEmpty) { + return "${widget.hintText} cannot be empty!"; + } + return null; + }, + obscureText: _obscureText, + onChanged: widget.onChanged, + ), + ], + ), + ); + } +} From 0ec2120741941daedd9680812065b9ddcf43860e Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Thu, 19 Jun 2025 13:04:30 +0530 Subject: [PATCH 17/70] feat: replace DropdownButtonFormField with ADPopupMenu for improved UI consistency --- .../auth/api_key_auth_fields.dart | 36 ++++----- .../common_widgets/auth/jwt_auth_fields.dart | 75 ++++++++----------- .../common_widgets/auth_textfield.dart | 3 +- .../request_pane/request_auth.dart | 30 ++++---- 4 files changed, 63 insertions(+), 81 deletions(-) diff --git a/lib/screens/common_widgets/auth/api_key_auth_fields.dart b/lib/screens/common_widgets/auth/api_key_auth_fields.dart index 6b4998749..1cc1c1760 100644 --- a/lib/screens/common_widgets/auth/api_key_auth_fields.dart +++ b/lib/screens/common_widgets/auth/api_key_auth_fields.dart @@ -2,6 +2,7 @@ import 'package:apidash/screens/common_widgets/auth_textfield.dart'; import 'package:apidash_core/consts.dart'; import 'package:apidash_core/models/auth/api_auth_model.dart'; import 'package:apidash_core/models/auth/auth_api_key_model.dart'; +import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; class ApiKeyAuthFields extends StatefulWidget { @@ -40,35 +41,26 @@ class _ApiKeyAuthFieldsState extends State { Text( "Add to", style: TextStyle( - fontWeight: FontWeight.bold, + fontWeight: FontWeight.normal, + fontSize: 14, ), ), SizedBox( height: 4, ), - DropdownButtonFormField( - value: _addKeyTo, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - items: [ - DropdownMenuItem( - value: 'header', - child: Text('Header'), - ), - DropdownMenuItem( - value: 'query', - child: Text('Query Params'), - ), + ADPopupMenu( + value: _addKeyTo == 'header' ? 'Header' : 'Query Params', + values: const [ + ('header', 'Header'), + ('query', 'Query Params'), ], + tooltip: "Select where to add API key", + isOutlined: true, onChanged: (String? newLocation) { if (newLocation != null) { + setState(() { + _addKeyTo = newLocation; + }); _updateApiKeyAuth(); } }, @@ -82,7 +74,7 @@ class _ApiKeyAuthFieldsState extends State { const SizedBox(height: 16), AuthTextField( controller: _keyController, - hintText: "API KeyName", + hintText: "API Key", isObscureText: true, onChanged: (value) => _updateApiKeyAuth(), ), diff --git a/lib/screens/common_widgets/auth/jwt_auth_fields.dart b/lib/screens/common_widgets/auth/jwt_auth_fields.dart index 4a478aabf..600bbacd9 100644 --- a/lib/screens/common_widgets/auth/jwt_auth_fields.dart +++ b/lib/screens/common_widgets/auth/jwt_auth_fields.dart @@ -1,4 +1,5 @@ import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; import 'package:apidash_core/apidash_core.dart'; @@ -42,33 +43,25 @@ class _JwtAuthFieldsState extends State { Text( "Add JWT token to", style: TextStyle( - fontWeight: FontWeight.bold, + fontWeight: FontWeight.normal, + fontSize: 14, ), ), SizedBox(height: 4), - DropdownButtonFormField( - value: _addTokenTo, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - items: [ - DropdownMenuItem( - value: 'header', - child: Text('Request Header'), - ), - DropdownMenuItem( - value: 'query', - child: Text('Query Parameters'), - ), + ADPopupMenu( + value: + _addTokenTo == 'header' ? 'Request Header' : 'Query Parameters', + values: const [ + ('header', 'Request Header'), + ('query', 'Query Parameters'), ], + tooltip: "Select where to add JWT token", + isOutlined: true, onChanged: (String? newAddTokenTo) { if (newAddTokenTo != null) { + setState(() { + _addTokenTo = newAddTokenTo; + }); _updateJwtAuth(); } }, @@ -77,33 +70,25 @@ class _JwtAuthFieldsState extends State { Text( "Algorithm", style: TextStyle( - fontWeight: FontWeight.bold, + fontWeight: FontWeight.normal, + fontSize: 14, ), ), SizedBox(height: 4), - DropdownButtonFormField( + ADPopupMenu( value: _algorithm, - decoration: InputDecoration( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width - 100, - ), - contentPadding: const EdgeInsets.all(18), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - items: [ - 'HS256', - 'HS384', - 'HS512', - ].map((algorithm) { - return DropdownMenuItem( - value: algorithm, - child: Text(algorithm), - ); - }).toList(), + values: const [ + ('HS256', 'HS256'), + ('HS384', 'HS384'), + ('HS512', 'HS512'), + ], + tooltip: "Select JWT algorithm", + isOutlined: true, onChanged: (String? newAlgorithm) { if (newAlgorithm != null) { + setState(() { + _algorithm = newAlgorithm; + }); _updateJwtAuth(); } }, @@ -120,7 +105,8 @@ class _JwtAuthFieldsState extends State { title: Text( "Secret is Base64 encoded", style: TextStyle( - fontWeight: FontWeight.bold, + fontWeight: FontWeight.normal, + fontSize: 14, ), ), value: _isSecretBase64Encoded, @@ -138,7 +124,8 @@ class _JwtAuthFieldsState extends State { Text( "Payload (JSON format)", style: TextStyle( - fontWeight: FontWeight.bold, + fontWeight: FontWeight.normal, + fontSize: 14, ), ), SizedBox(height: 4), diff --git a/lib/screens/common_widgets/auth_textfield.dart b/lib/screens/common_widgets/auth_textfield.dart index 0dd03c6e1..ad28ce877 100644 --- a/lib/screens/common_widgets/auth_textfield.dart +++ b/lib/screens/common_widgets/auth_textfield.dart @@ -45,7 +45,8 @@ class _AuthFieldState extends State { Text( widget.hintText, style: TextStyle( - fontWeight: FontWeight.bold, + fontWeight: FontWeight.normal, + fontSize: 14, ), ), const SizedBox(height: 6), diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index 6d401ea7a..a1fe378f9 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -2,6 +2,7 @@ import 'package:apidash/screens/common_widgets/auth/api_key_auth_fields.dart'; import 'package:apidash/screens/common_widgets/auth/basic_auth_fields.dart'; import 'package:apidash/screens/common_widgets/auth/bearer_auth_fields.dart'; import 'package:apidash/screens/common_widgets/auth/jwt_auth_fields.dart'; +import 'package:apidash_design_system/widgets/popup_menu.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash_core/apidash_core.dart'; @@ -39,20 +40,20 @@ class EditAuthType extends ConsumerWidget { SizedBox( height: 8, ), - DropdownButtonFormField( - value: currentAuthType, - elevation: 4, - decoration: InputDecoration( - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(9), - ), - ), - items: APIAuthType.values.map((type) { - return DropdownMenuItem( - value: type, - child: Text(type.name.capitalize()), - ); - }).toList(), + ADPopupMenu( + value: currentAuthType.name.capitalize(), + values: const [ + (APIAuthType.none, 'None'), + (APIAuthType.basic, 'Basic'), + (APIAuthType.apiKey, 'API Key'), + (APIAuthType.bearer, 'Bearer'), + (APIAuthType.jwt, 'JWT'), + (APIAuthType.digest, 'Digest'), + (APIAuthType.oauth1, 'OAuth 1.0'), + (APIAuthType.oauth2, 'OAuth 2.0'), + ], + tooltip: "Select Authentication Type", + isOutlined: true, onChanged: (APIAuthType? newType) { final selectedRequest = ref.read(selectedRequestModelProvider); if (newType != null) { @@ -72,6 +73,7 @@ class EditAuthType extends ConsumerWidget { ); } + // ...existing code... Widget _buildAuthFields( BuildContext context, WidgetRef ref, From 5be9ffdcc1a0bdee2d56d106c73d121d24dd3f97 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Thu, 19 Jun 2025 14:00:31 +0530 Subject: [PATCH 18/70] feat: update AuthModel serialization to use explicitToJson for nested objects --- packages/apidash_core/lib/models/auth/api_auth_model.dart | 1 + .../lib/models/auth/api_auth_model.freezed.dart | 3 ++- .../apidash_core/lib/models/auth/api_auth_model.g.dart | 8 ++++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.dart b/packages/apidash_core/lib/models/auth/api_auth_model.dart index fc7d89252..c38a566ee 100644 --- a/packages/apidash_core/lib/models/auth/api_auth_model.dart +++ b/packages/apidash_core/lib/models/auth/api_auth_model.dart @@ -10,6 +10,7 @@ part 'api_auth_model.freezed.dart'; @freezed class AuthModel with _$AuthModel { + @JsonSerializable(explicitToJson: true) const factory AuthModel({ required APIAuthType type, AuthApiKeyModel? apikey, diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart b/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart index 60e4872ef..3ff7badfa 100644 --- a/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart +++ b/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart @@ -226,7 +226,8 @@ class __$$AuthModelImplCopyWithImpl<$Res> } /// @nodoc -@JsonSerializable() + +@JsonSerializable(explicitToJson: true) class _$AuthModelImpl implements _AuthModel { const _$AuthModelImpl( {required this.type, this.apikey, this.bearer, this.basic, this.jwt}); diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.g.dart b/packages/apidash_core/lib/models/auth/api_auth_model.g.dart index 96b5f69f7..8235bc7b2 100644 --- a/packages/apidash_core/lib/models/auth/api_auth_model.g.dart +++ b/packages/apidash_core/lib/models/auth/api_auth_model.g.dart @@ -26,10 +26,10 @@ _$AuthModelImpl _$$AuthModelImplFromJson(Map json) => Map _$$AuthModelImplToJson(_$AuthModelImpl instance) => { 'type': _$APIAuthTypeEnumMap[instance.type]!, - 'apikey': instance.apikey, - 'bearer': instance.bearer, - 'basic': instance.basic, - 'jwt': instance.jwt, + 'apikey': instance.apikey?.toJson(), + 'bearer': instance.bearer?.toJson(), + 'basic': instance.basic?.toJson(), + 'jwt': instance.jwt?.toJson(), }; const _$APIAuthTypeEnumMap = { From 99e5fa7cbbff23b90fd04053f109b89eb19755b7 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Thu, 19 Jun 2025 14:22:02 +0530 Subject: [PATCH 19/70] feat: enhance AuthModel serialization with anyMap support and add default name for API key --- .../common_widgets/auth/api_key_auth_fields.dart | 2 +- .../lib/models/auth/api_auth_model.dart | 5 ++++- .../lib/models/auth/api_auth_model.freezed.dart | 2 +- .../lib/models/auth/api_auth_model.g.dart | 15 +++++++++------ 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/screens/common_widgets/auth/api_key_auth_fields.dart b/lib/screens/common_widgets/auth/api_key_auth_fields.dart index 1cc1c1760..e3878adcc 100644 --- a/lib/screens/common_widgets/auth/api_key_auth_fields.dart +++ b/lib/screens/common_widgets/auth/api_key_auth_fields.dart @@ -29,7 +29,7 @@ class _ApiKeyAuthFieldsState extends State { super.initState(); final apiAuth = widget.authData?.apikey; _keyController = TextEditingController(text: apiAuth?.key ?? ''); - _nameController = TextEditingController(text: apiAuth?.name ?? ''); + _nameController = TextEditingController(text: apiAuth?.name ?? 'x-api-key'); _addKeyTo = apiAuth?.location ?? 'header'; } diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.dart b/packages/apidash_core/lib/models/auth/api_auth_model.dart index c38a566ee..c9b19607c 100644 --- a/packages/apidash_core/lib/models/auth/api_auth_model.dart +++ b/packages/apidash_core/lib/models/auth/api_auth_model.dart @@ -10,7 +10,10 @@ part 'api_auth_model.freezed.dart'; @freezed class AuthModel with _$AuthModel { - @JsonSerializable(explicitToJson: true) + @JsonSerializable( + explicitToJson: true, + anyMap: true, + ) const factory AuthModel({ required APIAuthType type, AuthApiKeyModel? apikey, diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart b/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart index 3ff7badfa..28ceaec6b 100644 --- a/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart +++ b/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart @@ -227,7 +227,7 @@ class __$$AuthModelImplCopyWithImpl<$Res> /// @nodoc -@JsonSerializable(explicitToJson: true) +@JsonSerializable(explicitToJson: true, anyMap: true) class _$AuthModelImpl implements _AuthModel { const _$AuthModelImpl( {required this.type, this.apikey, this.bearer, this.basic, this.jwt}); diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.g.dart b/packages/apidash_core/lib/models/auth/api_auth_model.g.dart index 8235bc7b2..fdbd6e092 100644 --- a/packages/apidash_core/lib/models/auth/api_auth_model.g.dart +++ b/packages/apidash_core/lib/models/auth/api_auth_model.g.dart @@ -6,21 +6,24 @@ part of 'api_auth_model.dart'; // JsonSerializableGenerator // ************************************************************************** -_$AuthModelImpl _$$AuthModelImplFromJson(Map json) => - _$AuthModelImpl( +_$AuthModelImpl _$$AuthModelImplFromJson(Map json) => _$AuthModelImpl( type: $enumDecode(_$APIAuthTypeEnumMap, json['type']), apikey: json['apikey'] == null ? null - : AuthApiKeyModel.fromJson(json['apikey'] as Map), + : AuthApiKeyModel.fromJson( + Map.from(json['apikey'] as Map)), bearer: json['bearer'] == null ? null - : AuthBearerModel.fromJson(json['bearer'] as Map), + : AuthBearerModel.fromJson( + Map.from(json['bearer'] as Map)), basic: json['basic'] == null ? null - : AuthBasicAuthModel.fromJson(json['basic'] as Map), + : AuthBasicAuthModel.fromJson( + Map.from(json['basic'] as Map)), jwt: json['jwt'] == null ? null - : AuthJwtModel.fromJson(json['jwt'] as Map), + : AuthJwtModel.fromJson( + Map.from(json['jwt'] as Map)), ); Map _$$AuthModelImplToJson(_$AuthModelImpl instance) => From 987d9ca96a03fdbfb9934c9096f5e5b2efd133ed Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Thu, 19 Jun 2025 16:37:19 +0530 Subject: [PATCH 20/70] feat: enhance EditAuthType to support read-only in history view --- .../history_widgets/his_request_pane.dart | 15 ++- .../request_pane/request_auth.dart | 115 ++++++++++++------ 2 files changed, 87 insertions(+), 43 deletions(-) diff --git a/lib/screens/history/history_widgets/his_request_pane.dart b/lib/screens/history/history_widgets/his_request_pane.dart index c1e8995d5..6d6f1cb52 100644 --- a/lib/screens/history/history_widgets/his_request_pane.dart +++ b/lib/screens/history/history_widgets/his_request_pane.dart @@ -39,11 +39,12 @@ class HistoryRequestPane extends ConsumerWidget { .select((value) => value?.httpRequestModel.hasQuery)) ?? false; - final scriptsLength = ref.watch(selectedHistoryRequestModelProvider - .select((value) => value?.preRequestScript?.length)) ?? - ref.watch(selectedHistoryRequestModelProvider - .select((value) => value?.postRequestScript?.length)) ?? - 0; + final hasAuth = ref.watch(selectedHistoryRequestModelProvider.select( + (value) => + value?.httpRequestModel.authModel?.type != APIAuthType.none)); + + final authModel = ref.watch(selectedHistoryRequestModelProvider + .select((value) => value?.httpRequestModel.authModel)); return switch (apiType) { APIType.rest => RequestPane( @@ -72,6 +73,10 @@ class HistoryRequestPane extends ConsumerWidget { rows: paramsMap, keyName: kNameURLParam, ), + EditAuthType( + authModel: authModel, + readOnly: true, + ), RequestDataTable( rows: headersMap, keyName: kNameHeader, diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index a1fe378f9..0ef2d12f6 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -9,22 +9,35 @@ import 'package:apidash_core/apidash_core.dart'; import 'package:apidash/providers/providers.dart'; class EditAuthType extends ConsumerWidget { - const EditAuthType({super.key}); + final AuthModel? authModel; + final bool readOnly; + + const EditAuthType({ + super.key, + this.authModel, + this.readOnly = false, + }); @override Widget build(BuildContext context, WidgetRef ref) { - final selectedRequest = ref.read(selectedRequestModelProvider); - - if (selectedRequest == null) { - return const SizedBox.shrink(); - } + final AuthModel? currentAuthData; + final APIAuthType currentAuthType; - final currentAuthType = ref.watch( - selectedRequestModelProvider - .select((request) => request?.authModel?.type ?? APIAuthType.none), - ); - final currentAuthData = selectedRequest.authModel; + if (authModel != null) { + currentAuthData = authModel; + currentAuthType = authModel!.type; + } else { + final selectedRequest = ref.read(selectedRequestModelProvider); + if (selectedRequest == null) { + return const SizedBox.shrink(); + } + currentAuthType = ref.watch( + selectedRequestModelProvider.select((request) => + request?.httpRequestModel?.authModel?.type ?? APIAuthType.none), + ); + currentAuthData = selectedRequest.httpRequestModel?.authModel; + } return SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(16.0), @@ -40,31 +53,53 @@ class EditAuthType extends ConsumerWidget { SizedBox( height: 8, ), - ADPopupMenu( - value: currentAuthType.name.capitalize(), - values: const [ - (APIAuthType.none, 'None'), - (APIAuthType.basic, 'Basic'), - (APIAuthType.apiKey, 'API Key'), - (APIAuthType.bearer, 'Bearer'), - (APIAuthType.jwt, 'JWT'), - (APIAuthType.digest, 'Digest'), - (APIAuthType.oauth1, 'OAuth 1.0'), - (APIAuthType.oauth2, 'OAuth 2.0'), - ], - tooltip: "Select Authentication Type", - isOutlined: true, - onChanged: (APIAuthType? newType) { - final selectedRequest = ref.read(selectedRequestModelProvider); - if (newType != null) { - ref.read(collectionStateNotifierProvider.notifier).update( - authData: selectedRequest?.authModel - ?.copyWith(type: newType) ?? - AuthModel(type: newType), - ); - } - }, - ), + if (readOnly) + Container( + padding: + const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surfaceContainerLowest, + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: + Theme.of(context).colorScheme.outline.withOpacity(0.3), + ), + ), + child: Text( + currentAuthType.name.toUpperCase(), + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.w500, + color: Theme.of(context).colorScheme.primary, + ), + ), + ) + else + ADPopupMenu( + value: currentAuthType.name.capitalize(), + values: const [ + (APIAuthType.none, 'None'), + (APIAuthType.basic, 'Basic'), + (APIAuthType.apiKey, 'API Key'), + (APIAuthType.bearer, 'Bearer'), + (APIAuthType.jwt, 'JWT'), + (APIAuthType.digest, 'Digest'), + (APIAuthType.oauth1, 'OAuth 1.0'), + (APIAuthType.oauth2, 'OAuth 2.0'), + ], + tooltip: "Select Authentication Type", + isOutlined: true, + onChanged: (APIAuthType? newType) { + final selectedRequest = + ref.read(selectedRequestModelProvider); + if (newType != null) { + ref.read(collectionStateNotifierProvider.notifier).update( + authData: selectedRequest?.httpRequestModel?.authModel + ?.copyWith(type: newType) ?? + AuthModel(type: newType), + ); + } + }, + ), const SizedBox(height: 48), _buildAuthFields(context, ref, currentAuthData), ], @@ -107,9 +142,13 @@ class EditAuthType extends ConsumerWidget { updateAuth: updateAuth, ); case APIAuthType.none: - return const Text("No authentication selected."); + return Text(readOnly + ? "No authentication was used for this request." + : "No authentication selected."); default: - return const Text("This auth type is not implemented yet."); + return Text(readOnly + ? "Authentication details for ${authData?.type.name} are not yet supported in history view." + : "This auth type is not implemented yet."); } } } From 620c2750eea63b2cbd0531f1ee6f4cb4985dc529 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Thu, 19 Jun 2025 17:11:31 +0530 Subject: [PATCH 21/70] fix: change JWT generation failure handling to throw an exception instead of returning a basic JWT --- packages/apidash_core/lib/utils/auth_utils.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/apidash_core/lib/utils/auth_utils.dart b/packages/apidash_core/lib/utils/auth_utils.dart index 4e03b1440..df6bf864c 100644 --- a/packages/apidash_core/lib/utils/auth_utils.dart +++ b/packages/apidash_core/lib/utils/auth_utils.dart @@ -45,8 +45,7 @@ String generateJWT(AuthJwtModel jwtAuth) { return '$encodedHeader.$encodedPayload.$signature'; } catch (e) { - // Return a basic JWT if generation fails - return 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; + throw Exception('Failed to generate JWT: $e'); } } From 5a6e2b103a5d6c093d859cd523e7a666cc1a828b Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Thu, 19 Jun 2025 17:47:37 +0530 Subject: [PATCH 22/70] feat: add authentication tab for graphql requests --- .../request_pane/request_pane_graphql.dart | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart index fb8d7bc98..9510c97b1 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart @@ -1,4 +1,6 @@ import 'package:apidash/consts.dart'; +import 'package:apidash/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart'; +import 'package:apidash_core/consts.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/providers/providers.dart'; @@ -23,11 +25,8 @@ class EditGraphQLRequestPane extends ConsumerWidget { .select((value) => value?.httpRequestModel?.hasQuery)) ?? false; - final scriptsLength = ref.watch(selectedRequestModelProvider - .select((value) => value?.preRequestScript?.length)) ?? - ref.watch(selectedRequestModelProvider - .select((value) => value?.postRequestScript?.length)) ?? - 0; + final hasAuth = ref.watch(selectedRequestModelProvider.select((value) => + value?.httpRequestModel?.authModel?.type != APIAuthType.none)); if (tabIndex >= 3) { tabIndex = 0; @@ -47,16 +46,19 @@ class EditGraphQLRequestPane extends ConsumerWidget { }, showIndicators: [ headerLength > 0, + hasAuth, hasQuery, scriptsLength > 0, ], tabLabels: const [ kLabelHeaders, + kLabelAuth, kLabelQuery, kLabelScripts, ], children: const [ EditRequestHeaders(), + EditAuthType(), EditRequestBody(), EditRequestScripts(), ], From e06cb2e0bf125a9af9835557932f1d8b16ae2886 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Thu, 19 Jun 2025 17:49:30 +0530 Subject: [PATCH 23/70] feat: add read-only authentication tab to graphql history request pane --- .../history/history_widgets/his_request_pane.dart | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/screens/history/history_widgets/his_request_pane.dart b/lib/screens/history/history_widgets/his_request_pane.dart index 6d6f1cb52..8ac2bf88e 100644 --- a/lib/screens/history/history_widgets/his_request_pane.dart +++ b/lib/screens/history/history_widgets/his_request_pane.dart @@ -1,3 +1,4 @@ +import 'package:apidash/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; @@ -60,7 +61,6 @@ class HistoryRequestPane extends ConsumerWidget { paramLength > 0, headerLength > 0, hasBody, - scriptsLength > 0 ], tabLabels: const [ kLabelURLParams, @@ -94,9 +94,14 @@ class HistoryRequestPane extends ConsumerWidget { !codePaneVisible; }, showViewCodeButton: !isCompact, - showIndicators: [headerLength > 0, hasQuery, scriptsLength > 0], + showIndicators: [ + headerLength > 0, + hasAuth, + hasQuery, + ], tabLabels: const [ kLabelHeaders, + kLabelAuth, kLabelQuery, kLabelScripts, ], @@ -105,6 +110,10 @@ class HistoryRequestPane extends ConsumerWidget { rows: headersMap, keyName: kNameHeader, ), + EditAuthType( + authModel: authModel, + readOnly: true, + ), const HisRequestBody(), const HistoryScriptsTab(), ], From bf170e144683a0721afda5bea94ec079a6ad3524 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Wed, 25 Jun 2025 10:12:53 +0530 Subject: [PATCH 24/70] feat: remove AuthModel from HttpRequestModel and integrate into HistoryRequestModel and RequestModel --- lib/models/history_request_model.dart | 3 +- lib/models/history_request_model.freezed.dart | 80 +++++----- lib/models/history_request_model.g.dart | 9 +- lib/models/request_model.dart | 3 +- lib/models/request_model.freezed.dart | 104 ++++++------ lib/models/request_model.g.dart | 9 +- lib/providers/collection_providers.dart | 46 ++---- .../history_widgets/his_request_pane.dart | 4 +- .../request_pane/request_auth.dart | 6 +- .../request_pane/request_pane_graphql.dart | 2 +- .../request_pane/request_pane_rest.dart | 5 +- .../lib/models/http_request_model.g.dart | 68 ++++++++ .../apidash_core/lib/utils/handle_auth.dart | 23 ++- .../models/http_request_model.freezed.dart | 151 ++++++++++++++++++ .../lib/services/http_service.dart | 6 +- pubspec.lock | 2 +- 16 files changed, 359 insertions(+), 162 deletions(-) create mode 100644 packages/apidash_core/lib/models/http_request_model.g.dart diff --git a/lib/models/history_request_model.dart b/lib/models/history_request_model.dart index 1ffc54608..4235d643b 100644 --- a/lib/models/history_request_model.dart +++ b/lib/models/history_request_model.dart @@ -16,8 +16,7 @@ class HistoryRequestModel with _$HistoryRequestModel { required HistoryMetaModel metaData, required HttpRequestModel httpRequestModel, required HttpResponseModel httpResponseModel, - String? preRequestScript, - String? postRequestScript, + required AuthModel? authModel, }) = _HistoryRequestModel; factory HistoryRequestModel.fromJson(Map json) => diff --git a/lib/models/history_request_model.freezed.dart b/lib/models/history_request_model.freezed.dart index ac43f3eee..8afe5c5a4 100644 --- a/lib/models/history_request_model.freezed.dart +++ b/lib/models/history_request_model.freezed.dart @@ -24,8 +24,7 @@ mixin _$HistoryRequestModel { HistoryMetaModel get metaData => throw _privateConstructorUsedError; HttpRequestModel get httpRequestModel => throw _privateConstructorUsedError; HttpResponseModel get httpResponseModel => throw _privateConstructorUsedError; - String? get preRequestScript => throw _privateConstructorUsedError; - String? get postRequestScript => throw _privateConstructorUsedError; + AuthModel? get authModel => throw _privateConstructorUsedError; /// Serializes this HistoryRequestModel to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -48,12 +47,12 @@ abstract class $HistoryRequestModelCopyWith<$Res> { HistoryMetaModel metaData, HttpRequestModel httpRequestModel, HttpResponseModel httpResponseModel, - String? preRequestScript, - String? postRequestScript}); + AuthModel? authModel}); $HistoryMetaModelCopyWith<$Res> get metaData; $HttpRequestModelCopyWith<$Res> get httpRequestModel; $HttpResponseModelCopyWith<$Res> get httpResponseModel; + $AuthModelCopyWith<$Res>? get authModel; } /// @nodoc @@ -75,8 +74,7 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel> Object? metaData = null, Object? httpRequestModel = null, Object? httpResponseModel = null, - Object? preRequestScript = freezed, - Object? postRequestScript = freezed, + Object? authModel = freezed, }) { return _then(_value.copyWith( historyId: null == historyId @@ -95,14 +93,10 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel> ? _value.httpResponseModel : httpResponseModel // ignore: cast_nullable_to_non_nullable as HttpResponseModel, - preRequestScript: freezed == preRequestScript - ? _value.preRequestScript - : preRequestScript // ignore: cast_nullable_to_non_nullable - as String?, - postRequestScript: freezed == postRequestScript - ? _value.postRequestScript - : postRequestScript // ignore: cast_nullable_to_non_nullable - as String?, + authModel: freezed == authModel + ? _value.authModel + : authModel // ignore: cast_nullable_to_non_nullable + as AuthModel?, ) as $Val); } @@ -135,6 +129,20 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel> return _then(_value.copyWith(httpResponseModel: value) as $Val); }); } + + /// Create a copy of HistoryRequestModel + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $AuthModelCopyWith<$Res>? get authModel { + if (_value.authModel == null) { + return null; + } + + return $AuthModelCopyWith<$Res>(_value.authModel!, (value) { + return _then(_value.copyWith(authModel: value) as $Val); + }); + } } /// @nodoc @@ -150,8 +158,7 @@ abstract class _$$HistoryRequestModelImplCopyWith<$Res> HistoryMetaModel metaData, HttpRequestModel httpRequestModel, HttpResponseModel httpResponseModel, - String? preRequestScript, - String? postRequestScript}); + AuthModel? authModel}); @override $HistoryMetaModelCopyWith<$Res> get metaData; @@ -159,6 +166,8 @@ abstract class _$$HistoryRequestModelImplCopyWith<$Res> $HttpRequestModelCopyWith<$Res> get httpRequestModel; @override $HttpResponseModelCopyWith<$Res> get httpResponseModel; + @override + $AuthModelCopyWith<$Res>? get authModel; } /// @nodoc @@ -178,8 +187,7 @@ class __$$HistoryRequestModelImplCopyWithImpl<$Res> Object? metaData = null, Object? httpRequestModel = null, Object? httpResponseModel = null, - Object? preRequestScript = freezed, - Object? postRequestScript = freezed, + Object? authModel = freezed, }) { return _then(_$HistoryRequestModelImpl( historyId: null == historyId @@ -198,14 +206,10 @@ class __$$HistoryRequestModelImplCopyWithImpl<$Res> ? _value.httpResponseModel : httpResponseModel // ignore: cast_nullable_to_non_nullable as HttpResponseModel, - preRequestScript: freezed == preRequestScript - ? _value.preRequestScript - : preRequestScript // ignore: cast_nullable_to_non_nullable - as String?, - postRequestScript: freezed == postRequestScript - ? _value.postRequestScript - : postRequestScript // ignore: cast_nullable_to_non_nullable - as String?, + authModel: freezed == authModel + ? _value.authModel + : authModel // ignore: cast_nullable_to_non_nullable + as AuthModel?, )); } } @@ -219,8 +223,7 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel { required this.metaData, required this.httpRequestModel, required this.httpResponseModel, - this.preRequestScript, - this.postRequestScript}); + required this.authModel}); factory _$HistoryRequestModelImpl.fromJson(Map json) => _$$HistoryRequestModelImplFromJson(json); @@ -234,13 +237,11 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel { @override final HttpResponseModel httpResponseModel; @override - final String? preRequestScript; - @override - final String? postRequestScript; + final AuthModel? authModel; @override String toString() { - return 'HistoryRequestModel(historyId: $historyId, metaData: $metaData, httpRequestModel: $httpRequestModel, httpResponseModel: $httpResponseModel, preRequestScript: $preRequestScript, postRequestScript: $postRequestScript)'; + return 'HistoryRequestModel(historyId: $historyId, metaData: $metaData, httpRequestModel: $httpRequestModel, httpResponseModel: $httpResponseModel, authModel: $authModel)'; } @override @@ -256,16 +257,14 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel { other.httpRequestModel == httpRequestModel) && (identical(other.httpResponseModel, httpResponseModel) || other.httpResponseModel == httpResponseModel) && - (identical(other.preRequestScript, preRequestScript) || - other.preRequestScript == preRequestScript) && - (identical(other.postRequestScript, postRequestScript) || - other.postRequestScript == postRequestScript)); + (identical(other.authModel, authModel) || + other.authModel == authModel)); } @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash(runtimeType, historyId, metaData, - httpRequestModel, httpResponseModel, preRequestScript, postRequestScript); + httpRequestModel, httpResponseModel, authModel); /// Create a copy of HistoryRequestModel /// with the given fields replaced by the non-null parameter values. @@ -290,8 +289,7 @@ abstract class _HistoryRequestModel implements HistoryRequestModel { required final HistoryMetaModel metaData, required final HttpRequestModel httpRequestModel, required final HttpResponseModel httpResponseModel, - final String? preRequestScript, - final String? postRequestScript}) = _$HistoryRequestModelImpl; + required final AuthModel? authModel}) = _$HistoryRequestModelImpl; factory _HistoryRequestModel.fromJson(Map json) = _$HistoryRequestModelImpl.fromJson; @@ -305,9 +303,7 @@ abstract class _HistoryRequestModel implements HistoryRequestModel { @override HttpResponseModel get httpResponseModel; @override - String? get preRequestScript; - @override - String? get postRequestScript; + AuthModel? get authModel; /// Create a copy of HistoryRequestModel /// with the given fields replaced by the non-null parameter values. diff --git a/lib/models/history_request_model.g.dart b/lib/models/history_request_model.g.dart index 705a20222..a3f852fd2 100644 --- a/lib/models/history_request_model.g.dart +++ b/lib/models/history_request_model.g.dart @@ -15,8 +15,10 @@ _$HistoryRequestModelImpl _$$HistoryRequestModelImplFromJson(Map json) => Map.from(json['httpRequestModel'] as Map)), httpResponseModel: HttpResponseModel.fromJson( Map.from(json['httpResponseModel'] as Map)), - preRequestScript: json['preRequestScript'] as String?, - postRequestScript: json['postRequestScript'] as String?, + authModel: json['authModel'] == null + ? null + : AuthModel.fromJson( + Map.from(json['authModel'] as Map)), ); Map _$$HistoryRequestModelImplToJson( @@ -26,6 +28,5 @@ Map _$$HistoryRequestModelImplToJson( 'metaData': instance.metaData.toJson(), 'httpRequestModel': instance.httpRequestModel.toJson(), 'httpResponseModel': instance.httpResponseModel.toJson(), - 'preRequestScript': instance.preRequestScript, - 'postRequestScript': instance.postRequestScript, + 'authModel': instance.authModel?.toJson(), }; diff --git a/lib/models/request_model.dart b/lib/models/request_model.dart index a3eda0ba6..4cf4eef86 100644 --- a/lib/models/request_model.dart +++ b/lib/models/request_model.dart @@ -23,8 +23,7 @@ class RequestModel with _$RequestModel { HttpResponseModel? httpResponseModel, @JsonKey(includeToJson: false) @Default(false) bool isWorking, @JsonKey(includeToJson: false) DateTime? sendingTime, - String? preRequestScript, - String? postRequestScript, + @Default(AuthModel(type: APIAuthType.none)) AuthModel? authModel, }) = _RequestModel; factory RequestModel.fromJson(Map json) => diff --git a/lib/models/request_model.freezed.dart b/lib/models/request_model.freezed.dart index 392c34f8a..d8b9c4172 100644 --- a/lib/models/request_model.freezed.dart +++ b/lib/models/request_model.freezed.dart @@ -36,8 +36,7 @@ mixin _$RequestModel { bool get isWorking => throw _privateConstructorUsedError; @JsonKey(includeToJson: false) DateTime? get sendingTime => throw _privateConstructorUsedError; - String? get preRequestScript => throw _privateConstructorUsedError; - String? get postRequestScript => throw _privateConstructorUsedError; + AuthModel? get authModel => throw _privateConstructorUsedError; /// Serializes this RequestModel to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -68,12 +67,12 @@ abstract class $RequestModelCopyWith<$Res> { HttpResponseModel? httpResponseModel, @JsonKey(includeToJson: false) bool isWorking, @JsonKey(includeToJson: false) DateTime? sendingTime, - String? preRequestScript, - String? postRequestScript}); + AuthModel? authModel}); $AuthModelCopyWith<$Res>? get authModel; $HttpRequestModelCopyWith<$Res>? get httpRequestModel; $HttpResponseModelCopyWith<$Res>? get httpResponseModel; + $AuthModelCopyWith<$Res>? get authModel; } /// @nodoc @@ -103,8 +102,7 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> Object? httpResponseModel = freezed, Object? isWorking = null, Object? sendingTime = freezed, - Object? preRequestScript = freezed, - Object? postRequestScript = freezed, + Object? authModel = freezed, }) { return _then(_value.copyWith( id: null == id @@ -155,14 +153,10 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> ? _value.sendingTime : sendingTime // ignore: cast_nullable_to_non_nullable as DateTime?, - preRequestScript: freezed == preRequestScript - ? _value.preRequestScript - : preRequestScript // ignore: cast_nullable_to_non_nullable - as String?, - postRequestScript: freezed == postRequestScript - ? _value.postRequestScript - : postRequestScript // ignore: cast_nullable_to_non_nullable - as String?, + authModel: freezed == authModel + ? _value.authModel + : authModel // ignore: cast_nullable_to_non_nullable + as AuthModel?, ) as $Val); } @@ -207,6 +201,20 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> return _then(_value.copyWith(httpResponseModel: value) as $Val); }); } + + /// Create a copy of RequestModel + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $AuthModelCopyWith<$Res>? get authModel { + if (_value.authModel == null) { + return null; + } + + return $AuthModelCopyWith<$Res>(_value.authModel!, (value) { + return _then(_value.copyWith(authModel: value) as $Val); + }); + } } /// @nodoc @@ -230,8 +238,7 @@ abstract class _$$RequestModelImplCopyWith<$Res> HttpResponseModel? httpResponseModel, @JsonKey(includeToJson: false) bool isWorking, @JsonKey(includeToJson: false) DateTime? sendingTime, - String? preRequestScript, - String? postRequestScript}); + AuthModel? authModel}); @override $AuthModelCopyWith<$Res>? get authModel; @@ -239,6 +246,8 @@ abstract class _$$RequestModelImplCopyWith<$Res> $HttpRequestModelCopyWith<$Res>? get httpRequestModel; @override $HttpResponseModelCopyWith<$Res>? get httpResponseModel; + @override + $AuthModelCopyWith<$Res>? get authModel; } /// @nodoc @@ -266,8 +275,7 @@ class __$$RequestModelImplCopyWithImpl<$Res> Object? httpResponseModel = freezed, Object? isWorking = null, Object? sendingTime = freezed, - Object? preRequestScript = freezed, - Object? postRequestScript = freezed, + Object? authModel = freezed, }) { return _then(_$RequestModelImpl( id: null == id @@ -317,14 +325,10 @@ class __$$RequestModelImplCopyWithImpl<$Res> ? _value.sendingTime : sendingTime // ignore: cast_nullable_to_non_nullable as DateTime?, - preRequestScript: freezed == preRequestScript - ? _value.preRequestScript - : preRequestScript // ignore: cast_nullable_to_non_nullable - as String?, - postRequestScript: freezed == postRequestScript - ? _value.postRequestScript - : postRequestScript // ignore: cast_nullable_to_non_nullable - as String?, + authModel: freezed == authModel + ? _value.authModel + : authModel // ignore: cast_nullable_to_non_nullable + as AuthModel?, )); } } @@ -346,8 +350,7 @@ class _$RequestModelImpl implements _RequestModel { this.httpResponseModel, @JsonKey(includeToJson: false) this.isWorking = false, @JsonKey(includeToJson: false) this.sendingTime, - this.preRequestScript, - this.postRequestScript}); + this.authModel = const AuthModel(type: APIAuthType.none)}); factory _$RequestModelImpl.fromJson(Map json) => _$$RequestModelImplFromJson(json); @@ -384,13 +387,12 @@ class _$RequestModelImpl implements _RequestModel { @JsonKey(includeToJson: false) final DateTime? sendingTime; @override - final String? preRequestScript; - @override - final String? postRequestScript; + @JsonKey() + final AuthModel? authModel; @override String toString() { - return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, authModel: $authModel, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime)'; + return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime, authModel: $authModel)'; } @override @@ -418,10 +420,8 @@ class _$RequestModelImpl implements _RequestModel { other.isWorking == isWorking) && (identical(other.sendingTime, sendingTime) || other.sendingTime == sendingTime) && - (identical(other.preRequestScript, preRequestScript) || - other.preRequestScript == preRequestScript) && - (identical(other.postRequestScript, postRequestScript) || - other.postRequestScript == postRequestScript)); + (identical(other.authModel, authModel) || + other.authModel == authModel)); } @JsonKey(includeFromJson: false, includeToJson: false) @@ -440,8 +440,7 @@ class _$RequestModelImpl implements _RequestModel { httpResponseModel, isWorking, sendingTime, - preRequestScript, - postRequestScript); + authModel); /// Create a copy of RequestModel /// with the given fields replaced by the non-null parameter values. @@ -461,19 +460,18 @@ class _$RequestModelImpl implements _RequestModel { abstract class _RequestModel implements RequestModel { const factory _RequestModel( - {required final String id, - final APIType apiType, - final String name, - final String description, - final AuthModel? authModel, - @JsonKey(includeToJson: false) final dynamic requestTabIndex, - final HttpRequestModel? httpRequestModel, - final int? responseStatus, - final String? message, - final HttpResponseModel? httpResponseModel, - @JsonKey(includeToJson: false) final bool isWorking, - @JsonKey(includeToJson: false) final DateTime? sendingTime}) = - _$RequestModelImpl; + {required final String id, + final APIType apiType, + final String name, + final String description, + @JsonKey(includeToJson: false) final dynamic requestTabIndex, + final HttpRequestModel? httpRequestModel, + final int? responseStatus, + final String? message, + final HttpResponseModel? httpResponseModel, + @JsonKey(includeToJson: false) final bool isWorking, + @JsonKey(includeToJson: false) final DateTime? sendingTime, + final AuthModel? authModel}) = _$RequestModelImpl; factory _RequestModel.fromJson(Map json) = _$RequestModelImpl.fromJson; @@ -506,9 +504,7 @@ abstract class _RequestModel implements RequestModel { @JsonKey(includeToJson: false) DateTime? get sendingTime; @override - String? get preRequestScript; - @override - String? get postRequestScript; + AuthModel? get authModel; /// Create a copy of RequestModel /// with the given fields replaced by the non-null parameter values. diff --git a/lib/models/request_model.g.dart b/lib/models/request_model.g.dart index 6c6337262..e5a15d1cc 100644 --- a/lib/models/request_model.g.dart +++ b/lib/models/request_model.g.dart @@ -31,8 +31,10 @@ _$RequestModelImpl _$$RequestModelImplFromJson(Map json) => _$RequestModelImpl( sendingTime: json['sendingTime'] == null ? null : DateTime.parse(json['sendingTime'] as String), - preRequestScript: json['preRequestScript'] as String?, - postRequestScript: json['postRequestScript'] as String?, + authModel: json['authModel'] == null + ? const AuthModel(type: APIAuthType.none) + : AuthModel.fromJson( + Map.from(json['authModel'] as Map)), ); Map _$$RequestModelImplToJson(_$RequestModelImpl instance) => @@ -46,8 +48,7 @@ Map _$$RequestModelImplToJson(_$RequestModelImpl instance) => 'responseStatus': instance.responseStatus, 'message': instance.message, 'httpResponseModel': instance.httpResponseModel?.toJson(), - 'preRequestScript': instance.preRequestScript, - 'postRequestScript': instance.postRequestScript, + 'authModel': instance.authModel?.toJson(), }; const _$APITypeEnumMap = { diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 98e5ddeba..6cf3a7b21 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -239,6 +239,7 @@ class CollectionStateNotifier name: name ?? currentModel.name, description: description ?? currentModel.description, requestTabIndex: requestTabIndex ?? currentModel.requestTabIndex, + authModel: authData ?? currentModel.authModel, httpRequestModel: currentHttpRequestModel?.copyWith( method: method ?? currentHttpRequestModel.method, url: url ?? currentHttpRequestModel.url, @@ -317,6 +318,7 @@ class CollectionStateNotifier requestId, apiType, requestModel.authModel, + requestModel.authModel, substitutedHttpRequestModel, defaultUriScheme: defaultUriScheme, noSSL: noSSL, @@ -343,38 +345,20 @@ class CollectionStateNotifier ); String newHistoryId = getNewUuid(); HistoryRequestModel model = HistoryRequestModel( - historyId: newHistoryId, - metaData: HistoryMetaModel( historyId: newHistoryId, - requestId: requestId, - apiType: requestModel.apiType, - name: requestModel.name, - url: substitutedHttpRequestModel.url, - method: substitutedHttpRequestModel.method, - responseStatus: statusCode, - timeStamp: DateTime.now(), - ), - httpRequestModel: substitutedHttpRequestModel, - httpResponseModel: httpResponseModel, - preRequestScript: requestModel.preRequestScript, - postRequestScript: requestModel.postRequestScript, - ); - - if (!requestModel.postRequestScript.isNullOrEmpty()) { - newRequestModel = await handlePostResponseScript( - newRequestModel, - originalEnvironmentModel, - (envModel, updatedValues) { - ref - .read(environmentsStateNotifierProvider.notifier) - .updateEnvironment( - envModel.id, - name: envModel.name, - values: updatedValues, - ); - }, - ); - } + metaData: HistoryMetaModel( + historyId: newHistoryId, + requestId: requestId, + apiType: requestModel.apiType, + name: requestModel.name, + url: substitutedHttpRequestModel.url, + method: substitutedHttpRequestModel.method, + responseStatus: statusCode, + timeStamp: DateTime.now(), + ), + httpRequestModel: substitutedHttpRequestModel, + httpResponseModel: httpResponseModel, + authModel: requestModel.authModel); ref.read(historyMetaStateNotifier.notifier).addHistoryRequest(model); } diff --git a/lib/screens/history/history_widgets/his_request_pane.dart b/lib/screens/history/history_widgets/his_request_pane.dart index 8ac2bf88e..1e361827c 100644 --- a/lib/screens/history/history_widgets/his_request_pane.dart +++ b/lib/screens/history/history_widgets/his_request_pane.dart @@ -42,10 +42,10 @@ class HistoryRequestPane extends ConsumerWidget { final hasAuth = ref.watch(selectedHistoryRequestModelProvider.select( (value) => - value?.httpRequestModel.authModel?.type != APIAuthType.none)); + value?.authModel?.type != APIAuthType.none)); final authModel = ref.watch(selectedHistoryRequestModelProvider - .select((value) => value?.httpRequestModel.authModel)); + .select((value) => value?.authModel)); return switch (apiType) { APIType.rest => RequestPane( diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index 0ef2d12f6..dbf4578c5 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -34,9 +34,9 @@ class EditAuthType extends ConsumerWidget { currentAuthType = ref.watch( selectedRequestModelProvider.select((request) => - request?.httpRequestModel?.authModel?.type ?? APIAuthType.none), + request?.authModel?.type ?? APIAuthType.none), ); - currentAuthData = selectedRequest.httpRequestModel?.authModel; + currentAuthData = selectedRequest.authModel; } return SingleChildScrollView( child: Padding( @@ -93,7 +93,7 @@ class EditAuthType extends ConsumerWidget { ref.read(selectedRequestModelProvider); if (newType != null) { ref.read(collectionStateNotifierProvider.notifier).update( - authData: selectedRequest?.httpRequestModel?.authModel + authData: selectedRequest?.authModel ?.copyWith(type: newType) ?? AuthModel(type: newType), ); diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart index 9510c97b1..66b100a22 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart @@ -26,7 +26,7 @@ class EditGraphQLRequestPane extends ConsumerWidget { false; final hasAuth = ref.watch(selectedRequestModelProvider.select((value) => - value?.httpRequestModel?.authModel?.type != APIAuthType.none)); + value?.authModel?.type != APIAuthType.none)); if (tabIndex >= 3) { tabIndex = 0; diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart index c3177e8ba..ee89918b7 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart @@ -29,9 +29,8 @@ class EditRestRequestPane extends ConsumerWidget { .select((value) => value?.httpRequestModel?.hasBody)) ?? false; - final hasAuth = ref.watch(selectedRequestModelProvider - .select((value) => value?.authModel?.type != APIAuthType.none)); - false; + final hasAuth = ref.watch(selectedRequestModelProvider.select((value) => + value?.authModel?.type != APIAuthType.none)); return RequestPane( selectedId: selectedId, diff --git a/packages/apidash_core/lib/models/http_request_model.g.dart b/packages/apidash_core/lib/models/http_request_model.g.dart new file mode 100644 index 000000000..13795ded4 --- /dev/null +++ b/packages/apidash_core/lib/models/http_request_model.g.dart @@ -0,0 +1,68 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'http_request_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$HttpRequestModelImpl _$$HttpRequestModelImplFromJson(Map json) => + _$HttpRequestModelImpl( + method: $enumDecodeNullable(_$HTTPVerbEnumMap, json['method']) ?? + HTTPVerb.get, + url: json['url'] as String? ?? "", + headers: (json['headers'] as List?) + ?.map((e) => + NameValueModel.fromJson(Map.from(e as Map))) + .toList(), + params: (json['params'] as List?) + ?.map((e) => + NameValueModel.fromJson(Map.from(e as Map))) + .toList(), + isHeaderEnabledList: (json['isHeaderEnabledList'] as List?) + ?.map((e) => e as bool) + .toList(), + isParamEnabledList: (json['isParamEnabledList'] as List?) + ?.map((e) => e as bool) + .toList(), + bodyContentType: + $enumDecodeNullable(_$ContentTypeEnumMap, json['bodyContentType']) ?? + ContentType.json, + body: json['body'] as String?, + query: json['query'] as String?, + formData: (json['formData'] as List?) + ?.map((e) => + FormDataModel.fromJson(Map.from(e as Map))) + .toList(), + ); + +Map _$$HttpRequestModelImplToJson( + _$HttpRequestModelImpl instance) => + { + 'method': _$HTTPVerbEnumMap[instance.method]!, + 'url': instance.url, + 'headers': instance.headers?.map((e) => e.toJson()).toList(), + 'params': instance.params?.map((e) => e.toJson()).toList(), + 'isHeaderEnabledList': instance.isHeaderEnabledList, + 'isParamEnabledList': instance.isParamEnabledList, + 'bodyContentType': _$ContentTypeEnumMap[instance.bodyContentType]!, + 'body': instance.body, + 'query': instance.query, + 'formData': instance.formData?.map((e) => e.toJson()).toList(), + }; + +const _$HTTPVerbEnumMap = { + HTTPVerb.get: 'get', + HTTPVerb.head: 'head', + HTTPVerb.post: 'post', + HTTPVerb.put: 'put', + HTTPVerb.patch: 'patch', + HTTPVerb.delete: 'delete', + HTTPVerb.options: 'options', +}; + +const _$ContentTypeEnumMap = { + ContentType.json: 'json', + ContentType.text: 'text', + ContentType.formdata: 'formdata', +}; diff --git a/packages/apidash_core/lib/utils/handle_auth.dart b/packages/apidash_core/lib/utils/handle_auth.dart index f46c5db81..5cbf7e8fd 100644 --- a/packages/apidash_core/lib/utils/handle_auth.dart +++ b/packages/apidash_core/lib/utils/handle_auth.dart @@ -5,9 +5,8 @@ import 'package:apidash_core/models/http_request_model.dart'; import 'package:apidash_core/utils/auth_utils.dart'; import 'package:seed/seed.dart'; -HttpRequestModel handleAuth( - HttpRequestModel httpRequestModel, AuthModel? auth) { - if (auth == null || auth.type == APIAuthType.none) { +HttpRequestModel handleAuth(HttpRequestModel httpRequestModel,AuthModel? authData) { + if (authData == null || authData.type == APIAuthType.none) { return httpRequestModel; } @@ -19,10 +18,10 @@ HttpRequestModel handleAuth( List updatedParamEnabledList = List.from(httpRequestModel.isParamEnabledList ?? []); - switch (auth.type) { + switch (authData.type) { case APIAuthType.basic: - if (auth.basic != null) { - final basicAuth = auth.basic!; + if (authData.basic != null) { + final basicAuth = authData.basic!; final encoded = base64Encode( utf8.encode('${basicAuth.username}:${basicAuth.password}')); updatedHeaders.add( @@ -32,8 +31,8 @@ HttpRequestModel handleAuth( break; case APIAuthType.bearer: - if (auth.bearer != null) { - final bearerAuth = auth.bearer!; + if (authData.bearer != null) { + final bearerAuth = authData.bearer!; updatedHeaders.add(NameValueModel( name: 'Authorization', value: 'Bearer ${bearerAuth.token}')); updatedHeaderEnabledList.add(true); @@ -41,8 +40,8 @@ HttpRequestModel handleAuth( break; case APIAuthType.jwt: - if (auth.jwt != null) { - final jwtAuth = auth.jwt!; + if (authData.jwt != null) { + final jwtAuth = authData.jwt!; // Generate JWT token final jwtToken = generateJWT(jwtAuth); @@ -67,8 +66,8 @@ HttpRequestModel handleAuth( break; case APIAuthType.apiKey: - if (auth.apikey != null) { - final apiKeyAuth = auth.apikey!; + if (authData.apikey != null) { + final apiKeyAuth = authData.apikey!; if (apiKeyAuth.location == 'header') { updatedHeaders.add( NameValueModel(name: apiKeyAuth.name, value: apiKeyAuth.key)); diff --git a/packages/better_networking/lib/models/http_request_model.freezed.dart b/packages/better_networking/lib/models/http_request_model.freezed.dart index 864ae7e0b..73ef7423c 100644 --- a/packages/better_networking/lib/models/http_request_model.freezed.dart +++ b/packages/better_networking/lib/models/http_request_model.freezed.dart @@ -61,6 +61,17 @@ abstract class $HttpRequestModelCopyWith<$Res> { String? query, List? formData, }); + $Res call( + {HTTPVerb method, + String url, + List? headers, + List? params, + List? isHeaderEnabledList, + List? isParamEnabledList, + ContentType bodyContentType, + String? body, + String? query, + List? formData}); } /// @nodoc @@ -135,6 +146,49 @@ class _$HttpRequestModelCopyWithImpl<$Res, $Val extends HttpRequestModel> as $Val, ); } + return _then(_value.copyWith( + method: null == method + ? _value.method + : method // ignore: cast_nullable_to_non_nullable + as HTTPVerb, + url: null == url + ? _value.url + : url // ignore: cast_nullable_to_non_nullable + as String, + headers: freezed == headers + ? _value.headers + : headers // ignore: cast_nullable_to_non_nullable + as List?, + params: freezed == params + ? _value.params + : params // ignore: cast_nullable_to_non_nullable + as List?, + isHeaderEnabledList: freezed == isHeaderEnabledList + ? _value.isHeaderEnabledList + : isHeaderEnabledList // ignore: cast_nullable_to_non_nullable + as List?, + isParamEnabledList: freezed == isParamEnabledList + ? _value.isParamEnabledList + : isParamEnabledList // ignore: cast_nullable_to_non_nullable + as List?, + bodyContentType: null == bodyContentType + ? _value.bodyContentType + : bodyContentType // ignore: cast_nullable_to_non_nullable + as ContentType, + body: freezed == body + ? _value.body + : body // ignore: cast_nullable_to_non_nullable + as String?, + query: freezed == query + ? _value.query + : query // ignore: cast_nullable_to_non_nullable + as String?, + formData: freezed == formData + ? _value.formData + : formData // ignore: cast_nullable_to_non_nullable + as List?, + ) as $Val); + } } /// @nodoc @@ -158,6 +212,17 @@ abstract class _$$HttpRequestModelImplCopyWith<$Res> String? query, List? formData, }); + $Res call( + {HTTPVerb method, + String url, + List? headers, + List? params, + List? isHeaderEnabledList, + List? isParamEnabledList, + ContentType bodyContentType, + String? body, + String? query, + List? formData}); } /// @nodoc @@ -229,6 +294,48 @@ class __$$HttpRequestModelImplCopyWithImpl<$Res> as List?, ), ); + return _then(_$HttpRequestModelImpl( + method: null == method + ? _value.method + : method // ignore: cast_nullable_to_non_nullable + as HTTPVerb, + url: null == url + ? _value.url + : url // ignore: cast_nullable_to_non_nullable + as String, + headers: freezed == headers + ? _value._headers + : headers // ignore: cast_nullable_to_non_nullable + as List?, + params: freezed == params + ? _value._params + : params // ignore: cast_nullable_to_non_nullable + as List?, + isHeaderEnabledList: freezed == isHeaderEnabledList + ? _value._isHeaderEnabledList + : isHeaderEnabledList // ignore: cast_nullable_to_non_nullable + as List?, + isParamEnabledList: freezed == isParamEnabledList + ? _value._isParamEnabledList + : isParamEnabledList // ignore: cast_nullable_to_non_nullable + as List?, + bodyContentType: null == bodyContentType + ? _value.bodyContentType + : bodyContentType // ignore: cast_nullable_to_non_nullable + as ContentType, + body: freezed == body + ? _value.body + : body // ignore: cast_nullable_to_non_nullable + as String?, + query: freezed == query + ? _value.query + : query // ignore: cast_nullable_to_non_nullable + as String?, + formData: freezed == formData + ? _value._formData + : formData // ignore: cast_nullable_to_non_nullable + as List?, + )); } } @@ -253,6 +360,23 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { _isParamEnabledList = isParamEnabledList, _formData = formData, super._(); + const _$HttpRequestModelImpl( + {this.method = HTTPVerb.get, + this.url = "", + final List? headers, + final List? params, + final List? isHeaderEnabledList, + final List? isParamEnabledList, + this.bodyContentType = ContentType.json, + this.body, + this.query, + final List? formData}) + : _headers = headers, + _params = params, + _isHeaderEnabledList = isHeaderEnabledList, + _isParamEnabledList = isParamEnabledList, + _formData = formData, + super._(); factory _$HttpRequestModelImpl.fromJson(Map json) => _$$HttpRequestModelImplFromJson(json); @@ -325,6 +449,7 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { @override String toString() { return 'HttpRequestModel(method: $method, url: $url, headers: $headers, params: $params, isHeaderEnabledList: $isHeaderEnabledList, isParamEnabledList: $isParamEnabledList, bodyContentType: $bodyContentType, body: $body, query: $query, formData: $formData)'; + return 'HttpRequestModel(method: $method, url: $url, headers: $headers, params: $params, isHeaderEnabledList: $isHeaderEnabledList, isParamEnabledList: $isParamEnabledList, bodyContentType: $bodyContentType, body: $body, query: $query, formData: $formData)'; } @override @@ -344,6 +469,10 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { other._isParamEnabledList, _isParamEnabledList, ) && + const DeepCollectionEquality() + .equals(other._isHeaderEnabledList, _isHeaderEnabledList) && + const DeepCollectionEquality() + .equals(other._isParamEnabledList, _isParamEnabledList) && (identical(other.bodyContentType, bodyContentType) || other.bodyContentType == bodyContentType) && (identical(other.body, body) || other.body == body) && @@ -366,6 +495,17 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { query, const DeepCollectionEquality().hash(_formData), ); + runtimeType, + method, + url, + const DeepCollectionEquality().hash(_headers), + const DeepCollectionEquality().hash(_params), + const DeepCollectionEquality().hash(_isHeaderEnabledList), + const DeepCollectionEquality().hash(_isParamEnabledList), + bodyContentType, + body, + query, + const DeepCollectionEquality().hash(_formData)); /// Create a copy of HttpRequestModel /// with the given fields replaced by the non-null parameter values. @@ -397,6 +537,17 @@ abstract class _HttpRequestModel extends HttpRequestModel { final String? query, final List? formData, }) = _$HttpRequestModelImpl; + const factory _HttpRequestModel( + {final HTTPVerb method, + final String url, + final List? headers, + final List? params, + final List? isHeaderEnabledList, + final List? isParamEnabledList, + final ContentType bodyContentType, + final String? body, + final String? query, + final List? formData}) = _$HttpRequestModelImpl; const _HttpRequestModel._() : super._(); factory _HttpRequestModel.fromJson(Map json) = diff --git a/packages/better_networking/lib/services/http_service.dart b/packages/better_networking/lib/services/http_service.dart index 62478b71d..047d83afb 100644 --- a/packages/better_networking/lib/services/http_service.dart +++ b/packages/better_networking/lib/services/http_service.dart @@ -17,7 +17,7 @@ final httpClientManager = HttpClientManager(); Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( String requestId, APIType apiType, - AuthModel? authModel, + AuthModel? authData, HttpRequestModel requestModel, { SupportedUriSchemes defaultUriScheme = kDefaultUriScheme, bool noSSL = false, @@ -28,7 +28,11 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( final client = httpClientManager.createClient(requestId, noSSL: noSSL); // Handle authentication +<<<<<<< HEAD:packages/better_networking/lib/services/http_service.dart final authenticatedRequestModel = handleAuth(requestModel, authModel); +======= + final authenticatedRequestModel = handleAuth(requestModel, authData); +>>>>>>> f24eb4e6 (feat: remove AuthModel from HttpRequestModel and integrate into HistoryRequestModel and RequestModel):packages/apidash_core/lib/services/http_service.dart (Uri?, String?) uriRec = getValidRequestUri( authenticatedRequestModel.url, diff --git a/pubspec.lock b/pubspec.lock index 97ee48710..d73a53cad 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -710,7 +710,7 @@ packages: source: path version: "0.0.1" highlight: - dependency: "direct main" + dependency: transitive description: name: highlight sha256: "5353a83ffe3e3eca7df0abfb72dcf3fa66cc56b953728e7113ad4ad88497cf21" From 8d8940d57da0ff96d6c18b305b35647567049280 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Wed, 25 Jun 2025 22:49:20 +0530 Subject: [PATCH 25/70] feat: add read-only support to authentication fields --- .../auth/api_key_auth_fields.dart | 4 ++++ .../common_widgets/auth/basic_auth_fields.dart | 4 ++++ .../common_widgets/auth/bearer_auth_fields.dart | 3 +++ .../common_widgets/auth/jwt_auth_fields.dart | 4 ++++ lib/screens/common_widgets/auth_textfield.dart | 3 +++ .../details_card/request_pane/request_auth.dart | 17 +++++++++++++++-- 6 files changed, 33 insertions(+), 2 deletions(-) diff --git a/lib/screens/common_widgets/auth/api_key_auth_fields.dart b/lib/screens/common_widgets/auth/api_key_auth_fields.dart index e3878adcc..1412cdcc7 100644 --- a/lib/screens/common_widgets/auth/api_key_auth_fields.dart +++ b/lib/screens/common_widgets/auth/api_key_auth_fields.dart @@ -7,12 +7,14 @@ import 'package:flutter/material.dart'; class ApiKeyAuthFields extends StatefulWidget { final AuthModel? authData; + final bool readOnly; final Function(AuthModel?) updateAuth; const ApiKeyAuthFields({ super.key, required this.authData, required this.updateAuth, + this.readOnly = false }); @override @@ -67,12 +69,14 @@ class _ApiKeyAuthFieldsState extends State { ), const SizedBox(height: 16), AuthTextField( + readOnly: widget.readOnly, controller: _nameController, hintText: "Header/Query Param Name", onChanged: (value) => _updateApiKeyAuth(), ), const SizedBox(height: 16), AuthTextField( + readOnly: widget.readOnly, controller: _keyController, hintText: "API Key", isObscureText: true, diff --git a/lib/screens/common_widgets/auth/basic_auth_fields.dart b/lib/screens/common_widgets/auth/basic_auth_fields.dart index 887f68abd..6cb6ad1ac 100644 --- a/lib/screens/common_widgets/auth/basic_auth_fields.dart +++ b/lib/screens/common_widgets/auth/basic_auth_fields.dart @@ -5,11 +5,13 @@ import 'package:apidash_core/apidash_core.dart'; class BasicAuthFields extends StatelessWidget { final AuthModel? authData; final Function(AuthModel?) updateAuth; + final bool readOnly; const BasicAuthFields({ super.key, required this.authData, required this.updateAuth, + this.readOnly = false, }); @override @@ -25,6 +27,7 @@ class BasicAuthFields extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ AuthTextField( + readOnly: readOnly, hintText: "Username", controller: usernameController, onChanged: (_) => _updateBasicAuth( @@ -34,6 +37,7 @@ class BasicAuthFields extends StatelessWidget { ), const SizedBox(height: 16), AuthTextField( + readOnly: readOnly, hintText: "Password", isObscureText: true, controller: passwordController, diff --git a/lib/screens/common_widgets/auth/bearer_auth_fields.dart b/lib/screens/common_widgets/auth/bearer_auth_fields.dart index da7de3c91..322ab52b1 100644 --- a/lib/screens/common_widgets/auth/bearer_auth_fields.dart +++ b/lib/screens/common_widgets/auth/bearer_auth_fields.dart @@ -5,11 +5,13 @@ import 'package:flutter/material.dart'; class BearerAuthFields extends StatefulWidget { final AuthModel? authData; final Function(AuthModel?) updateAuth; + final bool readOnly; const BearerAuthFields({ super.key, required this.authData, required this.updateAuth, + this.readOnly = false, }); @override @@ -29,6 +31,7 @@ class _BearerAuthFieldsState extends State { @override Widget build(BuildContext context) { return AuthTextField( + readOnly: widget.readOnly, controller: _tokenController, hintText: "Token", isObscureText: true, diff --git a/lib/screens/common_widgets/auth/jwt_auth_fields.dart b/lib/screens/common_widgets/auth/jwt_auth_fields.dart index 600bbacd9..cdde66c22 100644 --- a/lib/screens/common_widgets/auth/jwt_auth_fields.dart +++ b/lib/screens/common_widgets/auth/jwt_auth_fields.dart @@ -6,11 +6,13 @@ import 'package:apidash_core/apidash_core.dart'; class JwtAuthFields extends StatefulWidget { final AuthModel? authData; final Function(AuthModel?) updateAuth; + final bool readOnly; const JwtAuthFields({ super.key, required this.authData, required this.updateAuth, + this.readOnly = false, }); @override @@ -95,6 +97,7 @@ class _JwtAuthFieldsState extends State { ), const SizedBox(height: 16), AuthTextField( + readOnly: widget.readOnly, controller: _secretController, isObscureText: true, hintText: "Secret key", @@ -130,6 +133,7 @@ class _JwtAuthFieldsState extends State { ), SizedBox(height: 4), TextField( + readOnly: widget.readOnly, controller: _payloadController, maxLines: 4, decoration: InputDecoration( diff --git a/lib/screens/common_widgets/auth_textfield.dart b/lib/screens/common_widgets/auth_textfield.dart index ad28ce877..28610c9bb 100644 --- a/lib/screens/common_widgets/auth_textfield.dart +++ b/lib/screens/common_widgets/auth_textfield.dart @@ -7,12 +7,14 @@ class AuthTextField extends StatefulWidget { final TextEditingController controller; final bool isObscureText; final Function(String)? onChanged; + final bool readOnly; const AuthTextField({ super.key, required this.hintText, required this.controller, required this.onChanged, + this.readOnly = false, this.isObscureText = false, }); @@ -51,6 +53,7 @@ class _AuthFieldState extends State { ), const SizedBox(height: 6), TextFormField( + readOnly: widget.readOnly, controller: widget.controller, style: kCodeStyle.copyWith( color: Theme.of(context).colorScheme.onSurface, diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index dbf4578c5..2a10d50ac 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:apidash/screens/common_widgets/auth/api_key_auth_fields.dart'; import 'package:apidash/screens/common_widgets/auth/basic_auth_fields.dart'; import 'package:apidash/screens/common_widgets/auth/bearer_auth_fields.dart'; @@ -24,17 +26,19 @@ class EditAuthType extends ConsumerWidget { final APIAuthType currentAuthType; if (authModel != null) { + log("Got Auth Model"); currentAuthData = authModel; currentAuthType = authModel!.type; } else { + log("Using Provider"); final selectedRequest = ref.read(selectedRequestModelProvider); if (selectedRequest == null) { return const SizedBox.shrink(); } currentAuthType = ref.watch( - selectedRequestModelProvider.select((request) => - request?.authModel?.type ?? APIAuthType.none), + selectedRequestModelProvider + .select((request) => request?.authModel?.type ?? APIAuthType.none), ); currentAuthData = selectedRequest.authModel; } @@ -115,6 +119,11 @@ class EditAuthType extends ConsumerWidget { AuthModel? authData, ) { void updateAuth(AuthModel? model) { + if (model == null) { + ref.read(collectionStateNotifierProvider.notifier).update( + authData: AuthModel(type: APIAuthType.none), + ); + } ref.read(collectionStateNotifierProvider.notifier).update( authData: model, ); @@ -123,21 +132,25 @@ class EditAuthType extends ConsumerWidget { switch (authData?.type) { case APIAuthType.basic: return BasicAuthFields( + readOnly: readOnly, authData: authData, updateAuth: updateAuth, ); case APIAuthType.bearer: return BearerAuthFields( + readOnly: readOnly, authData: authData, updateAuth: updateAuth, ); case APIAuthType.apiKey: return ApiKeyAuthFields( + readOnly: readOnly, authData: authData, updateAuth: updateAuth, ); case APIAuthType.jwt: return JwtAuthFields( + readOnly: readOnly, authData: authData, updateAuth: updateAuth, ); From a17d6fdd9f34155cf9d8703c54e8ccd12cfec2ab Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Wed, 25 Jun 2025 22:53:32 +0530 Subject: [PATCH 26/70] chore: remove logging in EditAuthType --- lib/providers/collection_providers.dart | 1 + .../editor_pane/details_card/request_pane/request_auth.dart | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 6cf3a7b21..1212b8ba2 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -430,6 +430,7 @@ class CollectionStateNotifier : (state?[id]?.copyWith(httpResponseModel: null))?.toJson(), ); } + await hiveHandler.removeUnused(); ref.read(saveDataStateProvider.notifier).state = false; ref.read(hasUnsavedChangesProvider.notifier).state = false; diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index 2a10d50ac..1e54d46f9 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -1,5 +1,3 @@ -import 'dart:developer'; - import 'package:apidash/screens/common_widgets/auth/api_key_auth_fields.dart'; import 'package:apidash/screens/common_widgets/auth/basic_auth_fields.dart'; import 'package:apidash/screens/common_widgets/auth/bearer_auth_fields.dart'; @@ -26,11 +24,9 @@ class EditAuthType extends ConsumerWidget { final APIAuthType currentAuthType; if (authModel != null) { - log("Got Auth Model"); currentAuthData = authModel; currentAuthType = authModel!.type; } else { - log("Using Provider"); final selectedRequest = ref.read(selectedRequestModelProvider); if (selectedRequest == null) { return const SizedBox.shrink(); From 3903277aa940deb6dee0e2a619909ba0859383ad Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Wed, 2 Jul 2025 21:03:16 +0530 Subject: [PATCH 27/70] chore: resolve merge conflicts --- lib/models/history_request_model.dart | 2 + lib/models/history_request_model.freezed.dart | 55 +++++++++++- lib/models/history_request_model.g.dart | 4 + lib/models/request_model.dart | 3 +- lib/models/request_model.freezed.dart | 83 ++++++++++--------- lib/models/request_model.g.dart | 9 +- lib/providers/collection_providers.dart | 50 +++++++---- .../history_widgets/his_request_pane.dart | 9 ++ .../request_pane/request_pane_graphql.dart | 6 ++ .../request_pane/request_pane_rest.dart | 10 +++ packages/apidash_core/lib/consts.dart | 11 --- .../lib/models/http_request_model.g.dart | 68 --------------- packages/apidash_core/lib/models/models.dart | 2 - .../apidash_core/lib/utils/handle_auth.dart | 2 - 14 files changed, 167 insertions(+), 147 deletions(-) delete mode 100644 packages/apidash_core/lib/models/http_request_model.g.dart diff --git a/lib/models/history_request_model.dart b/lib/models/history_request_model.dart index 4235d643b..51715f5c6 100644 --- a/lib/models/history_request_model.dart +++ b/lib/models/history_request_model.dart @@ -16,6 +16,8 @@ class HistoryRequestModel with _$HistoryRequestModel { required HistoryMetaModel metaData, required HttpRequestModel httpRequestModel, required HttpResponseModel httpResponseModel, + String? preRequestScript, + String? postRequestScript, required AuthModel? authModel, }) = _HistoryRequestModel; diff --git a/lib/models/history_request_model.freezed.dart b/lib/models/history_request_model.freezed.dart index 8afe5c5a4..b2c9f0ef9 100644 --- a/lib/models/history_request_model.freezed.dart +++ b/lib/models/history_request_model.freezed.dart @@ -24,6 +24,8 @@ mixin _$HistoryRequestModel { HistoryMetaModel get metaData => throw _privateConstructorUsedError; HttpRequestModel get httpRequestModel => throw _privateConstructorUsedError; HttpResponseModel get httpResponseModel => throw _privateConstructorUsedError; + String? get preRequestScript => throw _privateConstructorUsedError; + String? get postRequestScript => throw _privateConstructorUsedError; AuthModel? get authModel => throw _privateConstructorUsedError; /// Serializes this HistoryRequestModel to a JSON map. @@ -47,6 +49,8 @@ abstract class $HistoryRequestModelCopyWith<$Res> { HistoryMetaModel metaData, HttpRequestModel httpRequestModel, HttpResponseModel httpResponseModel, + String? preRequestScript, + String? postRequestScript, AuthModel? authModel}); $HistoryMetaModelCopyWith<$Res> get metaData; @@ -74,6 +78,8 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel> Object? metaData = null, Object? httpRequestModel = null, Object? httpResponseModel = null, + Object? preRequestScript = freezed, + Object? postRequestScript = freezed, Object? authModel = freezed, }) { return _then(_value.copyWith( @@ -93,6 +99,14 @@ class _$HistoryRequestModelCopyWithImpl<$Res, $Val extends HistoryRequestModel> ? _value.httpResponseModel : httpResponseModel // ignore: cast_nullable_to_non_nullable as HttpResponseModel, + preRequestScript: freezed == preRequestScript + ? _value.preRequestScript + : preRequestScript // ignore: cast_nullable_to_non_nullable + as String?, + postRequestScript: freezed == postRequestScript + ? _value.postRequestScript + : postRequestScript // ignore: cast_nullable_to_non_nullable + as String?, authModel: freezed == authModel ? _value.authModel : authModel // ignore: cast_nullable_to_non_nullable @@ -158,6 +172,8 @@ abstract class _$$HistoryRequestModelImplCopyWith<$Res> HistoryMetaModel metaData, HttpRequestModel httpRequestModel, HttpResponseModel httpResponseModel, + String? preRequestScript, + String? postRequestScript, AuthModel? authModel}); @override @@ -187,6 +203,8 @@ class __$$HistoryRequestModelImplCopyWithImpl<$Res> Object? metaData = null, Object? httpRequestModel = null, Object? httpResponseModel = null, + Object? preRequestScript = freezed, + Object? postRequestScript = freezed, Object? authModel = freezed, }) { return _then(_$HistoryRequestModelImpl( @@ -206,6 +224,14 @@ class __$$HistoryRequestModelImplCopyWithImpl<$Res> ? _value.httpResponseModel : httpResponseModel // ignore: cast_nullable_to_non_nullable as HttpResponseModel, + preRequestScript: freezed == preRequestScript + ? _value.preRequestScript + : preRequestScript // ignore: cast_nullable_to_non_nullable + as String?, + postRequestScript: freezed == postRequestScript + ? _value.postRequestScript + : postRequestScript // ignore: cast_nullable_to_non_nullable + as String?, authModel: freezed == authModel ? _value.authModel : authModel // ignore: cast_nullable_to_non_nullable @@ -223,6 +249,8 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel { required this.metaData, required this.httpRequestModel, required this.httpResponseModel, + this.preRequestScript, + this.postRequestScript, required this.authModel}); factory _$HistoryRequestModelImpl.fromJson(Map json) => @@ -237,11 +265,15 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel { @override final HttpResponseModel httpResponseModel; @override + final String? preRequestScript; + @override + final String? postRequestScript; + @override final AuthModel? authModel; @override String toString() { - return 'HistoryRequestModel(historyId: $historyId, metaData: $metaData, httpRequestModel: $httpRequestModel, httpResponseModel: $httpResponseModel, authModel: $authModel)'; + return 'HistoryRequestModel(historyId: $historyId, metaData: $metaData, httpRequestModel: $httpRequestModel, httpResponseModel: $httpResponseModel, preRequestScript: $preRequestScript, postRequestScript: $postRequestScript, authModel: $authModel)'; } @override @@ -257,14 +289,25 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel { other.httpRequestModel == httpRequestModel) && (identical(other.httpResponseModel, httpResponseModel) || other.httpResponseModel == httpResponseModel) && + (identical(other.preRequestScript, preRequestScript) || + other.preRequestScript == preRequestScript) && + (identical(other.postRequestScript, postRequestScript) || + other.postRequestScript == postRequestScript) && (identical(other.authModel, authModel) || other.authModel == authModel)); } @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => Object.hash(runtimeType, historyId, metaData, - httpRequestModel, httpResponseModel, authModel); + int get hashCode => Object.hash( + runtimeType, + historyId, + metaData, + httpRequestModel, + httpResponseModel, + preRequestScript, + postRequestScript, + authModel); /// Create a copy of HistoryRequestModel /// with the given fields replaced by the non-null parameter values. @@ -289,6 +332,8 @@ abstract class _HistoryRequestModel implements HistoryRequestModel { required final HistoryMetaModel metaData, required final HttpRequestModel httpRequestModel, required final HttpResponseModel httpResponseModel, + final String? preRequestScript, + final String? postRequestScript, required final AuthModel? authModel}) = _$HistoryRequestModelImpl; factory _HistoryRequestModel.fromJson(Map json) = @@ -303,6 +348,10 @@ abstract class _HistoryRequestModel implements HistoryRequestModel { @override HttpResponseModel get httpResponseModel; @override + String? get preRequestScript; + @override + String? get postRequestScript; + @override AuthModel? get authModel; /// Create a copy of HistoryRequestModel diff --git a/lib/models/history_request_model.g.dart b/lib/models/history_request_model.g.dart index a3f852fd2..66aee83b7 100644 --- a/lib/models/history_request_model.g.dart +++ b/lib/models/history_request_model.g.dart @@ -15,6 +15,8 @@ _$HistoryRequestModelImpl _$$HistoryRequestModelImplFromJson(Map json) => Map.from(json['httpRequestModel'] as Map)), httpResponseModel: HttpResponseModel.fromJson( Map.from(json['httpResponseModel'] as Map)), + preRequestScript: json['preRequestScript'] as String?, + postRequestScript: json['postRequestScript'] as String?, authModel: json['authModel'] == null ? null : AuthModel.fromJson( @@ -28,5 +30,7 @@ Map _$$HistoryRequestModelImplToJson( 'metaData': instance.metaData.toJson(), 'httpRequestModel': instance.httpRequestModel.toJson(), 'httpResponseModel': instance.httpResponseModel.toJson(), + 'preRequestScript': instance.preRequestScript, + 'postRequestScript': instance.postRequestScript, 'authModel': instance.authModel?.toJson(), }; diff --git a/lib/models/request_model.dart b/lib/models/request_model.dart index 4cf4eef86..a3eda0ba6 100644 --- a/lib/models/request_model.dart +++ b/lib/models/request_model.dart @@ -23,7 +23,8 @@ class RequestModel with _$RequestModel { HttpResponseModel? httpResponseModel, @JsonKey(includeToJson: false) @Default(false) bool isWorking, @JsonKey(includeToJson: false) DateTime? sendingTime, - @Default(AuthModel(type: APIAuthType.none)) AuthModel? authModel, + String? preRequestScript, + String? postRequestScript, }) = _RequestModel; factory RequestModel.fromJson(Map json) => diff --git a/lib/models/request_model.freezed.dart b/lib/models/request_model.freezed.dart index d8b9c4172..eca69ebed 100644 --- a/lib/models/request_model.freezed.dart +++ b/lib/models/request_model.freezed.dart @@ -36,7 +36,8 @@ mixin _$RequestModel { bool get isWorking => throw _privateConstructorUsedError; @JsonKey(includeToJson: false) DateTime? get sendingTime => throw _privateConstructorUsedError; - AuthModel? get authModel => throw _privateConstructorUsedError; + String? get preRequestScript => throw _privateConstructorUsedError; + String? get postRequestScript => throw _privateConstructorUsedError; /// Serializes this RequestModel to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -67,12 +68,12 @@ abstract class $RequestModelCopyWith<$Res> { HttpResponseModel? httpResponseModel, @JsonKey(includeToJson: false) bool isWorking, @JsonKey(includeToJson: false) DateTime? sendingTime, - AuthModel? authModel}); + String? preRequestScript, + String? postRequestScript}); $AuthModelCopyWith<$Res>? get authModel; $HttpRequestModelCopyWith<$Res>? get httpRequestModel; $HttpResponseModelCopyWith<$Res>? get httpResponseModel; - $AuthModelCopyWith<$Res>? get authModel; } /// @nodoc @@ -102,7 +103,8 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> Object? httpResponseModel = freezed, Object? isWorking = null, Object? sendingTime = freezed, - Object? authModel = freezed, + Object? preRequestScript = freezed, + Object? postRequestScript = freezed, }) { return _then(_value.copyWith( id: null == id @@ -153,10 +155,14 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> ? _value.sendingTime : sendingTime // ignore: cast_nullable_to_non_nullable as DateTime?, - authModel: freezed == authModel - ? _value.authModel - : authModel // ignore: cast_nullable_to_non_nullable - as AuthModel?, + preRequestScript: freezed == preRequestScript + ? _value.preRequestScript + : preRequestScript // ignore: cast_nullable_to_non_nullable + as String?, + postRequestScript: freezed == postRequestScript + ? _value.postRequestScript + : postRequestScript // ignore: cast_nullable_to_non_nullable + as String?, ) as $Val); } @@ -201,20 +207,6 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> return _then(_value.copyWith(httpResponseModel: value) as $Val); }); } - - /// Create a copy of RequestModel - /// with the given fields replaced by the non-null parameter values. - @override - @pragma('vm:prefer-inline') - $AuthModelCopyWith<$Res>? get authModel { - if (_value.authModel == null) { - return null; - } - - return $AuthModelCopyWith<$Res>(_value.authModel!, (value) { - return _then(_value.copyWith(authModel: value) as $Val); - }); - } } /// @nodoc @@ -238,7 +230,8 @@ abstract class _$$RequestModelImplCopyWith<$Res> HttpResponseModel? httpResponseModel, @JsonKey(includeToJson: false) bool isWorking, @JsonKey(includeToJson: false) DateTime? sendingTime, - AuthModel? authModel}); + String? preRequestScript, + String? postRequestScript}); @override $AuthModelCopyWith<$Res>? get authModel; @@ -246,8 +239,6 @@ abstract class _$$RequestModelImplCopyWith<$Res> $HttpRequestModelCopyWith<$Res>? get httpRequestModel; @override $HttpResponseModelCopyWith<$Res>? get httpResponseModel; - @override - $AuthModelCopyWith<$Res>? get authModel; } /// @nodoc @@ -275,7 +266,8 @@ class __$$RequestModelImplCopyWithImpl<$Res> Object? httpResponseModel = freezed, Object? isWorking = null, Object? sendingTime = freezed, - Object? authModel = freezed, + Object? preRequestScript = freezed, + Object? postRequestScript = freezed, }) { return _then(_$RequestModelImpl( id: null == id @@ -325,10 +317,14 @@ class __$$RequestModelImplCopyWithImpl<$Res> ? _value.sendingTime : sendingTime // ignore: cast_nullable_to_non_nullable as DateTime?, - authModel: freezed == authModel - ? _value.authModel - : authModel // ignore: cast_nullable_to_non_nullable - as AuthModel?, + preRequestScript: freezed == preRequestScript + ? _value.preRequestScript + : preRequestScript // ignore: cast_nullable_to_non_nullable + as String?, + postRequestScript: freezed == postRequestScript + ? _value.postRequestScript + : postRequestScript // ignore: cast_nullable_to_non_nullable + as String?, )); } } @@ -350,7 +346,8 @@ class _$RequestModelImpl implements _RequestModel { this.httpResponseModel, @JsonKey(includeToJson: false) this.isWorking = false, @JsonKey(includeToJson: false) this.sendingTime, - this.authModel = const AuthModel(type: APIAuthType.none)}); + this.preRequestScript, + this.postRequestScript}); factory _$RequestModelImpl.fromJson(Map json) => _$$RequestModelImplFromJson(json); @@ -387,12 +384,13 @@ class _$RequestModelImpl implements _RequestModel { @JsonKey(includeToJson: false) final DateTime? sendingTime; @override - @JsonKey() - final AuthModel? authModel; + final String? preRequestScript; + @override + final String? postRequestScript; @override String toString() { - return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime, authModel: $authModel)'; + return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, authModel: $authModel, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime, preRequestScript: $preRequestScript, postRequestScript: $postRequestScript)'; } @override @@ -420,8 +418,10 @@ class _$RequestModelImpl implements _RequestModel { other.isWorking == isWorking) && (identical(other.sendingTime, sendingTime) || other.sendingTime == sendingTime) && - (identical(other.authModel, authModel) || - other.authModel == authModel)); + (identical(other.preRequestScript, preRequestScript) || + other.preRequestScript == preRequestScript) && + (identical(other.postRequestScript, postRequestScript) || + other.postRequestScript == postRequestScript)); } @JsonKey(includeFromJson: false, includeToJson: false) @@ -440,7 +440,8 @@ class _$RequestModelImpl implements _RequestModel { httpResponseModel, isWorking, sendingTime, - authModel); + preRequestScript, + postRequestScript); /// Create a copy of RequestModel /// with the given fields replaced by the non-null parameter values. @@ -464,6 +465,7 @@ abstract class _RequestModel implements RequestModel { final APIType apiType, final String name, final String description, + final AuthModel? authModel, @JsonKey(includeToJson: false) final dynamic requestTabIndex, final HttpRequestModel? httpRequestModel, final int? responseStatus, @@ -471,7 +473,8 @@ abstract class _RequestModel implements RequestModel { final HttpResponseModel? httpResponseModel, @JsonKey(includeToJson: false) final bool isWorking, @JsonKey(includeToJson: false) final DateTime? sendingTime, - final AuthModel? authModel}) = _$RequestModelImpl; + final String? preRequestScript, + final String? postRequestScript}) = _$RequestModelImpl; factory _RequestModel.fromJson(Map json) = _$RequestModelImpl.fromJson; @@ -504,7 +507,9 @@ abstract class _RequestModel implements RequestModel { @JsonKey(includeToJson: false) DateTime? get sendingTime; @override - AuthModel? get authModel; + String? get preRequestScript; + @override + String? get postRequestScript; /// Create a copy of RequestModel /// with the given fields replaced by the non-null parameter values. diff --git a/lib/models/request_model.g.dart b/lib/models/request_model.g.dart index e5a15d1cc..6c6337262 100644 --- a/lib/models/request_model.g.dart +++ b/lib/models/request_model.g.dart @@ -31,10 +31,8 @@ _$RequestModelImpl _$$RequestModelImplFromJson(Map json) => _$RequestModelImpl( sendingTime: json['sendingTime'] == null ? null : DateTime.parse(json['sendingTime'] as String), - authModel: json['authModel'] == null - ? const AuthModel(type: APIAuthType.none) - : AuthModel.fromJson( - Map.from(json['authModel'] as Map)), + preRequestScript: json['preRequestScript'] as String?, + postRequestScript: json['postRequestScript'] as String?, ); Map _$$RequestModelImplToJson(_$RequestModelImpl instance) => @@ -48,7 +46,8 @@ Map _$$RequestModelImplToJson(_$RequestModelImpl instance) => 'responseStatus': instance.responseStatus, 'message': instance.message, 'httpResponseModel': instance.httpResponseModel?.toJson(), - 'authModel': instance.authModel?.toJson(), + 'preRequestScript': instance.preRequestScript, + 'postRequestScript': instance.postRequestScript, }; const _$APITypeEnumMap = { diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 1212b8ba2..468e59e70 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -239,7 +239,6 @@ class CollectionStateNotifier name: name ?? currentModel.name, description: description ?? currentModel.description, requestTabIndex: requestTabIndex ?? currentModel.requestTabIndex, - authModel: authData ?? currentModel.authModel, httpRequestModel: currentHttpRequestModel?.copyWith( method: method ?? currentHttpRequestModel.method, url: url ?? currentHttpRequestModel.url, @@ -318,7 +317,6 @@ class CollectionStateNotifier requestId, apiType, requestModel.authModel, - requestModel.authModel, substitutedHttpRequestModel, defaultUriScheme: defaultUriScheme, noSSL: noSSL, @@ -345,21 +343,41 @@ class CollectionStateNotifier ); String newHistoryId = getNewUuid(); HistoryRequestModel model = HistoryRequestModel( + historyId: newHistoryId, + metaData: HistoryMetaModel( historyId: newHistoryId, - metaData: HistoryMetaModel( - historyId: newHistoryId, - requestId: requestId, - apiType: requestModel.apiType, - name: requestModel.name, - url: substitutedHttpRequestModel.url, - method: substitutedHttpRequestModel.method, - responseStatus: statusCode, - timeStamp: DateTime.now(), - ), - httpRequestModel: substitutedHttpRequestModel, - httpResponseModel: httpResponseModel, - authModel: requestModel.authModel); + requestId: requestId, + apiType: requestModel.apiType, + name: requestModel.name, + url: substitutedHttpRequestModel.url, + method: substitutedHttpRequestModel.method, + responseStatus: statusCode, + timeStamp: DateTime.now(), + ), + httpRequestModel: substitutedHttpRequestModel, + httpResponseModel: httpResponseModel, + preRequestScript: requestModel.preRequestScript, + postRequestScript: requestModel.postRequestScript, + authModel: requestModel.authModel, + ); + ref.read(historyMetaStateNotifier.notifier).addHistoryRequest(model); + + if (!requestModel.postRequestScript.isNullOrEmpty()) { + newRequestModel = await handlePostResponseScript( + newRequestModel, + originalEnvironmentModel, + (envModel, updatedValues) { + ref + .read(environmentsStateNotifierProvider.notifier) + .updateEnvironment( + envModel.id, + name: envModel.name, + values: updatedValues, + ); + }, + ); + } } // update state with response data @@ -430,7 +448,7 @@ class CollectionStateNotifier : (state?[id]?.copyWith(httpResponseModel: null))?.toJson(), ); } - + await hiveHandler.removeUnused(); ref.read(saveDataStateProvider.notifier).state = false; ref.read(hasUnsavedChangesProvider.notifier).state = false; diff --git a/lib/screens/history/history_widgets/his_request_pane.dart b/lib/screens/history/history_widgets/his_request_pane.dart index 1e361827c..21855779b 100644 --- a/lib/screens/history/history_widgets/his_request_pane.dart +++ b/lib/screens/history/history_widgets/his_request_pane.dart @@ -40,6 +40,13 @@ class HistoryRequestPane extends ConsumerWidget { .select((value) => value?.httpRequestModel.hasQuery)) ?? false; + final scriptsLength = ref.watch(selectedHistoryRequestModelProvider + .select((value) => value?.preRequestScript?.length)) ?? + ref.watch(selectedHistoryRequestModelProvider + .select((value) => value?.postRequestScript?.length)) ?? + 0; + + final hasAuth = ref.watch(selectedHistoryRequestModelProvider.select( (value) => value?.authModel?.type != APIAuthType.none)); @@ -61,6 +68,7 @@ class HistoryRequestPane extends ConsumerWidget { paramLength > 0, headerLength > 0, hasBody, + scriptsLength > 0, ], tabLabels: const [ kLabelURLParams, @@ -98,6 +106,7 @@ class HistoryRequestPane extends ConsumerWidget { headerLength > 0, hasAuth, hasQuery, + scriptsLength > 0 ], tabLabels: const [ kLabelHeaders, diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart index 66b100a22..66dac8fd6 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart @@ -28,6 +28,12 @@ class EditGraphQLRequestPane extends ConsumerWidget { final hasAuth = ref.watch(selectedRequestModelProvider.select((value) => value?.authModel?.type != APIAuthType.none)); + final scriptsLength = ref.watch(selectedHistoryRequestModelProvider + .select((value) => value?.preRequestScript?.length)) ?? + ref.watch(selectedHistoryRequestModelProvider + .select((value) => value?.postRequestScript?.length)) ?? + 0; + if (tabIndex >= 3) { tabIndex = 0; } diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart index ee89918b7..68bf526fb 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart @@ -8,6 +8,7 @@ import 'request_headers.dart'; import 'request_params.dart'; import 'request_body.dart'; import 'request_auth.dart'; +import 'request_scripts.dart'; class EditRestRequestPane extends ConsumerWidget { const EditRestRequestPane({super.key}); @@ -29,6 +30,12 @@ class EditRestRequestPane extends ConsumerWidget { .select((value) => value?.httpRequestModel?.hasBody)) ?? false; + final scriptsLength = ref.watch(selectedRequestModelProvider + .select((value) => value?.preRequestScript?.length)) ?? + ref.watch(selectedRequestModelProvider + .select((value) => value?.postRequestScript?.length)) ?? + 0; + final hasAuth = ref.watch(selectedRequestModelProvider.select((value) => value?.authModel?.type != APIAuthType.none)); @@ -50,18 +57,21 @@ class EditRestRequestPane extends ConsumerWidget { hasAuth, headerLength > 0, hasBody, + scriptsLength > 0, ], tabLabels: const [ kLabelURLParams, kLabelAuth, kLabelHeaders, kLabelBody, + kLabelScripts, ], children: const [ EditRequestURLParams(), EditAuthType(), EditRequestHeaders(), EditRequestBody(), + EditRequestScripts(), ], ); } diff --git a/packages/apidash_core/lib/consts.dart b/packages/apidash_core/lib/consts.dart index 747fb89fc..09cd3f65f 100644 --- a/packages/apidash_core/lib/consts.dart +++ b/packages/apidash_core/lib/consts.dart @@ -1,14 +1,3 @@ -import 'dart:convert'; - -enum APIType { - rest("HTTP", "HTTP"), - graphql("GraphQL", "GQL"); - - const APIType(this.label, this.abbr); - final String label; - final String abbr; -} - enum APIAuthType { none, basic, diff --git a/packages/apidash_core/lib/models/http_request_model.g.dart b/packages/apidash_core/lib/models/http_request_model.g.dart deleted file mode 100644 index 13795ded4..000000000 --- a/packages/apidash_core/lib/models/http_request_model.g.dart +++ /dev/null @@ -1,68 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'http_request_model.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -_$HttpRequestModelImpl _$$HttpRequestModelImplFromJson(Map json) => - _$HttpRequestModelImpl( - method: $enumDecodeNullable(_$HTTPVerbEnumMap, json['method']) ?? - HTTPVerb.get, - url: json['url'] as String? ?? "", - headers: (json['headers'] as List?) - ?.map((e) => - NameValueModel.fromJson(Map.from(e as Map))) - .toList(), - params: (json['params'] as List?) - ?.map((e) => - NameValueModel.fromJson(Map.from(e as Map))) - .toList(), - isHeaderEnabledList: (json['isHeaderEnabledList'] as List?) - ?.map((e) => e as bool) - .toList(), - isParamEnabledList: (json['isParamEnabledList'] as List?) - ?.map((e) => e as bool) - .toList(), - bodyContentType: - $enumDecodeNullable(_$ContentTypeEnumMap, json['bodyContentType']) ?? - ContentType.json, - body: json['body'] as String?, - query: json['query'] as String?, - formData: (json['formData'] as List?) - ?.map((e) => - FormDataModel.fromJson(Map.from(e as Map))) - .toList(), - ); - -Map _$$HttpRequestModelImplToJson( - _$HttpRequestModelImpl instance) => - { - 'method': _$HTTPVerbEnumMap[instance.method]!, - 'url': instance.url, - 'headers': instance.headers?.map((e) => e.toJson()).toList(), - 'params': instance.params?.map((e) => e.toJson()).toList(), - 'isHeaderEnabledList': instance.isHeaderEnabledList, - 'isParamEnabledList': instance.isParamEnabledList, - 'bodyContentType': _$ContentTypeEnumMap[instance.bodyContentType]!, - 'body': instance.body, - 'query': instance.query, - 'formData': instance.formData?.map((e) => e.toJson()).toList(), - }; - -const _$HTTPVerbEnumMap = { - HTTPVerb.get: 'get', - HTTPVerb.head: 'head', - HTTPVerb.post: 'post', - HTTPVerb.put: 'put', - HTTPVerb.patch: 'patch', - HTTPVerb.delete: 'delete', - HTTPVerb.options: 'options', -}; - -const _$ContentTypeEnumMap = { - ContentType.json: 'json', - ContentType.text: 'text', - ContentType.formdata: 'formdata', -}; diff --git a/packages/apidash_core/lib/models/models.dart b/packages/apidash_core/lib/models/models.dart index 4b84832f7..dd91ed39b 100644 --- a/packages/apidash_core/lib/models/models.dart +++ b/packages/apidash_core/lib/models/models.dart @@ -1,6 +1,4 @@ export 'environment_model.dart'; -export 'http_request_model.dart'; -export 'http_response_model.dart'; export 'auth/api_auth_model.dart'; export 'auth/auth_api_key_model.dart'; export 'auth/auth_basic_model.dart'; diff --git a/packages/apidash_core/lib/utils/handle_auth.dart b/packages/apidash_core/lib/utils/handle_auth.dart index 5cbf7e8fd..2922b81c2 100644 --- a/packages/apidash_core/lib/utils/handle_auth.dart +++ b/packages/apidash_core/lib/utils/handle_auth.dart @@ -1,9 +1,7 @@ import 'dart:convert'; import 'package:apidash_core/consts.dart'; import 'package:apidash_core/models/auth/api_auth_model.dart'; -import 'package:apidash_core/models/http_request_model.dart'; import 'package:apidash_core/utils/auth_utils.dart'; -import 'package:seed/seed.dart'; HttpRequestModel handleAuth(HttpRequestModel httpRequestModel,AuthModel? authData) { if (authData == null || authData.type == APIAuthType.none) { From a11c8338227ca444d611b2e307c22007e18e5bc6 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Wed, 2 Jul 2025 22:07:47 +0530 Subject: [PATCH 28/70] refactor: move auth models to better_networking package --- .../auth/api_key_auth_fields.dart | 17 +- .../request_pane/request_pane_graphql.dart | 6 +- packages/apidash_core/lib/consts.dart | 11 - .../lib/models/auth/auth_api_key_model.g.dart | 23 -- packages/apidash_core/lib/models/models.dart | 7 +- .../better_networking_example/lib/main.dart | 2 + packages/better_networking/lib/consts.dart | 2 + .../lib/models/auth/api_auth_model.dart | 0 .../models/auth/api_auth_model.freezed.dart | 158 ++++++----- .../lib/models/auth/api_auth_model.g.dart | 38 +-- .../lib/models/auth/auth_api_key_model.dart | 0 .../auth/auth_api_key_model.freezed.dart | 107 ++++---- .../lib/models/auth/auth_api_key_model.g.dart | 23 ++ .../lib/models/auth/auth_basic_model.dart | 0 .../models/auth/auth_basic_model.freezed.dart | 98 +++---- .../lib/models/auth/auth_basic_model.g.dart | 20 +- .../lib/models/auth/auth_bearer_model.dart | 0 .../auth/auth_bearer_model.freezed.dart | 65 ++--- .../lib/models/auth/auth_bearer_model.g.dart | 12 +- .../lib/models/auth/auth_jwt_model.dart | 0 .../models/auth/auth_jwt_model.freezed.dart | 252 ++++++++++-------- .../lib/models/auth/auth_jwt_model.g.dart | 0 .../models/http_request_model.freezed.dart | 151 ----------- .../better_networking/lib/models/models.dart | 5 + .../lib/services/http_service.dart | 5 - .../lib/utils/auth_utils.dart | 2 +- .../lib/utils/handle_auth.dart | 7 +- .../better_networking/lib/utils/utils.dart | 1 + 28 files changed, 452 insertions(+), 560 deletions(-) delete mode 100644 packages/apidash_core/lib/models/auth/auth_api_key_model.g.dart rename packages/{apidash_core => better_networking}/lib/models/auth/api_auth_model.dart (100%) rename packages/{apidash_core => better_networking}/lib/models/auth/api_auth_model.freezed.dart (70%) rename packages/{apidash_core => better_networking}/lib/models/auth/api_auth_model.g.dart (57%) rename packages/{apidash_core => better_networking}/lib/models/auth/auth_api_key_model.dart (100%) rename packages/{apidash_core => better_networking}/lib/models/auth/auth_api_key_model.freezed.dart (69%) create mode 100644 packages/better_networking/lib/models/auth/auth_api_key_model.g.dart rename packages/{apidash_core => better_networking}/lib/models/auth/auth_basic_model.dart (100%) rename packages/{apidash_core => better_networking}/lib/models/auth/auth_basic_model.freezed.dart (68%) rename packages/{apidash_core => better_networking}/lib/models/auth/auth_basic_model.g.dart (54%) rename packages/{apidash_core => better_networking}/lib/models/auth/auth_bearer_model.dart (100%) rename packages/{apidash_core => better_networking}/lib/models/auth/auth_bearer_model.freezed.dart (76%) rename packages/{apidash_core => better_networking}/lib/models/auth/auth_bearer_model.g.dart (63%) rename packages/{apidash_core => better_networking}/lib/models/auth/auth_jwt_model.dart (100%) rename packages/{apidash_core => better_networking}/lib/models/auth/auth_jwt_model.freezed.dart (56%) rename packages/{apidash_core => better_networking}/lib/models/auth/auth_jwt_model.g.dart (100%) rename packages/{apidash_core => better_networking}/lib/utils/auth_utils.dart (97%) rename packages/{apidash_core => better_networking}/lib/utils/handle_auth.dart (95%) diff --git a/lib/screens/common_widgets/auth/api_key_auth_fields.dart b/lib/screens/common_widgets/auth/api_key_auth_fields.dart index 1412cdcc7..a32e3d423 100644 --- a/lib/screens/common_widgets/auth/api_key_auth_fields.dart +++ b/lib/screens/common_widgets/auth/api_key_auth_fields.dart @@ -1,7 +1,5 @@ import 'package:apidash/screens/common_widgets/auth_textfield.dart'; -import 'package:apidash_core/consts.dart'; -import 'package:apidash_core/models/auth/api_auth_model.dart'; -import 'package:apidash_core/models/auth/auth_api_key_model.dart'; +import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; @@ -10,12 +8,11 @@ class ApiKeyAuthFields extends StatefulWidget { final bool readOnly; final Function(AuthModel?) updateAuth; - const ApiKeyAuthFields({ - super.key, - required this.authData, - required this.updateAuth, - this.readOnly = false - }); + const ApiKeyAuthFields( + {super.key, + required this.authData, + required this.updateAuth, + this.readOnly = false}); @override State createState() => _ApiKeyAuthFieldsState(); @@ -76,7 +73,7 @@ class _ApiKeyAuthFieldsState extends State { ), const SizedBox(height: 16), AuthTextField( - readOnly: widget.readOnly, + readOnly: widget.readOnly, controller: _keyController, hintText: "API Key", isObscureText: true, diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart index 66dac8fd6..f9e18078a 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart @@ -1,6 +1,6 @@ import 'package:apidash/consts.dart'; import 'package:apidash/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart'; -import 'package:apidash_core/consts.dart'; +import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/providers/providers.dart'; @@ -25,8 +25,8 @@ class EditGraphQLRequestPane extends ConsumerWidget { .select((value) => value?.httpRequestModel?.hasQuery)) ?? false; - final hasAuth = ref.watch(selectedRequestModelProvider.select((value) => - value?.authModel?.type != APIAuthType.none)); + final hasAuth = ref.watch(selectedRequestModelProvider + .select((value) => value?.authModel?.type != APIAuthType.none)); final scriptsLength = ref.watch(selectedHistoryRequestModelProvider .select((value) => value?.preRequestScript?.length)) ?? diff --git a/packages/apidash_core/lib/consts.dart b/packages/apidash_core/lib/consts.dart index 09cd3f65f..3d5d19c86 100644 --- a/packages/apidash_core/lib/consts.dart +++ b/packages/apidash_core/lib/consts.dart @@ -1,12 +1 @@ -enum APIAuthType { - none, - basic, - apiKey, - bearer, - jwt, - digest, - oauth1, - oauth2, -} - enum EnvironmentVariableType { variable, secret } diff --git a/packages/apidash_core/lib/models/auth/auth_api_key_model.g.dart b/packages/apidash_core/lib/models/auth/auth_api_key_model.g.dart deleted file mode 100644 index f04e5c84b..000000000 --- a/packages/apidash_core/lib/models/auth/auth_api_key_model.g.dart +++ /dev/null @@ -1,23 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'auth_api_key_model.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -_$AuthApiKeyModelImpl _$$AuthApiKeyModelImplFromJson( - Map json) => - _$AuthApiKeyModelImpl( - key: json['key'] as String, - location: json['location'] as String? ?? 'header', - name: json['name'] as String? ?? 'x-api-key', - ); - -Map _$$AuthApiKeyModelImplToJson( - _$AuthApiKeyModelImpl instance) => - { - 'key': instance.key, - 'location': instance.location, - 'name': instance.name, - }; diff --git a/packages/apidash_core/lib/models/models.dart b/packages/apidash_core/lib/models/models.dart index dd91ed39b..5bfff79e1 100644 --- a/packages/apidash_core/lib/models/models.dart +++ b/packages/apidash_core/lib/models/models.dart @@ -1,6 +1 @@ -export 'environment_model.dart'; -export 'auth/api_auth_model.dart'; -export 'auth/auth_api_key_model.dart'; -export 'auth/auth_basic_model.dart'; -export 'auth/auth_bearer_model.dart'; -export 'auth/auth_jwt_model.dart'; +export 'environment_model.dart'; \ No newline at end of file diff --git a/packages/better_networking/better_networking_example/lib/main.dart b/packages/better_networking/better_networking_example/lib/main.dart index 61bb42bb4..996867e44 100644 --- a/packages/better_networking/better_networking_example/lib/main.dart +++ b/packages/better_networking/better_networking_example/lib/main.dart @@ -54,6 +54,7 @@ class _BetterNetworkingExampleState extends State { final (resp, duration, err) = await sendHttpRequest( 'G1', APIType.rest, + AuthModel(type: APIAuthType.none), HttpRequestModel( url: 'https://reqres.in/api/users/2', method: HTTPVerb.get, @@ -80,6 +81,7 @@ class _BetterNetworkingExampleState extends State { final (resp, duration, err) = await sendHttpRequest( 'P1', APIType.rest, + AuthModel(type: APIAuthType.none), HttpRequestModel( url: 'https://reqres.in/api/users', method: HTTPVerb.post, diff --git a/packages/better_networking/lib/consts.dart b/packages/better_networking/lib/consts.dart index 61fe1e506..493561adb 100644 --- a/packages/better_networking/lib/consts.dart +++ b/packages/better_networking/lib/consts.dart @@ -9,6 +9,8 @@ enum APIType { final String abbr; } +enum APIAuthType { none, basic, apiKey, bearer, jwt, digest, oauth1, oauth2} + enum HTTPVerb { get("GET"), head("HEAD"), diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.dart b/packages/better_networking/lib/models/auth/api_auth_model.dart similarity index 100% rename from packages/apidash_core/lib/models/auth/api_auth_model.dart rename to packages/better_networking/lib/models/auth/api_auth_model.dart diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart b/packages/better_networking/lib/models/auth/api_auth_model.freezed.dart similarity index 70% rename from packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart rename to packages/better_networking/lib/models/auth/api_auth_model.freezed.dart index 28ceaec6b..44fa1cb2b 100644 --- a/packages/apidash_core/lib/models/auth/api_auth_model.freezed.dart +++ b/packages/better_networking/lib/models/auth/api_auth_model.freezed.dart @@ -12,7 +12,8 @@ part of 'api_auth_model.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models', +); AuthModel _$AuthModelFromJson(Map json) { return _AuthModel.fromJson(json); @@ -41,12 +42,13 @@ abstract class $AuthModelCopyWith<$Res> { factory $AuthModelCopyWith(AuthModel value, $Res Function(AuthModel) then) = _$AuthModelCopyWithImpl<$Res, AuthModel>; @useResult - $Res call( - {APIAuthType type, - AuthApiKeyModel? apikey, - AuthBearerModel? bearer, - AuthBasicAuthModel? basic, - AuthJwtModel? jwt}); + $Res call({ + APIAuthType type, + AuthApiKeyModel? apikey, + AuthBearerModel? bearer, + AuthBasicAuthModel? basic, + AuthJwtModel? jwt, + }); $AuthApiKeyModelCopyWith<$Res>? get apikey; $AuthBearerModelCopyWith<$Res>? get bearer; @@ -75,28 +77,31 @@ class _$AuthModelCopyWithImpl<$Res, $Val extends AuthModel> Object? basic = freezed, Object? jwt = freezed, }) { - return _then(_value.copyWith( - type: null == type - ? _value.type - : type // ignore: cast_nullable_to_non_nullable - as APIAuthType, - apikey: freezed == apikey - ? _value.apikey - : apikey // ignore: cast_nullable_to_non_nullable - as AuthApiKeyModel?, - bearer: freezed == bearer - ? _value.bearer - : bearer // ignore: cast_nullable_to_non_nullable - as AuthBearerModel?, - basic: freezed == basic - ? _value.basic - : basic // ignore: cast_nullable_to_non_nullable - as AuthBasicAuthModel?, - jwt: freezed == jwt - ? _value.jwt - : jwt // ignore: cast_nullable_to_non_nullable - as AuthJwtModel?, - ) as $Val); + return _then( + _value.copyWith( + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as APIAuthType, + apikey: freezed == apikey + ? _value.apikey + : apikey // ignore: cast_nullable_to_non_nullable + as AuthApiKeyModel?, + bearer: freezed == bearer + ? _value.bearer + : bearer // ignore: cast_nullable_to_non_nullable + as AuthBearerModel?, + basic: freezed == basic + ? _value.basic + : basic // ignore: cast_nullable_to_non_nullable + as AuthBasicAuthModel?, + jwt: freezed == jwt + ? _value.jwt + : jwt // ignore: cast_nullable_to_non_nullable + as AuthJwtModel?, + ) + as $Val, + ); } /// Create a copy of AuthModel @@ -160,16 +165,18 @@ class _$AuthModelCopyWithImpl<$Res, $Val extends AuthModel> abstract class _$$AuthModelImplCopyWith<$Res> implements $AuthModelCopyWith<$Res> { factory _$$AuthModelImplCopyWith( - _$AuthModelImpl value, $Res Function(_$AuthModelImpl) then) = - __$$AuthModelImplCopyWithImpl<$Res>; + _$AuthModelImpl value, + $Res Function(_$AuthModelImpl) then, + ) = __$$AuthModelImplCopyWithImpl<$Res>; @override @useResult - $Res call( - {APIAuthType type, - AuthApiKeyModel? apikey, - AuthBearerModel? bearer, - AuthBasicAuthModel? basic, - AuthJwtModel? jwt}); + $Res call({ + APIAuthType type, + AuthApiKeyModel? apikey, + AuthBearerModel? bearer, + AuthBasicAuthModel? basic, + AuthJwtModel? jwt, + }); @override $AuthApiKeyModelCopyWith<$Res>? get apikey; @@ -186,8 +193,9 @@ class __$$AuthModelImplCopyWithImpl<$Res> extends _$AuthModelCopyWithImpl<$Res, _$AuthModelImpl> implements _$$AuthModelImplCopyWith<$Res> { __$$AuthModelImplCopyWithImpl( - _$AuthModelImpl _value, $Res Function(_$AuthModelImpl) _then) - : super(_value, _then); + _$AuthModelImpl _value, + $Res Function(_$AuthModelImpl) _then, + ) : super(_value, _then); /// Create a copy of AuthModel /// with the given fields replaced by the non-null parameter values. @@ -200,28 +208,30 @@ class __$$AuthModelImplCopyWithImpl<$Res> Object? basic = freezed, Object? jwt = freezed, }) { - return _then(_$AuthModelImpl( - type: null == type - ? _value.type - : type // ignore: cast_nullable_to_non_nullable - as APIAuthType, - apikey: freezed == apikey - ? _value.apikey - : apikey // ignore: cast_nullable_to_non_nullable - as AuthApiKeyModel?, - bearer: freezed == bearer - ? _value.bearer - : bearer // ignore: cast_nullable_to_non_nullable - as AuthBearerModel?, - basic: freezed == basic - ? _value.basic - : basic // ignore: cast_nullable_to_non_nullable - as AuthBasicAuthModel?, - jwt: freezed == jwt - ? _value.jwt - : jwt // ignore: cast_nullable_to_non_nullable - as AuthJwtModel?, - )); + return _then( + _$AuthModelImpl( + type: null == type + ? _value.type + : type // ignore: cast_nullable_to_non_nullable + as APIAuthType, + apikey: freezed == apikey + ? _value.apikey + : apikey // ignore: cast_nullable_to_non_nullable + as AuthApiKeyModel?, + bearer: freezed == bearer + ? _value.bearer + : bearer // ignore: cast_nullable_to_non_nullable + as AuthBearerModel?, + basic: freezed == basic + ? _value.basic + : basic // ignore: cast_nullable_to_non_nullable + as AuthBasicAuthModel?, + jwt: freezed == jwt + ? _value.jwt + : jwt // ignore: cast_nullable_to_non_nullable + as AuthJwtModel?, + ), + ); } } @@ -229,8 +239,13 @@ class __$$AuthModelImplCopyWithImpl<$Res> @JsonSerializable(explicitToJson: true, anyMap: true) class _$AuthModelImpl implements _AuthModel { - const _$AuthModelImpl( - {required this.type, this.apikey, this.bearer, this.basic, this.jwt}); + const _$AuthModelImpl({ + required this.type, + this.apikey, + this.bearer, + this.basic, + this.jwt, + }); factory _$AuthModelImpl.fromJson(Map json) => _$$AuthModelImplFromJson(json); @@ -278,19 +293,18 @@ class _$AuthModelImpl implements _AuthModel { @override Map toJson() { - return _$$AuthModelImplToJson( - this, - ); + return _$$AuthModelImplToJson(this); } } abstract class _AuthModel implements AuthModel { - const factory _AuthModel( - {required final APIAuthType type, - final AuthApiKeyModel? apikey, - final AuthBearerModel? bearer, - final AuthBasicAuthModel? basic, - final AuthJwtModel? jwt}) = _$AuthModelImpl; + const factory _AuthModel({ + required final APIAuthType type, + final AuthApiKeyModel? apikey, + final AuthBearerModel? bearer, + final AuthBasicAuthModel? basic, + final AuthJwtModel? jwt, + }) = _$AuthModelImpl; factory _AuthModel.fromJson(Map json) = _$AuthModelImpl.fromJson; diff --git a/packages/apidash_core/lib/models/auth/api_auth_model.g.dart b/packages/better_networking/lib/models/auth/api_auth_model.g.dart similarity index 57% rename from packages/apidash_core/lib/models/auth/api_auth_model.g.dart rename to packages/better_networking/lib/models/auth/api_auth_model.g.dart index fdbd6e092..fd8673246 100644 --- a/packages/apidash_core/lib/models/auth/api_auth_model.g.dart +++ b/packages/better_networking/lib/models/auth/api_auth_model.g.dart @@ -7,24 +7,26 @@ part of 'api_auth_model.dart'; // ************************************************************************** _$AuthModelImpl _$$AuthModelImplFromJson(Map json) => _$AuthModelImpl( - type: $enumDecode(_$APIAuthTypeEnumMap, json['type']), - apikey: json['apikey'] == null - ? null - : AuthApiKeyModel.fromJson( - Map.from(json['apikey'] as Map)), - bearer: json['bearer'] == null - ? null - : AuthBearerModel.fromJson( - Map.from(json['bearer'] as Map)), - basic: json['basic'] == null - ? null - : AuthBasicAuthModel.fromJson( - Map.from(json['basic'] as Map)), - jwt: json['jwt'] == null - ? null - : AuthJwtModel.fromJson( - Map.from(json['jwt'] as Map)), - ); + type: $enumDecode(_$APIAuthTypeEnumMap, json['type']), + apikey: json['apikey'] == null + ? null + : AuthApiKeyModel.fromJson( + Map.from(json['apikey'] as Map), + ), + bearer: json['bearer'] == null + ? null + : AuthBearerModel.fromJson( + Map.from(json['bearer'] as Map), + ), + basic: json['basic'] == null + ? null + : AuthBasicAuthModel.fromJson( + Map.from(json['basic'] as Map), + ), + jwt: json['jwt'] == null + ? null + : AuthJwtModel.fromJson(Map.from(json['jwt'] as Map)), +); Map _$$AuthModelImplToJson(_$AuthModelImpl instance) => { diff --git a/packages/apidash_core/lib/models/auth/auth_api_key_model.dart b/packages/better_networking/lib/models/auth/auth_api_key_model.dart similarity index 100% rename from packages/apidash_core/lib/models/auth/auth_api_key_model.dart rename to packages/better_networking/lib/models/auth/auth_api_key_model.dart diff --git a/packages/apidash_core/lib/models/auth/auth_api_key_model.freezed.dart b/packages/better_networking/lib/models/auth/auth_api_key_model.freezed.dart similarity index 69% rename from packages/apidash_core/lib/models/auth/auth_api_key_model.freezed.dart rename to packages/better_networking/lib/models/auth/auth_api_key_model.freezed.dart index 3b9b272f2..525e00913 100644 --- a/packages/apidash_core/lib/models/auth/auth_api_key_model.freezed.dart +++ b/packages/better_networking/lib/models/auth/auth_api_key_model.freezed.dart @@ -12,7 +12,8 @@ part of 'auth_api_key_model.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models', +); AuthApiKeyModel _$AuthApiKeyModelFromJson(Map json) { return _AuthApiKeyModel.fromJson(json); @@ -38,8 +39,9 @@ mixin _$AuthApiKeyModel { /// @nodoc abstract class $AuthApiKeyModelCopyWith<$Res> { factory $AuthApiKeyModelCopyWith( - AuthApiKeyModel value, $Res Function(AuthApiKeyModel) then) = - _$AuthApiKeyModelCopyWithImpl<$Res, AuthApiKeyModel>; + AuthApiKeyModel value, + $Res Function(AuthApiKeyModel) then, + ) = _$AuthApiKeyModelCopyWithImpl<$Res, AuthApiKeyModel>; @useResult $Res call({String key, String location, String name}); } @@ -63,29 +65,33 @@ class _$AuthApiKeyModelCopyWithImpl<$Res, $Val extends AuthApiKeyModel> Object? location = null, Object? name = null, }) { - return _then(_value.copyWith( - key: null == key - ? _value.key - : key // ignore: cast_nullable_to_non_nullable - as String, - location: null == location - ? _value.location - : location // ignore: cast_nullable_to_non_nullable - as String, - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - ) as $Val); + return _then( + _value.copyWith( + key: null == key + ? _value.key + : key // ignore: cast_nullable_to_non_nullable + as String, + location: null == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as String, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + ) + as $Val, + ); } } /// @nodoc abstract class _$$AuthApiKeyModelImplCopyWith<$Res> implements $AuthApiKeyModelCopyWith<$Res> { - factory _$$AuthApiKeyModelImplCopyWith(_$AuthApiKeyModelImpl value, - $Res Function(_$AuthApiKeyModelImpl) then) = - __$$AuthApiKeyModelImplCopyWithImpl<$Res>; + factory _$$AuthApiKeyModelImplCopyWith( + _$AuthApiKeyModelImpl value, + $Res Function(_$AuthApiKeyModelImpl) then, + ) = __$$AuthApiKeyModelImplCopyWithImpl<$Res>; @override @useResult $Res call({String key, String location, String name}); @@ -96,8 +102,9 @@ class __$$AuthApiKeyModelImplCopyWithImpl<$Res> extends _$AuthApiKeyModelCopyWithImpl<$Res, _$AuthApiKeyModelImpl> implements _$$AuthApiKeyModelImplCopyWith<$Res> { __$$AuthApiKeyModelImplCopyWithImpl( - _$AuthApiKeyModelImpl _value, $Res Function(_$AuthApiKeyModelImpl) _then) - : super(_value, _then); + _$AuthApiKeyModelImpl _value, + $Res Function(_$AuthApiKeyModelImpl) _then, + ) : super(_value, _then); /// Create a copy of AuthApiKeyModel /// with the given fields replaced by the non-null parameter values. @@ -108,28 +115,33 @@ class __$$AuthApiKeyModelImplCopyWithImpl<$Res> Object? location = null, Object? name = null, }) { - return _then(_$AuthApiKeyModelImpl( - key: null == key - ? _value.key - : key // ignore: cast_nullable_to_non_nullable - as String, - location: null == location - ? _value.location - : location // ignore: cast_nullable_to_non_nullable - as String, - name: null == name - ? _value.name - : name // ignore: cast_nullable_to_non_nullable - as String, - )); + return _then( + _$AuthApiKeyModelImpl( + key: null == key + ? _value.key + : key // ignore: cast_nullable_to_non_nullable + as String, + location: null == location + ? _value.location + : location // ignore: cast_nullable_to_non_nullable + as String, + name: null == name + ? _value.name + : name // ignore: cast_nullable_to_non_nullable + as String, + ), + ); } } /// @nodoc @JsonSerializable() class _$AuthApiKeyModelImpl implements _AuthApiKeyModel { - const _$AuthApiKeyModelImpl( - {required this.key, this.location = 'header', this.name = 'x-api-key'}); + const _$AuthApiKeyModelImpl({ + required this.key, + this.location = 'header', + this.name = 'x-api-key', + }); factory _$AuthApiKeyModelImpl.fromJson(Map json) => _$$AuthApiKeyModelImplFromJson(json); @@ -139,7 +151,7 @@ class _$AuthApiKeyModelImpl implements _AuthApiKeyModel { @override @JsonKey() final String location; -// 'header' or 'query' + // 'header' or 'query' @override @JsonKey() final String name; @@ -171,21 +183,22 @@ class _$AuthApiKeyModelImpl implements _AuthApiKeyModel { @pragma('vm:prefer-inline') _$$AuthApiKeyModelImplCopyWith<_$AuthApiKeyModelImpl> get copyWith => __$$AuthApiKeyModelImplCopyWithImpl<_$AuthApiKeyModelImpl>( - this, _$identity); + this, + _$identity, + ); @override Map toJson() { - return _$$AuthApiKeyModelImplToJson( - this, - ); + return _$$AuthApiKeyModelImplToJson(this); } } abstract class _AuthApiKeyModel implements AuthApiKeyModel { - const factory _AuthApiKeyModel( - {required final String key, - final String location, - final String name}) = _$AuthApiKeyModelImpl; + const factory _AuthApiKeyModel({ + required final String key, + final String location, + final String name, + }) = _$AuthApiKeyModelImpl; factory _AuthApiKeyModel.fromJson(Map json) = _$AuthApiKeyModelImpl.fromJson; diff --git a/packages/better_networking/lib/models/auth/auth_api_key_model.g.dart b/packages/better_networking/lib/models/auth/auth_api_key_model.g.dart new file mode 100644 index 000000000..a88f104cb --- /dev/null +++ b/packages/better_networking/lib/models/auth/auth_api_key_model.g.dart @@ -0,0 +1,23 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'auth_api_key_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$AuthApiKeyModelImpl _$$AuthApiKeyModelImplFromJson( + Map json, +) => _$AuthApiKeyModelImpl( + key: json['key'] as String, + location: json['location'] as String? ?? 'header', + name: json['name'] as String? ?? 'x-api-key', +); + +Map _$$AuthApiKeyModelImplToJson( + _$AuthApiKeyModelImpl instance, +) => { + 'key': instance.key, + 'location': instance.location, + 'name': instance.name, +}; diff --git a/packages/apidash_core/lib/models/auth/auth_basic_model.dart b/packages/better_networking/lib/models/auth/auth_basic_model.dart similarity index 100% rename from packages/apidash_core/lib/models/auth/auth_basic_model.dart rename to packages/better_networking/lib/models/auth/auth_basic_model.dart diff --git a/packages/apidash_core/lib/models/auth/auth_basic_model.freezed.dart b/packages/better_networking/lib/models/auth/auth_basic_model.freezed.dart similarity index 68% rename from packages/apidash_core/lib/models/auth/auth_basic_model.freezed.dart rename to packages/better_networking/lib/models/auth/auth_basic_model.freezed.dart index d5c1a07f2..62e2399d6 100644 --- a/packages/apidash_core/lib/models/auth/auth_basic_model.freezed.dart +++ b/packages/better_networking/lib/models/auth/auth_basic_model.freezed.dart @@ -12,7 +12,8 @@ part of 'auth_basic_model.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models', +); AuthBasicAuthModel _$AuthBasicAuthModelFromJson(Map json) { return _AuthBasicAuthModel.fromJson(json); @@ -36,8 +37,9 @@ mixin _$AuthBasicAuthModel { /// @nodoc abstract class $AuthBasicAuthModelCopyWith<$Res> { factory $AuthBasicAuthModelCopyWith( - AuthBasicAuthModel value, $Res Function(AuthBasicAuthModel) then) = - _$AuthBasicAuthModelCopyWithImpl<$Res, AuthBasicAuthModel>; + AuthBasicAuthModel value, + $Res Function(AuthBasicAuthModel) then, + ) = _$AuthBasicAuthModelCopyWithImpl<$Res, AuthBasicAuthModel>; @useResult $Res call({String username, String password}); } @@ -56,29 +58,30 @@ class _$AuthBasicAuthModelCopyWithImpl<$Res, $Val extends AuthBasicAuthModel> /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override - $Res call({ - Object? username = null, - Object? password = null, - }) { - return _then(_value.copyWith( - username: null == username - ? _value.username - : username // ignore: cast_nullable_to_non_nullable - as String, - password: null == password - ? _value.password - : password // ignore: cast_nullable_to_non_nullable - as String, - ) as $Val); + $Res call({Object? username = null, Object? password = null}) { + return _then( + _value.copyWith( + username: null == username + ? _value.username + : username // ignore: cast_nullable_to_non_nullable + as String, + password: null == password + ? _value.password + : password // ignore: cast_nullable_to_non_nullable + as String, + ) + as $Val, + ); } } /// @nodoc abstract class _$$AuthBasicAuthModelImplCopyWith<$Res> implements $AuthBasicAuthModelCopyWith<$Res> { - factory _$$AuthBasicAuthModelImplCopyWith(_$AuthBasicAuthModelImpl value, - $Res Function(_$AuthBasicAuthModelImpl) then) = - __$$AuthBasicAuthModelImplCopyWithImpl<$Res>; + factory _$$AuthBasicAuthModelImplCopyWith( + _$AuthBasicAuthModelImpl value, + $Res Function(_$AuthBasicAuthModelImpl) then, + ) = __$$AuthBasicAuthModelImplCopyWithImpl<$Res>; @override @useResult $Res call({String username, String password}); @@ -88,36 +91,38 @@ abstract class _$$AuthBasicAuthModelImplCopyWith<$Res> class __$$AuthBasicAuthModelImplCopyWithImpl<$Res> extends _$AuthBasicAuthModelCopyWithImpl<$Res, _$AuthBasicAuthModelImpl> implements _$$AuthBasicAuthModelImplCopyWith<$Res> { - __$$AuthBasicAuthModelImplCopyWithImpl(_$AuthBasicAuthModelImpl _value, - $Res Function(_$AuthBasicAuthModelImpl) _then) - : super(_value, _then); + __$$AuthBasicAuthModelImplCopyWithImpl( + _$AuthBasicAuthModelImpl _value, + $Res Function(_$AuthBasicAuthModelImpl) _then, + ) : super(_value, _then); /// Create a copy of AuthBasicAuthModel /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override - $Res call({ - Object? username = null, - Object? password = null, - }) { - return _then(_$AuthBasicAuthModelImpl( - username: null == username - ? _value.username - : username // ignore: cast_nullable_to_non_nullable - as String, - password: null == password - ? _value.password - : password // ignore: cast_nullable_to_non_nullable - as String, - )); + $Res call({Object? username = null, Object? password = null}) { + return _then( + _$AuthBasicAuthModelImpl( + username: null == username + ? _value.username + : username // ignore: cast_nullable_to_non_nullable + as String, + password: null == password + ? _value.password + : password // ignore: cast_nullable_to_non_nullable + as String, + ), + ); } } /// @nodoc @JsonSerializable() class _$AuthBasicAuthModelImpl implements _AuthBasicAuthModel { - const _$AuthBasicAuthModelImpl( - {required this.username, required this.password}); + const _$AuthBasicAuthModelImpl({ + required this.username, + required this.password, + }); factory _$AuthBasicAuthModelImpl.fromJson(Map json) => _$$AuthBasicAuthModelImplFromJson(json); @@ -154,20 +159,21 @@ class _$AuthBasicAuthModelImpl implements _AuthBasicAuthModel { @pragma('vm:prefer-inline') _$$AuthBasicAuthModelImplCopyWith<_$AuthBasicAuthModelImpl> get copyWith => __$$AuthBasicAuthModelImplCopyWithImpl<_$AuthBasicAuthModelImpl>( - this, _$identity); + this, + _$identity, + ); @override Map toJson() { - return _$$AuthBasicAuthModelImplToJson( - this, - ); + return _$$AuthBasicAuthModelImplToJson(this); } } abstract class _AuthBasicAuthModel implements AuthBasicAuthModel { - const factory _AuthBasicAuthModel( - {required final String username, - required final String password}) = _$AuthBasicAuthModelImpl; + const factory _AuthBasicAuthModel({ + required final String username, + required final String password, + }) = _$AuthBasicAuthModelImpl; factory _AuthBasicAuthModel.fromJson(Map json) = _$AuthBasicAuthModelImpl.fromJson; diff --git a/packages/apidash_core/lib/models/auth/auth_basic_model.g.dart b/packages/better_networking/lib/models/auth/auth_basic_model.g.dart similarity index 54% rename from packages/apidash_core/lib/models/auth/auth_basic_model.g.dart rename to packages/better_networking/lib/models/auth/auth_basic_model.g.dart index d093c2fe4..6291328b4 100644 --- a/packages/apidash_core/lib/models/auth/auth_basic_model.g.dart +++ b/packages/better_networking/lib/models/auth/auth_basic_model.g.dart @@ -7,15 +7,15 @@ part of 'auth_basic_model.dart'; // ************************************************************************** _$AuthBasicAuthModelImpl _$$AuthBasicAuthModelImplFromJson( - Map json) => - _$AuthBasicAuthModelImpl( - username: json['username'] as String, - password: json['password'] as String, - ); + Map json, +) => _$AuthBasicAuthModelImpl( + username: json['username'] as String, + password: json['password'] as String, +); Map _$$AuthBasicAuthModelImplToJson( - _$AuthBasicAuthModelImpl instance) => - { - 'username': instance.username, - 'password': instance.password, - }; + _$AuthBasicAuthModelImpl instance, +) => { + 'username': instance.username, + 'password': instance.password, +}; diff --git a/packages/apidash_core/lib/models/auth/auth_bearer_model.dart b/packages/better_networking/lib/models/auth/auth_bearer_model.dart similarity index 100% rename from packages/apidash_core/lib/models/auth/auth_bearer_model.dart rename to packages/better_networking/lib/models/auth/auth_bearer_model.dart diff --git a/packages/apidash_core/lib/models/auth/auth_bearer_model.freezed.dart b/packages/better_networking/lib/models/auth/auth_bearer_model.freezed.dart similarity index 76% rename from packages/apidash_core/lib/models/auth/auth_bearer_model.freezed.dart rename to packages/better_networking/lib/models/auth/auth_bearer_model.freezed.dart index b94aa4132..a590fcce5 100644 --- a/packages/apidash_core/lib/models/auth/auth_bearer_model.freezed.dart +++ b/packages/better_networking/lib/models/auth/auth_bearer_model.freezed.dart @@ -12,7 +12,8 @@ part of 'auth_bearer_model.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models', +); AuthBearerModel _$AuthBearerModelFromJson(Map json) { return _AuthBearerModel.fromJson(json); @@ -35,8 +36,9 @@ mixin _$AuthBearerModel { /// @nodoc abstract class $AuthBearerModelCopyWith<$Res> { factory $AuthBearerModelCopyWith( - AuthBearerModel value, $Res Function(AuthBearerModel) then) = - _$AuthBearerModelCopyWithImpl<$Res, AuthBearerModel>; + AuthBearerModel value, + $Res Function(AuthBearerModel) then, + ) = _$AuthBearerModelCopyWithImpl<$Res, AuthBearerModel>; @useResult $Res call({String token}); } @@ -55,24 +57,26 @@ class _$AuthBearerModelCopyWithImpl<$Res, $Val extends AuthBearerModel> /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override - $Res call({ - Object? token = null, - }) { - return _then(_value.copyWith( - token: null == token - ? _value.token - : token // ignore: cast_nullable_to_non_nullable - as String, - ) as $Val); + $Res call({Object? token = null}) { + return _then( + _value.copyWith( + token: null == token + ? _value.token + : token // ignore: cast_nullable_to_non_nullable + as String, + ) + as $Val, + ); } } /// @nodoc abstract class _$$AuthBearerModelImplCopyWith<$Res> implements $AuthBearerModelCopyWith<$Res> { - factory _$$AuthBearerModelImplCopyWith(_$AuthBearerModelImpl value, - $Res Function(_$AuthBearerModelImpl) then) = - __$$AuthBearerModelImplCopyWithImpl<$Res>; + factory _$$AuthBearerModelImplCopyWith( + _$AuthBearerModelImpl value, + $Res Function(_$AuthBearerModelImpl) then, + ) = __$$AuthBearerModelImplCopyWithImpl<$Res>; @override @useResult $Res call({String token}); @@ -83,22 +87,23 @@ class __$$AuthBearerModelImplCopyWithImpl<$Res> extends _$AuthBearerModelCopyWithImpl<$Res, _$AuthBearerModelImpl> implements _$$AuthBearerModelImplCopyWith<$Res> { __$$AuthBearerModelImplCopyWithImpl( - _$AuthBearerModelImpl _value, $Res Function(_$AuthBearerModelImpl) _then) - : super(_value, _then); + _$AuthBearerModelImpl _value, + $Res Function(_$AuthBearerModelImpl) _then, + ) : super(_value, _then); /// Create a copy of AuthBearerModel /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override - $Res call({ - Object? token = null, - }) { - return _then(_$AuthBearerModelImpl( - token: null == token - ? _value.token - : token // ignore: cast_nullable_to_non_nullable - as String, - )); + $Res call({Object? token = null}) { + return _then( + _$AuthBearerModelImpl( + token: null == token + ? _value.token + : token // ignore: cast_nullable_to_non_nullable + as String, + ), + ); } } @@ -137,13 +142,13 @@ class _$AuthBearerModelImpl implements _AuthBearerModel { @pragma('vm:prefer-inline') _$$AuthBearerModelImplCopyWith<_$AuthBearerModelImpl> get copyWith => __$$AuthBearerModelImplCopyWithImpl<_$AuthBearerModelImpl>( - this, _$identity); + this, + _$identity, + ); @override Map toJson() { - return _$$AuthBearerModelImplToJson( - this, - ); + return _$$AuthBearerModelImplToJson(this); } } diff --git a/packages/apidash_core/lib/models/auth/auth_bearer_model.g.dart b/packages/better_networking/lib/models/auth/auth_bearer_model.g.dart similarity index 63% rename from packages/apidash_core/lib/models/auth/auth_bearer_model.g.dart rename to packages/better_networking/lib/models/auth/auth_bearer_model.g.dart index a986b911e..34c150d85 100644 --- a/packages/apidash_core/lib/models/auth/auth_bearer_model.g.dart +++ b/packages/better_networking/lib/models/auth/auth_bearer_model.g.dart @@ -7,13 +7,9 @@ part of 'auth_bearer_model.dart'; // ************************************************************************** _$AuthBearerModelImpl _$$AuthBearerModelImplFromJson( - Map json) => - _$AuthBearerModelImpl( - token: json['token'] as String, - ); + Map json, +) => _$AuthBearerModelImpl(token: json['token'] as String); Map _$$AuthBearerModelImplToJson( - _$AuthBearerModelImpl instance) => - { - 'token': instance.token, - }; + _$AuthBearerModelImpl instance, +) => {'token': instance.token}; diff --git a/packages/apidash_core/lib/models/auth/auth_jwt_model.dart b/packages/better_networking/lib/models/auth/auth_jwt_model.dart similarity index 100% rename from packages/apidash_core/lib/models/auth/auth_jwt_model.dart rename to packages/better_networking/lib/models/auth/auth_jwt_model.dart diff --git a/packages/apidash_core/lib/models/auth/auth_jwt_model.freezed.dart b/packages/better_networking/lib/models/auth/auth_jwt_model.freezed.dart similarity index 56% rename from packages/apidash_core/lib/models/auth/auth_jwt_model.freezed.dart rename to packages/better_networking/lib/models/auth/auth_jwt_model.freezed.dart index cf35ed41e..c6d5fbf6e 100644 --- a/packages/apidash_core/lib/models/auth/auth_jwt_model.freezed.dart +++ b/packages/better_networking/lib/models/auth/auth_jwt_model.freezed.dart @@ -12,7 +12,8 @@ part of 'auth_jwt_model.dart'; T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( - 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models', +); AuthJwtModel _$AuthJwtModelFromJson(Map json) { return _AuthJwtModel.fromJson(json); @@ -42,18 +43,20 @@ mixin _$AuthJwtModel { /// @nodoc abstract class $AuthJwtModelCopyWith<$Res> { factory $AuthJwtModelCopyWith( - AuthJwtModel value, $Res Function(AuthJwtModel) then) = - _$AuthJwtModelCopyWithImpl<$Res, AuthJwtModel>; + AuthJwtModel value, + $Res Function(AuthJwtModel) then, + ) = _$AuthJwtModelCopyWithImpl<$Res, AuthJwtModel>; @useResult - $Res call( - {String secret, - String payload, - String addTokenTo, - String algorithm, - bool isSecretBase64Encoded, - String headerPrefix, - String queryParamKey, - String header}); + $Res call({ + String secret, + String payload, + String addTokenTo, + String algorithm, + bool isSecretBase64Encoded, + String headerPrefix, + String queryParamKey, + String header, + }); } /// @nodoc @@ -80,40 +83,43 @@ class _$AuthJwtModelCopyWithImpl<$Res, $Val extends AuthJwtModel> Object? queryParamKey = null, Object? header = null, }) { - return _then(_value.copyWith( - secret: null == secret - ? _value.secret - : secret // ignore: cast_nullable_to_non_nullable - as String, - payload: null == payload - ? _value.payload - : payload // ignore: cast_nullable_to_non_nullable - as String, - addTokenTo: null == addTokenTo - ? _value.addTokenTo - : addTokenTo // ignore: cast_nullable_to_non_nullable - as String, - algorithm: null == algorithm - ? _value.algorithm - : algorithm // ignore: cast_nullable_to_non_nullable - as String, - isSecretBase64Encoded: null == isSecretBase64Encoded - ? _value.isSecretBase64Encoded - : isSecretBase64Encoded // ignore: cast_nullable_to_non_nullable - as bool, - headerPrefix: null == headerPrefix - ? _value.headerPrefix - : headerPrefix // ignore: cast_nullable_to_non_nullable - as String, - queryParamKey: null == queryParamKey - ? _value.queryParamKey - : queryParamKey // ignore: cast_nullable_to_non_nullable - as String, - header: null == header - ? _value.header - : header // ignore: cast_nullable_to_non_nullable - as String, - ) as $Val); + return _then( + _value.copyWith( + secret: null == secret + ? _value.secret + : secret // ignore: cast_nullable_to_non_nullable + as String, + payload: null == payload + ? _value.payload + : payload // ignore: cast_nullable_to_non_nullable + as String, + addTokenTo: null == addTokenTo + ? _value.addTokenTo + : addTokenTo // ignore: cast_nullable_to_non_nullable + as String, + algorithm: null == algorithm + ? _value.algorithm + : algorithm // ignore: cast_nullable_to_non_nullable + as String, + isSecretBase64Encoded: null == isSecretBase64Encoded + ? _value.isSecretBase64Encoded + : isSecretBase64Encoded // ignore: cast_nullable_to_non_nullable + as bool, + headerPrefix: null == headerPrefix + ? _value.headerPrefix + : headerPrefix // ignore: cast_nullable_to_non_nullable + as String, + queryParamKey: null == queryParamKey + ? _value.queryParamKey + : queryParamKey // ignore: cast_nullable_to_non_nullable + as String, + header: null == header + ? _value.header + : header // ignore: cast_nullable_to_non_nullable + as String, + ) + as $Val, + ); } } @@ -121,19 +127,21 @@ class _$AuthJwtModelCopyWithImpl<$Res, $Val extends AuthJwtModel> abstract class _$$AuthJwtModelImplCopyWith<$Res> implements $AuthJwtModelCopyWith<$Res> { factory _$$AuthJwtModelImplCopyWith( - _$AuthJwtModelImpl value, $Res Function(_$AuthJwtModelImpl) then) = - __$$AuthJwtModelImplCopyWithImpl<$Res>; + _$AuthJwtModelImpl value, + $Res Function(_$AuthJwtModelImpl) then, + ) = __$$AuthJwtModelImplCopyWithImpl<$Res>; @override @useResult - $Res call( - {String secret, - String payload, - String addTokenTo, - String algorithm, - bool isSecretBase64Encoded, - String headerPrefix, - String queryParamKey, - String header}); + $Res call({ + String secret, + String payload, + String addTokenTo, + String algorithm, + bool isSecretBase64Encoded, + String headerPrefix, + String queryParamKey, + String header, + }); } /// @nodoc @@ -141,8 +149,9 @@ class __$$AuthJwtModelImplCopyWithImpl<$Res> extends _$AuthJwtModelCopyWithImpl<$Res, _$AuthJwtModelImpl> implements _$$AuthJwtModelImplCopyWith<$Res> { __$$AuthJwtModelImplCopyWithImpl( - _$AuthJwtModelImpl _value, $Res Function(_$AuthJwtModelImpl) _then) - : super(_value, _then); + _$AuthJwtModelImpl _value, + $Res Function(_$AuthJwtModelImpl) _then, + ) : super(_value, _then); /// Create a copy of AuthJwtModel /// with the given fields replaced by the non-null parameter values. @@ -158,55 +167,58 @@ class __$$AuthJwtModelImplCopyWithImpl<$Res> Object? queryParamKey = null, Object? header = null, }) { - return _then(_$AuthJwtModelImpl( - secret: null == secret - ? _value.secret - : secret // ignore: cast_nullable_to_non_nullable - as String, - payload: null == payload - ? _value.payload - : payload // ignore: cast_nullable_to_non_nullable - as String, - addTokenTo: null == addTokenTo - ? _value.addTokenTo - : addTokenTo // ignore: cast_nullable_to_non_nullable - as String, - algorithm: null == algorithm - ? _value.algorithm - : algorithm // ignore: cast_nullable_to_non_nullable - as String, - isSecretBase64Encoded: null == isSecretBase64Encoded - ? _value.isSecretBase64Encoded - : isSecretBase64Encoded // ignore: cast_nullable_to_non_nullable - as bool, - headerPrefix: null == headerPrefix - ? _value.headerPrefix - : headerPrefix // ignore: cast_nullable_to_non_nullable - as String, - queryParamKey: null == queryParamKey - ? _value.queryParamKey - : queryParamKey // ignore: cast_nullable_to_non_nullable - as String, - header: null == header - ? _value.header - : header // ignore: cast_nullable_to_non_nullable - as String, - )); + return _then( + _$AuthJwtModelImpl( + secret: null == secret + ? _value.secret + : secret // ignore: cast_nullable_to_non_nullable + as String, + payload: null == payload + ? _value.payload + : payload // ignore: cast_nullable_to_non_nullable + as String, + addTokenTo: null == addTokenTo + ? _value.addTokenTo + : addTokenTo // ignore: cast_nullable_to_non_nullable + as String, + algorithm: null == algorithm + ? _value.algorithm + : algorithm // ignore: cast_nullable_to_non_nullable + as String, + isSecretBase64Encoded: null == isSecretBase64Encoded + ? _value.isSecretBase64Encoded + : isSecretBase64Encoded // ignore: cast_nullable_to_non_nullable + as bool, + headerPrefix: null == headerPrefix + ? _value.headerPrefix + : headerPrefix // ignore: cast_nullable_to_non_nullable + as String, + queryParamKey: null == queryParamKey + ? _value.queryParamKey + : queryParamKey // ignore: cast_nullable_to_non_nullable + as String, + header: null == header + ? _value.header + : header // ignore: cast_nullable_to_non_nullable + as String, + ), + ); } } /// @nodoc @JsonSerializable() class _$AuthJwtModelImpl implements _AuthJwtModel { - const _$AuthJwtModelImpl( - {required this.secret, - required this.payload, - required this.addTokenTo, - required this.algorithm, - required this.isSecretBase64Encoded, - required this.headerPrefix, - required this.queryParamKey, - required this.header}); + const _$AuthJwtModelImpl({ + required this.secret, + required this.payload, + required this.addTokenTo, + required this.algorithm, + required this.isSecretBase64Encoded, + required this.headerPrefix, + required this.queryParamKey, + required this.header, + }); factory _$AuthJwtModelImpl.fromJson(Map json) => _$$AuthJwtModelImplFromJson(json); @@ -255,8 +267,17 @@ class _$AuthJwtModelImpl implements _AuthJwtModel { @JsonKey(includeFromJson: false, includeToJson: false) @override - int get hashCode => Object.hash(runtimeType, secret, payload, addTokenTo, - algorithm, isSecretBase64Encoded, headerPrefix, queryParamKey, header); + int get hashCode => Object.hash( + runtimeType, + secret, + payload, + addTokenTo, + algorithm, + isSecretBase64Encoded, + headerPrefix, + queryParamKey, + header, + ); /// Create a copy of AuthJwtModel /// with the given fields replaced by the non-null parameter values. @@ -268,22 +289,21 @@ class _$AuthJwtModelImpl implements _AuthJwtModel { @override Map toJson() { - return _$$AuthJwtModelImplToJson( - this, - ); + return _$$AuthJwtModelImplToJson(this); } } abstract class _AuthJwtModel implements AuthJwtModel { - const factory _AuthJwtModel( - {required final String secret, - required final String payload, - required final String addTokenTo, - required final String algorithm, - required final bool isSecretBase64Encoded, - required final String headerPrefix, - required final String queryParamKey, - required final String header}) = _$AuthJwtModelImpl; + const factory _AuthJwtModel({ + required final String secret, + required final String payload, + required final String addTokenTo, + required final String algorithm, + required final bool isSecretBase64Encoded, + required final String headerPrefix, + required final String queryParamKey, + required final String header, + }) = _$AuthJwtModelImpl; factory _AuthJwtModel.fromJson(Map json) = _$AuthJwtModelImpl.fromJson; diff --git a/packages/apidash_core/lib/models/auth/auth_jwt_model.g.dart b/packages/better_networking/lib/models/auth/auth_jwt_model.g.dart similarity index 100% rename from packages/apidash_core/lib/models/auth/auth_jwt_model.g.dart rename to packages/better_networking/lib/models/auth/auth_jwt_model.g.dart diff --git a/packages/better_networking/lib/models/http_request_model.freezed.dart b/packages/better_networking/lib/models/http_request_model.freezed.dart index 73ef7423c..864ae7e0b 100644 --- a/packages/better_networking/lib/models/http_request_model.freezed.dart +++ b/packages/better_networking/lib/models/http_request_model.freezed.dart @@ -61,17 +61,6 @@ abstract class $HttpRequestModelCopyWith<$Res> { String? query, List? formData, }); - $Res call( - {HTTPVerb method, - String url, - List? headers, - List? params, - List? isHeaderEnabledList, - List? isParamEnabledList, - ContentType bodyContentType, - String? body, - String? query, - List? formData}); } /// @nodoc @@ -146,49 +135,6 @@ class _$HttpRequestModelCopyWithImpl<$Res, $Val extends HttpRequestModel> as $Val, ); } - return _then(_value.copyWith( - method: null == method - ? _value.method - : method // ignore: cast_nullable_to_non_nullable - as HTTPVerb, - url: null == url - ? _value.url - : url // ignore: cast_nullable_to_non_nullable - as String, - headers: freezed == headers - ? _value.headers - : headers // ignore: cast_nullable_to_non_nullable - as List?, - params: freezed == params - ? _value.params - : params // ignore: cast_nullable_to_non_nullable - as List?, - isHeaderEnabledList: freezed == isHeaderEnabledList - ? _value.isHeaderEnabledList - : isHeaderEnabledList // ignore: cast_nullable_to_non_nullable - as List?, - isParamEnabledList: freezed == isParamEnabledList - ? _value.isParamEnabledList - : isParamEnabledList // ignore: cast_nullable_to_non_nullable - as List?, - bodyContentType: null == bodyContentType - ? _value.bodyContentType - : bodyContentType // ignore: cast_nullable_to_non_nullable - as ContentType, - body: freezed == body - ? _value.body - : body // ignore: cast_nullable_to_non_nullable - as String?, - query: freezed == query - ? _value.query - : query // ignore: cast_nullable_to_non_nullable - as String?, - formData: freezed == formData - ? _value.formData - : formData // ignore: cast_nullable_to_non_nullable - as List?, - ) as $Val); - } } /// @nodoc @@ -212,17 +158,6 @@ abstract class _$$HttpRequestModelImplCopyWith<$Res> String? query, List? formData, }); - $Res call( - {HTTPVerb method, - String url, - List? headers, - List? params, - List? isHeaderEnabledList, - List? isParamEnabledList, - ContentType bodyContentType, - String? body, - String? query, - List? formData}); } /// @nodoc @@ -294,48 +229,6 @@ class __$$HttpRequestModelImplCopyWithImpl<$Res> as List?, ), ); - return _then(_$HttpRequestModelImpl( - method: null == method - ? _value.method - : method // ignore: cast_nullable_to_non_nullable - as HTTPVerb, - url: null == url - ? _value.url - : url // ignore: cast_nullable_to_non_nullable - as String, - headers: freezed == headers - ? _value._headers - : headers // ignore: cast_nullable_to_non_nullable - as List?, - params: freezed == params - ? _value._params - : params // ignore: cast_nullable_to_non_nullable - as List?, - isHeaderEnabledList: freezed == isHeaderEnabledList - ? _value._isHeaderEnabledList - : isHeaderEnabledList // ignore: cast_nullable_to_non_nullable - as List?, - isParamEnabledList: freezed == isParamEnabledList - ? _value._isParamEnabledList - : isParamEnabledList // ignore: cast_nullable_to_non_nullable - as List?, - bodyContentType: null == bodyContentType - ? _value.bodyContentType - : bodyContentType // ignore: cast_nullable_to_non_nullable - as ContentType, - body: freezed == body - ? _value.body - : body // ignore: cast_nullable_to_non_nullable - as String?, - query: freezed == query - ? _value.query - : query // ignore: cast_nullable_to_non_nullable - as String?, - formData: freezed == formData - ? _value._formData - : formData // ignore: cast_nullable_to_non_nullable - as List?, - )); } } @@ -360,23 +253,6 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { _isParamEnabledList = isParamEnabledList, _formData = formData, super._(); - const _$HttpRequestModelImpl( - {this.method = HTTPVerb.get, - this.url = "", - final List? headers, - final List? params, - final List? isHeaderEnabledList, - final List? isParamEnabledList, - this.bodyContentType = ContentType.json, - this.body, - this.query, - final List? formData}) - : _headers = headers, - _params = params, - _isHeaderEnabledList = isHeaderEnabledList, - _isParamEnabledList = isParamEnabledList, - _formData = formData, - super._(); factory _$HttpRequestModelImpl.fromJson(Map json) => _$$HttpRequestModelImplFromJson(json); @@ -449,7 +325,6 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { @override String toString() { return 'HttpRequestModel(method: $method, url: $url, headers: $headers, params: $params, isHeaderEnabledList: $isHeaderEnabledList, isParamEnabledList: $isParamEnabledList, bodyContentType: $bodyContentType, body: $body, query: $query, formData: $formData)'; - return 'HttpRequestModel(method: $method, url: $url, headers: $headers, params: $params, isHeaderEnabledList: $isHeaderEnabledList, isParamEnabledList: $isParamEnabledList, bodyContentType: $bodyContentType, body: $body, query: $query, formData: $formData)'; } @override @@ -469,10 +344,6 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { other._isParamEnabledList, _isParamEnabledList, ) && - const DeepCollectionEquality() - .equals(other._isHeaderEnabledList, _isHeaderEnabledList) && - const DeepCollectionEquality() - .equals(other._isParamEnabledList, _isParamEnabledList) && (identical(other.bodyContentType, bodyContentType) || other.bodyContentType == bodyContentType) && (identical(other.body, body) || other.body == body) && @@ -495,17 +366,6 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { query, const DeepCollectionEquality().hash(_formData), ); - runtimeType, - method, - url, - const DeepCollectionEquality().hash(_headers), - const DeepCollectionEquality().hash(_params), - const DeepCollectionEquality().hash(_isHeaderEnabledList), - const DeepCollectionEquality().hash(_isParamEnabledList), - bodyContentType, - body, - query, - const DeepCollectionEquality().hash(_formData)); /// Create a copy of HttpRequestModel /// with the given fields replaced by the non-null parameter values. @@ -537,17 +397,6 @@ abstract class _HttpRequestModel extends HttpRequestModel { final String? query, final List? formData, }) = _$HttpRequestModelImpl; - const factory _HttpRequestModel( - {final HTTPVerb method, - final String url, - final List? headers, - final List? params, - final List? isHeaderEnabledList, - final List? isParamEnabledList, - final ContentType bodyContentType, - final String? body, - final String? query, - final List? formData}) = _$HttpRequestModelImpl; const _HttpRequestModel._() : super._(); factory _HttpRequestModel.fromJson(Map json) = diff --git a/packages/better_networking/lib/models/models.dart b/packages/better_networking/lib/models/models.dart index a33c6fddc..f5ac6b1f0 100644 --- a/packages/better_networking/lib/models/models.dart +++ b/packages/better_networking/lib/models/models.dart @@ -1,2 +1,7 @@ export 'http_request_model.dart'; export 'http_response_model.dart'; +export 'auth/api_auth_model.dart'; +export 'auth/auth_api_key_model.dart'; +export 'auth/auth_basic_model.dart'; +export 'auth/auth_bearer_model.dart'; +export 'auth/auth_jwt_model.dart'; diff --git a/packages/better_networking/lib/services/http_service.dart b/packages/better_networking/lib/services/http_service.dart index 047d83afb..78c75f50f 100644 --- a/packages/better_networking/lib/services/http_service.dart +++ b/packages/better_networking/lib/services/http_service.dart @@ -7,7 +7,6 @@ import '../consts.dart'; import '../extensions/extensions.dart'; import '../models/models.dart'; import '../utils/utils.dart'; -import '../utils/handle_auth.dart'; import 'http_client_manager.dart'; typedef HttpResponse = http.Response; @@ -28,11 +27,7 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( final client = httpClientManager.createClient(requestId, noSSL: noSSL); // Handle authentication -<<<<<<< HEAD:packages/better_networking/lib/services/http_service.dart - final authenticatedRequestModel = handleAuth(requestModel, authModel); -======= final authenticatedRequestModel = handleAuth(requestModel, authData); ->>>>>>> f24eb4e6 (feat: remove AuthModel from HttpRequestModel and integrate into HistoryRequestModel and RequestModel):packages/apidash_core/lib/services/http_service.dart (Uri?, String?) uriRec = getValidRequestUri( authenticatedRequestModel.url, diff --git a/packages/apidash_core/lib/utils/auth_utils.dart b/packages/better_networking/lib/utils/auth_utils.dart similarity index 97% rename from packages/apidash_core/lib/utils/auth_utils.dart rename to packages/better_networking/lib/utils/auth_utils.dart index df6bf864c..303a3e90d 100644 --- a/packages/apidash_core/lib/utils/auth_utils.dart +++ b/packages/better_networking/lib/utils/auth_utils.dart @@ -1,6 +1,6 @@ import 'dart:convert'; import 'dart:typed_data'; -import 'package:apidash_core/models/auth/auth_jwt_model.dart'; +import 'package:better_networking/models/auth/auth_jwt_model.dart'; import 'package:crypto/crypto.dart'; String generateJWT(AuthJwtModel jwtAuth) { diff --git a/packages/apidash_core/lib/utils/handle_auth.dart b/packages/better_networking/lib/utils/handle_auth.dart similarity index 95% rename from packages/apidash_core/lib/utils/handle_auth.dart rename to packages/better_networking/lib/utils/handle_auth.dart index 2922b81c2..45a3f08cb 100644 --- a/packages/apidash_core/lib/utils/handle_auth.dart +++ b/packages/better_networking/lib/utils/handle_auth.dart @@ -1,7 +1,8 @@ import 'dart:convert'; -import 'package:apidash_core/consts.dart'; -import 'package:apidash_core/models/auth/api_auth_model.dart'; -import 'package:apidash_core/utils/auth_utils.dart'; +import 'package:better_networking/utils/auth_utils.dart'; +import 'package:better_networking/better_networking.dart'; + +import '../models/auth/api_auth_model.dart'; HttpRequestModel handleAuth(HttpRequestModel httpRequestModel,AuthModel? authData) { if (authData == null || authData.type == APIAuthType.none) { diff --git a/packages/better_networking/lib/utils/utils.dart b/packages/better_networking/lib/utils/utils.dart index d334a022f..95bfa9317 100644 --- a/packages/better_networking/lib/utils/utils.dart +++ b/packages/better_networking/lib/utils/utils.dart @@ -4,3 +4,4 @@ export 'http_request_utils.dart'; export 'http_response_utils.dart'; export 'string_utils.dart' hide RandomStringGenerator; export 'uri_utils.dart'; +export 'handle_auth.dart'; From 4284f47fe63b906dd160168c90e076ce7bf3375d Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Wed, 2 Jul 2025 22:25:45 +0530 Subject: [PATCH 29/70] fix: add missing crypto dependency to better_networking package add missing auth tab in HistoryRequestPane --- lib/screens/history/history_widgets/his_request_pane.dart | 8 ++++---- packages/apidash_core/pubspec.yaml | 1 - packages/better_networking/pubspec.yaml | 1 + 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/screens/history/history_widgets/his_request_pane.dart b/lib/screens/history/history_widgets/his_request_pane.dart index 21855779b..05266ebfc 100644 --- a/lib/screens/history/history_widgets/his_request_pane.dart +++ b/lib/screens/history/history_widgets/his_request_pane.dart @@ -46,10 +46,8 @@ class HistoryRequestPane extends ConsumerWidget { .select((value) => value?.postRequestScript?.length)) ?? 0; - - final hasAuth = ref.watch(selectedHistoryRequestModelProvider.select( - (value) => - value?.authModel?.type != APIAuthType.none)); + final hasAuth = ref.watch(selectedHistoryRequestModelProvider + .select((value) => value?.authModel?.type != APIAuthType.none)); final authModel = ref.watch(selectedHistoryRequestModelProvider .select((value) => value?.authModel)); @@ -66,12 +64,14 @@ class HistoryRequestPane extends ConsumerWidget { showViewCodeButton: !isCompact, showIndicators: [ paramLength > 0, + hasAuth, headerLength > 0, hasBody, scriptsLength > 0, ], tabLabels: const [ kLabelURLParams, + kLabelAuth, kLabelHeaders, kLabelBody, kLabelScripts, diff --git a/packages/apidash_core/pubspec.yaml b/packages/apidash_core/pubspec.yaml index ca73b2796..2c010a07a 100644 --- a/packages/apidash_core/pubspec.yaml +++ b/packages/apidash_core/pubspec.yaml @@ -23,7 +23,6 @@ dependencies: postman: path: ../postman xml: ^6.3.0 - crypto: ^3.0.6 dev_dependencies: flutter_test: diff --git a/packages/better_networking/pubspec.yaml b/packages/better_networking/pubspec.yaml index 1f91a5124..6cd119599 100644 --- a/packages/better_networking/pubspec.yaml +++ b/packages/better_networking/pubspec.yaml @@ -25,6 +25,7 @@ dependencies: json_annotation: ^4.9.0 seed: ^0.0.3 xml: ^6.3.0 + crypto: ^3.0.6 dev_dependencies: flutter_test: From 6c5862cd855765657bca3cd3a1aaa927a98ae7b8 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Thu, 3 Jul 2025 12:12:18 +0530 Subject: [PATCH 30/70] refactor: move authModel to HttpRequestModel --- lib/models/request_model.dart | 1 - lib/models/request_model.freezed.dart | 42 +----------------- lib/models/request_model.g.dart | 5 --- lib/providers/collection_providers.dart | 8 ++-- .../request_pane/request_auth.dart | 13 +++--- .../request_pane/request_pane_graphql.dart | 2 +- .../request_pane/request_pane_rest.dart | 2 +- .../better_networking_example/pubspec.lock | 8 ++++ .../lib/models/http_request_model.dart | 2 + .../models/http_request_model.freezed.dart | 44 ++++++++++++++++++- .../lib/models/http_request_model.g.dart | 4 ++ 11 files changed, 71 insertions(+), 60 deletions(-) diff --git a/lib/models/request_model.dart b/lib/models/request_model.dart index a3eda0ba6..4d63c2adc 100644 --- a/lib/models/request_model.dart +++ b/lib/models/request_model.dart @@ -15,7 +15,6 @@ class RequestModel with _$RequestModel { @Default(APIType.rest) APIType apiType, @Default("") String name, @Default("") String description, - @Default(AuthModel(type: APIAuthType.none)) AuthModel? authModel, @JsonKey(includeToJson: false) @Default(0) requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, diff --git a/lib/models/request_model.freezed.dart b/lib/models/request_model.freezed.dart index eca69ebed..72f607bd5 100644 --- a/lib/models/request_model.freezed.dart +++ b/lib/models/request_model.freezed.dart @@ -24,7 +24,6 @@ mixin _$RequestModel { APIType get apiType => throw _privateConstructorUsedError; String get name => throw _privateConstructorUsedError; String get description => throw _privateConstructorUsedError; - AuthModel? get authModel => throw _privateConstructorUsedError; @JsonKey(includeToJson: false) dynamic get requestTabIndex => throw _privateConstructorUsedError; HttpRequestModel? get httpRequestModel => throw _privateConstructorUsedError; @@ -60,7 +59,6 @@ abstract class $RequestModelCopyWith<$Res> { APIType apiType, String name, String description, - AuthModel? authModel, @JsonKey(includeToJson: false) dynamic requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, @@ -71,7 +69,6 @@ abstract class $RequestModelCopyWith<$Res> { String? preRequestScript, String? postRequestScript}); - $AuthModelCopyWith<$Res>? get authModel; $HttpRequestModelCopyWith<$Res>? get httpRequestModel; $HttpResponseModelCopyWith<$Res>? get httpResponseModel; } @@ -95,7 +92,6 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> Object? apiType = null, Object? name = null, Object? description = null, - Object? authModel = freezed, Object? requestTabIndex = freezed, Object? httpRequestModel = freezed, Object? responseStatus = freezed, @@ -123,10 +119,6 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> ? _value.description : description // ignore: cast_nullable_to_non_nullable as String, - authModel: freezed == authModel - ? _value.authModel - : authModel // ignore: cast_nullable_to_non_nullable - as AuthModel?, requestTabIndex: freezed == requestTabIndex ? _value.requestTabIndex : requestTabIndex // ignore: cast_nullable_to_non_nullable @@ -166,20 +158,6 @@ class _$RequestModelCopyWithImpl<$Res, $Val extends RequestModel> ) as $Val); } - /// Create a copy of RequestModel - /// with the given fields replaced by the non-null parameter values. - @override - @pragma('vm:prefer-inline') - $AuthModelCopyWith<$Res>? get authModel { - if (_value.authModel == null) { - return null; - } - - return $AuthModelCopyWith<$Res>(_value.authModel!, (value) { - return _then(_value.copyWith(authModel: value) as $Val); - }); - } - /// Create a copy of RequestModel /// with the given fields replaced by the non-null parameter values. @override @@ -222,7 +200,6 @@ abstract class _$$RequestModelImplCopyWith<$Res> APIType apiType, String name, String description, - AuthModel? authModel, @JsonKey(includeToJson: false) dynamic requestTabIndex, HttpRequestModel? httpRequestModel, int? responseStatus, @@ -233,8 +210,6 @@ abstract class _$$RequestModelImplCopyWith<$Res> String? preRequestScript, String? postRequestScript}); - @override - $AuthModelCopyWith<$Res>? get authModel; @override $HttpRequestModelCopyWith<$Res>? get httpRequestModel; @override @@ -258,7 +233,6 @@ class __$$RequestModelImplCopyWithImpl<$Res> Object? apiType = null, Object? name = null, Object? description = null, - Object? authModel = freezed, Object? requestTabIndex = freezed, Object? httpRequestModel = freezed, Object? responseStatus = freezed, @@ -286,10 +260,6 @@ class __$$RequestModelImplCopyWithImpl<$Res> ? _value.description : description // ignore: cast_nullable_to_non_nullable as String, - authModel: freezed == authModel - ? _value.authModel - : authModel // ignore: cast_nullable_to_non_nullable - as AuthModel?, requestTabIndex: freezed == requestTabIndex ? _value.requestTabIndex! : requestTabIndex, @@ -338,7 +308,6 @@ class _$RequestModelImpl implements _RequestModel { this.apiType = APIType.rest, this.name = "", this.description = "", - this.authModel = const AuthModel(type: APIAuthType.none), @JsonKey(includeToJson: false) this.requestTabIndex = 0, this.httpRequestModel, this.responseStatus, @@ -364,9 +333,6 @@ class _$RequestModelImpl implements _RequestModel { @JsonKey() final String description; @override - @JsonKey() - final AuthModel? authModel; - @override @JsonKey(includeToJson: false) final dynamic requestTabIndex; @override @@ -390,7 +356,7 @@ class _$RequestModelImpl implements _RequestModel { @override String toString() { - return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, authModel: $authModel, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime, preRequestScript: $preRequestScript, postRequestScript: $postRequestScript)'; + return 'RequestModel(id: $id, apiType: $apiType, name: $name, description: $description, requestTabIndex: $requestTabIndex, httpRequestModel: $httpRequestModel, responseStatus: $responseStatus, message: $message, httpResponseModel: $httpResponseModel, isWorking: $isWorking, sendingTime: $sendingTime, preRequestScript: $preRequestScript, postRequestScript: $postRequestScript)'; } @override @@ -403,8 +369,6 @@ class _$RequestModelImpl implements _RequestModel { (identical(other.name, name) || other.name == name) && (identical(other.description, description) || other.description == description) && - (identical(other.authModel, authModel) || - other.authModel == authModel) && const DeepCollectionEquality() .equals(other.requestTabIndex, requestTabIndex) && (identical(other.httpRequestModel, httpRequestModel) || @@ -432,7 +396,6 @@ class _$RequestModelImpl implements _RequestModel { apiType, name, description, - authModel, const DeepCollectionEquality().hash(requestTabIndex), httpRequestModel, responseStatus, @@ -465,7 +428,6 @@ abstract class _RequestModel implements RequestModel { final APIType apiType, final String name, final String description, - final AuthModel? authModel, @JsonKey(includeToJson: false) final dynamic requestTabIndex, final HttpRequestModel? httpRequestModel, final int? responseStatus, @@ -488,8 +450,6 @@ abstract class _RequestModel implements RequestModel { @override String get description; @override - AuthModel? get authModel; - @override @JsonKey(includeToJson: false) dynamic get requestTabIndex; @override diff --git a/lib/models/request_model.g.dart b/lib/models/request_model.g.dart index 6c6337262..d4f6ec206 100644 --- a/lib/models/request_model.g.dart +++ b/lib/models/request_model.g.dart @@ -12,10 +12,6 @@ _$RequestModelImpl _$$RequestModelImplFromJson(Map json) => _$RequestModelImpl( APIType.rest, name: json['name'] as String? ?? "", description: json['description'] as String? ?? "", - authModel: json['authModel'] == null - ? const AuthModel(type: APIAuthType.none) - : AuthModel.fromJson( - Map.from(json['authModel'] as Map)), requestTabIndex: json['requestTabIndex'] ?? 0, httpRequestModel: json['httpRequestModel'] == null ? null @@ -41,7 +37,6 @@ Map _$$RequestModelImplToJson(_$RequestModelImpl instance) => 'apiType': _$APITypeEnumMap[instance.apiType]!, 'name': instance.name, 'description': instance.description, - 'authModel': instance.authModel?.toJson(), 'httpRequestModel': instance.httpRequestModel?.toJson(), 'responseStatus': instance.responseStatus, 'message': instance.message, diff --git a/lib/providers/collection_providers.dart b/lib/providers/collection_providers.dart index 468e59e70..094346578 100644 --- a/lib/providers/collection_providers.dart +++ b/lib/providers/collection_providers.dart @@ -207,7 +207,7 @@ class CollectionStateNotifier String? id, HTTPVerb? method, APIType? apiType, - AuthModel? authData, + AuthModel? authModel, String? url, String? name, String? description, @@ -235,7 +235,6 @@ class CollectionStateNotifier var currentHttpRequestModel = currentModel.httpRequestModel; final newModel = currentModel.copyWith( apiType: apiType ?? currentModel.apiType, - authModel: authData ?? currentModel.authModel, name: name ?? currentModel.name, description: description ?? currentModel.description, requestTabIndex: requestTabIndex ?? currentModel.requestTabIndex, @@ -244,6 +243,7 @@ class CollectionStateNotifier url: url ?? currentHttpRequestModel.url, headers: headers ?? currentHttpRequestModel.headers, params: params ?? currentHttpRequestModel.params, + authModel: authModel ?? currentHttpRequestModel.authModel, isHeaderEnabledList: isHeaderEnabledList ?? currentHttpRequestModel.isHeaderEnabledList, isParamEnabledList: @@ -316,7 +316,7 @@ class CollectionStateNotifier var responseRec = await sendHttpRequest( requestId, apiType, - requestModel.authModel, + requestModel.httpRequestModel?.authModel, substitutedHttpRequestModel, defaultUriScheme: defaultUriScheme, noSSL: noSSL, @@ -358,7 +358,7 @@ class CollectionStateNotifier httpResponseModel: httpResponseModel, preRequestScript: requestModel.preRequestScript, postRequestScript: requestModel.postRequestScript, - authModel: requestModel.authModel, + authModel: requestModel.httpRequestModel?.authModel, ); ref.read(historyMetaStateNotifier.notifier).addHistoryRequest(model); diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index 1e54d46f9..dd5cc1c7f 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -33,10 +33,10 @@ class EditAuthType extends ConsumerWidget { } currentAuthType = ref.watch( - selectedRequestModelProvider - .select((request) => request?.authModel?.type ?? APIAuthType.none), + selectedRequestModelProvider.select((request) => + request?.httpRequestModel?.authModel?.type ?? APIAuthType.none), ); - currentAuthData = selectedRequest.authModel; + currentAuthData = selectedRequest.httpRequestModel?.authModel; } return SingleChildScrollView( child: Padding( @@ -93,7 +93,8 @@ class EditAuthType extends ConsumerWidget { ref.read(selectedRequestModelProvider); if (newType != null) { ref.read(collectionStateNotifierProvider.notifier).update( - authData: selectedRequest?.authModel + authModel: selectedRequest + ?.httpRequestModel?.authModel ?.copyWith(type: newType) ?? AuthModel(type: newType), ); @@ -117,11 +118,11 @@ class EditAuthType extends ConsumerWidget { void updateAuth(AuthModel? model) { if (model == null) { ref.read(collectionStateNotifierProvider.notifier).update( - authData: AuthModel(type: APIAuthType.none), + authModel: AuthModel(type: APIAuthType.none), ); } ref.read(collectionStateNotifierProvider.notifier).update( - authData: model, + authModel: model, ); } diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart index f9e18078a..91be2b7b7 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart @@ -26,7 +26,7 @@ class EditGraphQLRequestPane extends ConsumerWidget { false; final hasAuth = ref.watch(selectedRequestModelProvider - .select((value) => value?.authModel?.type != APIAuthType.none)); + .select((value) => value?.httpRequestModel?.authModel?.type != APIAuthType.none)); final scriptsLength = ref.watch(selectedHistoryRequestModelProvider .select((value) => value?.preRequestScript?.length)) ?? diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart index 68bf526fb..aef0e67a1 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_rest.dart @@ -37,7 +37,7 @@ class EditRestRequestPane extends ConsumerWidget { 0; final hasAuth = ref.watch(selectedRequestModelProvider.select((value) => - value?.authModel?.type != APIAuthType.none)); + value?.httpRequestModel?.authModel?.type != APIAuthType.none)); return RequestPane( selectedId: selectedId, diff --git a/packages/better_networking/better_networking_example/pubspec.lock b/packages/better_networking/better_networking_example/pubspec.lock index 366394abb..2e6737af4 100644 --- a/packages/better_networking/better_networking_example/pubspec.lock +++ b/packages/better_networking/better_networking_example/pubspec.lock @@ -48,6 +48,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.19.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" + source: hosted + version: "3.0.6" cupertino_icons: dependency: "direct main" description: diff --git a/packages/better_networking/lib/models/http_request_model.dart b/packages/better_networking/lib/models/http_request_model.dart index 2d915cfa6..7fbaa6481 100644 --- a/packages/better_networking/lib/models/http_request_model.dart +++ b/packages/better_networking/lib/models/http_request_model.dart @@ -5,6 +5,7 @@ import '../extensions/extensions.dart'; import '../utils/utils.dart' show rowsToFormDataMapList, rowsToMap, getEnabledRows; import '../consts.dart'; +import 'auth/api_auth_model.dart'; part 'http_request_model.freezed.dart'; part 'http_request_model.g.dart'; @@ -19,6 +20,7 @@ class HttpRequestModel with _$HttpRequestModel { @Default("") String url, List? headers, List? params, + @Default(AuthModel(type: APIAuthType.none)) AuthModel? authModel, List? isHeaderEnabledList, List? isParamEnabledList, @Default(ContentType.json) ContentType bodyContentType, diff --git a/packages/better_networking/lib/models/http_request_model.freezed.dart b/packages/better_networking/lib/models/http_request_model.freezed.dart index 864ae7e0b..871d6012c 100644 --- a/packages/better_networking/lib/models/http_request_model.freezed.dart +++ b/packages/better_networking/lib/models/http_request_model.freezed.dart @@ -25,6 +25,7 @@ mixin _$HttpRequestModel { String get url => throw _privateConstructorUsedError; List? get headers => throw _privateConstructorUsedError; List? get params => throw _privateConstructorUsedError; + AuthModel? get authModel => throw _privateConstructorUsedError; List? get isHeaderEnabledList => throw _privateConstructorUsedError; List? get isParamEnabledList => throw _privateConstructorUsedError; ContentType get bodyContentType => throw _privateConstructorUsedError; @@ -54,6 +55,7 @@ abstract class $HttpRequestModelCopyWith<$Res> { String url, List? headers, List? params, + AuthModel? authModel, List? isHeaderEnabledList, List? isParamEnabledList, ContentType bodyContentType, @@ -61,6 +63,8 @@ abstract class $HttpRequestModelCopyWith<$Res> { String? query, List? formData, }); + + $AuthModelCopyWith<$Res>? get authModel; } /// @nodoc @@ -82,6 +86,7 @@ class _$HttpRequestModelCopyWithImpl<$Res, $Val extends HttpRequestModel> Object? url = null, Object? headers = freezed, Object? params = freezed, + Object? authModel = freezed, Object? isHeaderEnabledList = freezed, Object? isParamEnabledList = freezed, Object? bodyContentType = null, @@ -107,6 +112,10 @@ class _$HttpRequestModelCopyWithImpl<$Res, $Val extends HttpRequestModel> ? _value.params : params // ignore: cast_nullable_to_non_nullable as List?, + authModel: freezed == authModel + ? _value.authModel + : authModel // ignore: cast_nullable_to_non_nullable + as AuthModel?, isHeaderEnabledList: freezed == isHeaderEnabledList ? _value.isHeaderEnabledList : isHeaderEnabledList // ignore: cast_nullable_to_non_nullable @@ -135,6 +144,20 @@ class _$HttpRequestModelCopyWithImpl<$Res, $Val extends HttpRequestModel> as $Val, ); } + + /// Create a copy of HttpRequestModel + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $AuthModelCopyWith<$Res>? get authModel { + if (_value.authModel == null) { + return null; + } + + return $AuthModelCopyWith<$Res>(_value.authModel!, (value) { + return _then(_value.copyWith(authModel: value) as $Val); + }); + } } /// @nodoc @@ -151,6 +174,7 @@ abstract class _$$HttpRequestModelImplCopyWith<$Res> String url, List? headers, List? params, + AuthModel? authModel, List? isHeaderEnabledList, List? isParamEnabledList, ContentType bodyContentType, @@ -158,6 +182,9 @@ abstract class _$$HttpRequestModelImplCopyWith<$Res> String? query, List? formData, }); + + @override + $AuthModelCopyWith<$Res>? get authModel; } /// @nodoc @@ -178,6 +205,7 @@ class __$$HttpRequestModelImplCopyWithImpl<$Res> Object? url = null, Object? headers = freezed, Object? params = freezed, + Object? authModel = freezed, Object? isHeaderEnabledList = freezed, Object? isParamEnabledList = freezed, Object? bodyContentType = null, @@ -203,6 +231,10 @@ class __$$HttpRequestModelImplCopyWithImpl<$Res> ? _value._params : params // ignore: cast_nullable_to_non_nullable as List?, + authModel: freezed == authModel + ? _value.authModel + : authModel // ignore: cast_nullable_to_non_nullable + as AuthModel?, isHeaderEnabledList: freezed == isHeaderEnabledList ? _value._isHeaderEnabledList : isHeaderEnabledList // ignore: cast_nullable_to_non_nullable @@ -241,6 +273,7 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { this.url = "", final List? headers, final List? params, + this.authModel = const AuthModel(type: APIAuthType.none), final List? isHeaderEnabledList, final List? isParamEnabledList, this.bodyContentType = ContentType.json, @@ -283,6 +316,9 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { return EqualUnmodifiableListView(value); } + @override + @JsonKey() + final AuthModel? authModel; final List? _isHeaderEnabledList; @override List? get isHeaderEnabledList { @@ -324,7 +360,7 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { @override String toString() { - return 'HttpRequestModel(method: $method, url: $url, headers: $headers, params: $params, isHeaderEnabledList: $isHeaderEnabledList, isParamEnabledList: $isParamEnabledList, bodyContentType: $bodyContentType, body: $body, query: $query, formData: $formData)'; + return 'HttpRequestModel(method: $method, url: $url, headers: $headers, params: $params, authModel: $authModel, isHeaderEnabledList: $isHeaderEnabledList, isParamEnabledList: $isParamEnabledList, bodyContentType: $bodyContentType, body: $body, query: $query, formData: $formData)'; } @override @@ -336,6 +372,8 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { (identical(other.url, url) || other.url == url) && const DeepCollectionEquality().equals(other._headers, _headers) && const DeepCollectionEquality().equals(other._params, _params) && + (identical(other.authModel, authModel) || + other.authModel == authModel) && const DeepCollectionEquality().equals( other._isHeaderEnabledList, _isHeaderEnabledList, @@ -359,6 +397,7 @@ class _$HttpRequestModelImpl extends _HttpRequestModel { url, const DeepCollectionEquality().hash(_headers), const DeepCollectionEquality().hash(_params), + authModel, const DeepCollectionEquality().hash(_isHeaderEnabledList), const DeepCollectionEquality().hash(_isParamEnabledList), bodyContentType, @@ -390,6 +429,7 @@ abstract class _HttpRequestModel extends HttpRequestModel { final String url, final List? headers, final List? params, + final AuthModel? authModel, final List? isHeaderEnabledList, final List? isParamEnabledList, final ContentType bodyContentType, @@ -411,6 +451,8 @@ abstract class _HttpRequestModel extends HttpRequestModel { @override List? get params; @override + AuthModel? get authModel; + @override List? get isHeaderEnabledList; @override List? get isParamEnabledList; diff --git a/packages/better_networking/lib/models/http_request_model.g.dart b/packages/better_networking/lib/models/http_request_model.g.dart index bd024acc3..48e7a17aa 100644 --- a/packages/better_networking/lib/models/http_request_model.g.dart +++ b/packages/better_networking/lib/models/http_request_model.g.dart @@ -18,6 +18,9 @@ _$HttpRequestModelImpl _$$HttpRequestModelImplFromJson( params: (json['params'] as List?) ?.map((e) => NameValueModel.fromJson(Map.from(e as Map))) .toList(), + authModel: json['authModel'] == null + ? const AuthModel(type: APIAuthType.none) + : AuthModel.fromJson(Map.from(json['authModel'] as Map)), isHeaderEnabledList: (json['isHeaderEnabledList'] as List?) ?.map((e) => e as bool) .toList(), @@ -41,6 +44,7 @@ Map _$$HttpRequestModelImplToJson( 'url': instance.url, 'headers': instance.headers?.map((e) => e.toJson()).toList(), 'params': instance.params?.map((e) => e.toJson()).toList(), + 'authModel': instance.authModel?.toJson(), 'isHeaderEnabledList': instance.isHeaderEnabledList, 'isParamEnabledList': instance.isParamEnabledList, 'bodyContentType': _$ContentTypeEnumMap[instance.bodyContentType]!, From 92af4fba77542ce9d22355c580aefc51744e2f80 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Thu, 3 Jul 2025 19:24:56 +0530 Subject: [PATCH 31/70] feat: add digest authentication --- .../auth/digest_auth_fields.dart | 139 ++++++++ .../request_pane/request_auth.dart | 86 +++-- .../better_networking_example/pubspec.lock | 8 + packages/better_networking/lib/consts.dart | 3 +- .../lib/models/auth/api_auth_model.dart | 7 +- .../models/auth/api_auth_model.freezed.dart | 43 ++- .../lib/models/auth/api_auth_model.g.dart | 6 + .../lib/models/auth/auth_digest_model.dart | 20 ++ .../auth/auth_digest_model.freezed.dart | 314 ++++++++++++++++++ .../lib/models/auth/auth_digest_model.g.dart | 31 ++ .../better_networking/lib/models/models.dart | 1 + .../lib/services/http_service.dart | 12 +- .../lib/utils/auth/digest_auth_utils.dart | 237 +++++++++++++ .../lib/utils/auth/handle_auth.dart | 175 ++++++++++ .../jwt_auth_utils.dart} | 0 .../lib/utils/handle_auth.dart | 101 ------ .../better_networking/lib/utils/utils.dart | 2 +- packages/better_networking/pubspec.yaml | 1 + 18 files changed, 1026 insertions(+), 160 deletions(-) create mode 100644 lib/screens/common_widgets/auth/digest_auth_fields.dart create mode 100644 packages/better_networking/lib/models/auth/auth_digest_model.dart create mode 100644 packages/better_networking/lib/models/auth/auth_digest_model.freezed.dart create mode 100644 packages/better_networking/lib/models/auth/auth_digest_model.g.dart create mode 100644 packages/better_networking/lib/utils/auth/digest_auth_utils.dart create mode 100644 packages/better_networking/lib/utils/auth/handle_auth.dart rename packages/better_networking/lib/utils/{auth_utils.dart => auth/jwt_auth_utils.dart} (100%) delete mode 100644 packages/better_networking/lib/utils/handle_auth.dart diff --git a/lib/screens/common_widgets/auth/digest_auth_fields.dart b/lib/screens/common_widgets/auth/digest_auth_fields.dart new file mode 100644 index 000000000..7fc7850b0 --- /dev/null +++ b/lib/screens/common_widgets/auth/digest_auth_fields.dart @@ -0,0 +1,139 @@ +import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash_design_system/widgets/widgets.dart'; +import 'package:flutter/material.dart'; + +class DigestAuthFields extends StatefulWidget { + final AuthModel? authData; + final bool readOnly; + final Function(AuthModel?) updateAuth; + + const DigestAuthFields({ + super.key, + required this.authData, + required this.updateAuth, + this.readOnly = false, + }); + + @override + State createState() => _DigestAuthFieldsState(); +} + +class _DigestAuthFieldsState extends State { + late TextEditingController _usernameController; + late TextEditingController _passwordController; + late TextEditingController _realmController; + late TextEditingController _nonceController; + late String _algorithmController; + late TextEditingController _qopController; + late TextEditingController _opaqueController; + + @override + void initState() { + super.initState(); + final digest = widget.authData?.digest; + _usernameController = TextEditingController(text: digest?.username ?? ''); + _passwordController = TextEditingController(text: digest?.password ?? ''); + _realmController = TextEditingController(text: digest?.realm ?? ''); + _nonceController = TextEditingController(text: digest?.nonce ?? ''); + _algorithmController = digest?.algorithm ?? 'MD5'; + _qopController = TextEditingController(text: digest?.qop ?? 'auth'); + _opaqueController = TextEditingController(text: digest?.opaque ?? ''); + } + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AuthTextField( + readOnly: widget.readOnly, + controller: _usernameController, + hintText: "Username", + onChanged: (_) => _updateDigestAuth(), + ), + const SizedBox(height: 16), + AuthTextField( + readOnly: widget.readOnly, + controller: _passwordController, + hintText: "Password", + isObscureText: true, + onChanged: (_) => _updateDigestAuth(), + ), + const SizedBox(height: 16), + AuthTextField( + readOnly: widget.readOnly, + controller: _realmController, + hintText: "Realm", + onChanged: (_) => _updateDigestAuth(), + ), + const SizedBox(height: 16), + AuthTextField( + readOnly: widget.readOnly, + controller: _nonceController, + hintText: "Nonce", + onChanged: (_) => _updateDigestAuth(), + ), + const SizedBox(height: 16), + Text( + "Algorithm", + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: 14, + ), + ), + SizedBox(height: 4), + ADPopupMenu( + value: _algorithmController.trim(), + values: const [ + ('MD5', 'MD5'), + ('MD5-sess', 'MD5-sess'), + ('SHA-256', 'SHA-256'), + ('SHA-256-sess', 'SHA-256-sess'), + ], + tooltip: "this algorithm will be used to produce the digest", + isOutlined: true, + onChanged: (String? newLocation) { + if (newLocation != null) { + setState(() { + _algorithmController = newLocation; + }); + _updateDigestAuth(); + } + }, + ), + const SizedBox(height: 16), + AuthTextField( + readOnly: widget.readOnly, + controller: _qopController, + hintText: "QOP (e.g. auth)", + onChanged: (_) => _updateDigestAuth(), + ), + const SizedBox(height: 16), + AuthTextField( + readOnly: widget.readOnly, + controller: _opaqueController, + hintText: "Opaque", + onChanged: (_) => _updateDigestAuth(), + ), + ], + ); + } + + void _updateDigestAuth() { + widget.updateAuth( + widget.authData?.copyWith( + type: APIAuthType.digest, + digest: AuthDigestModel( + username: _usernameController.text.trim(), + password: _passwordController.text.trim(), + realm: _realmController.text.trim(), + nonce: _nonceController.text.trim(), + algorithm: _algorithmController.trim(), + qop: _qopController.text.trim(), + opaque: _opaqueController.text.trim(), + ), + ), + ); + } +} diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index dd5cc1c7f..971d98dd0 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -1,6 +1,7 @@ import 'package:apidash/screens/common_widgets/auth/api_key_auth_fields.dart'; import 'package:apidash/screens/common_widgets/auth/basic_auth_fields.dart'; import 'package:apidash/screens/common_widgets/auth/bearer_auth_fields.dart'; +import 'package:apidash/screens/common_widgets/auth/digest_auth_fields.dart'; import 'package:apidash/screens/common_widgets/auth/jwt_auth_fields.dart'; import 'package:apidash_design_system/widgets/popup_menu.dart'; import 'package:flutter/material.dart'; @@ -53,54 +54,37 @@ class EditAuthType extends ConsumerWidget { SizedBox( height: 8, ), - if (readOnly) - Container( - padding: - const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerLowest, - borderRadius: BorderRadius.circular(8), - border: Border.all( - color: - Theme.of(context).colorScheme.outline.withOpacity(0.3), - ), - ), - child: Text( - currentAuthType.name.toUpperCase(), - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - fontWeight: FontWeight.w500, - color: Theme.of(context).colorScheme.primary, - ), - ), - ) - else - ADPopupMenu( - value: currentAuthType.name.capitalize(), - values: const [ - (APIAuthType.none, 'None'), - (APIAuthType.basic, 'Basic'), - (APIAuthType.apiKey, 'API Key'), - (APIAuthType.bearer, 'Bearer'), - (APIAuthType.jwt, 'JWT'), - (APIAuthType.digest, 'Digest'), - (APIAuthType.oauth1, 'OAuth 1.0'), - (APIAuthType.oauth2, 'OAuth 2.0'), - ], - tooltip: "Select Authentication Type", - isOutlined: true, - onChanged: (APIAuthType? newType) { - final selectedRequest = - ref.read(selectedRequestModelProvider); - if (newType != null) { - ref.read(collectionStateNotifierProvider.notifier).update( - authModel: selectedRequest - ?.httpRequestModel?.authModel - ?.copyWith(type: newType) ?? - AuthModel(type: newType), - ); - } - }, - ), + ADPopupMenu( + value: currentAuthType.name.capitalize(), + values: const [ + (APIAuthType.none, 'None'), + (APIAuthType.basic, 'Basic'), + (APIAuthType.apiKey, 'API Key'), + (APIAuthType.bearer, 'Bearer'), + (APIAuthType.jwt, 'JWT'), + (APIAuthType.digest, 'Digest'), + (APIAuthType.oauth1, 'OAuth 1.0'), + (APIAuthType.oauth2, 'OAuth 2.0'), + ], + tooltip: "Select Authentication Type", + isOutlined: true, + onChanged: readOnly + ? null + : (APIAuthType? newType) { + final selectedRequest = + ref.read(selectedRequestModelProvider); + if (newType != null) { + ref + .read(collectionStateNotifierProvider.notifier) + .update( + authModel: selectedRequest + ?.httpRequestModel?.authModel + ?.copyWith(type: newType) ?? + AuthModel(type: newType), + ); + } + }, + ), const SizedBox(height: 48), _buildAuthFields(context, ref, currentAuthData), ], @@ -151,6 +135,12 @@ class EditAuthType extends ConsumerWidget { authData: authData, updateAuth: updateAuth, ); + case APIAuthType.digest: + return DigestAuthFields( + readOnly: readOnly, + authData: authData, + updateAuth: updateAuth, + ); case APIAuthType.none: return Text(readOnly ? "No authentication was used for this request." diff --git a/packages/better_networking/better_networking_example/pubspec.lock b/packages/better_networking/better_networking_example/pubspec.lock index 2e6737af4..908096b79 100644 --- a/packages/better_networking/better_networking_example/pubspec.lock +++ b/packages/better_networking/better_networking_example/pubspec.lock @@ -48,6 +48,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.19.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" crypto: dependency: transitive description: diff --git a/packages/better_networking/lib/consts.dart b/packages/better_networking/lib/consts.dart index 493561adb..23038c7ee 100644 --- a/packages/better_networking/lib/consts.dart +++ b/packages/better_networking/lib/consts.dart @@ -9,7 +9,7 @@ enum APIType { final String abbr; } -enum APIAuthType { none, basic, apiKey, bearer, jwt, digest, oauth1, oauth2} +enum APIAuthType { none, basic, apiKey, bearer, jwt, digest, oauth1, oauth2 } enum HTTPVerb { get("GET"), @@ -98,4 +98,5 @@ const LineSplitter kSplitter = LineSplitter(); const kCodeCharsPerLineLimit = 200; const kHeaderContentType = "Content-Type"; +const kHeaderWwwAuthenticate = 'www-authenticate'; const kMsgRequestCancelled = 'Request Cancelled'; diff --git a/packages/better_networking/lib/models/auth/api_auth_model.dart b/packages/better_networking/lib/models/auth/api_auth_model.dart index c9b19607c..824ab543a 100644 --- a/packages/better_networking/lib/models/auth/api_auth_model.dart +++ b/packages/better_networking/lib/models/auth/api_auth_model.dart @@ -4,22 +4,21 @@ import 'auth_api_key_model.dart'; import 'auth_basic_model.dart'; import 'auth_bearer_model.dart'; import 'auth_jwt_model.dart'; +import 'auth_digest_model.dart'; part 'api_auth_model.g.dart'; part 'api_auth_model.freezed.dart'; @freezed class AuthModel with _$AuthModel { - @JsonSerializable( - explicitToJson: true, - anyMap: true, - ) + @JsonSerializable(explicitToJson: true, anyMap: true) const factory AuthModel({ required APIAuthType type, AuthApiKeyModel? apikey, AuthBearerModel? bearer, AuthBasicAuthModel? basic, AuthJwtModel? jwt, + AuthDigestModel? digest, }) = _AuthModel; factory AuthModel.fromJson(Map json) => diff --git a/packages/better_networking/lib/models/auth/api_auth_model.freezed.dart b/packages/better_networking/lib/models/auth/api_auth_model.freezed.dart index 44fa1cb2b..4e592fcc8 100644 --- a/packages/better_networking/lib/models/auth/api_auth_model.freezed.dart +++ b/packages/better_networking/lib/models/auth/api_auth_model.freezed.dart @@ -26,6 +26,7 @@ mixin _$AuthModel { AuthBearerModel? get bearer => throw _privateConstructorUsedError; AuthBasicAuthModel? get basic => throw _privateConstructorUsedError; AuthJwtModel? get jwt => throw _privateConstructorUsedError; + AuthDigestModel? get digest => throw _privateConstructorUsedError; /// Serializes this AuthModel to a JSON map. Map toJson() => throw _privateConstructorUsedError; @@ -48,12 +49,14 @@ abstract class $AuthModelCopyWith<$Res> { AuthBearerModel? bearer, AuthBasicAuthModel? basic, AuthJwtModel? jwt, + AuthDigestModel? digest, }); $AuthApiKeyModelCopyWith<$Res>? get apikey; $AuthBearerModelCopyWith<$Res>? get bearer; $AuthBasicAuthModelCopyWith<$Res>? get basic; $AuthJwtModelCopyWith<$Res>? get jwt; + $AuthDigestModelCopyWith<$Res>? get digest; } /// @nodoc @@ -76,6 +79,7 @@ class _$AuthModelCopyWithImpl<$Res, $Val extends AuthModel> Object? bearer = freezed, Object? basic = freezed, Object? jwt = freezed, + Object? digest = freezed, }) { return _then( _value.copyWith( @@ -99,6 +103,10 @@ class _$AuthModelCopyWithImpl<$Res, $Val extends AuthModel> ? _value.jwt : jwt // ignore: cast_nullable_to_non_nullable as AuthJwtModel?, + digest: freezed == digest + ? _value.digest + : digest // ignore: cast_nullable_to_non_nullable + as AuthDigestModel?, ) as $Val, ); @@ -159,6 +167,20 @@ class _$AuthModelCopyWithImpl<$Res, $Val extends AuthModel> return _then(_value.copyWith(jwt: value) as $Val); }); } + + /// Create a copy of AuthModel + /// with the given fields replaced by the non-null parameter values. + @override + @pragma('vm:prefer-inline') + $AuthDigestModelCopyWith<$Res>? get digest { + if (_value.digest == null) { + return null; + } + + return $AuthDigestModelCopyWith<$Res>(_value.digest!, (value) { + return _then(_value.copyWith(digest: value) as $Val); + }); + } } /// @nodoc @@ -176,6 +198,7 @@ abstract class _$$AuthModelImplCopyWith<$Res> AuthBearerModel? bearer, AuthBasicAuthModel? basic, AuthJwtModel? jwt, + AuthDigestModel? digest, }); @override @@ -186,6 +209,8 @@ abstract class _$$AuthModelImplCopyWith<$Res> $AuthBasicAuthModelCopyWith<$Res>? get basic; @override $AuthJwtModelCopyWith<$Res>? get jwt; + @override + $AuthDigestModelCopyWith<$Res>? get digest; } /// @nodoc @@ -207,6 +232,7 @@ class __$$AuthModelImplCopyWithImpl<$Res> Object? bearer = freezed, Object? basic = freezed, Object? jwt = freezed, + Object? digest = freezed, }) { return _then( _$AuthModelImpl( @@ -230,6 +256,10 @@ class __$$AuthModelImplCopyWithImpl<$Res> ? _value.jwt : jwt // ignore: cast_nullable_to_non_nullable as AuthJwtModel?, + digest: freezed == digest + ? _value.digest + : digest // ignore: cast_nullable_to_non_nullable + as AuthDigestModel?, ), ); } @@ -245,6 +275,7 @@ class _$AuthModelImpl implements _AuthModel { this.bearer, this.basic, this.jwt, + this.digest, }); factory _$AuthModelImpl.fromJson(Map json) => @@ -260,10 +291,12 @@ class _$AuthModelImpl implements _AuthModel { final AuthBasicAuthModel? basic; @override final AuthJwtModel? jwt; + @override + final AuthDigestModel? digest; @override String toString() { - return 'AuthModel(type: $type, apikey: $apikey, bearer: $bearer, basic: $basic, jwt: $jwt)'; + return 'AuthModel(type: $type, apikey: $apikey, bearer: $bearer, basic: $basic, jwt: $jwt, digest: $digest)'; } @override @@ -275,13 +308,14 @@ class _$AuthModelImpl implements _AuthModel { (identical(other.apikey, apikey) || other.apikey == apikey) && (identical(other.bearer, bearer) || other.bearer == bearer) && (identical(other.basic, basic) || other.basic == basic) && - (identical(other.jwt, jwt) || other.jwt == jwt)); + (identical(other.jwt, jwt) || other.jwt == jwt) && + (identical(other.digest, digest) || other.digest == digest)); } @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => - Object.hash(runtimeType, type, apikey, bearer, basic, jwt); + Object.hash(runtimeType, type, apikey, bearer, basic, jwt, digest); /// Create a copy of AuthModel /// with the given fields replaced by the non-null parameter values. @@ -304,6 +338,7 @@ abstract class _AuthModel implements AuthModel { final AuthBearerModel? bearer, final AuthBasicAuthModel? basic, final AuthJwtModel? jwt, + final AuthDigestModel? digest, }) = _$AuthModelImpl; factory _AuthModel.fromJson(Map json) = @@ -319,6 +354,8 @@ abstract class _AuthModel implements AuthModel { AuthBasicAuthModel? get basic; @override AuthJwtModel? get jwt; + @override + AuthDigestModel? get digest; /// Create a copy of AuthModel /// with the given fields replaced by the non-null parameter values. diff --git a/packages/better_networking/lib/models/auth/api_auth_model.g.dart b/packages/better_networking/lib/models/auth/api_auth_model.g.dart index fd8673246..7b6ac4182 100644 --- a/packages/better_networking/lib/models/auth/api_auth_model.g.dart +++ b/packages/better_networking/lib/models/auth/api_auth_model.g.dart @@ -26,6 +26,11 @@ _$AuthModelImpl _$$AuthModelImplFromJson(Map json) => _$AuthModelImpl( jwt: json['jwt'] == null ? null : AuthJwtModel.fromJson(Map.from(json['jwt'] as Map)), + digest: json['digest'] == null + ? null + : AuthDigestModel.fromJson( + Map.from(json['digest'] as Map), + ), ); Map _$$AuthModelImplToJson(_$AuthModelImpl instance) => @@ -35,6 +40,7 @@ Map _$$AuthModelImplToJson(_$AuthModelImpl instance) => 'bearer': instance.bearer?.toJson(), 'basic': instance.basic?.toJson(), 'jwt': instance.jwt?.toJson(), + 'digest': instance.digest?.toJson(), }; const _$APIAuthTypeEnumMap = { diff --git a/packages/better_networking/lib/models/auth/auth_digest_model.dart b/packages/better_networking/lib/models/auth/auth_digest_model.dart new file mode 100644 index 000000000..2c2bc3ac6 --- /dev/null +++ b/packages/better_networking/lib/models/auth/auth_digest_model.dart @@ -0,0 +1,20 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'auth_digest_model.g.dart'; +part 'auth_digest_model.freezed.dart'; + +@freezed +class AuthDigestModel with _$AuthDigestModel { + const factory AuthDigestModel({ + required String username, + required String password, + required String realm, + required String nonce, + required String algorithm, + required String qop, + required String opaque, + }) = _AuthDigestModel; + + factory AuthDigestModel.fromJson(Map json) => + _$AuthDigestModelFromJson(json); +} diff --git a/packages/better_networking/lib/models/auth/auth_digest_model.freezed.dart b/packages/better_networking/lib/models/auth/auth_digest_model.freezed.dart new file mode 100644 index 000000000..2dd2f05ff --- /dev/null +++ b/packages/better_networking/lib/models/auth/auth_digest_model.freezed.dart @@ -0,0 +1,314 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'auth_digest_model.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models', +); + +AuthDigestModel _$AuthDigestModelFromJson(Map json) { + return _AuthDigestModel.fromJson(json); +} + +/// @nodoc +mixin _$AuthDigestModel { + String get username => throw _privateConstructorUsedError; + String get password => throw _privateConstructorUsedError; + String get realm => throw _privateConstructorUsedError; + String get nonce => throw _privateConstructorUsedError; + String get algorithm => throw _privateConstructorUsedError; + String get qop => throw _privateConstructorUsedError; + String get opaque => throw _privateConstructorUsedError; + + /// Serializes this AuthDigestModel to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of AuthDigestModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $AuthDigestModelCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $AuthDigestModelCopyWith<$Res> { + factory $AuthDigestModelCopyWith( + AuthDigestModel value, + $Res Function(AuthDigestModel) then, + ) = _$AuthDigestModelCopyWithImpl<$Res, AuthDigestModel>; + @useResult + $Res call({ + String username, + String password, + String realm, + String nonce, + String algorithm, + String qop, + String opaque, + }); +} + +/// @nodoc +class _$AuthDigestModelCopyWithImpl<$Res, $Val extends AuthDigestModel> + implements $AuthDigestModelCopyWith<$Res> { + _$AuthDigestModelCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of AuthDigestModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? username = null, + Object? password = null, + Object? realm = null, + Object? nonce = null, + Object? algorithm = null, + Object? qop = null, + Object? opaque = null, + }) { + return _then( + _value.copyWith( + username: null == username + ? _value.username + : username // ignore: cast_nullable_to_non_nullable + as String, + password: null == password + ? _value.password + : password // ignore: cast_nullable_to_non_nullable + as String, + realm: null == realm + ? _value.realm + : realm // ignore: cast_nullable_to_non_nullable + as String, + nonce: null == nonce + ? _value.nonce + : nonce // ignore: cast_nullable_to_non_nullable + as String, + algorithm: null == algorithm + ? _value.algorithm + : algorithm // ignore: cast_nullable_to_non_nullable + as String, + qop: null == qop + ? _value.qop + : qop // ignore: cast_nullable_to_non_nullable + as String, + opaque: null == opaque + ? _value.opaque + : opaque // ignore: cast_nullable_to_non_nullable + as String, + ) + as $Val, + ); + } +} + +/// @nodoc +abstract class _$$AuthDigestModelImplCopyWith<$Res> + implements $AuthDigestModelCopyWith<$Res> { + factory _$$AuthDigestModelImplCopyWith( + _$AuthDigestModelImpl value, + $Res Function(_$AuthDigestModelImpl) then, + ) = __$$AuthDigestModelImplCopyWithImpl<$Res>; + @override + @useResult + $Res call({ + String username, + String password, + String realm, + String nonce, + String algorithm, + String qop, + String opaque, + }); +} + +/// @nodoc +class __$$AuthDigestModelImplCopyWithImpl<$Res> + extends _$AuthDigestModelCopyWithImpl<$Res, _$AuthDigestModelImpl> + implements _$$AuthDigestModelImplCopyWith<$Res> { + __$$AuthDigestModelImplCopyWithImpl( + _$AuthDigestModelImpl _value, + $Res Function(_$AuthDigestModelImpl) _then, + ) : super(_value, _then); + + /// Create a copy of AuthDigestModel + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? username = null, + Object? password = null, + Object? realm = null, + Object? nonce = null, + Object? algorithm = null, + Object? qop = null, + Object? opaque = null, + }) { + return _then( + _$AuthDigestModelImpl( + username: null == username + ? _value.username + : username // ignore: cast_nullable_to_non_nullable + as String, + password: null == password + ? _value.password + : password // ignore: cast_nullable_to_non_nullable + as String, + realm: null == realm + ? _value.realm + : realm // ignore: cast_nullable_to_non_nullable + as String, + nonce: null == nonce + ? _value.nonce + : nonce // ignore: cast_nullable_to_non_nullable + as String, + algorithm: null == algorithm + ? _value.algorithm + : algorithm // ignore: cast_nullable_to_non_nullable + as String, + qop: null == qop + ? _value.qop + : qop // ignore: cast_nullable_to_non_nullable + as String, + opaque: null == opaque + ? _value.opaque + : opaque // ignore: cast_nullable_to_non_nullable + as String, + ), + ); + } +} + +/// @nodoc +@JsonSerializable() +class _$AuthDigestModelImpl implements _AuthDigestModel { + const _$AuthDigestModelImpl({ + required this.username, + required this.password, + required this.realm, + required this.nonce, + required this.algorithm, + required this.qop, + required this.opaque, + }); + + factory _$AuthDigestModelImpl.fromJson(Map json) => + _$$AuthDigestModelImplFromJson(json); + + @override + final String username; + @override + final String password; + @override + final String realm; + @override + final String nonce; + @override + final String algorithm; + @override + final String qop; + @override + final String opaque; + + @override + String toString() { + return 'AuthDigestModel(username: $username, password: $password, realm: $realm, nonce: $nonce, algorithm: $algorithm, qop: $qop, opaque: $opaque)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$AuthDigestModelImpl && + (identical(other.username, username) || + other.username == username) && + (identical(other.password, password) || + other.password == password) && + (identical(other.realm, realm) || other.realm == realm) && + (identical(other.nonce, nonce) || other.nonce == nonce) && + (identical(other.algorithm, algorithm) || + other.algorithm == algorithm) && + (identical(other.qop, qop) || other.qop == qop) && + (identical(other.opaque, opaque) || other.opaque == opaque)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + username, + password, + realm, + nonce, + algorithm, + qop, + opaque, + ); + + /// Create a copy of AuthDigestModel + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$AuthDigestModelImplCopyWith<_$AuthDigestModelImpl> get copyWith => + __$$AuthDigestModelImplCopyWithImpl<_$AuthDigestModelImpl>( + this, + _$identity, + ); + + @override + Map toJson() { + return _$$AuthDigestModelImplToJson(this); + } +} + +abstract class _AuthDigestModel implements AuthDigestModel { + const factory _AuthDigestModel({ + required final String username, + required final String password, + required final String realm, + required final String nonce, + required final String algorithm, + required final String qop, + required final String opaque, + }) = _$AuthDigestModelImpl; + + factory _AuthDigestModel.fromJson(Map json) = + _$AuthDigestModelImpl.fromJson; + + @override + String get username; + @override + String get password; + @override + String get realm; + @override + String get nonce; + @override + String get algorithm; + @override + String get qop; + @override + String get opaque; + + /// Create a copy of AuthDigestModel + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$AuthDigestModelImplCopyWith<_$AuthDigestModelImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/packages/better_networking/lib/models/auth/auth_digest_model.g.dart b/packages/better_networking/lib/models/auth/auth_digest_model.g.dart new file mode 100644 index 000000000..ebbf878b1 --- /dev/null +++ b/packages/better_networking/lib/models/auth/auth_digest_model.g.dart @@ -0,0 +1,31 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'auth_digest_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$AuthDigestModelImpl _$$AuthDigestModelImplFromJson( + Map json, +) => _$AuthDigestModelImpl( + username: json['username'] as String, + password: json['password'] as String, + realm: json['realm'] as String, + nonce: json['nonce'] as String, + algorithm: json['algorithm'] as String, + qop: json['qop'] as String, + opaque: json['opaque'] as String, +); + +Map _$$AuthDigestModelImplToJson( + _$AuthDigestModelImpl instance, +) => { + 'username': instance.username, + 'password': instance.password, + 'realm': instance.realm, + 'nonce': instance.nonce, + 'algorithm': instance.algorithm, + 'qop': instance.qop, + 'opaque': instance.opaque, +}; diff --git a/packages/better_networking/lib/models/models.dart b/packages/better_networking/lib/models/models.dart index f5ac6b1f0..2987393d9 100644 --- a/packages/better_networking/lib/models/models.dart +++ b/packages/better_networking/lib/models/models.dart @@ -5,3 +5,4 @@ export 'auth/auth_api_key_model.dart'; export 'auth/auth_basic_model.dart'; export 'auth/auth_bearer_model.dart'; export 'auth/auth_jwt_model.dart'; +export 'auth/auth_digest_model.dart'; diff --git a/packages/better_networking/lib/services/http_service.dart b/packages/better_networking/lib/services/http_service.dart index 78c75f50f..7c670f9d0 100644 --- a/packages/better_networking/lib/services/http_service.dart +++ b/packages/better_networking/lib/services/http_service.dart @@ -20,14 +20,22 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( HttpRequestModel requestModel, { SupportedUriSchemes defaultUriScheme = kDefaultUriScheme, bool noSSL = false, + bool enableAuth = true, }) async { if (httpClientManager.wasRequestCancelled(requestId)) { httpClientManager.removeCancelledRequest(requestId); } final client = httpClientManager.createClient(requestId, noSSL: noSSL); - // Handle authentication - final authenticatedRequestModel = handleAuth(requestModel, authData); + HttpRequestModel authenticatedRequestModel = requestModel.copyWith(); + + try { + if (enableAuth) { + authenticatedRequestModel = await handleAuth(requestModel, authData); + } + } catch (e) { + return (null, null, e.toString()); + } (Uri?, String?) uriRec = getValidRequestUri( authenticatedRequestModel.url, diff --git a/packages/better_networking/lib/utils/auth/digest_auth_utils.dart b/packages/better_networking/lib/utils/auth/digest_auth_utils.dart new file mode 100644 index 000000000..fc4a90720 --- /dev/null +++ b/packages/better_networking/lib/utils/auth/digest_auth_utils.dart @@ -0,0 +1,237 @@ +import 'dart:convert'; +import 'dart:math' as math; + +import 'package:convert/convert.dart'; +import 'package:crypto/crypto.dart' as crypto; +import '../../models/auth/auth_digest_model.dart'; +import '../../models/models.dart'; + +Map? splitAuthenticateHeader(String header) { + if (!header.startsWith('Digest ')) { + return null; + } + header = header.substring(7); // remove 'Digest ' + + var ret = {}; + + final components = header.split(',').map((token) => token.trim()); + for (var component in components) { + final kv = component.split('='); + ret[kv[0]] = kv.getRange(1, kv.length).join('=').replaceAll('"', ''); + } + return ret; +} + +String sha256Hash(String data) { + var content = const Utf8Encoder().convert(data); + var sha256 = crypto.sha256; + var digest = sha256.convert(content).toString(); + return digest; +} + +String md5Hash(String data) { + var content = const Utf8Encoder().convert(data); + var md5 = crypto.md5; + var digest = md5.convert(content).toString(); + return digest; +} + +String _formatNonceCount(int nc) { + return nc.toRadixString(16).padLeft(8, '0'); +} + +String _computeHA1( + String realm, + String? algorithm, + String username, + String password, + String? nonce, + String? cnonce, +) { + if (algorithm == 'MD5') { + final token1 = '$username:$realm:$password'; + return md5Hash(token1); + } else if (algorithm == 'MD5-sess') { + final token1 = '$username:$realm:$password'; + final md51 = md5Hash(token1); + final token2 = '$md51:$nonce:$cnonce'; + return md5Hash(token2); + } else if (algorithm == 'SHA-256') { + final token1 = '$username:$realm:$password'; + return sha256Hash(token1); + } else if (algorithm == 'SHA-256-sess') { + final token1 = '$username:$realm:$password'; + final sha256_1 = sha256Hash(token1); + final token2 = '$sha256_1:$nonce:$cnonce'; + return sha256Hash(token2); + } else { + throw ArgumentError.value(algorithm, 'algorithm', 'Unsupported algorithm'); + } +} + +Map computeResponse( + String method, + String path, + String body, + String? algorithm, + String? qop, + String? opaque, + String realm, + String? cnonce, + String? nonce, + int nc, + String username, + String password, +) { + var ret = {}; + + algorithm ??= 'MD5'; + final ha1 = _computeHA1(realm, algorithm, username, password, nonce, cnonce); + + String ha2; + + if (algorithm.startsWith('MD5')) { + if (qop == 'auth-int') { + final bodyHash = md5Hash(body); + final token2 = '$method:$path:$bodyHash'; + ha2 = md5Hash(token2); + } else { + // qop in [null, auth] + final token2 = '$method:$path'; + ha2 = md5Hash(token2); + } + } else { + if (qop == 'auth-int') { + final bodyHash = sha256Hash(body); + final token2 = '$method:$path:$bodyHash'; + ha2 = sha256Hash(token2); + } else { + // qop in [null, auth] + final token2 = '$method:$path'; + ha2 = sha256Hash(token2); + } + } + + final nonceCount = _formatNonceCount(nc); + ret['username'] = username; + ret['realm'] = realm; + ret['nonce'] = nonce; + ret['uri'] = path; + if (qop != null) { + ret['qop'] = qop; + } + ret['nc'] = nonceCount; + ret['cnonce'] = cnonce; + if (opaque != null) { + ret['opaque'] = opaque; + } + ret['algorithm'] = algorithm; + + if (algorithm.startsWith('MD5')) { + if (qop == null) { + final token3 = '$ha1:$nonce:$ha2'; + ret['response'] = md5Hash(token3); + } else if (qop == 'auth' || qop == 'auth-int') { + final token3 = '$ha1:$nonce:$nonceCount:$cnonce:$qop:$ha2'; + ret['response'] = md5Hash(token3); + } + } else { + if (qop == null) { + final token3 = '$ha1:$nonce:$ha2'; + ret['response'] = sha256Hash(token3); + } else if (qop == 'auth' || qop == 'auth-int') { + final token3 = '$ha1:$nonce:$nonceCount:$cnonce:$qop:$ha2'; + ret['response'] = sha256Hash(token3); + } + } + + return ret; +} + +class DigestAuth { + String username; + String password; + + // must get from first response + String? _algorithm; + String? _qop; + String? _realm; + String? _nonce; + String? _opaque; + + int _nc = 0; // request counter + + DigestAuth(this.username, this.password); + + // Constructor that takes an AuthDigestModel + DigestAuth.fromModel(AuthDigestModel model) + : username = model.username, + password = model.password, + _realm = model.realm, + _nonce = model.nonce, + _algorithm = model.algorithm, + _qop = model.qop, + _opaque = model.opaque.isNotEmpty ? model.opaque : null; + + String _computeNonce() { + final rnd = math.Random.secure(); + + final values = List.generate(16, (i) => rnd.nextInt(256)); + + return hex.encode(values); + } + + String getAuthString(HttpRequestModel res) { + final cnonce = _computeNonce(); + final url = Uri.parse(res.url); + final method = res.method.name.toUpperCase(); + final body = res.body ?? ''; + _nc += 1; + // if url has query parameters, append query to path + final path = url.hasQuery ? '${url.path}?${url.query}' : url.path; + + // after the first request we have the nonce, so we can provide credentials + final authValues = computeResponse( + method, + path, + body, + _algorithm, + _qop, + _opaque, + _realm!, + cnonce, + _nonce, + _nc, + username, + password, + ); + final authValuesString = authValues.entries + .where((e) => e.value != null) + .map( + (e) => [ + e.key, + '=', + ['algorithm', 'qop', 'nc'].contains(e.key) ? '' : '"', + e.value, + ['algorithm', 'qop', 'nc'].contains(e.key) ? '' : '"', + ].join(''), + ) + .toList() + .join(', '); + final authString = 'Digest $authValuesString'; + return authString; + } + + // TODO: Use this function + void initFromAuthenticateHeader(String /*!*/ authInfo) { + final values = splitAuthenticateHeader(authInfo); + if (values != null) { + _algorithm = values['algorithm'] ?? _algorithm; + _qop = values['qop'] ?? _qop; + _realm = values['realm'] ?? _realm; + _nonce = values['nonce'] ?? _nonce; + _opaque = values['opaque'] ?? _opaque; + _nc = 0; + } + } +} diff --git a/packages/better_networking/lib/utils/auth/handle_auth.dart b/packages/better_networking/lib/utils/auth/handle_auth.dart new file mode 100644 index 000000000..231b7643a --- /dev/null +++ b/packages/better_networking/lib/utils/auth/handle_auth.dart @@ -0,0 +1,175 @@ +import 'dart:convert'; +import 'dart:math'; +import 'package:better_networking/utils/auth/jwt_auth_utils.dart'; +import 'package:better_networking/utils/auth/digest_auth_utils.dart'; +import 'package:better_networking/better_networking.dart'; + +Future handleAuth( + HttpRequestModel httpRequestModel, + AuthModel? authData, +) async { + if (authData == null || authData.type == APIAuthType.none) { + return httpRequestModel; + } + + List updatedHeaders = List.from( + httpRequestModel.headers ?? [], + ); + List updatedParams = List.from(httpRequestModel.params ?? []); + List updatedHeaderEnabledList = List.from( + httpRequestModel.isHeaderEnabledList ?? [], + ); + List updatedParamEnabledList = List.from( + httpRequestModel.isParamEnabledList ?? [], + ); + + switch (authData.type) { + case APIAuthType.basic: + if (authData.basic != null) { + final basicAuth = authData.basic!; + final encoded = base64Encode( + utf8.encode('${basicAuth.username}:${basicAuth.password}'), + ); + updatedHeaders.add( + NameValueModel(name: 'Authorization', value: 'Basic $encoded'), + ); + updatedHeaderEnabledList.add(true); + } + break; + + case APIAuthType.bearer: + if (authData.bearer != null) { + final bearerAuth = authData.bearer!; + updatedHeaders.add( + NameValueModel( + name: 'Authorization', + value: 'Bearer ${bearerAuth.token}', + ), + ); + updatedHeaderEnabledList.add(true); + } + break; + + case APIAuthType.jwt: + if (authData.jwt != null) { + final jwtAuth = authData.jwt!; + + // Generate JWT token + final jwtToken = generateJWT(jwtAuth); + + if (jwtAuth.addTokenTo == 'header') { + // Add to request header with prefix + final headerValue = jwtAuth.headerPrefix.isNotEmpty + ? '${jwtAuth.headerPrefix} $jwtToken' + : jwtToken; + updatedHeaders.add( + NameValueModel(name: 'Authorization', value: headerValue), + ); + updatedHeaderEnabledList.add(true); + } else if (jwtAuth.addTokenTo == 'query') { + // Add to query parameters(if selected) + final paramKey = jwtAuth.queryParamKey.isNotEmpty + ? jwtAuth.queryParamKey + : 'token'; + updatedParams.add(NameValueModel(name: paramKey, value: jwtToken)); + updatedParamEnabledList.add(true); + } + } + break; + + case APIAuthType.apiKey: + if (authData.apikey != null) { + final apiKeyAuth = authData.apikey!; + if (apiKeyAuth.location == 'header') { + updatedHeaders.add( + NameValueModel(name: apiKeyAuth.name, value: apiKeyAuth.key), + ); + updatedHeaderEnabledList.add(true); + } else if (apiKeyAuth.location == 'query') { + updatedParams.add( + NameValueModel(name: apiKeyAuth.name, value: apiKeyAuth.key), + ); + updatedParamEnabledList.add(true); + } + } + break; + + case APIAuthType.none: + break; + case APIAuthType.digest: + if (authData.digest != null) { + final digestAuthModel = authData.digest!; + + if (digestAuthModel.realm.isNotEmpty && + digestAuthModel.nonce.isNotEmpty) { + final digestAuth = DigestAuth.fromModel(digestAuthModel); + final authString = digestAuth.getAuthString(httpRequestModel); + + updatedHeaders.add( + NameValueModel(name: 'Authorization', value: authString), + ); + updatedHeaderEnabledList.add(true); + } else { + final httpResult = await sendHttpRequest( + "digest-${Random.secure()}", + APIType.rest, + authData, + httpRequestModel, + enableAuth: false, + ); + final httpResponse = httpResult.$1; + + if (httpResponse == null) { + throw Exception("Initial Digest request failed: no response"); + } + + if (httpResponse.statusCode == 401) { + final wwwAuthHeader = httpResponse.headers[kHeaderWwwAuthenticate]; + + if (wwwAuthHeader == null) { + throw Exception("401 response missing www-authenticate header"); + } + + final authParams = splitAuthenticateHeader(wwwAuthHeader); + + if (authParams == null) { + throw Exception("Invalid Digest header format"); + } + + final updatedDigestModel = digestAuthModel.copyWith( + realm: authParams['realm'] ?? '', + nonce: authParams['nonce'] ?? '', + algorithm: authParams['algorithm'] ?? 'MD5', + qop: authParams['qop'] ?? 'auth', + opaque: authParams['opaque'] ?? '', + ); + + final digestAuth = DigestAuth.fromModel(updatedDigestModel); + final authString = digestAuth.getAuthString(httpRequestModel); + updatedHeaders.add( + NameValueModel(name: 'Authorization', value: authString), + ); + updatedHeaderEnabledList.add(true); + } else { + throw Exception( + "Initial Digest request failed due to unexpected status code: ${httpResponse.body}. Status Code: ${httpResponse.statusCode}", + ); + } + } + } + break; + case APIAuthType.oauth1: + // TODO: Handle this case. + throw UnimplementedError(); + case APIAuthType.oauth2: + // TODO: Handle this case. + throw UnimplementedError(); + } + + return httpRequestModel.copyWith( + headers: updatedHeaders, + params: updatedParams, + isHeaderEnabledList: updatedHeaderEnabledList, + isParamEnabledList: updatedParamEnabledList, + ); +} diff --git a/packages/better_networking/lib/utils/auth_utils.dart b/packages/better_networking/lib/utils/auth/jwt_auth_utils.dart similarity index 100% rename from packages/better_networking/lib/utils/auth_utils.dart rename to packages/better_networking/lib/utils/auth/jwt_auth_utils.dart diff --git a/packages/better_networking/lib/utils/handle_auth.dart b/packages/better_networking/lib/utils/handle_auth.dart deleted file mode 100644 index 45a3f08cb..000000000 --- a/packages/better_networking/lib/utils/handle_auth.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'dart:convert'; -import 'package:better_networking/utils/auth_utils.dart'; -import 'package:better_networking/better_networking.dart'; - -import '../models/auth/api_auth_model.dart'; - -HttpRequestModel handleAuth(HttpRequestModel httpRequestModel,AuthModel? authData) { - if (authData == null || authData.type == APIAuthType.none) { - return httpRequestModel; - } - - List updatedHeaders = - List.from(httpRequestModel.headers ?? []); - List updatedParams = List.from(httpRequestModel.params ?? []); - List updatedHeaderEnabledList = - List.from(httpRequestModel.isHeaderEnabledList ?? []); - List updatedParamEnabledList = - List.from(httpRequestModel.isParamEnabledList ?? []); - - switch (authData.type) { - case APIAuthType.basic: - if (authData.basic != null) { - final basicAuth = authData.basic!; - final encoded = base64Encode( - utf8.encode('${basicAuth.username}:${basicAuth.password}')); - updatedHeaders.add( - NameValueModel(name: 'Authorization', value: 'Basic $encoded')); - updatedHeaderEnabledList.add(true); - } - break; - - case APIAuthType.bearer: - if (authData.bearer != null) { - final bearerAuth = authData.bearer!; - updatedHeaders.add(NameValueModel( - name: 'Authorization', value: 'Bearer ${bearerAuth.token}')); - updatedHeaderEnabledList.add(true); - } - break; - - case APIAuthType.jwt: - if (authData.jwt != null) { - final jwtAuth = authData.jwt!; - - // Generate JWT token - final jwtToken = generateJWT(jwtAuth); - - if (jwtAuth.addTokenTo == 'header') { - // Add to request header with prefix - final headerValue = jwtAuth.headerPrefix.isNotEmpty - ? '${jwtAuth.headerPrefix} $jwtToken' - : jwtToken; - updatedHeaders - .add(NameValueModel(name: 'Authorization', value: headerValue)); - updatedHeaderEnabledList.add(true); - } else if (jwtAuth.addTokenTo == 'query') { - // Add to query parameters(if selected) - final paramKey = jwtAuth.queryParamKey.isNotEmpty - ? jwtAuth.queryParamKey - : 'token'; - updatedParams.add(NameValueModel(name: paramKey, value: jwtToken)); - updatedParamEnabledList.add(true); - } - } - break; - - case APIAuthType.apiKey: - if (authData.apikey != null) { - final apiKeyAuth = authData.apikey!; - if (apiKeyAuth.location == 'header') { - updatedHeaders.add( - NameValueModel(name: apiKeyAuth.name, value: apiKeyAuth.key)); - updatedHeaderEnabledList.add(true); - } else if (apiKeyAuth.location == 'query') { - updatedParams.add( - NameValueModel(name: apiKeyAuth.name, value: apiKeyAuth.key)); - updatedParamEnabledList.add(true); - } - } - break; - - case APIAuthType.none: - break; - case APIAuthType.digest: - // TODO: Handle this case. - throw UnimplementedError(); - case APIAuthType.oauth1: - // TODO: Handle this case. - throw UnimplementedError(); - case APIAuthType.oauth2: - // TODO: Handle this case. - throw UnimplementedError(); - } - - return httpRequestModel.copyWith( - headers: updatedHeaders, - params: updatedParams, - isHeaderEnabledList: updatedHeaderEnabledList, - isParamEnabledList: updatedParamEnabledList, - ); -} diff --git a/packages/better_networking/lib/utils/utils.dart b/packages/better_networking/lib/utils/utils.dart index 95bfa9317..7857ed81c 100644 --- a/packages/better_networking/lib/utils/utils.dart +++ b/packages/better_networking/lib/utils/utils.dart @@ -4,4 +4,4 @@ export 'http_request_utils.dart'; export 'http_response_utils.dart'; export 'string_utils.dart' hide RandomStringGenerator; export 'uri_utils.dart'; -export 'handle_auth.dart'; +export 'auth/handle_auth.dart'; diff --git a/packages/better_networking/pubspec.yaml b/packages/better_networking/pubspec.yaml index 6cd119599..eeabb911a 100644 --- a/packages/better_networking/pubspec.yaml +++ b/packages/better_networking/pubspec.yaml @@ -26,6 +26,7 @@ dependencies: seed: ^0.0.3 xml: ^6.3.0 crypto: ^3.0.6 + convert: ^3.1.2 dev_dependencies: flutter_test: From d5ca13b356472ff59edbd3258dfcaa6a9ff3487c Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sun, 6 Jul 2025 12:19:27 +0530 Subject: [PATCH 32/70] feat: enhance JWT support with private key handling and additional algorithms --- .../common_widgets/auth/jwt_auth_fields.dart | 101 +++++++--- .../better_networking_example/pubspec.lock | 40 ++++ .../lib/models/auth/auth_jwt_model.dart | 1 + .../models/auth/auth_jwt_model.freezed.dart | 24 ++- .../lib/models/auth/auth_jwt_model.g.dart | 2 + .../lib/utils/auth/jwt_auth_utils.dart | 121 ++++++------ packages/better_networking/pubspec.yaml | 2 +- .../test/utils/auth/jwt_auth_utils_test.dart | 178 ++++++++++++++++++ 8 files changed, 386 insertions(+), 83 deletions(-) create mode 100644 packages/better_networking/test/utils/auth/jwt_auth_utils_test.dart diff --git a/lib/screens/common_widgets/auth/jwt_auth_fields.dart b/lib/screens/common_widgets/auth/jwt_auth_fields.dart index cdde66c22..44f97c986 100644 --- a/lib/screens/common_widgets/auth/jwt_auth_fields.dart +++ b/lib/screens/common_widgets/auth/jwt_auth_fields.dart @@ -21,6 +21,7 @@ class JwtAuthFields extends StatefulWidget { class _JwtAuthFieldsState extends State { late TextEditingController _secretController; + late TextEditingController _privateKeyController; late TextEditingController _payloadController; late String _addTokenTo; late String _algorithm; @@ -31,6 +32,7 @@ class _JwtAuthFieldsState extends State { super.initState(); final jwt = widget.authData?.jwt; _secretController = TextEditingController(text: jwt?.secret ?? ''); + _privateKeyController = TextEditingController(text: jwt?.privateKey ?? ''); _payloadController = TextEditingController(text: jwt?.payload ?? ''); _addTokenTo = jwt?.addTokenTo ?? 'header'; _algorithm = jwt?.algorithm ?? 'HS256'; @@ -83,6 +85,17 @@ class _JwtAuthFieldsState extends State { ('HS256', 'HS256'), ('HS384', 'HS384'), ('HS512', 'HS512'), + ('RS256', 'RS256'), + ('RS384', 'RS384'), + ('RS512', 'RS512'), + ('PS256', 'PS256'), + ('PS384', 'PS384'), + ('PS512', 'PS512'), + ('ES256', 'ES256'), + ('ES256K', 'ES256K'), + ('ES384', 'ES384'), + ('ES512', 'ES512'), + ('EdDSA', 'EdDSA'), ], tooltip: "Select JWT algorithm", isOutlined: true, @@ -96,33 +109,78 @@ class _JwtAuthFieldsState extends State { }, ), const SizedBox(height: 16), - AuthTextField( - readOnly: widget.readOnly, - controller: _secretController, - isObscureText: true, - hintText: "Secret key", - onChanged: (value) => _updateJwtAuth(), - ), - const SizedBox(height: 16), - CheckboxListTile( - title: Text( - "Secret is Base64 encoded", + if (_algorithm.startsWith('HS')) ...[ + AuthTextField( + readOnly: widget.readOnly, + controller: _secretController, + isObscureText: true, + hintText: "Secret key", + onChanged: (value) => _updateJwtAuth(), + ), + const SizedBox(height: 16), + CheckboxListTile( + title: Text( + "Secret is Base64 encoded", + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: 14, + ), + ), + value: _isSecretBase64Encoded, + contentPadding: EdgeInsets.zero, + controlAffinity: ListTileControlAffinity.leading, + onChanged: (bool? value) { + setState(() { + _isSecretBase64Encoded = value ?? false; + }); + + _updateJwtAuth(); + }, + ), + ] else ...[ + Text( + "Private Key (PEM Format)", style: TextStyle( fontWeight: FontWeight.normal, fontSize: 14, ), ), - value: _isSecretBase64Encoded, - contentPadding: EdgeInsets.zero, - controlAffinity: ListTileControlAffinity.leading, - onChanged: (bool? value) { - setState(() { - _isSecretBase64Encoded = value ?? false; - }); + SizedBox(height: 4), + TextField( + readOnly: widget.readOnly, + controller: _privateKeyController, + maxLines: 5, + decoration: InputDecoration( + filled: true, + fillColor: Theme.of(context).colorScheme.surfaceContainerLowest, + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width - 100, + ), + contentPadding: const EdgeInsets.all(18), + hintText: ''' +-----BEGIN RSA PRIVATE KEY----- +Private Key in PKCS#8 PEM Format +-----END RSA PRIVATE KEY----- +''', + hintStyle: Theme.of(context).textTheme.bodyMedium, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.outline, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.surfaceContainerHighest, + ), + ), + ), + onChanged: (value) => _updateJwtAuth(), + ), + ], - _updateJwtAuth(); - }, - ), const SizedBox(height: 16), Text( "Payload (JSON format)", @@ -284,6 +342,7 @@ class _JwtAuthFieldsState extends State { type: APIAuthType.jwt, jwt: AuthJwtModel( secret: _secretController.text.trim(), + privateKey: _privateKeyController.text.trim(), payload: _payloadController.text.trim(), addTokenTo: _addTokenTo, algorithm: _algorithm, diff --git a/packages/better_networking/better_networking_example/pubspec.lock b/packages/better_networking/better_networking_example/pubspec.lock index 908096b79..10c4eb736 100644 --- a/packages/better_networking/better_networking_example/pubspec.lock +++ b/packages/better_networking/better_networking_example/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + adaptive_number: + dependency: transitive + description: + name: adaptive_number + sha256: "3a567544e9b5c9c803006f51140ad544aedc79604fd4f3f2c1380003f97c1d77" + url: "https://pub.dev" + source: hosted + version: "1.0.0" async: dependency: transitive description: @@ -72,6 +80,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + dart_jsonwebtoken: + dependency: transitive + description: + name: dart_jsonwebtoken + sha256: "21ce9f8a8712f741e8d6876a9c82c0f8a257fe928c4378a91d8527b92a3fd413" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + ed25519_edwards: + dependency: transitive + description: + name: ed25519_edwards + sha256: "6ce0112d131327ec6d42beede1e5dfd526069b18ad45dcf654f15074ad9276cd" + url: "https://pub.dev" + source: hosted + version: "0.3.1" fake_async: dependency: transitive description: @@ -80,6 +104,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.3" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -210,6 +242,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.0" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "92aa3841d083cc4b0f4709b5c74fd6409a3e6ba833ffc7dc6a8fee096366acf5" + url: "https://pub.dev" + source: hosted + version: "4.0.0" seed: dependency: "direct overridden" description: diff --git a/packages/better_networking/lib/models/auth/auth_jwt_model.dart b/packages/better_networking/lib/models/auth/auth_jwt_model.dart index 61b165a57..a2e82e053 100644 --- a/packages/better_networking/lib/models/auth/auth_jwt_model.dart +++ b/packages/better_networking/lib/models/auth/auth_jwt_model.dart @@ -7,6 +7,7 @@ part 'auth_jwt_model.g.dart'; class AuthJwtModel with _$AuthJwtModel { const factory AuthJwtModel({ required String secret, + String? privateKey, required String payload, required String addTokenTo, required String algorithm, diff --git a/packages/better_networking/lib/models/auth/auth_jwt_model.freezed.dart b/packages/better_networking/lib/models/auth/auth_jwt_model.freezed.dart index c6d5fbf6e..151e18f53 100644 --- a/packages/better_networking/lib/models/auth/auth_jwt_model.freezed.dart +++ b/packages/better_networking/lib/models/auth/auth_jwt_model.freezed.dart @@ -22,6 +22,7 @@ AuthJwtModel _$AuthJwtModelFromJson(Map json) { /// @nodoc mixin _$AuthJwtModel { String get secret => throw _privateConstructorUsedError; + String? get privateKey => throw _privateConstructorUsedError; String get payload => throw _privateConstructorUsedError; String get addTokenTo => throw _privateConstructorUsedError; String get algorithm => throw _privateConstructorUsedError; @@ -49,6 +50,7 @@ abstract class $AuthJwtModelCopyWith<$Res> { @useResult $Res call({ String secret, + String? privateKey, String payload, String addTokenTo, String algorithm, @@ -75,6 +77,7 @@ class _$AuthJwtModelCopyWithImpl<$Res, $Val extends AuthJwtModel> @override $Res call({ Object? secret = null, + Object? privateKey = freezed, Object? payload = null, Object? addTokenTo = null, Object? algorithm = null, @@ -89,6 +92,10 @@ class _$AuthJwtModelCopyWithImpl<$Res, $Val extends AuthJwtModel> ? _value.secret : secret // ignore: cast_nullable_to_non_nullable as String, + privateKey: freezed == privateKey + ? _value.privateKey + : privateKey // ignore: cast_nullable_to_non_nullable + as String?, payload: null == payload ? _value.payload : payload // ignore: cast_nullable_to_non_nullable @@ -134,6 +141,7 @@ abstract class _$$AuthJwtModelImplCopyWith<$Res> @useResult $Res call({ String secret, + String? privateKey, String payload, String addTokenTo, String algorithm, @@ -159,6 +167,7 @@ class __$$AuthJwtModelImplCopyWithImpl<$Res> @override $Res call({ Object? secret = null, + Object? privateKey = freezed, Object? payload = null, Object? addTokenTo = null, Object? algorithm = null, @@ -173,6 +182,10 @@ class __$$AuthJwtModelImplCopyWithImpl<$Res> ? _value.secret : secret // ignore: cast_nullable_to_non_nullable as String, + privateKey: freezed == privateKey + ? _value.privateKey + : privateKey // ignore: cast_nullable_to_non_nullable + as String?, payload: null == payload ? _value.payload : payload // ignore: cast_nullable_to_non_nullable @@ -211,6 +224,7 @@ class __$$AuthJwtModelImplCopyWithImpl<$Res> class _$AuthJwtModelImpl implements _AuthJwtModel { const _$AuthJwtModelImpl({ required this.secret, + this.privateKey, required this.payload, required this.addTokenTo, required this.algorithm, @@ -226,6 +240,8 @@ class _$AuthJwtModelImpl implements _AuthJwtModel { @override final String secret; @override + final String? privateKey; + @override final String payload; @override final String addTokenTo; @@ -242,7 +258,7 @@ class _$AuthJwtModelImpl implements _AuthJwtModel { @override String toString() { - return 'AuthJwtModel(secret: $secret, payload: $payload, addTokenTo: $addTokenTo, algorithm: $algorithm, isSecretBase64Encoded: $isSecretBase64Encoded, headerPrefix: $headerPrefix, queryParamKey: $queryParamKey, header: $header)'; + return 'AuthJwtModel(secret: $secret, privateKey: $privateKey, payload: $payload, addTokenTo: $addTokenTo, algorithm: $algorithm, isSecretBase64Encoded: $isSecretBase64Encoded, headerPrefix: $headerPrefix, queryParamKey: $queryParamKey, header: $header)'; } @override @@ -251,6 +267,8 @@ class _$AuthJwtModelImpl implements _AuthJwtModel { (other.runtimeType == runtimeType && other is _$AuthJwtModelImpl && (identical(other.secret, secret) || other.secret == secret) && + (identical(other.privateKey, privateKey) || + other.privateKey == privateKey) && (identical(other.payload, payload) || other.payload == payload) && (identical(other.addTokenTo, addTokenTo) || other.addTokenTo == addTokenTo) && @@ -270,6 +288,7 @@ class _$AuthJwtModelImpl implements _AuthJwtModel { int get hashCode => Object.hash( runtimeType, secret, + privateKey, payload, addTokenTo, algorithm, @@ -296,6 +315,7 @@ class _$AuthJwtModelImpl implements _AuthJwtModel { abstract class _AuthJwtModel implements AuthJwtModel { const factory _AuthJwtModel({ required final String secret, + final String? privateKey, required final String payload, required final String addTokenTo, required final String algorithm, @@ -311,6 +331,8 @@ abstract class _AuthJwtModel implements AuthJwtModel { @override String get secret; @override + String? get privateKey; + @override String get payload; @override String get addTokenTo; diff --git a/packages/better_networking/lib/models/auth/auth_jwt_model.g.dart b/packages/better_networking/lib/models/auth/auth_jwt_model.g.dart index 4e415d108..cdd58a283 100644 --- a/packages/better_networking/lib/models/auth/auth_jwt_model.g.dart +++ b/packages/better_networking/lib/models/auth/auth_jwt_model.g.dart @@ -9,6 +9,7 @@ part of 'auth_jwt_model.dart'; _$AuthJwtModelImpl _$$AuthJwtModelImplFromJson(Map json) => _$AuthJwtModelImpl( secret: json['secret'] as String, + privateKey: json['privateKey'] as String?, payload: json['payload'] as String, addTokenTo: json['addTokenTo'] as String, algorithm: json['algorithm'] as String, @@ -21,6 +22,7 @@ _$AuthJwtModelImpl _$$AuthJwtModelImplFromJson(Map json) => Map _$$AuthJwtModelImplToJson(_$AuthJwtModelImpl instance) => { 'secret': instance.secret, + 'privateKey': instance.privateKey, 'payload': instance.payload, 'addTokenTo': instance.addTokenTo, 'algorithm': instance.algorithm, diff --git a/packages/better_networking/lib/utils/auth/jwt_auth_utils.dart b/packages/better_networking/lib/utils/auth/jwt_auth_utils.dart index 303a3e90d..791a30443 100644 --- a/packages/better_networking/lib/utils/auth/jwt_auth_utils.dart +++ b/packages/better_networking/lib/utils/auth/jwt_auth_utils.dart @@ -1,94 +1,95 @@ import 'dart:convert'; -import 'dart:typed_data'; +import 'dart:developer'; import 'package:better_networking/models/auth/auth_jwt_model.dart'; -import 'package:crypto/crypto.dart'; +import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart'; String generateJWT(AuthJwtModel jwtAuth) { try { - Map header; + // Parse header if provided + Map headerMap = {}; if (jwtAuth.header.isNotEmpty) { try { - header = json.decode(jwtAuth.header) as Map; + headerMap = json.decode(jwtAuth.header) as Map; } catch (e) { - header = {}; + // If header parsing fails, use empty header + headerMap = {}; } - } else { - header = {}; } - header['typ'] = header['typ'] ?? 'JWT'; - header['alg'] = jwtAuth.algorithm; - Map payload; + + // Parse payload if provided + Map payloadMap = {}; if (jwtAuth.payload.isNotEmpty) { try { - payload = json.decode(jwtAuth.payload) as Map; + payloadMap = json.decode(jwtAuth.payload) as Map; } catch (e) { - payload = {}; + // If payload parsing fails, use empty payload + payloadMap = {}; } - } else { - payload = {}; - } - if (!payload.containsKey('iat')) { - payload['iat'] = DateTime.now().millisecondsSinceEpoch ~/ 1000; } - // Encode header and payload - final encodedHeader = _base64UrlEncode(utf8.encode(json.encode(header))); - final encodedPayload = _base64UrlEncode(utf8.encode(json.encode(payload))); + // Add issued at time if not present + if (!payloadMap.containsKey('iat')) { + payloadMap['iat'] = DateTime.now().millisecondsSinceEpoch ~/ 1000; + } + final jwt = JWT(payloadMap, header: headerMap); - // Create signature - final signature = _createSignature( - '$encodedHeader.$encodedPayload', + final key = _createKey( jwtAuth.secret, jwtAuth.algorithm, jwtAuth.isSecretBase64Encoded, + jwtAuth.privateKey, + ); + final token = jwt.sign( + key, + algorithm: JWTAlgorithm.fromName(jwtAuth.algorithm), ); - return '$encodedHeader.$encodedPayload.$signature'; + return token; } catch (e) { - throw Exception('Failed to generate JWT: $e'); + log(e.toString()); + throw Exception('Failed to generate JSON Wweb Token: $e'); } } -String _createSignature( - String data, String secret, String algorithm, bool isSecretBase64Encoded) { - try { - Uint8List secretBytes; +JWTKey _createKey( + String secret, + String algorithm, + bool isSecretBase64Encoded, + String? privateKey, +) { + if (algorithm.startsWith('HS')) { if (isSecretBase64Encoded) { - secretBytes = base64.decode(secret); + final decodedSecret = base64.decode(secret); + return SecretKey(String.fromCharCodes(decodedSecret)); } else { - secretBytes = utf8.encode(secret); + return SecretKey(secret); } + } + if (algorithm.startsWith('RS') || algorithm.startsWith('PS')) { + if (privateKey == null) { + throw Exception( + 'Failed to generate JSON Wweb Token: Private Key not Found', + ); + } + return RSAPrivateKey(privateKey); + } + if (algorithm.startsWith('ES')) { + if (privateKey == null) { + throw Exception( + 'Failed to generate JSON Wweb Token: Private Key not Found', + ); + } + return ECPrivateKey(privateKey); + } - final dataBytes = utf8.encode(data); - - switch (algorithm) { - case 'HS256': - final hmac = Hmac(sha256, secretBytes); - final digest = hmac.convert(dataBytes); - return _base64UrlEncode(digest.bytes); - - case 'HS384': - final hmac = Hmac(sha384, secretBytes); - final digest = hmac.convert(dataBytes); - return _base64UrlEncode(digest.bytes); - - case 'HS512': - final hmac = Hmac(sha512, secretBytes); - final digest = hmac.convert(dataBytes); - return _base64UrlEncode(digest.bytes); - - default: - // Default to HS256 - final hmac = Hmac(sha256, secretBytes); - final digest = hmac.convert(dataBytes); - return _base64UrlEncode(digest.bytes); + if (algorithm == 'EdDSA') { + if (privateKey == null) { + throw Exception( + 'Failed to generate JSON Wweb Token: Private Key not Found', + ); } - } catch (e) { - // Return placeholder signature if creation fails - return _base64UrlEncode(utf8.encode('signature_generation_failed')); + return EdDSAPrivateKey.fromPEM(privateKey); } -} -String _base64UrlEncode(List bytes) { - return base64Url.encode(bytes).replaceAll('=', ''); + return SecretKey(secret, isBase64Encoded: isSecretBase64Encoded); } diff --git a/packages/better_networking/pubspec.yaml b/packages/better_networking/pubspec.yaml index eeabb911a..5214f3997 100644 --- a/packages/better_networking/pubspec.yaml +++ b/packages/better_networking/pubspec.yaml @@ -26,7 +26,7 @@ dependencies: seed: ^0.0.3 xml: ^6.3.0 crypto: ^3.0.6 - convert: ^3.1.2 + dart_jsonwebtoken: ^3.2.0 dev_dependencies: flutter_test: diff --git a/packages/better_networking/test/utils/auth/jwt_auth_utils_test.dart b/packages/better_networking/test/utils/auth/jwt_auth_utils_test.dart new file mode 100644 index 000000000..009560381 --- /dev/null +++ b/packages/better_networking/test/utils/auth/jwt_auth_utils_test.dart @@ -0,0 +1,178 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:better_networking/models/auth/auth_jwt_model.dart'; +import 'package:better_networking/utils/auth/jwt_auth_utils.dart'; +import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart'; + +void main() { + group('JWT Auth Utils Tests', () { + test('should generate JWT with HS256 algorithm', () { + const jwtAuth = AuthJwtModel( + secret: 'test_secret', + payload: '{"user_id": 123, "username": "testuser"}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: '{"typ": "JWT"}', + ); + + final token = generateJWT(jwtAuth); + expect(token, isNotEmpty); + expect(token.split('.').length, equals(3)); // JWT has 3 parts + + // Verify the token can be decoded + final decoded = JWT.decode(token); + expect(decoded.payload['user_id'], equals(123)); + expect(decoded.payload['username'], equals('testuser')); + }); + + test('should generate JWT with HS384 algorithm', () { + const jwtAuth = AuthJwtModel( + secret: 'test_secret_384', + payload: '{"role": "admin"}', + addTokenTo: 'header', + algorithm: 'HS384', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: '', + ); + + final token = generateJWT(jwtAuth); + expect(token, isNotEmpty); + expect(token.split('.').length, equals(3)); + + // Verify the token can be decoded + final decoded = JWT.decode(token); + expect(decoded.payload['role'], equals('admin')); + }); + + test('should generate JWT with HS512 algorithm', () { + const jwtAuth = AuthJwtModel( + secret: 'test_secret_512', + payload: '{"exp": 1234567890}', + addTokenTo: 'header', + algorithm: 'HS512', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: '', + ); + + final token = generateJWT(jwtAuth); + expect(token, isNotEmpty); + expect(token.split('.').length, equals(3)); + + // Verify the token can be decoded + final decoded = JWT.decode(token); + expect(decoded.payload['exp'], equals(1234567890)); + }); + + test('should generate JWT with base64 encoded secret', () { + const secretBase64 = 'dGVzdF9zZWNyZXQ='; // base64 encoded "test_secret" + const jwtAuth = AuthJwtModel( + secret: secretBase64, + payload: '{"test": "value"}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: true, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: '', + ); + + final token = generateJWT(jwtAuth); + expect(token, isNotEmpty); + expect(token.split('.').length, equals(3)); + + // Verify the token can be decoded + final decoded = JWT.decode(token); + expect(decoded.payload['test'], equals('value')); + }); + + test('should handle empty payload', () { + const jwtAuth = AuthJwtModel( + secret: 'test_secret', + payload: '', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: '', + ); + + final token = generateJWT(jwtAuth); + expect(token, isNotEmpty); + expect(token.split('.').length, equals(3)); + + // Verify the token can be decoded and has iat + final decoded = JWT.decode(token); + expect(decoded.payload['iat'], isNotNull); + }); + + test('should handle invalid JSON payload gracefully', () { + const jwtAuth = AuthJwtModel( + secret: 'test_secret', + payload: 'invalid json', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: '', + ); + + final token = generateJWT(jwtAuth); + expect(token, isNotEmpty); + expect(token.split('.').length, equals(3)); + + // Should have at least iat in payload + final decoded = JWT.decode(token); + expect(decoded.payload['iat'], isNotNull); + }); + + test('should verify generated JWT with correct secret', () { + const secret = 'verification_secret'; + const jwtAuth = AuthJwtModel( + secret: secret, + payload: '{"user": "test"}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: '', + ); + + final token = generateJWT(jwtAuth); + + // Verify with correct secret + expect(() => JWT.verify(token, SecretKey(secret)), returnsNormally); + }); + + test('should fail verification with wrong secret', () { + const secret = 'correct_secret'; + const wrongSecret = 'wrong_secret'; + const jwtAuth = AuthJwtModel( + secret: secret, + payload: '{"user": "test"}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: '', + ); + + final token = generateJWT(jwtAuth); + + // Verify with wrong secret should throw + expect( + () => JWT.verify(token, SecretKey(wrongSecret)), + throwsA(isA()), + ); + }); + }); +} From 13bf0549f1649c0a418fe6cd19bd6017605e9471 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sun, 6 Jul 2025 12:22:04 +0530 Subject: [PATCH 33/70] refactor: remove unused digest authentication model import and clean up JWT handling comments --- .../lib/utils/auth/digest_auth_utils.dart | 14 -------------- .../lib/utils/auth/handle_auth.dart | 4 ---- 2 files changed, 18 deletions(-) diff --git a/packages/better_networking/lib/utils/auth/digest_auth_utils.dart b/packages/better_networking/lib/utils/auth/digest_auth_utils.dart index fc4a90720..bfe701580 100644 --- a/packages/better_networking/lib/utils/auth/digest_auth_utils.dart +++ b/packages/better_networking/lib/utils/auth/digest_auth_utils.dart @@ -3,7 +3,6 @@ import 'dart:math' as math; import 'package:convert/convert.dart'; import 'package:crypto/crypto.dart' as crypto; -import '../../models/auth/auth_digest_model.dart'; import '../../models/models.dart'; Map? splitAuthenticateHeader(String header) { @@ -221,17 +220,4 @@ class DigestAuth { final authString = 'Digest $authValuesString'; return authString; } - - // TODO: Use this function - void initFromAuthenticateHeader(String /*!*/ authInfo) { - final values = splitAuthenticateHeader(authInfo); - if (values != null) { - _algorithm = values['algorithm'] ?? _algorithm; - _qop = values['qop'] ?? _qop; - _realm = values['realm'] ?? _realm; - _nonce = values['nonce'] ?? _nonce; - _opaque = values['opaque'] ?? _opaque; - _nc = 0; - } - } } diff --git a/packages/better_networking/lib/utils/auth/handle_auth.dart b/packages/better_networking/lib/utils/auth/handle_auth.dart index 231b7643a..26663144a 100644 --- a/packages/better_networking/lib/utils/auth/handle_auth.dart +++ b/packages/better_networking/lib/utils/auth/handle_auth.dart @@ -53,12 +53,9 @@ Future handleAuth( case APIAuthType.jwt: if (authData.jwt != null) { final jwtAuth = authData.jwt!; - - // Generate JWT token final jwtToken = generateJWT(jwtAuth); if (jwtAuth.addTokenTo == 'header') { - // Add to request header with prefix final headerValue = jwtAuth.headerPrefix.isNotEmpty ? '${jwtAuth.headerPrefix} $jwtToken' : jwtToken; @@ -67,7 +64,6 @@ Future handleAuth( ); updatedHeaderEnabledList.add(true); } else if (jwtAuth.addTokenTo == 'query') { - // Add to query parameters(if selected) final paramKey = jwtAuth.queryParamKey.isNotEmpty ? jwtAuth.queryParamKey : 'token'; From c39b8fbe6d6d7d5413fa2d372c04aabc75818921 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sun, 6 Jul 2025 12:22:58 +0530 Subject: [PATCH 34/70] refactor: remove unused import and logging from JWT generation --- packages/better_networking/lib/utils/auth/jwt_auth_utils.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/better_networking/lib/utils/auth/jwt_auth_utils.dart b/packages/better_networking/lib/utils/auth/jwt_auth_utils.dart index 791a30443..3a81a07aa 100644 --- a/packages/better_networking/lib/utils/auth/jwt_auth_utils.dart +++ b/packages/better_networking/lib/utils/auth/jwt_auth_utils.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'dart:developer'; import 'package:better_networking/models/auth/auth_jwt_model.dart'; import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart'; @@ -46,7 +45,6 @@ String generateJWT(AuthJwtModel jwtAuth) { return token; } catch (e) { - log(e.toString()); throw Exception('Failed to generate JSON Wweb Token: $e'); } } From 32855fd2f9214909bfa3bdf0b3e5ca06d4a6d72d Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sun, 6 Jul 2025 12:28:35 +0530 Subject: [PATCH 35/70] refactor: update authentication handling to check authData instead of enableAuth flag --- packages/better_networking/lib/services/http_service.dart | 3 +-- packages/better_networking/lib/utils/auth/handle_auth.dart | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/better_networking/lib/services/http_service.dart b/packages/better_networking/lib/services/http_service.dart index 7c670f9d0..844ef69be 100644 --- a/packages/better_networking/lib/services/http_service.dart +++ b/packages/better_networking/lib/services/http_service.dart @@ -20,7 +20,6 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( HttpRequestModel requestModel, { SupportedUriSchemes defaultUriScheme = kDefaultUriScheme, bool noSSL = false, - bool enableAuth = true, }) async { if (httpClientManager.wasRequestCancelled(requestId)) { httpClientManager.removeCancelledRequest(requestId); @@ -30,7 +29,7 @@ Future<(HttpResponse?, Duration?, String?)> sendHttpRequest( HttpRequestModel authenticatedRequestModel = requestModel.copyWith(); try { - if (enableAuth) { + if (authData != null && authData.type != APIAuthType.none) { authenticatedRequestModel = await handleAuth(requestModel, authData); } } catch (e) { diff --git a/packages/better_networking/lib/utils/auth/handle_auth.dart b/packages/better_networking/lib/utils/auth/handle_auth.dart index 26663144a..8228f87e2 100644 --- a/packages/better_networking/lib/utils/auth/handle_auth.dart +++ b/packages/better_networking/lib/utils/auth/handle_auth.dart @@ -111,7 +111,6 @@ Future handleAuth( APIType.rest, authData, httpRequestModel, - enableAuth: false, ); final httpResponse = httpResult.$1; From 8d4eedc21be4192129a848ccdc1dbdf2728ece5c Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Mon, 7 Jul 2025 02:03:47 +0530 Subject: [PATCH 36/70] tests: add authentication unit tests --- .../test/utils/auth/auth_handling_test.dart | 338 ++++++++++ .../test/utils/auth/auth_models_test.dart | 340 +++++++++++ pubspec.lock | 32 + test/models/history_models.dart | 30 +- test/models/http_request_model_test.dart | 321 ++++++++++ test/models/http_request_models.dart | 16 + test/models/request_models.dart | 36 -- test/models/response_model_test.dart | 27 +- test/providers/collection_providers_test.dart | 576 ++++++++++++++++++ 9 files changed, 1658 insertions(+), 58 deletions(-) create mode 100644 packages/better_networking/test/utils/auth/auth_handling_test.dart create mode 100644 packages/better_networking/test/utils/auth/auth_models_test.dart diff --git a/packages/better_networking/test/utils/auth/auth_handling_test.dart b/packages/better_networking/test/utils/auth/auth_handling_test.dart new file mode 100644 index 000000000..b461ea166 --- /dev/null +++ b/packages/better_networking/test/utils/auth/auth_handling_test.dart @@ -0,0 +1,338 @@ +import 'package:better_networking/better_networking.dart'; +import 'package:test/test.dart'; + +void main() { + group('Authentication Handling Tests', () { + test( + 'given sendHttpRequest when no authentication is provided then it should not throw any error', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + final result = await sendHttpRequest( + 'test-request', + APIType.rest, + null, + httpRequestModel, + ); + + expect( + result.$1?.request?.url.toString(), + equals('https://api.apidash.dev/users'), + ); + }, + ); + test( + 'given handleAuth when no authentication is provided then it should return the same httpRequestModel', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + final result = await handleAuth(httpRequestModel, null); + + expect(result.headers, isNull); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when none authentication type is provided then it should add any headers or throw errors', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const authModel = AuthModel(type: APIAuthType.none); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.headers, isEmpty); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when basic authentication fields are provided then it should add an authorization header', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const basicAuth = AuthBasicAuthModel( + username: 'testuser', + password: 'testpass', + ); + const authModel = AuthModel(type: APIAuthType.basic, basic: basicAuth); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.headers, isNotEmpty); + expect( + result.headers?.any((h) => h.name.toLowerCase() == 'authorization'), + isTrue, + ); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when handle bearer authentication fields are provided then it should add an authorization header', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const bearerAuth = AuthBearerModel(token: 'bearer-token-123'); + const authModel = AuthModel( + type: APIAuthType.bearer, + bearer: bearerAuth, + ); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.headers, isNotEmpty); + expect( + result.headers?.any((h) => h.name.toLowerCase() == 'authorization'), + isTrue, + ); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when API key authentication fields are provided then it should add an authorization header', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const apiKeyAuth = AuthApiKeyModel( + key: 'api-key-123', + location: 'header', + name: 'X-API-Key', + ); + const authModel = AuthModel( + type: APIAuthType.apiKey, + apikey: apiKeyAuth, + ); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.headers, isNotEmpty); + expect( + result.headers?.any((h) => h.name.toLowerCase() == 'x-api-key'), + isTrue, + ); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when API key authentication fields are provided then it should add an authorization query', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const apiKeyAuth = AuthApiKeyModel( + key: 'api-key-123', + location: 'query', + name: 'apikey', + ); + const authModel = AuthModel( + type: APIAuthType.apiKey, + apikey: apiKeyAuth, + ); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.params, isNotEmpty); + expect(result.params?.any((p) => p.name == 'apikey'), isTrue); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when JWT authentication fields are provided then it should add an authorization header', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const jwtAuth = AuthJwtModel( + secret: 'jwt-secret', + payload: '{"sub": "1234567890"}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: 'Authorization', + ); + const authModel = AuthModel(type: APIAuthType.jwt, jwt: jwtAuth); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.headers, isNotEmpty); + expect( + result.headers?.any((h) => h.name.toLowerCase() == 'authorization'), + isTrue, + ); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when digest authentication fields are provided then it should add an authorization header', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const digestAuth = AuthDigestModel( + username: 'digestuser', + password: 'digestpass', + realm: 'test-realm', + nonce: 'test-nonce', + algorithm: 'MD5', + qop: 'auth', + opaque: 'test-opaque', + ); + const authModel = AuthModel( + type: APIAuthType.digest, + digest: digestAuth, + ); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.headers, isNotEmpty); + expect( + result.headers?.any((h) => h.name.toLowerCase() == 'authorization'), + isTrue, + ); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when multiple headers are provided then it should add an authorization header to the existing headers', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + headers: [ + NameValueModel(name: 'Content-Type', value: 'application/json'), + NameValueModel(name: 'Accept', value: 'application/json'), + ], + ); + + const bearerAuth = AuthBearerModel(token: 'bearer-token-123'); + const authModel = AuthModel( + type: APIAuthType.bearer, + bearer: bearerAuth, + ); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.headers, isNotEmpty); + expect(result.headers?.any((h) => h.name == 'Content-Type'), isTrue); + expect(result.headers?.any((h) => h.name == 'Accept'), isTrue); + expect( + result.headers?.any((h) => h.name.toLowerCase() == 'authorization'), + isTrue, + ); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when multiple params are provided then it should add it to the existing params', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + params: [ + NameValueModel(name: 'limit', value: '10'), + NameValueModel(name: 'offset', value: '0'), + ], + ); + + const apiKeyAuth = AuthApiKeyModel( + key: 'api-key-123', + location: 'query', + name: 'apikey', + ); + const authModel = AuthModel( + type: APIAuthType.apiKey, + apikey: apiKeyAuth, + ); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.params, isNotEmpty); + expect(result.params?.any((p) => p.name == 'limit'), isTrue); + expect(result.params?.any((p) => p.name == 'offset'), isTrue); + expect(result.params?.any((p) => p.name == 'apikey'), isTrue); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when special characters are provided it should not throw an error', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const basicAuth = AuthBasicAuthModel( + username: 'user@domain.com', + password: r'P@ssw0rd!@#$%^&*()', + ); + const authModel = AuthModel(type: APIAuthType.basic, basic: basicAuth); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.headers, isNotEmpty); + expect( + result.headers?.any((h) => h.name.toLowerCase() == 'authorization'), + isTrue, + ); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when no values are provided it should not throw an error', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const basicAuth = AuthBasicAuthModel(username: '', password: ''); + const authModel = AuthModel(type: APIAuthType.basic, basic: basicAuth); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.headers, isNotEmpty); + expect( + result.headers?.any((h) => h.name.toLowerCase() == 'authorization'), + isTrue, + ); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + }); +} diff --git a/packages/better_networking/test/utils/auth/auth_models_test.dart b/packages/better_networking/test/utils/auth/auth_models_test.dart new file mode 100644 index 000000000..1c7b0cd23 --- /dev/null +++ b/packages/better_networking/test/utils/auth/auth_models_test.dart @@ -0,0 +1,340 @@ +import 'package:better_networking/better_networking.dart'; +import 'package:test/test.dart'; + +void main() { + group('AuthModel Tests', () { + test('should create AuthModel with none type', () { + const authModel = AuthModel(type: APIAuthType.none); + + expect(authModel.type, APIAuthType.none); + expect(authModel.basic, isNull); + expect(authModel.bearer, isNull); + expect(authModel.apikey, isNull); + expect(authModel.jwt, isNull); + expect(authModel.digest, isNull); + }); + + test('should create AuthModel with basic authentication', () { + const basicAuth = AuthBasicAuthModel( + username: 'testuser', + password: 'testpass', + ); + + const authModel = AuthModel( + type: APIAuthType.basic, + basic: basicAuth, + ); + + expect(authModel.type, APIAuthType.basic); + expect(authModel.basic, isNotNull); + expect(authModel.basic?.username, 'testuser'); + expect(authModel.basic?.password, 'testpass'); + }); + + test('should create AuthModel with bearer token', () { + const bearerAuth = AuthBearerModel(token: 'bearer-token-123'); + + const authModel = AuthModel( + type: APIAuthType.bearer, + bearer: bearerAuth, + ); + + expect(authModel.type, APIAuthType.bearer); + expect(authModel.bearer, isNotNull); + expect(authModel.bearer?.token, 'bearer-token-123'); + }); + + test('should create AuthModel with API key authentication', () { + const apiKeyAuth = AuthApiKeyModel( + key: 'api-key-123', + location: 'header', + name: 'X-API-Key', + ); + + const authModel = AuthModel( + type: APIAuthType.apiKey, + apikey: apiKeyAuth, + ); + + expect(authModel.type, APIAuthType.apiKey); + expect(authModel.apikey, isNotNull); + expect(authModel.apikey?.key, 'api-key-123'); + expect(authModel.apikey?.location, 'header'); + expect(authModel.apikey?.name, 'X-API-Key'); + }); + + test('should create AuthModel with JWT authentication', () { + const jwtAuth = AuthJwtModel( + secret: 'jwt-secret', + payload: '{"sub": "1234567890"}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: 'Authorization', + ); + + const authModel = AuthModel( + type: APIAuthType.jwt, + jwt: jwtAuth, + ); + + expect(authModel.type, APIAuthType.jwt); + expect(authModel.jwt, isNotNull); + expect(authModel.jwt?.secret, 'jwt-secret'); + expect(authModel.jwt?.algorithm, 'HS256'); + expect(authModel.jwt?.isSecretBase64Encoded, false); + }); + + test('should create AuthModel with digest authentication', () { + const digestAuth = AuthDigestModel( + username: 'digestuser', + password: 'digestpass', + realm: 'test-realm', + nonce: 'test-nonce', + algorithm: 'MD5', + qop: 'auth', + opaque: 'test-opaque', + ); + + const authModel = AuthModel( + type: APIAuthType.digest, + digest: digestAuth, + ); + + expect(authModel.type, APIAuthType.digest); + expect(authModel.digest, isNotNull); + expect(authModel.digest?.username, 'digestuser'); + expect(authModel.digest?.realm, 'test-realm'); + expect(authModel.digest?.algorithm, 'MD5'); + }); + + test('should serialize and deserialize AuthModel correctly', () { + const originalModel = AuthModel( + type: APIAuthType.basic, + basic: AuthBasicAuthModel( + username: 'testuser', + password: 'testpass', + ), + ); + + final json = originalModel.toJson(); + final deserializedModel = AuthModel.fromJson(json); + + expect(deserializedModel.type, originalModel.type); + expect(deserializedModel.basic?.username, originalModel.basic?.username); + expect(deserializedModel.basic?.password, originalModel.basic?.password); + }); + + test('should handle copyWith for AuthModel', () { + const originalModel = AuthModel( + type: APIAuthType.basic, + basic: AuthBasicAuthModel( + username: 'testuser', + password: 'testpass', + ), + ); + + const newBasicAuth = AuthBasicAuthModel( + username: 'newuser', + password: 'newpass', + ); + + final copiedModel = originalModel.copyWith( + type: APIAuthType.basic, + basic: newBasicAuth, + ); + + expect(copiedModel.type, APIAuthType.basic); + expect(copiedModel.basic?.username, 'newuser'); + expect(copiedModel.basic?.password, 'newpass'); + }); + + test('should handle API key with default values', () { + const apiKeyAuth = AuthApiKeyModel(key: 'test-key'); + + expect(apiKeyAuth.key, 'test-key'); + expect(apiKeyAuth.location, 'header'); + expect(apiKeyAuth.name, 'x-api-key'); + }); + + test('should handle API key with custom values', () { + const apiKeyAuth = AuthApiKeyModel( + key: 'custom-key', + location: 'query', + name: 'api_key', + ); + + expect(apiKeyAuth.key, 'custom-key'); + expect(apiKeyAuth.location, 'query'); + expect(apiKeyAuth.name, 'api_key'); + }); + + test('should handle JWT with private key', () { + const jwtAuth = AuthJwtModel( + secret: 'jwt-secret', + privateKey: 'private-key-content', + payload: '{"sub": "1234567890"}', + addTokenTo: 'header', + algorithm: 'RS256', + isSecretBase64Encoded: true, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: 'Authorization', + ); + + expect(jwtAuth.secret, 'jwt-secret'); + expect(jwtAuth.privateKey, 'private-key-content'); + expect(jwtAuth.algorithm, 'RS256'); + expect(jwtAuth.isSecretBase64Encoded, true); + }); + + test('should handle edge cases with empty strings', () { + const basicAuth = AuthBasicAuthModel( + username: '', + password: '', + ); + + const authModel = AuthModel( + type: APIAuthType.basic, + basic: basicAuth, + ); + + expect(authModel.basic?.username, ''); + expect(authModel.basic?.password, ''); + }); + + test('should handle JSON serialization with null values', () { + const authModel = AuthModel(type: APIAuthType.none); + + final json = authModel.toJson(); + final deserializedModel = AuthModel.fromJson(json); + + expect(deserializedModel.type, APIAuthType.none); + expect(deserializedModel.basic, isNull); + expect(deserializedModel.bearer, isNull); + expect(deserializedModel.apikey, isNull); + expect(deserializedModel.jwt, isNull); + expect(deserializedModel.digest, isNull); + }); + + test('should handle complex JWT payload', () { + const complexPayload = ''' + { + "sub": "1234567890", + "name": "John Doe", + "iat": 1516239022, + "exp": 1516242622, + "roles": ["admin", "user"], + "permissions": { + "read": true, + "write": false + } + } + '''; + + const jwtAuth = AuthJwtModel( + secret: 'complex-secret', + payload: complexPayload, + addTokenTo: 'header', + algorithm: 'HS512', + isSecretBase64Encoded: false, + headerPrefix: 'JWT', + queryParamKey: 'jwt_token', + header: 'X-JWT-Token', + ); + + expect(jwtAuth.payload, complexPayload); + expect(jwtAuth.headerPrefix, 'JWT'); + expect(jwtAuth.queryParamKey, 'jwt_token'); + expect(jwtAuth.header, 'X-JWT-Token'); + }); + + test('should handle digest auth with all parameters', () { + const digestAuth = AuthDigestModel( + username: 'digestuser', + password: 'digestpass', + realm: 'api.example.com', + nonce: 'dcd98b7102dd2f0e8b11d0f600bfb0c093', + algorithm: 'SHA-256', + qop: 'auth-int', + opaque: '5ccc069c403ebaf9f0171e9517f40e41', + ); + + expect(digestAuth.username, 'digestuser'); + expect(digestAuth.password, 'digestpass'); + expect(digestAuth.realm, 'api.example.com'); + expect(digestAuth.nonce, 'dcd98b7102dd2f0e8b11d0f600bfb0c093'); + expect(digestAuth.algorithm, 'SHA-256'); + expect(digestAuth.qop, 'auth-int'); + expect(digestAuth.opaque, '5ccc069c403ebaf9f0171e9517f40e41'); + }); + }); + + test('should handle type mismatch scenarios', () { + // Test when type is basic but bearer data is provided + const authModel = AuthModel( + type: APIAuthType.basic, + bearer: AuthBearerModel(token: 'token'), + ); + + expect(authModel.type, APIAuthType.basic); + expect(authModel.bearer?.token, 'token'); + expect(authModel.basic, isNull); + }); + + test('should handle multiple auth types provided', () { + const authModel = AuthModel( + type: APIAuthType.bearer, + basic: AuthBasicAuthModel(username: 'user', password: 'pass'), + bearer: AuthBearerModel(token: 'token'), + apikey: AuthApiKeyModel(key: 'key'), + ); + + expect(authModel.type, APIAuthType.bearer); + expect(authModel.basic, isNotNull); + expect(authModel.bearer, isNotNull); + expect(authModel.apikey, isNotNull); + }); + + test('should handle serialization with special characters', () { + const basicAuth = AuthBasicAuthModel( + username: 'user@domain.com', + password: r'P@ssw0rd!@#$%^&*()', + ); + + const authModel = AuthModel(type: APIAuthType.basic, basic: basicAuth); + + final json = authModel.toJson(); + final deserializedModel = AuthModel.fromJson(json); + + expect(deserializedModel.basic?.username, 'user@domain.com'); + expect(deserializedModel.basic?.password, r'P@ssw0rd!@#$%^&*()'); + }); + + test('should handle very long strings', () { + final longString = 'a' * 1000; + + final bearerAuth = AuthBearerModel(token: longString); + final authModel = AuthModel(type: APIAuthType.bearer, bearer: bearerAuth); + + expect(authModel.bearer?.token, longString); + expect(authModel.bearer?.token.length, 1000); + }); + + test('should handle Unicode characters', () { + const basicAuth = AuthBasicAuthModel( + username: 'user_测试_тест_テスト', + password: 'password_🔑_🚀_💻', + ); + + const authModel = AuthModel(type: APIAuthType.basic, basic: basicAuth); + + final json = authModel.toJson(); + final deserializedModel = AuthModel.fromJson(json); + + expect(deserializedModel.basic?.username, 'user_测试_тест_テスト'); + expect(deserializedModel.basic?.password, 'password_🔑_🚀_💻'); + }); +} diff --git a/pubspec.lock b/pubspec.lock index d73a53cad..97b7d5b2c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,14 @@ packages: url: "https://pub.dev" source: hosted version: "82.0.0" + adaptive_number: + dependency: transitive + description: + name: adaptive_number + sha256: "3a567544e9b5c9c803006f51140ad544aedc79604fd4f3f2c1380003f97c1d77" + url: "https://pub.dev" + source: hosted + version: "1.0.0" analyzer: dependency: transitive description: @@ -349,6 +357,14 @@ packages: relative: true source: path version: "0.1.3" + dart_jsonwebtoken: + dependency: transitive + description: + name: dart_jsonwebtoken + sha256: "21ce9f8a8712f741e8d6876a9c82c0f8a257fe928c4378a91d8527b92a3fd413" + url: "https://pub.dev" + source: hosted + version: "3.2.0" dart_style: dependency: "direct main" description: @@ -381,6 +397,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.0" + ed25519_edwards: + dependency: transitive + description: + name: ed25519_edwards + sha256: "6ce0112d131327ec6d42beede1e5dfd526069b18ad45dcf654f15074ad9276cd" + url: "https://pub.dev" + source: hosted + version: "0.3.1" equatable: dependency: transitive description: @@ -1246,6 +1270,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "92aa3841d083cc4b0f4709b5c74fd6409a3e6ba833ffc7dc6a8fee096366acf5" + url: "https://pub.dev" + source: hosted + version: "4.0.0" pool: dependency: transitive description: diff --git a/test/models/history_models.dart b/test/models/history_models.dart index 557b3a2ef..6de41dc1b 100644 --- a/test/models/history_models.dart +++ b/test/models/history_models.dart @@ -18,11 +18,11 @@ final historyMetaModel1 = HistoryMetaModel( /// Basic History Request model 1 final historyRequestModel1 = HistoryRequestModel( - historyId: 'historyId1', - metaData: historyMetaModel1, - httpRequestModel: httpRequestModelGet4, - httpResponseModel: responseModel, -); + historyId: 'historyId1', + metaData: historyMetaModel1, + httpRequestModel: httpRequestModelGet4, + httpResponseModel: responseModel, + authModel: AuthModel(type: APIAuthType.none)); final historyMetaModel2 = HistoryMetaModel( historyId: 'historyId2', @@ -35,11 +35,11 @@ final historyMetaModel2 = HistoryMetaModel( ); final historyRequestModel2 = HistoryRequestModel( - historyId: 'historyId2', - metaData: historyMetaModel2, - httpRequestModel: httpRequestModelPost10, - httpResponseModel: responseModel, -); + historyId: 'historyId2', + metaData: historyMetaModel2, + httpRequestModel: httpRequestModelPost10, + httpResponseModel: responseModel, + authModel: AuthModel(type: APIAuthType.none)); /// JSONs final Map historyMetaModelJson1 = { @@ -59,7 +59,15 @@ final Map historyRequestModelJson1 = { "httpRequestModel": httpRequestModelGet4Json, "httpResponseModel": responseModelJson, 'preRequestScript': null, - 'postRequestScript': null + 'postRequestScript': null, + 'authModel': { + 'type': 'none', + 'apikey': null, + 'bearer': null, + 'basic': null, + 'jwt': null, + 'digest': null + } }; final Map historyMetaModelJson2 = { diff --git a/test/models/http_request_model_test.dart b/test/models/http_request_model_test.dart index 78a520978..2a5cd3970 100644 --- a/test/models/http_request_model_test.dart +++ b/test/models/http_request_model_test.dart @@ -83,4 +83,325 @@ void main() { var httpRequestModel3 = httpRequestModel.copyWith(headers: null); expect(httpRequestModel3.headers, null); }); + + group('HttpRequestModel Auth Tests', () { + test('should create HttpRequestModel with no authentication', () { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + expect(httpRequestModel.authModel?.type, APIAuthType.none); + }); + + test('should create HttpRequestModel with basic authentication', () { + const basicAuth = AuthBasicAuthModel( + username: 'testuser', + password: 'testpass', + ); + const authModel = AuthModel( + type: APIAuthType.basic, + basic: basicAuth, + ); + + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + authModel: authModel, + ); + + expect(httpRequestModel.authModel, isNotNull); + expect(httpRequestModel.authModel?.type, APIAuthType.basic); + expect(httpRequestModel.authModel?.basic?.username, 'testuser'); + expect(httpRequestModel.authModel?.basic?.password, 'testpass'); + }); + + test('should create HttpRequestModel with bearer authentication', () { + const bearerAuth = AuthBearerModel(token: 'bearer-token-123'); + const authModel = AuthModel( + type: APIAuthType.bearer, + bearer: bearerAuth, + ); + + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.post, + url: 'https://api.apidash.dev/users', + authModel: authModel, + ); + + expect(httpRequestModel.authModel?.type, APIAuthType.bearer); + expect(httpRequestModel.authModel?.bearer?.token, 'bearer-token-123'); + }); + + test('should create HttpRequestModel with API key authentication', () { + const apiKeyAuth = AuthApiKeyModel( + key: 'api-key-123', + location: 'header', + name: 'X-API-Key', + ); + const authModel = AuthModel( + type: APIAuthType.apiKey, + apikey: apiKeyAuth, + ); + + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + authModel: authModel, + ); + + expect(httpRequestModel.authModel?.type, APIAuthType.apiKey); + expect(httpRequestModel.authModel?.apikey?.key, 'api-key-123'); + expect(httpRequestModel.authModel?.apikey?.location, 'header'); + expect(httpRequestModel.authModel?.apikey?.name, 'X-API-Key'); + }); + + test('should create HttpRequestModel with JWT authentication', () { + const jwtAuth = AuthJwtModel( + secret: 'jwt-secret', + payload: '{"sub": "1234567890"}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: 'Authorization', + ); + const authModel = AuthModel( + type: APIAuthType.jwt, + jwt: jwtAuth, + ); + + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.patch, + url: 'https://api.apidash.dev/users/1', + authModel: authModel, + ); + + expect(httpRequestModel.authModel?.type, APIAuthType.jwt); + expect(httpRequestModel.authModel?.jwt?.secret, 'jwt-secret'); + expect(httpRequestModel.authModel?.jwt?.algorithm, 'HS256'); + expect(httpRequestModel.authModel?.jwt?.isSecretBase64Encoded, false); + }); + + test('should create HttpRequestModel with digest authentication', () { + const digestAuth = AuthDigestModel( + username: 'digestuser', + password: 'digestpass', + realm: 'test-realm', + nonce: 'test-nonce', + algorithm: 'MD5', + qop: 'auth', + opaque: 'test-opaque', + ); + const authModel = AuthModel( + type: APIAuthType.digest, + digest: digestAuth, + ); + + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.delete, + url: 'https://api.apidash.dev/users/1', + authModel: authModel, + ); + + expect(httpRequestModel.authModel?.type, APIAuthType.digest); + expect(httpRequestModel.authModel?.digest?.username, 'digestuser'); + expect(httpRequestModel.authModel?.digest?.realm, 'test-realm'); + expect(httpRequestModel.authModel?.digest?.algorithm, 'MD5'); + }); + + test( + 'should serialize and deserialize HttpRequestModel with auth correctly', + () { + const basicAuth = AuthBasicAuthModel( + username: 'testuser', + password: 'testpass', + ); + const authModel = AuthModel( + type: APIAuthType.basic, + basic: basicAuth, + ); + + const originalModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + authModel: authModel, + ); + + final json = originalModel.toJson(); + final deserializedModel = HttpRequestModel.fromJson(json); + + expect(deserializedModel.method, originalModel.method); + expect(deserializedModel.url, originalModel.url); + expect(deserializedModel.authModel?.type, originalModel.authModel?.type); + expect(deserializedModel.authModel?.basic?.username, + originalModel.authModel?.basic?.username); + expect(deserializedModel.authModel?.basic?.password, + originalModel.authModel?.basic?.password); + }); + + test('should handle copyWith for HttpRequestModel with auth', () { + const originalAuth = AuthBasicAuthModel( + username: 'testuser', + password: 'testpass', + ); + const originalAuthModel = AuthModel( + type: APIAuthType.basic, + basic: originalAuth, + ); + + const originalModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + authModel: originalAuthModel, + ); + + const newAuth = AuthBearerModel(token: 'new-bearer-token'); + const newAuthModel = AuthModel( + type: APIAuthType.bearer, + bearer: newAuth, + ); + + final copiedModel = originalModel.copyWith( + authModel: newAuthModel, + ); + + expect(copiedModel.method, originalModel.method); + expect(copiedModel.url, originalModel.url); + expect(copiedModel.authModel?.type, APIAuthType.bearer); + expect(copiedModel.authModel?.bearer?.token, 'new-bearer-token'); + }); + + test('should handle HttpRequestModel with complex auth scenarios', () { + const complexPayload = ''' + { + "sub": "1234567890", + "name": "John Doe", + "iat": 1516239022, + "exp": 1516242622, + "roles": ["admin", "user"], + "permissions": { + "read": true, + "write": false + } + } + '''; + + const jwtAuth = AuthJwtModel( + secret: 'complex-secret', + privateKey: 'private-key-content', + payload: complexPayload, + addTokenTo: 'query', + algorithm: 'RS256', + isSecretBase64Encoded: true, + headerPrefix: 'JWT', + queryParamKey: 'jwt_token', + header: 'X-JWT-Token', + ); + const authModel = AuthModel( + type: APIAuthType.jwt, + jwt: jwtAuth, + ); + + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.post, + url: 'https://api.apidash.dev/secure-endpoint', + authModel: authModel, + headers: [ + NameValueModel(name: 'Content-Type', value: 'application/json'), + NameValueModel(name: 'Accept', value: 'application/json'), + ], + ); + + expect(httpRequestModel.authModel?.jwt?.payload, complexPayload); + expect( + httpRequestModel.authModel?.jwt?.privateKey, 'private-key-content'); + expect(httpRequestModel.authModel?.jwt?.algorithm, 'RS256'); + expect(httpRequestModel.authModel?.jwt?.isSecretBase64Encoded, true); + expect(httpRequestModel.authModel?.jwt?.addTokenTo, 'query'); + }); + + test('should handle HttpRequestModel with auth and other fields', () { + const apiKeyAuth = AuthApiKeyModel( + key: 'api-key-123', + location: 'header', + name: 'X-API-Key', + ); + const authModel = AuthModel( + type: APIAuthType.apiKey, + apikey: apiKeyAuth, + ); + + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.post, + url: 'https://api.apidash.dev/users', + authModel: authModel, + headers: [ + NameValueModel(name: 'Content-Type', value: 'application/json'), + NameValueModel(name: 'Accept', value: 'application/json'), + ], + params: [ + NameValueModel(name: 'limit', value: '10'), + NameValueModel(name: 'offset', value: '0'), + ], + body: '{"name": "John Doe", "email": "john@example.com"}', + bodyContentType: ContentType.json, + ); + + expect(httpRequestModel.authModel?.type, APIAuthType.apiKey); + expect(httpRequestModel.authModel?.apikey?.key, 'api-key-123'); + expect(httpRequestModel.headers?.length, 2); + expect(httpRequestModel.params?.length, 2); + expect(httpRequestModel.body, + '{"name": "John Doe", "email": "john@example.com"}'); + expect(httpRequestModel.bodyContentType, ContentType.json); + }); + + test('should handle HttpRequestModel with multiple auth types in sequence', + () { + const originalAuth = AuthBasicAuthModel( + username: 'testuser', + password: 'testpass', + ); + const originalAuthModel = AuthModel( + type: APIAuthType.basic, + basic: originalAuth, + ); + + var httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + authModel: originalAuthModel, + ); + + expect(httpRequestModel.authModel?.type, APIAuthType.basic); + + // Change to bearer + const bearerAuth = AuthBearerModel(token: 'bearer-token'); + const bearerAuthModel = AuthModel( + type: APIAuthType.bearer, + bearer: bearerAuth, + ); + + httpRequestModel = httpRequestModel.copyWith(authModel: bearerAuthModel); + expect(httpRequestModel.authModel?.type, APIAuthType.bearer); + + // Change to API key + const apiKeyAuth = AuthApiKeyModel( + key: 'api-key', + location: 'query', + name: 'key', + ); + const apiKeyAuthModel = AuthModel( + type: APIAuthType.apiKey, + apikey: apiKeyAuth, + ); + + httpRequestModel = httpRequestModel.copyWith(authModel: apiKeyAuthModel); + expect(httpRequestModel.authModel?.type, APIAuthType.apiKey); + expect(httpRequestModel.authModel?.apikey?.location, 'query'); + expect(httpRequestModel.authModel?.apikey?.name, 'key'); + }); + }); } diff --git a/test/models/http_request_models.dart b/test/models/http_request_models.dart index 10b84edaf..f5980fbe6 100644 --- a/test/models/http_request_models.dart +++ b/test/models/http_request_models.dart @@ -384,6 +384,14 @@ const httpRequestModelGet4Json = { {'name': 'add_space', 'value': 'true'}, {'name': 'trailing_zeros', 'value': 'true'} ], + 'authModel': { + 'type': 'none', + 'apikey': null, + 'bearer': null, + 'basic': null, + 'jwt': null, + 'digest': null + }, "isHeaderEnabledList": null, "isParamEnabledList": null, "bodyContentType": "json", @@ -403,6 +411,14 @@ const httpRequestModelPost10Json = { {'name': 'size', 'value': '2'}, {'name': 'len', 'value': '3'} ], + 'authModel': { + 'type': 'none', + 'apikey': null, + 'bearer': null, + 'basic': null, + 'jwt': null, + 'digest': null + }, 'isHeaderEnabledList': [false, true], 'isParamEnabledList': null, "bodyContentType": 'json', diff --git a/test/models/request_models.dart b/test/models/request_models.dart index 9c89bc19c..1762706cc 100644 --- a/test/models/request_models.dart +++ b/test/models/request_models.dart @@ -7,7 +7,6 @@ import 'http_response_models.dart'; const requestModelGet1 = RequestModel( id: 'get1', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet1, ); @@ -15,7 +14,6 @@ const requestModelGet1 = RequestModel( const requestModelGet2 = RequestModel( id: 'get2', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet2, ); @@ -23,7 +21,6 @@ const requestModelGet2 = RequestModel( const requestModelGet3 = RequestModel( id: 'get3', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet3, ); @@ -31,7 +28,6 @@ const requestModelGet3 = RequestModel( const requestModelGet4 = RequestModel( id: 'get4', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet4, ); @@ -39,7 +35,6 @@ const requestModelGet4 = RequestModel( const requestModelGet5 = RequestModel( id: 'get5', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet5, ); @@ -47,7 +42,6 @@ const requestModelGet5 = RequestModel( const requestModelGet6 = RequestModel( id: 'get6', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet6, ); @@ -55,7 +49,6 @@ const requestModelGet6 = RequestModel( const requestModelGet7 = RequestModel( id: 'get7', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet7, ); @@ -63,7 +56,6 @@ const requestModelGet7 = RequestModel( const requestModelGet8 = RequestModel( id: 'get8', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet8, ); @@ -71,7 +63,6 @@ const requestModelGet8 = RequestModel( const requestModelGet9 = RequestModel( id: 'get9', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet9, ); @@ -79,7 +70,6 @@ const requestModelGet9 = RequestModel( const requestModelGet10 = RequestModel( id: 'get10', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet10, ); @@ -87,7 +77,6 @@ const requestModelGet10 = RequestModel( const requestModelGet11 = RequestModel( id: 'get11', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet11, ); @@ -95,7 +84,6 @@ const requestModelGet11 = RequestModel( const requestModelGet12 = RequestModel( id: 'get12', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet12, ); @@ -103,7 +91,6 @@ const requestModelGet12 = RequestModel( const requestModelHead1 = RequestModel( id: 'head1', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelHead1, ); @@ -111,7 +98,6 @@ const requestModelHead1 = RequestModel( const requestModelHead2 = RequestModel( id: 'head2', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelHead2, ); @@ -119,7 +105,6 @@ const requestModelHead2 = RequestModel( const requestModelPost1 = RequestModel( id: 'post1', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost1, ); @@ -127,7 +112,6 @@ const requestModelPost1 = RequestModel( const requestModelPost2 = RequestModel( id: 'post2', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost2, ); @@ -135,7 +119,6 @@ const requestModelPost2 = RequestModel( const requestModelPost3 = RequestModel( id: 'post3', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost3, ); @@ -143,7 +126,6 @@ const requestModelPost3 = RequestModel( const requestModelPost4 = RequestModel( id: 'post4', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost4, ); @@ -151,7 +133,6 @@ const requestModelPost4 = RequestModel( const requestModelPost5 = RequestModel( id: 'post5', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost5, ); @@ -159,7 +140,6 @@ const requestModelPost5 = RequestModel( const requestModelPost6 = RequestModel( id: 'post6', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost6, ); @@ -167,7 +147,6 @@ const requestModelPost6 = RequestModel( const requestModelPost7 = RequestModel( id: 'post7', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost7, ); @@ -175,7 +154,6 @@ const requestModelPost7 = RequestModel( const requestModelPost8 = RequestModel( id: 'post8', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost8, ); @@ -183,14 +161,12 @@ const requestModelPost8 = RequestModel( const requestModelPost9 = RequestModel( id: 'post9', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost9, ); const requestModelPost10 = RequestModel( id: 'post9', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost10, ); @@ -198,7 +174,6 @@ const requestModelPost10 = RequestModel( const requestModelPut1 = RequestModel( id: 'put1', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPut1, ); @@ -206,7 +181,6 @@ const requestModelPut1 = RequestModel( const requestModelPatch1 = RequestModel( id: 'patch1', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPatch1, ); @@ -214,7 +188,6 @@ const requestModelPatch1 = RequestModel( const requestModelDelete1 = RequestModel( id: 'delete1', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelDelete1, ); @@ -222,7 +195,6 @@ const requestModelDelete1 = RequestModel( const requestModelDelete2 = RequestModel( id: 'delete2', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelDelete2, ); @@ -230,7 +202,6 @@ const requestModelDelete2 = RequestModel( RequestModel testRequestModel = RequestModel( id: '1', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost10, responseStatus: 200, httpResponseModel: responseModel, @@ -241,7 +212,6 @@ Map requestModelJson = { 'id': '1', 'apiType': 'rest', 'name': '', - 'authModel': '', 'description': '', 'httpRequestModel': httpRequestModelPost10Json, 'responseStatus': 200, @@ -255,7 +225,6 @@ Map requestModelJson = { const requestModelGet13 = RequestModel( id: 'get13', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGet13, ); @@ -263,7 +232,6 @@ const requestModelGet13 = RequestModel( const requestModelGetBadSSL = RequestModel( id: 'badSSL', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelGetBadSSL, ); @@ -271,7 +239,6 @@ const requestModelGetBadSSL = RequestModel( const requestModelPost11 = RequestModel( id: 'post11', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost11, ); @@ -279,7 +246,6 @@ const requestModelPost11 = RequestModel( const requestModelPost12 = RequestModel( id: 'post12', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost12, ); @@ -287,13 +253,11 @@ const requestModelPost12 = RequestModel( const requestModelPost13 = RequestModel( id: 'post13', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelPost13, ); const requestModelOptions1 = RequestModel( id: 'options1', apiType: APIType.rest, - authModel: AuthModel(type: APIAuthType.none), httpRequestModel: httpRequestModelOptions1, ); diff --git a/test/models/response_model_test.dart b/test/models/response_model_test.dart index bef5eff8f..56ba1e2ab 100644 --- a/test/models/response_model_test.dart +++ b/test/models/response_model_test.dart @@ -17,7 +17,7 @@ void main() { var responseRec = await sendHttpRequest( requestModelGet1.id, requestModelGet1.apiType, - requestModelGet1.authModel, + AuthModel(type: APIAuthType.none), requestModelGet1.httpRequestModel!, defaultUriScheme: kDefaultUriScheme, noSSL: false, @@ -36,7 +36,7 @@ void main() { var responseRec = await sendHttpRequest( requestModelGet13.id, requestModelGet13.apiType, - requestModelGet13.authModel, + AuthModel(type: APIAuthType.none), requestModelGet13.httpRequestModel!, defaultUriScheme: kDefaultUriScheme, noSSL: false, @@ -54,7 +54,7 @@ void main() { var responseRec = await sendHttpRequest( requestModelPost11.id, requestModelPost11.apiType, - requestModelPost11.authModel, + AuthModel(type: APIAuthType.none), requestModelPost11.httpRequestModel!, ); @@ -69,7 +69,7 @@ void main() { var responseRec = await sendHttpRequest( requestModelPost12.id, requestModelPost12.apiType, - requestModelPost12.authModel, + AuthModel(type: APIAuthType.none), requestModelPost12.httpRequestModel!, ); @@ -83,7 +83,7 @@ void main() { var responseRec = await sendHttpRequest( requestModelPost13.id, requestModelPost13.apiType, - requestModelPost13.authModel, + AuthModel(type: APIAuthType.none), requestModelPost13.httpRequestModel!, ); @@ -97,7 +97,7 @@ void main() { var responseRec = await sendHttpRequest( requestModelGetBadSSL.id, requestModelGetBadSSL.apiType, - requestModelGetBadSSL.authModel, + AuthModel(type: APIAuthType.none), requestModelGetBadSSL.httpRequestModel!, defaultUriScheme: kDefaultUriScheme, noSSL: false, @@ -110,7 +110,7 @@ void main() { var responseRec = await sendHttpRequest( requestModelGetBadSSL.id, requestModelGetBadSSL.apiType, - requestModelGetBadSSL.authModel, + AuthModel(type: APIAuthType.none), requestModelGetBadSSL.httpRequestModel!, defaultUriScheme: kDefaultUriScheme, noSSL: true, @@ -131,7 +131,7 @@ void main() { var responseRec = await sendHttpRequest( requestModelOptions1.id, requestModelOptions1.apiType, - requestModelOptions1.authModel, + AuthModel(type: APIAuthType.none), requestModelOptions1.httpRequestModel!, defaultUriScheme: kDefaultUriScheme, noSSL: false, @@ -139,9 +139,14 @@ void main() { final responseData = responseModel.fromResponse(response: responseRec.$1!); expect(responseData.statusCode, 200); - expect(responseData.headers?['access-control-allow-methods'], 'GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS'); - expect(responseData.headers?['access-control-allow-methods']?.contains("OPTIONS"), true); - expect(responseData.headers?['allow'], 'GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS'); + expect(responseData.headers?['access-control-allow-methods'], + 'GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS'); + expect( + responseData.headers?['access-control-allow-methods'] + ?.contains("OPTIONS"), + true); + expect(responseData.headers?['allow'], + 'GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS'); expect(responseData.headers?['allow']?.contains("OPTIONS"), true); }); } diff --git a/test/providers/collection_providers_test.dart b/test/providers/collection_providers_test.dart index 097b71f0b..3bf59f83d 100644 --- a/test/providers/collection_providers_test.dart +++ b/test/providers/collection_providers_test.dart @@ -51,4 +51,580 @@ void main() async { // Verify that the Snackbar is shown expect(find.text('Switched to POST method'), findsOneWidget); }, skip: true); + + group('CollectionStateNotifier Auth Tests', () { + late ProviderContainer container; + late CollectionStateNotifier notifier; + + setUp(() { + container = createContainer(); + notifier = container.read(collectionStateNotifierProvider.notifier); + }); + + test('should update request with basic authentication', () { + final id = notifier.state!.entries.first.key; + const basicAuth = AuthBasicAuthModel( + username: 'testuser', + password: 'testpass', + ); + const authModel = AuthModel( + type: APIAuthType.basic, + basic: basicAuth, + ); + + notifier.update(id: id, authModel: authModel); + + final updatedRequest = notifier.getRequestModel(id); + expect( + updatedRequest?.httpRequestModel?.authModel?.type, APIAuthType.basic); + expect(updatedRequest?.httpRequestModel?.authModel?.basic?.username, + 'testuser'); + expect(updatedRequest?.httpRequestModel?.authModel?.basic?.password, + 'testpass'); + }); + + test('should update request with bearer authentication', () { + final id = notifier.state!.entries.first.key; + const bearerAuth = AuthBearerModel(token: 'bearer-token-123'); + const authModel = AuthModel( + type: APIAuthType.bearer, + bearer: bearerAuth, + ); + + notifier.update(id: id, authModel: authModel); + + final updatedRequest = notifier.getRequestModel(id); + expect(updatedRequest?.httpRequestModel?.authModel?.type, + APIAuthType.bearer); + expect(updatedRequest?.httpRequestModel?.authModel?.bearer?.token, + 'bearer-token-123'); + }); + + test('should update request with API key authentication', () { + final id = notifier.state!.entries.first.key; + const apiKeyAuth = AuthApiKeyModel( + key: 'api-key-123', + location: 'header', + name: 'X-API-Key', + ); + const authModel = AuthModel( + type: APIAuthType.apiKey, + apikey: apiKeyAuth, + ); + + notifier.update(id: id, authModel: authModel); + + final updatedRequest = notifier.getRequestModel(id); + expect(updatedRequest?.httpRequestModel?.authModel?.type, + APIAuthType.apiKey); + expect(updatedRequest?.httpRequestModel?.authModel?.apikey?.key, + 'api-key-123'); + expect(updatedRequest?.httpRequestModel?.authModel?.apikey?.location, + 'header'); + expect(updatedRequest?.httpRequestModel?.authModel?.apikey?.name, + 'X-API-Key'); + }); + + test('should update request with JWT authentication', () { + final id = notifier.state!.entries.first.key; + const jwtAuth = AuthJwtModel( + secret: 'jwt-secret', + payload: '{"sub": "1234567890"}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: 'Authorization', + ); + const authModel = AuthModel( + type: APIAuthType.jwt, + jwt: jwtAuth, + ); + + notifier.update(id: id, authModel: authModel); + + final updatedRequest = notifier.getRequestModel(id); + expect( + updatedRequest?.httpRequestModel?.authModel?.type, APIAuthType.jwt); + expect(updatedRequest?.httpRequestModel?.authModel?.jwt?.secret, + 'jwt-secret'); + expect( + updatedRequest?.httpRequestModel?.authModel?.jwt?.algorithm, 'HS256'); + expect( + updatedRequest + ?.httpRequestModel?.authModel?.jwt?.isSecretBase64Encoded, + false); + }); + + test('should update request with digest authentication', () { + final id = notifier.state!.entries.first.key; + const digestAuth = AuthDigestModel( + username: 'digestuser', + password: 'digestpass', + realm: 'test-realm', + nonce: 'test-nonce', + algorithm: 'MD5', + qop: 'auth', + opaque: 'test-opaque', + ); + const authModel = AuthModel( + type: APIAuthType.digest, + digest: digestAuth, + ); + + notifier.update(id: id, authModel: authModel); + + final updatedRequest = notifier.getRequestModel(id); + expect(updatedRequest?.httpRequestModel?.authModel?.type, + APIAuthType.digest); + expect(updatedRequest?.httpRequestModel?.authModel?.digest?.username, + 'digestuser'); + expect(updatedRequest?.httpRequestModel?.authModel?.digest?.realm, + 'test-realm'); + expect(updatedRequest?.httpRequestModel?.authModel?.digest?.algorithm, + 'MD5'); + }); + + test('should remove authentication when set to none', () { + final id = notifier.state!.entries.first.key; + + // First add auth + const basicAuth = AuthBasicAuthModel( + username: 'testuser', + password: 'testpass', + ); + const authModel = AuthModel( + type: APIAuthType.basic, + basic: basicAuth, + ); + notifier.update(id: id, authModel: authModel); + + // Then remove auth + const noAuthModel = AuthModel(type: APIAuthType.none); + notifier.update(id: id, authModel: noAuthModel); + + final updatedRequest = notifier.getRequestModel(id); + expect( + updatedRequest?.httpRequestModel?.authModel?.type, APIAuthType.none); + expect(updatedRequest?.httpRequestModel?.authModel?.basic, isNull); + }); + + test('should preserve auth when duplicating request', () { + final id = notifier.state!.entries.first.key; + const basicAuth = AuthBasicAuthModel( + username: 'testuser', + password: 'testpass', + ); + const authModel = AuthModel( + type: APIAuthType.basic, + basic: basicAuth, + ); + + notifier.update(id: id, authModel: authModel); + notifier.duplicate(id: id); + + final sequence = container.read(requestSequenceProvider); + final duplicatedId = sequence.firstWhere((element) => element != id); + final duplicatedRequest = notifier.getRequestModel(duplicatedId); + + expect(duplicatedRequest?.httpRequestModel?.authModel?.type, + APIAuthType.basic); + expect(duplicatedRequest?.httpRequestModel?.authModel?.basic?.username, + 'testuser'); + expect(duplicatedRequest?.httpRequestModel?.authModel?.basic?.password, + 'testpass'); + }); + + test('should not clear auth when clearing response', () { + final id = notifier.state!.entries.first.key; + const bearerAuth = AuthBearerModel(token: 'bearer-token-123'); + const authModel = AuthModel( + type: APIAuthType.bearer, + bearer: bearerAuth, + ); + + notifier.update(id: id, authModel: authModel); + notifier.clearResponse(id: id); + + final updatedRequest = notifier.getRequestModel(id); + // Auth should be preserved when clearing response + expect(updatedRequest?.httpRequestModel?.authModel?.type, + APIAuthType.bearer); + expect(updatedRequest?.httpRequestModel?.authModel?.bearer?.token, + 'bearer-token-123'); + }); + + test('should handle auth with special characters', () { + final id = notifier.state!.entries.first.key; + const basicAuth = AuthBasicAuthModel( + username: 'user@domain.com', + password: r'P@ssw0rd!@#$%^&*()', + ); + const authModel = AuthModel( + type: APIAuthType.basic, + basic: basicAuth, + ); + + notifier.update(id: id, authModel: authModel); + + final updatedRequest = notifier.getRequestModel(id); + expect(updatedRequest?.httpRequestModel?.authModel?.basic?.username, + 'user@domain.com'); + expect(updatedRequest?.httpRequestModel?.authModel?.basic?.password, + r'P@ssw0rd!@#$%^&*()'); + }); + + test('should handle multiple auth type changes', () { + final id = notifier.state!.entries.first.key; + + // Start with basic auth + const basicAuth = AuthBasicAuthModel( + username: 'testuser', + password: 'testpass', + ); + const basicAuthModel = AuthModel( + type: APIAuthType.basic, + basic: basicAuth, + ); + notifier.update(id: id, authModel: basicAuthModel); + + // Switch to bearer + const bearerAuth = AuthBearerModel(token: 'bearer-token-123'); + const bearerAuthModel = AuthModel( + type: APIAuthType.bearer, + bearer: bearerAuth, + ); + notifier.update(id: id, authModel: bearerAuthModel); + + // Switch to API key + const apiKeyAuth = AuthApiKeyModel( + key: 'api-key-123', + location: 'query', + name: 'apikey', + ); + const apiKeyAuthModel = AuthModel( + type: APIAuthType.apiKey, + apikey: apiKeyAuth, + ); + notifier.update(id: id, authModel: apiKeyAuthModel); + + final updatedRequest = notifier.getRequestModel(id); + expect(updatedRequest?.httpRequestModel?.authModel?.type, + APIAuthType.apiKey); + expect(updatedRequest?.httpRequestModel?.authModel?.apikey?.key, + 'api-key-123'); + expect(updatedRequest?.httpRequestModel?.authModel?.apikey?.location, + 'query'); + expect( + updatedRequest?.httpRequestModel?.authModel?.apikey?.name, 'apikey'); + }); + + test('should handle empty auth values', () { + final id = notifier.state!.entries.first.key; + const basicAuth = AuthBasicAuthModel( + username: '', + password: '', + ); + const authModel = AuthModel( + type: APIAuthType.basic, + basic: basicAuth, + ); + + notifier.update(id: id, authModel: authModel); + + final updatedRequest = notifier.getRequestModel(id); + expect( + updatedRequest?.httpRequestModel?.authModel?.type, APIAuthType.basic); + expect(updatedRequest?.httpRequestModel?.authModel?.basic?.username, ''); + expect(updatedRequest?.httpRequestModel?.authModel?.basic?.password, ''); + }); + + test('should save and load auth data correctly', () async { + final notifier = container.read(collectionStateNotifierProvider.notifier); + + final id = notifier.state!.entries.first.key; + const jwtAuth = AuthJwtModel( + secret: 'jwt-secret', + payload: '{"sub": "1234567890"}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: 'Authorization', + ); + const authModel = AuthModel( + type: APIAuthType.jwt, + jwt: jwtAuth, + ); + + notifier.update(id: id, authModel: authModel); + await notifier.saveData(); + + // Create new container and load data + late ProviderContainer newContainer; + try { + newContainer = ProviderContainer(); + + // Wait for the container to initialize by accessing the provider + final newNotifier = + newContainer.read(collectionStateNotifierProvider.notifier); + + // Give some time for the microtask in the constructor to complete + await Future.delayed(const Duration(milliseconds: 10)); + + final loadedRequest = newNotifier.getRequestModel(id); + + expect( + loadedRequest?.httpRequestModel?.authModel?.type, APIAuthType.jwt); + expect(loadedRequest?.httpRequestModel?.authModel?.jwt?.secret, + 'jwt-secret'); + expect(loadedRequest?.httpRequestModel?.authModel?.jwt?.algorithm, + 'HS256'); + } finally { + newContainer.dispose(); + } + }); + + test('should handle auth in addRequestModel', () { + const basicAuth = AuthBasicAuthModel( + username: 'testuser', + password: 'testpass', + ); + const authModel = AuthModel( + type: APIAuthType.basic, + basic: basicAuth, + ); + + final httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.example.com/users', + authModel: authModel, + ); + + notifier.addRequestModel(httpRequestModel, name: 'Test Request'); + + final sequence = container.read(requestSequenceProvider); + final addedRequest = notifier.getRequestModel(sequence.first); + + expect( + addedRequest?.httpRequestModel?.authModel?.type, APIAuthType.basic); + expect(addedRequest?.httpRequestModel?.authModel?.basic?.username, + 'testuser'); + expect(addedRequest?.httpRequestModel?.authModel?.basic?.password, + 'testpass'); + }); + + test('should handle complex JWT configuration', () { + final id = notifier.state!.entries.first.key; + const complexPayload = ''' + { + "sub": "1234567890", + "name": "John Doe", + "iat": 1516239022, + "exp": 1516242622, + "roles": ["admin", "user"], + "permissions": { + "read": true, + "write": false + } + } + '''; + + const jwtAuth = AuthJwtModel( + secret: 'complex-secret', + privateKey: 'private-key-content', + payload: complexPayload, + addTokenTo: 'query', + algorithm: 'RS256', + isSecretBase64Encoded: true, + headerPrefix: 'JWT', + queryParamKey: 'jwt_token', + header: 'X-JWT-Token', + ); + const authModel = AuthModel( + type: APIAuthType.jwt, + jwt: jwtAuth, + ); + + notifier.update(id: id, authModel: authModel); + + final updatedRequest = notifier.getRequestModel(id); + expect( + updatedRequest?.httpRequestModel?.authModel?.type, APIAuthType.jwt); + expect(updatedRequest?.httpRequestModel?.authModel?.jwt?.payload, + complexPayload); + expect(updatedRequest?.httpRequestModel?.authModel?.jwt?.privateKey, + 'private-key-content'); + expect( + updatedRequest?.httpRequestModel?.authModel?.jwt?.algorithm, 'RS256'); + expect( + updatedRequest + ?.httpRequestModel?.authModel?.jwt?.isSecretBase64Encoded, + true); + expect(updatedRequest?.httpRequestModel?.authModel?.jwt?.addTokenTo, + 'query'); + }); + + test('should handle API key in different locations', () { + final id = notifier.state!.entries.first.key; + + // Test header location + const headerApiKey = AuthApiKeyModel( + key: 'header-key', + location: 'header', + name: 'X-API-Key', + ); + const headerAuthModel = AuthModel( + type: APIAuthType.apiKey, + apikey: headerApiKey, + ); + notifier.update(id: id, authModel: headerAuthModel); + + var updatedRequest = notifier.getRequestModel(id); + expect(updatedRequest?.httpRequestModel?.authModel?.apikey?.location, + 'header'); + expect(updatedRequest?.httpRequestModel?.authModel?.apikey?.name, + 'X-API-Key'); + + // Test query location + const queryApiKey = AuthApiKeyModel( + key: 'query-key', + location: 'query', + name: 'apikey', + ); + const queryAuthModel = AuthModel( + type: APIAuthType.apiKey, + apikey: queryApiKey, + ); + notifier.update(id: id, authModel: queryAuthModel); + + updatedRequest = notifier.getRequestModel(id); + expect(updatedRequest?.httpRequestModel?.authModel?.apikey?.location, + 'query'); + expect( + updatedRequest?.httpRequestModel?.authModel?.apikey?.name, 'apikey'); + }); + + test('should handle digest auth with different algorithms', () { + final id = notifier.state!.entries.first.key; + + // Test MD5 algorithm + const md5DigestAuth = AuthDigestModel( + username: 'digestuser', + password: 'digestpass', + realm: 'test-realm', + nonce: 'test-nonce', + algorithm: 'MD5', + qop: 'auth', + opaque: 'test-opaque', + ); + const md5AuthModel = AuthModel( + type: APIAuthType.digest, + digest: md5DigestAuth, + ); + notifier.update(id: id, authModel: md5AuthModel); + + var updatedRequest = notifier.getRequestModel(id); + expect(updatedRequest?.httpRequestModel?.authModel?.digest?.algorithm, + 'MD5'); + + // Test SHA-256 algorithm + const sha256DigestAuth = AuthDigestModel( + username: 'digestuser', + password: 'digestpass', + realm: 'test-realm', + nonce: 'test-nonce', + algorithm: 'SHA-256', + qop: 'auth-int', + opaque: 'test-opaque', + ); + const sha256AuthModel = AuthModel( + type: APIAuthType.digest, + digest: sha256DigestAuth, + ); + notifier.update(id: id, authModel: sha256AuthModel); + + updatedRequest = notifier.getRequestModel(id); + expect(updatedRequest?.httpRequestModel?.authModel?.digest?.algorithm, + 'SHA-256'); + expect( + updatedRequest?.httpRequestModel?.authModel?.digest?.qop, 'auth-int'); + }); + + test('should handle auth model copyWith functionality', () { + final id = notifier.state!.entries.first.key; + const originalAuth = AuthBasicAuthModel( + username: 'original', + password: 'original', + ); + const originalAuthModel = AuthModel( + type: APIAuthType.basic, + basic: originalAuth, + ); + + notifier.update(id: id, authModel: originalAuthModel); + + // Update with copyWith + const updatedAuth = AuthBasicAuthModel( + username: 'updated', + password: 'updated', + ); + final updatedAuthModel = originalAuthModel.copyWith( + basic: updatedAuth, + ); + + notifier.update(id: id, authModel: updatedAuthModel); + + final updatedRequest = notifier.getRequestModel(id); + expect(updatedRequest?.httpRequestModel?.authModel?.basic?.username, + 'updated'); + expect(updatedRequest?.httpRequestModel?.authModel?.basic?.password, + 'updated'); + }); + + test('should handle auth with very long tokens', () { + final id = notifier.state!.entries.first.key; + final longToken = 'a' * 5000; // Very long token + + final bearerAuth = AuthBearerModel(token: longToken); + final authModel = AuthModel( + type: APIAuthType.bearer, + bearer: bearerAuth, + ); + + notifier.update(id: id, authModel: authModel); + + final updatedRequest = notifier.getRequestModel(id); + expect(updatedRequest?.httpRequestModel?.authModel?.bearer?.token, + longToken); + expect(updatedRequest?.httpRequestModel?.authModel?.bearer?.token.length, + 5000); + }); + + test('should handle auth with Unicode characters', () { + final id = notifier.state!.entries.first.key; + const basicAuth = AuthBasicAuthModel( + username: 'user_测试_тест_テスト', + password: 'password_🔑_🚀_💻', + ); + const authModel = AuthModel( + type: APIAuthType.basic, + basic: basicAuth, + ); + + notifier.update(id: id, authModel: authModel); + + final updatedRequest = notifier.getRequestModel(id); + expect(updatedRequest?.httpRequestModel?.authModel?.basic?.username, + 'user_测试_тест_テスト'); + expect(updatedRequest?.httpRequestModel?.authModel?.basic?.password, + 'password_🔑_🚀_💻'); + }); + + tearDown(() { + container.dispose(); + }); + }); } From a13d3d57d3c5c04c5b9632269b41e5e9cd87739f Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Mon, 7 Jul 2025 12:39:45 +0530 Subject: [PATCH 37/70] tests: add auth fields widget tests(coverage 98.4%) --- .../auth/api_key_auth_fields.dart | 9 +- .../auth/basic_auth_fields.dart | 8 +- .../auth/bearer_auth_fields.dart | 20 +- .../auth/digest_auth_fields.dart | 186 ++++---- .../request_pane/request_auth.dart | 2 - .../auth/api_key_auth_fields_test.dart | 294 +++++++++++++ .../auth/basic_auth_fields_test.dart | 231 ++++++++++ .../auth/bearer_auth_fields_test.dart | 237 ++++++++++ .../auth/digest_auth_fields_test.dart | 405 ++++++++++++++++++ .../auth/jwt_auth_fields_test.dart | 372 ++++++++++++++++ 10 files changed, 1665 insertions(+), 99 deletions(-) create mode 100644 test/screens/common_widgets/auth/api_key_auth_fields_test.dart create mode 100644 test/screens/common_widgets/auth/basic_auth_fields_test.dart create mode 100644 test/screens/common_widgets/auth/bearer_auth_fields_test.dart create mode 100644 test/screens/common_widgets/auth/digest_auth_fields_test.dart create mode 100644 test/screens/common_widgets/auth/jwt_auth_fields_test.dart diff --git a/lib/screens/common_widgets/auth/api_key_auth_fields.dart b/lib/screens/common_widgets/auth/api_key_auth_fields.dart index a32e3d423..8fd272c92 100644 --- a/lib/screens/common_widgets/auth/api_key_auth_fields.dart +++ b/lib/screens/common_widgets/auth/api_key_auth_fields.dart @@ -92,7 +92,14 @@ class _ApiKeyAuthFieldsState extends State { name: _nameController.text.trim(), location: _addKeyTo, ), - ), + ) ?? AuthModel( + type: APIAuthType.apiKey, + apikey: AuthApiKeyModel( + key: _keyController.text.trim(), + name: _nameController.text.trim(), + location: _addKeyTo, + ), + ) ); } } diff --git a/lib/screens/common_widgets/auth/basic_auth_fields.dart b/lib/screens/common_widgets/auth/basic_auth_fields.dart index 6cb6ad1ac..91f30336b 100644 --- a/lib/screens/common_widgets/auth/basic_auth_fields.dart +++ b/lib/screens/common_widgets/auth/basic_auth_fields.dart @@ -61,7 +61,13 @@ class BasicAuthFields extends StatelessWidget { username: usernameController.text.trim(), password: passwordController.text.trim(), ), - ), + ) ?? AuthModel( + type: APIAuthType.basic, + basic: AuthBasicAuthModel( + username: usernameController.text.trim(), + password: passwordController.text.trim(), + ), + ) ); } } diff --git a/lib/screens/common_widgets/auth/bearer_auth_fields.dart b/lib/screens/common_widgets/auth/bearer_auth_fields.dart index 322ab52b1..0569831f1 100644 --- a/lib/screens/common_widgets/auth/bearer_auth_fields.dart +++ b/lib/screens/common_widgets/auth/bearer_auth_fields.dart @@ -40,13 +40,17 @@ class _BearerAuthFieldsState extends State { } void _updateBearerAuth() { - widget.updateAuth( - widget.authData?.copyWith( - type: APIAuthType.bearer, - bearer: AuthBearerModel( - token: _tokenController.text.trim(), - ), - ), - ); + widget.updateAuth(widget.authData?.copyWith( + type: APIAuthType.bearer, + bearer: AuthBearerModel( + token: _tokenController.text.trim(), + ), + ) ?? + AuthModel( + type: APIAuthType.bearer, + bearer: AuthBearerModel( + token: _tokenController.text.trim(), + ), + )); } } diff --git a/lib/screens/common_widgets/auth/digest_auth_fields.dart b/lib/screens/common_widgets/auth/digest_auth_fields.dart index 7fc7850b0..859f3cec7 100644 --- a/lib/screens/common_widgets/auth/digest_auth_fields.dart +++ b/lib/screens/common_widgets/auth/digest_auth_fields.dart @@ -43,97 +43,109 @@ class _DigestAuthFieldsState extends State { @override Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AuthTextField( - readOnly: widget.readOnly, - controller: _usernameController, - hintText: "Username", - onChanged: (_) => _updateDigestAuth(), - ), - const SizedBox(height: 16), - AuthTextField( - readOnly: widget.readOnly, - controller: _passwordController, - hintText: "Password", - isObscureText: true, - onChanged: (_) => _updateDigestAuth(), - ), - const SizedBox(height: 16), - AuthTextField( - readOnly: widget.readOnly, - controller: _realmController, - hintText: "Realm", - onChanged: (_) => _updateDigestAuth(), - ), - const SizedBox(height: 16), - AuthTextField( - readOnly: widget.readOnly, - controller: _nonceController, - hintText: "Nonce", - onChanged: (_) => _updateDigestAuth(), - ), - const SizedBox(height: 16), - Text( - "Algorithm", - style: TextStyle( - fontWeight: FontWeight.normal, - fontSize: 14, + return SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AuthTextField( + readOnly: widget.readOnly, + controller: _usernameController, + hintText: "Username", + onChanged: (_) => _updateDigestAuth(), ), - ), - SizedBox(height: 4), - ADPopupMenu( - value: _algorithmController.trim(), - values: const [ - ('MD5', 'MD5'), - ('MD5-sess', 'MD5-sess'), - ('SHA-256', 'SHA-256'), - ('SHA-256-sess', 'SHA-256-sess'), - ], - tooltip: "this algorithm will be used to produce the digest", - isOutlined: true, - onChanged: (String? newLocation) { - if (newLocation != null) { - setState(() { - _algorithmController = newLocation; - }); - _updateDigestAuth(); - } - }, - ), - const SizedBox(height: 16), - AuthTextField( - readOnly: widget.readOnly, - controller: _qopController, - hintText: "QOP (e.g. auth)", - onChanged: (_) => _updateDigestAuth(), - ), - const SizedBox(height: 16), - AuthTextField( - readOnly: widget.readOnly, - controller: _opaqueController, - hintText: "Opaque", - onChanged: (_) => _updateDigestAuth(), - ), - ], + const SizedBox(height: 12), + AuthTextField( + readOnly: widget.readOnly, + controller: _passwordController, + hintText: "Password", + isObscureText: true, + onChanged: (_) => _updateDigestAuth(), + ), + const SizedBox(height: 12), + AuthTextField( + readOnly: widget.readOnly, + controller: _realmController, + hintText: "Realm", + onChanged: (_) => _updateDigestAuth(), + ), + const SizedBox(height: 12), + AuthTextField( + readOnly: widget.readOnly, + controller: _nonceController, + hintText: "Nonce", + onChanged: (_) => _updateDigestAuth(), + ), + const SizedBox(height: 12), + Text( + "Algorithm", + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: 14, + ), + ), + SizedBox(height: 4), + ADPopupMenu( + value: _algorithmController.trim(), + values: const [ + ('MD5', 'MD5'), + ('MD5-sess', 'MD5-sess'), + ('SHA-256', 'SHA-256'), + ('SHA-256-sess', 'SHA-256-sess'), + ], + tooltip: "this algorithm will be used to produce the digest", + isOutlined: true, + onChanged: (String? newLocation) { + if (newLocation != null) { + setState(() { + _algorithmController = newLocation; + }); + _updateDigestAuth(); + } + }, + ), + const SizedBox(height: 12), + AuthTextField( + readOnly: widget.readOnly, + controller: _qopController, + hintText: "QOP (e.g. auth)", + onChanged: (_) => _updateDigestAuth(), + ), + const SizedBox(height: 12), + AuthTextField( + readOnly: widget.readOnly, + controller: _opaqueController, + hintText: "Opaque", + onChanged: (_) => _updateDigestAuth(), + ), + ], + ), ); } void _updateDigestAuth() { - widget.updateAuth( - widget.authData?.copyWith( - type: APIAuthType.digest, - digest: AuthDigestModel( - username: _usernameController.text.trim(), - password: _passwordController.text.trim(), - realm: _realmController.text.trim(), - nonce: _nonceController.text.trim(), - algorithm: _algorithmController.trim(), - qop: _qopController.text.trim(), - opaque: _opaqueController.text.trim(), - ), - ), - ); + widget.updateAuth(widget.authData?.copyWith( + type: APIAuthType.digest, + digest: AuthDigestModel( + username: _usernameController.text.trim(), + password: _passwordController.text.trim(), + realm: _realmController.text.trim(), + nonce: _nonceController.text.trim(), + algorithm: _algorithmController.trim(), + qop: _qopController.text.trim(), + opaque: _opaqueController.text.trim(), + ), + ) ?? + AuthModel( + type: APIAuthType.digest, + digest: AuthDigestModel( + username: _usernameController.text.trim(), + password: _passwordController.text.trim(), + realm: _realmController.text.trim(), + nonce: _nonceController.text.trim(), + algorithm: _algorithmController.trim(), + qop: _qopController.text.trim(), + opaque: _opaqueController.text.trim(), + ), + )); } } diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index 971d98dd0..fd3e63621 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -92,8 +92,6 @@ class EditAuthType extends ConsumerWidget { ), ); } - - // ...existing code... Widget _buildAuthFields( BuildContext context, WidgetRef ref, diff --git a/test/screens/common_widgets/auth/api_key_auth_fields_test.dart b/test/screens/common_widgets/auth/api_key_auth_fields_test.dart new file mode 100644 index 000000000..19f80080c --- /dev/null +++ b/test/screens/common_widgets/auth/api_key_auth_fields_test.dart @@ -0,0 +1,294 @@ +import 'package:apidash/screens/common_widgets/auth/api_key_auth_fields.dart'; +import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('ApiKeyAuthFields Widget Tests', () { + late AuthModel? mockAuthData; + late Function(AuthModel?) mockUpdateAuth; + late List capturedAuthUpdates; + + setUp(() { + capturedAuthUpdates = []; + mockUpdateAuth = (AuthModel? authModel) { + capturedAuthUpdates.add(authModel); + }; + }); + + testWidgets('renders with default values when authData is null', + (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: ApiKeyAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.text('Add to'), findsOneWidget); + expect(find.byType(ADPopupMenu), findsOneWidget); + expect(find.byType(AuthTextField), findsNWidgets(2)); + expect(find.text('Header'), findsOneWidget); + }); + + testWidgets( + 'updates auth data when authData is null and API key value is changed', + (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: ApiKeyAuthFields( + authData: null, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Find the key field (second AuthTextField) + final keyField = find.byType(AuthTextField).last; + await tester.tap(keyField); + await tester.enterText(keyField, 'new-api-key'); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.apikey?.key, 'new-api-key'); + }); + + testWidgets('renders with existing API key auth data', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.apiKey, + apikey: AuthApiKeyModel( + key: 'test-api-key', + name: 'X-API-Key', + location: 'header', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: ApiKeyAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.text('Add to'), findsOneWidget); + expect(find.text('Header'), findsOneWidget); + expect(find.byType(AuthTextField), findsNWidgets(2)); + }); + + testWidgets('renders with query params location', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.apiKey, + apikey: AuthApiKeyModel( + key: 'test-api-key', + name: 'api_key', + location: 'query', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: ApiKeyAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.text('Add to'), findsOneWidget); + expect(find.text('Query Params'), findsOneWidget); + }); + + testWidgets('updates auth data when location dropdown changes', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.apiKey, + apikey: AuthApiKeyModel( + key: 'test-key', + name: 'X-API-Key', + location: 'header', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: ApiKeyAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Find and tap the dropdown + await tester.tap(find.byType(ADPopupMenu)); + await tester.pumpAndSettle(); + + // Select Query Params option + await tester.tap(find.text('Query Params').last); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.apikey?.location, 'query'); + }); + + testWidgets('updates auth data when API key name changes', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.apiKey, + apikey: AuthApiKeyModel( + key: 'test-key', + name: 'X-API-Key', + location: 'header', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: ApiKeyAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Find the name field (first AuthTextField) + final nameField = find.byType(AuthTextField).first; + await tester.tap(nameField); + await tester.enterText(nameField, 'Authorization'); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.apikey?.name, 'Authorization'); + }); + + testWidgets('updates auth data when API key value changes', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.apiKey, + apikey: AuthApiKeyModel( + key: 'old-key', + name: 'X-API-Key', + location: 'header', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: ApiKeyAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Find the key field (second AuthTextField) + final keyField = find.byType(AuthTextField).last; + await tester.tap(keyField); + await tester.enterText(keyField, 'new-api-key'); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.apikey?.key, 'new-api-key'); + }); + + testWidgets('respects readOnly property', (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.apiKey, + apikey: AuthApiKeyModel( + key: 'test-key', + name: 'X-API-Key', + location: 'header', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: ApiKeyAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + readOnly: true, + ), + ), + ), + ); + + // Verify that AuthTextField widgets are rendered + expect(find.byType(AuthTextField), findsNWidgets(2)); + + // The readOnly property should be passed to AuthTextField widgets + // This is verified by the widget structure itself + }); + + testWidgets('displays correct hint texts', (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: ApiKeyAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.text('Add to'), findsOneWidget); + // Check for the existence of the auth text fields + expect(find.byType(AuthTextField), findsNWidgets(2)); + }); + testWidgets('initializes with correct default values', + (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: ApiKeyAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Default location should be header + expect(find.text('Header'), findsOneWidget); + + // Default name should be 'x-api-key' in the text field + expect(find.text('x-api-key'), findsOneWidget); + }); + }); +} diff --git a/test/screens/common_widgets/auth/basic_auth_fields_test.dart b/test/screens/common_widgets/auth/basic_auth_fields_test.dart new file mode 100644 index 000000000..a2ca01bb2 --- /dev/null +++ b/test/screens/common_widgets/auth/basic_auth_fields_test.dart @@ -0,0 +1,231 @@ +import 'package:apidash/screens/common_widgets/auth/basic_auth_fields.dart'; +import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash_core/apidash_core.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('BasicAuthFields Widget Tests', () { + late AuthModel? mockAuthData; + late Function(AuthModel?) mockUpdateAuth; + late List capturedAuthUpdates; + + setUp(() { + capturedAuthUpdates = []; + mockUpdateAuth = (AuthModel? authModel) { + capturedAuthUpdates.add(authModel); + }; + }); + + testWidgets('renders with default values when authData is null', + (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BasicAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.byType(AuthTextField), findsNWidgets(2)); + expect(find.text('Username'), findsNWidgets(2)); + expect(find.text('Password'), findsNWidgets(2)); + }); + + testWidgets('renders with existing basic auth data', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.basic, + basic: AuthBasicAuthModel( + username: 'testuser', + password: 'testpass', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BasicAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.byType(AuthTextField), findsNWidgets(2)); + expect(find.text('Username'), findsExactly(2)); + expect(find.text('Password'), findsExactly(2)); + }); + + testWidgets('updates auth data when username changes', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.basic, + basic: AuthBasicAuthModel( + username: 'olduser', + password: 'password', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BasicAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Find the username field (first AuthTextField) + final usernameField = find.byType(AuthTextField).first; + await tester.tap(usernameField); + await tester.enterText(usernameField, 'newuser'); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.basic?.username, 'newuser'); + expect(lastUpdate?.type, APIAuthType.basic); + }); + + testWidgets('updates auth data when password changes', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.basic, + basic: AuthBasicAuthModel( + username: 'user', + password: 'oldpass', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BasicAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Find the password field (second AuthTextField) + final passwordField = find.byType(AuthTextField).last; + await tester.tap(passwordField); + await tester.enterText(passwordField, 'newpass'); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.basic?.password, 'newpass'); + expect(lastUpdate?.type, APIAuthType.basic); + }); + + testWidgets('respects readOnly property', (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.basic, + basic: AuthBasicAuthModel( + username: 'user', + password: 'pass', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BasicAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + readOnly: true, + ), + ), + ), + ); + + // Verify that AuthTextField widgets are rendered + expect(find.byType(AuthTextField), findsNWidgets(2)); + + // The readOnly property should be passed to AuthTextField widgets + // This is verified by the widget structure itself + }); + + testWidgets('displays correct hint texts', (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BasicAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.byType(AuthTextField), findsNWidgets(2)); + }); + + testWidgets('handles empty auth data gracefully', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.basic, + basic: AuthBasicAuthModel( + username: '', + password: '', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BasicAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.byType(AuthTextField), findsNWidgets(2)); + }); + + testWidgets('creates proper AuthModel on field changes', + (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BasicAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Enter username + final usernameField = find.byType(AuthTextField).first; + await tester.tap(usernameField); + await tester.enterText(usernameField, 'testuser'); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called with correct structure + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.type, APIAuthType.basic); + expect(lastUpdate?.basic?.username, 'testuser'); + }); + }); +} diff --git a/test/screens/common_widgets/auth/bearer_auth_fields_test.dart b/test/screens/common_widgets/auth/bearer_auth_fields_test.dart new file mode 100644 index 000000000..51ef74a94 --- /dev/null +++ b/test/screens/common_widgets/auth/bearer_auth_fields_test.dart @@ -0,0 +1,237 @@ +import 'package:apidash/screens/common_widgets/auth/bearer_auth_fields.dart'; +import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash_core/apidash_core.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('BearerAuthFields Widget Tests', () { + late AuthModel? mockAuthData; + late Function(AuthModel?) mockUpdateAuth; + late List capturedAuthUpdates; + + setUp(() { + capturedAuthUpdates = []; + mockUpdateAuth = (AuthModel? authModel) { + capturedAuthUpdates.add(authModel); + }; + }); + + testWidgets('renders with default values when authData is null', + (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BearerAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.byType(AuthTextField), findsOneWidget); + expect(find.text('Token'), findsNWidgets(2)); + }); + + testWidgets('renders with existing bearer auth data', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.bearer, + bearer: AuthBearerModel( + token: 'test-bearer-token', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BearerAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.byType(AuthTextField), findsOneWidget); + expect(find.text('Token'), findsNWidgets(2)); + }); + + testWidgets('updates auth data when token changes', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.bearer, + bearer: AuthBearerModel( + token: 'old-token', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BearerAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Find the token field + final tokenField = find.byType(AuthTextField); + await tester.tap(tokenField); + await tester.enterText(tokenField, 'new-bearer-token'); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.bearer?.token, 'new-bearer-token'); + expect(lastUpdate?.type, APIAuthType.bearer); + }); + + testWidgets('respects readOnly property', (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.bearer, + bearer: AuthBearerModel( + token: 'test-token', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BearerAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + readOnly: true, + ), + ), + ), + ); + + // Verify that AuthTextField widget is rendered + expect(find.byType(AuthTextField), findsOneWidget); + + // The readOnly property should be passed to AuthTextField widget + // This is verified by the widget structure itself + }); + + testWidgets('displays correct hint text', (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BearerAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.byType(AuthTextField), findsOneWidget); + }); + + testWidgets('handles empty auth data gracefully', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.bearer, + bearer: AuthBearerModel( + token: '', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BearerAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.byType(AuthTextField), findsOneWidget); + }); + + testWidgets('creates proper AuthModel on token change', + (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BearerAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Enter token + final tokenField = find.byType(AuthTextField); + await tester.tap(tokenField); + await tester.enterText(tokenField, 'test-bearer-token'); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called with correct structure + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.type, APIAuthType.bearer); + expect(lastUpdate?.bearer?.token, 'test-bearer-token'); + }); + + testWidgets('initializes with correct default token value', + (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BearerAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // The token field should be empty initially + expect(find.byType(AuthTextField), findsOneWidget); + }); + + testWidgets('trims whitespace from token input', + (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BearerAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Enter token with whitespace + final tokenField = find.byType(AuthTextField); + await tester.tap(tokenField); + await tester.enterText(tokenField, ' test-token '); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called with trimmed token + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.bearer?.token, 'test-token'); + }); + }); +} diff --git a/test/screens/common_widgets/auth/digest_auth_fields_test.dart b/test/screens/common_widgets/auth/digest_auth_fields_test.dart new file mode 100644 index 000000000..0c43e9ad2 --- /dev/null +++ b/test/screens/common_widgets/auth/digest_auth_fields_test.dart @@ -0,0 +1,405 @@ +import 'package:apidash/screens/common_widgets/auth/digest_auth_fields.dart'; +import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash_design_system/widgets/widgets.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('DigestAuthFields Widget Tests', () { + late AuthModel? mockAuthData; + late Function(AuthModel?) mockUpdateAuth; + late List capturedAuthUpdates; + + setUp(() { + capturedAuthUpdates = []; + mockUpdateAuth = (AuthModel? authModel) { + capturedAuthUpdates.add(authModel); + }; + }); + + testWidgets('renders with default values when authData is null', + (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: DigestAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.byType(AuthTextField), findsNWidgets(6)); + expect(find.byType(ADPopupMenu), findsOneWidget); + // Check for field labels (each AuthTextField creates a Text widget for label) + expect(find.text('Username'), findsNWidgets(2)); + expect(find.text('Password'), findsNWidgets(2)); + expect(find.text('Realm'), findsNWidgets(2)); + expect(find.text('Nonce'), findsNWidgets(2)); + expect(find.text('Algorithm'), findsOneWidget); + expect(find.text('QOP (e.g. auth)'), findsNWidgets(2)); + expect(find.text('Opaque'), findsNWidgets(2)); + }); + + testWidgets('renders with existing digest auth data', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.digest, + digest: AuthDigestModel( + username: 'testuser', + password: 'testpass', + realm: 'testrealm', + nonce: 'testnonce', + algorithm: 'MD5', + qop: 'auth', + opaque: 'testopaque', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: DigestAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.byType(AuthTextField), findsNWidgets(6)); + expect(find.byType(ADPopupMenu), findsOneWidget); + expect(find.text('MD5'), findsOneWidget); + }); + + testWidgets('updates auth data when username changes', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.digest, + digest: AuthDigestModel( + username: 'olduser', + password: 'pass', + realm: 'realm', + nonce: 'nonce', + algorithm: 'MD5', + qop: 'auth', + opaque: 'opaque', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: DigestAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Find the username field (first AuthTextField) + final usernameField = find.byType(AuthTextField).first; + await tester.tap(usernameField); + await tester.enterText(usernameField, 'newuser'); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.digest?.username, 'newuser'); + expect(lastUpdate?.type, APIAuthType.digest); + }); + + testWidgets('updates auth data when password changes', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.digest, + digest: AuthDigestModel( + username: 'user', + password: 'oldpass', + realm: 'realm', + nonce: 'nonce', + algorithm: 'MD5', + qop: 'auth', + opaque: 'opaque', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: DigestAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Find the password field (second AuthTextField) + final passwordField = find.byType(AuthTextField).at(1); + await tester.tap(passwordField); + await tester.enterText(passwordField, 'newpass'); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.digest?.password, 'newpass'); + expect(lastUpdate?.type, APIAuthType.digest); + }); + + testWidgets('updates auth data when algorithm dropdown changes', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.digest, + digest: AuthDigestModel( + username: 'user', + password: 'pass', + realm: 'realm', + nonce: 'nonce', + algorithm: 'MD5', + qop: 'auth', + opaque: 'opaque', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: DigestAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Find and tap the algorithm dropdown + await tester.tap(find.byType(ADPopupMenu)); + await tester.pumpAndSettle(); + + // Select SHA-256 option + await tester.tap(find.text('SHA-256').last); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.digest?.algorithm, 'SHA-256'); + }); + + testWidgets('updates auth data when realm changes', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.digest, + digest: AuthDigestModel( + username: 'user', + password: 'pass', + realm: 'oldrealm', + nonce: 'nonce', + algorithm: 'MD5', + qop: 'auth', + opaque: 'opaque', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: DigestAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Find the realm field (third AuthTextField) + final realmField = find.byType(AuthTextField).at(2); + await tester.tap(realmField); + await tester.enterText(realmField, 'newrealm'); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.digest?.realm, 'newrealm'); + }); + + testWidgets('respects readOnly property', (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.digest, + digest: AuthDigestModel( + username: 'user', + password: 'pass', + realm: 'realm', + nonce: 'nonce', + algorithm: 'MD5', + qop: 'auth', + opaque: 'opaque', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: DigestAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + readOnly: true, + ), + ), + ), + ); + + final usernameFieldFinder = find.byType(AuthTextField).first; + + // Try to enter text + await tester.enterText(usernameFieldFinder, 'testuser'); + await tester.pumpAndSettle(); + + // Ensure updateAuth was not called + expect(capturedAuthUpdates, isEmpty); + + // Check the field still shows original value + final textField = tester.widget(usernameFieldFinder); + expect(textField.controller.text, equals('user')); + }); + + testWidgets('displays correct hint texts', (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: DigestAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.byType(AuthTextField), findsNWidgets(6)); + expect(find.byType(ADPopupMenu), findsOneWidget); + expect(find.text('Algorithm'), findsOneWidget); + }); + + testWidgets('initializes with correct default values', + (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: DigestAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Default algorithm should be MD5 + expect(find.text('MD5'), findsOneWidget); + + // Default QOP should be 'auth' - but this is in the TextFormField value, not visible text + // We need to check the controller value instead + expect(find.byType(AuthTextField), findsNWidgets(6)); + }); + + testWidgets('creates proper AuthModel on field changes', + (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: DigestAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Enter username + final usernameField = find.byType(AuthTextField).first; + await tester.tap(usernameField); + await tester.enterText(usernameField, 'testuser'); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called with correct structure + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.type, APIAuthType.digest); + expect(lastUpdate?.digest?.username, 'testuser'); + expect(lastUpdate?.digest?.algorithm, 'MD5'); + }); + + testWidgets('handles all algorithm options correctly', + (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: DigestAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Test each algorithm option + final algorithms = ['MD5', 'MD5-sess', 'SHA-256', 'SHA-256-sess']; + + for (final algorithm in algorithms) { + // Tap the dropdown + await tester.tap(find.byType(ADPopupMenu)); + await tester.pumpAndSettle(); + + // Select the algorithm + await tester.tap(find.text(algorithm).last); + await tester.pumpAndSettle(); + + // Verify the selection + expect(find.text(algorithm), findsOneWidget); + } + }); + + testWidgets('trims whitespace from all field inputs', + (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: DigestAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Enter username with whitespace + final usernameField = find.byType(AuthTextField).first; + await tester.tap(usernameField); + await tester.enterText(usernameField, ' testuser '); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called with trimmed values + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.digest?.username, 'testuser'); + }); + }); +} diff --git a/test/screens/common_widgets/auth/jwt_auth_fields_test.dart b/test/screens/common_widgets/auth/jwt_auth_fields_test.dart new file mode 100644 index 000000000..7856c43b2 --- /dev/null +++ b/test/screens/common_widgets/auth/jwt_auth_fields_test.dart @@ -0,0 +1,372 @@ +import 'package:apidash/screens/common_widgets/auth/jwt_auth_fields.dart'; +import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('JwtAuthFields Widget Tests', () { + late AuthModel? mockAuthData; + late Function(AuthModel?) mockUpdateAuth; + late List capturedAuthUpdates; + + setUp(() { + capturedAuthUpdates = []; + mockUpdateAuth = (AuthModel? authModel) { + capturedAuthUpdates.add(authModel); + }; + }); + + testWidgets('renders with default values when authData is null', + (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: JwtAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.text('Add JWT token to'), findsOneWidget); + expect(find.text('Algorithm'), findsOneWidget); + expect(find.text('Payload (JSON format)'), findsOneWidget); + expect(find.byType(ADPopupMenu), findsNWidgets(2)); + expect(find.text('Request Header'), findsOneWidget); + expect(find.text('HS256'), findsOneWidget); + }); + + testWidgets('renders with existing JWT auth data', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: 'test-secret', + privateKey: '', + payload: '{"sub": "1234567890"}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: 'Authorization', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: JwtAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.text('Add JWT token to'), findsOneWidget); + expect(find.text('Algorithm'), findsOneWidget); + expect(find.text('Request Header'), findsOneWidget); + expect(find.text('HS256'), findsOneWidget); + }); + + testWidgets('shows secret field for HMAC algorithms', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: 'test-secret', + privateKey: '', + payload: '{}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: 'Authorization', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: JwtAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.text('Secret key'), findsExactly(2)); + expect(find.text('Secret is Base64 encoded'), findsOneWidget); + expect(find.byType(AuthTextField), findsOneWidget); + expect(find.byType(CheckboxListTile), findsOneWidget); + }); + + testWidgets('shows private key field for RSA algorithms', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: '', + privateKey: 'test-private-key', + payload: '{}', + addTokenTo: 'header', + algorithm: 'RS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: 'Authorization', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: JwtAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + expect(find.text('Private Key (PEM Format)'), findsOneWidget); + expect(find.text('Secret key'), findsNothing); + expect(find.byType(TextField), findsNWidgets(2)); // Private key + payload + }); + + testWidgets('updates auth data when add token to dropdown changes', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: 'secret', + privateKey: '', + payload: '{}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: 'Authorization', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: JwtAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Find and tap the first dropdown (add token to) + await tester.tap(find.byType(ADPopupMenu).first); + await tester.pumpAndSettle(); + + // Select Query Parameters option + await tester.tap(find.text('Query Parameters').last); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.jwt?.addTokenTo, 'query'); + }); + + testWidgets('updates auth data when algorithm dropdown changes', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: 'secret', + privateKey: '', + payload: '{}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: 'Authorization', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: JwtAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Find and tap the second dropdown (algorithm) + await tester.tap(find.byType(ADPopupMenu).last); + await tester.pumpAndSettle(); + + // Select RS256 option + await tester.tap(find.text('RS256').last); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.jwt?.algorithm, 'RS256'); + }); + + testWidgets('updates auth data when secret changes', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: 'old-secret', + privateKey: '', + payload: '{}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: 'Authorization', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: JwtAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Find the secret field + final secretField = find.byType(AuthTextField).first; + await tester.tap(secretField); + await tester.enterText(secretField, 'new-secret'); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.jwt?.secret, 'new-secret'); + }); + + testWidgets('updates auth data when payload changes', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: 'secret', + privateKey: '', + payload: '{}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: 'Authorization', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: JwtAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Find the payload field (TextField) + final payloadField = find.byType(TextField).last; + await tester.tap(payloadField); + await tester.enterText(payloadField, '{"sub": "1234567890"}'); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.jwt?.payload, '{"sub": "1234567890"}'); + }); + + testWidgets('updates auth data when Base64 checkbox changes', + (WidgetTester tester) async { + mockAuthData = const AuthModel( + type: APIAuthType.jwt, + jwt: AuthJwtModel( + secret: 'secret', + privateKey: '', + payload: '{}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: 'Authorization', + ), + ); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: JwtAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Find and tap the checkbox + await tester.tap(find.byType(CheckboxListTile)); + await tester.pumpAndSettle(); + + // Verify that updateAuth was called + expect(capturedAuthUpdates.length, greaterThan(0)); + final lastUpdate = capturedAuthUpdates.last; + expect(lastUpdate?.jwt?.isSecretBase64Encoded, true); + }); + + testWidgets('initializes with correct default values', + (WidgetTester tester) async { + mockAuthData = null; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: JwtAuthFields( + authData: mockAuthData, + updateAuth: mockUpdateAuth, + ), + ), + ), + ); + + // Default token location should be header + expect(find.text('Request Header'), findsOneWidget); + + // Default algorithm should be HS256 + expect(find.text('HS256'), findsOneWidget); + + // Default Base64 encoded should be false + expect(find.byType(CheckboxListTile), findsOneWidget); + }); + }); +} From dcccc2b761d1588c64c5d7993ef051265a0d9bdc Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Mon, 7 Jul 2025 21:49:09 +0530 Subject: [PATCH 38/70] tests: add api auth model tests(coverage 100%) --- .../test/models/auth/api_auth_model_test.dart | 225 ++++++++++++++++++ .../models/auth/auth_api_key_model_test.dart | 67 ++++++ .../models/auth/auth_basic_model_test.dart | 53 +++++ .../models/auth/auth_bearer_model_test.dart | 57 +++++ .../models/auth/auth_digest_model_test.dart | 87 +++++++ .../test/models/auth/auth_jwt_model_test.dart | 112 +++++++++ .../test/models/auth/auth_models.dart | 212 +++++++++++++++++ .../test/utils/auth/auth_handling_test.dart | 2 +- 8 files changed, 814 insertions(+), 1 deletion(-) create mode 100644 packages/better_networking/test/models/auth/api_auth_model_test.dart create mode 100644 packages/better_networking/test/models/auth/auth_api_key_model_test.dart create mode 100644 packages/better_networking/test/models/auth/auth_basic_model_test.dart create mode 100644 packages/better_networking/test/models/auth/auth_bearer_model_test.dart create mode 100644 packages/better_networking/test/models/auth/auth_digest_model_test.dart create mode 100644 packages/better_networking/test/models/auth/auth_jwt_model_test.dart create mode 100644 packages/better_networking/test/models/auth/auth_models.dart diff --git a/packages/better_networking/test/models/auth/api_auth_model_test.dart b/packages/better_networking/test/models/auth/api_auth_model_test.dart new file mode 100644 index 000000000..6946ed372 --- /dev/null +++ b/packages/better_networking/test/models/auth/api_auth_model_test.dart @@ -0,0 +1,225 @@ +import 'package:better_networking/models/auth/api_auth_model.dart'; +import 'package:better_networking/models/auth/auth_basic_model.dart'; +import 'package:better_networking/models/auth/auth_bearer_model.dart'; +import 'package:better_networking/consts.dart'; +import 'package:test/test.dart'; +import 'auth_models.dart'; + +void main() { + group('Testing AuthModel (API Auth Model)', () { + test("Testing AuthModel copyWith", () { + var authModel = authModel1; + final authModelCopyWith = authModel.copyWith( + type: APIAuthType.bearer, + bearer: const AuthBearerModel(token: 'new-bearer-token'), + basic: null, + ); + expect(authModelCopyWith.type, APIAuthType.bearer); + expect(authModelCopyWith.bearer?.token, 'new-bearer-token'); + expect(authModelCopyWith.basic, null); + // original model unchanged + expect(authModel.type, APIAuthType.basic); + expect(authModel.basic?.username, 'john_doe'); + }); + + test("Testing AuthModel toJson", () { + var authModel = authModel1; + expect(authModel.toJson(), authModelJson1); + }); + + test("Testing AuthModel fromJson for basic authentication", () { + var authModel = authModel1; + final modelFromJson = AuthModel.fromJson(authModelJson1); + expect(modelFromJson, authModel); + expect(modelFromJson.type, APIAuthType.basic); + expect(modelFromJson.basic?.username, 'john_doe'); + expect(modelFromJson.basic?.password, 'secure_password'); + }); + + test("Testing AuthModel fromJson for bearer authentication", () { + var authModel = authModel2; + final modelFromJson = AuthModel.fromJson(authModelJson2); + expect(modelFromJson, authModel); + expect(modelFromJson.type, APIAuthType.bearer); + expect( + modelFromJson.bearer?.token, + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c', + ); + }); + + test("Testing AuthModel fromJson for api key authentication", () { + var authModel = authModel3; + final apiKeyModelJson = { + "type": "apiKey", + "apikey": authApiKeyModelJson1, + "bearer": null, + "basic": null, + "jwt": null, + "digest": null, + }; + final modelFromJson = AuthModel.fromJson(apiKeyModelJson); + expect(modelFromJson, authModel); + expect(modelFromJson.type, APIAuthType.apiKey); + expect(modelFromJson.apikey?.key, 'ak-test-key-12345'); + expect(modelFromJson.apikey?.location, 'header'); + expect(modelFromJson.apikey?.name, 'x-api-key'); + }); + + test("Testing AuthModel fromJson for jwt authentication", () { + var authModel = authModel4; + final jwtModelJson = { + "type": "jwt", + "apikey": null, + "bearer": null, + "basic": null, + "jwt": authJwtModelJson1, + "digest": null, + }; + final modelFromJson = AuthModel.fromJson(jwtModelJson); + expect(modelFromJson, authModel); + expect(modelFromJson.type, APIAuthType.jwt); + expect(modelFromJson.jwt?.secret, 'jwt-secret-key'); + expect(modelFromJson.jwt?.algorithm, 'RS256'); + expect(modelFromJson.jwt?.isSecretBase64Encoded, true); + expect(modelFromJson.jwt?.headerPrefix, 'JWT'); + }); + + test("Testing AuthModel fromJson for digest authentication", () { + var authModel = authModel5; + final digestModelJson = { + "type": "digest", + "apikey": null, + "bearer": null, + "basic": null, + "jwt": null, + "digest": authDigestModelJson1, + }; + final modelFromJson = AuthModel.fromJson(digestModelJson); + expect(modelFromJson, authModel); + expect(modelFromJson.type, APIAuthType.digest); + expect(modelFromJson.digest?.algorithm, 'SHA-256'); + expect(modelFromJson.digest?.username, 'digest_user'); + expect(modelFromJson.digest?.password, 'digest_pass'); + expect(modelFromJson.digest?.realm, 'protected-area'); + expect(modelFromJson.digest?.qop, 'auth-int'); + }); + + test("Testing AuthModel getters for different auth types", () { + expect(authModelNone.type, APIAuthType.none); + expect(authModel1.type, APIAuthType.basic); + expect(authModel2.type, APIAuthType.bearer); + expect(authModel3.type, APIAuthType.apiKey); + expect(authModel4.type, APIAuthType.jwt); + expect(authModel5.type, APIAuthType.digest); + }); + + test("Testing AuthModel with basic authentication", () { + var authModel = authModel1; + expect(authModel.type, APIAuthType.basic); + expect(authModel.basic, isNotNull); + expect(authModel.basic?.username, 'john_doe'); + expect(authModel.basic?.password, 'secure_password'); + expect(authModel.bearer, null); + expect(authModel.apikey, null); + expect(authModel.jwt, null); + expect(authModel.digest, null); + }); + + test("Testing AuthModel with bearer authentication", () { + var authModel = authModel2; + expect(authModel.type, APIAuthType.bearer); + expect(authModel.bearer, isNotNull); + expect( + authModel.bearer?.token, + startsWith('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9'), + ); + expect(authModel.basic, null); + expect(authModel.apikey, null); + expect(authModel.jwt, null); + expect(authModel.digest, null); + }); + + test("Testing AuthModel with API key authentication", () { + var authModel = authModel3; + expect(authModel.type, APIAuthType.apiKey); + expect(authModel.apikey, isNotNull); + expect(authModel.apikey?.key, 'ak-test-key-12345'); + expect(authModel.apikey?.location, 'header'); + expect(authModel.apikey?.name, 'x-api-key'); + expect(authModel.basic, null); + expect(authModel.bearer, null); + expect(authModel.jwt, null); + expect(authModel.digest, null); + }); + + test("Testing AuthModel with JWT authentication", () { + var authModel = authModel4; + expect(authModel.type, APIAuthType.jwt); + expect(authModel.jwt, isNotNull); + expect(authModel.jwt?.secret, 'jwt-secret-key'); + expect(authModel.jwt?.algorithm, 'RS256'); + expect(authModel.jwt?.isSecretBase64Encoded, true); + expect(authModel.basic, null); + expect(authModel.bearer, null); + expect(authModel.apikey, null); + expect(authModel.digest, null); + }); + + test("Testing AuthModel with digest authentication", () { + var authModel = authModel5; + expect(authModel.type, APIAuthType.digest); + expect(authModel.digest, isNotNull); + expect(authModel.digest?.username, 'digest_user'); + expect(authModel.digest?.algorithm, 'SHA-256'); + expect(authModel.digest?.qop, 'auth-int'); + expect(authModel.basic, null); + expect(authModel.bearer, null); + expect(authModel.apikey, null); + expect(authModel.jwt, null); + }); + + test("Testing AuthModel with none authentication", () { + var authModel = authModelNone; + expect(authModel.type, APIAuthType.none); + expect(authModel.basic, null); + expect(authModel.bearer, null); + expect(authModel.apikey, null); + expect(authModel.jwt, null); + expect(authModel.digest, null); + }); + + test("Testing AuthModel equality", () { + const authModel1Copy = AuthModel( + type: APIAuthType.basic, + basic: AuthBasicAuthModel( + username: 'john_doe', + password: 'secure_password', + ), + ); + expect(authModel1, authModel1Copy); + expect(authModel1, isNot(authModel2)); + expect(authModelNone, const AuthModel(type: APIAuthType.none)); + }); + + test("Testing AuthModel JSON serialization for different types", () { + var bearerModel = authModel2; + var bearerJson = bearerModel.toJson(); + expect(bearerJson['type'], 'bearer'); + expect(bearerJson['bearer'], isNotNull); + expect(bearerJson['basic'], null); + + final modelFromJson = AuthModel.fromJson(authModelJson2); + expect(modelFromJson, bearerModel); + }); + + test("Testing AuthModel JSON serialization for none type", () { + var noneModel = authModelNone; + var noneJson = noneModel.toJson(); + expect(noneJson, authModelNoneJson); + + final modelFromJson = AuthModel.fromJson(authModelNoneJson); + expect(modelFromJson, noneModel); + expect(modelFromJson.type, APIAuthType.none); + }); + }); +} diff --git a/packages/better_networking/test/models/auth/auth_api_key_model_test.dart b/packages/better_networking/test/models/auth/auth_api_key_model_test.dart new file mode 100644 index 000000000..8a121b0c7 --- /dev/null +++ b/packages/better_networking/test/models/auth/auth_api_key_model_test.dart @@ -0,0 +1,67 @@ +import 'package:better_networking/models/auth/auth_api_key_model.dart'; +import 'package:test/test.dart'; +import 'auth_models.dart'; + +void main() { + group('Testing AuthApiKeyModel', () { + test("Testing AuthApiKeyModel copyWith", () { + var authApiKeyModel = authApiKeyModel1; + final authApiKeyModelCopyWith = authApiKeyModel.copyWith( + key: 'new_api_key', + location: 'query', + ); + expect(authApiKeyModelCopyWith.key, 'new_api_key'); + expect(authApiKeyModelCopyWith.location, 'query'); + // original model unchanged + expect(authApiKeyModel.key, 'ak-test-key-12345'); + expect(authApiKeyModel.location, 'header'); + expect(authApiKeyModel.name, 'x-api-key'); + }); + + test("Testing AuthApiKeyModel toJson", () { + var authApiKeyModel = authApiKeyModel1; + expect(authApiKeyModel.toJson(), authApiKeyModelJson1); + }); + + test("Testing AuthApiKeyModel fromJson", () { + var authApiKeyModel = authApiKeyModel1; + final modelFromJson = AuthApiKeyModel.fromJson(authApiKeyModelJson1); + expect(modelFromJson, authApiKeyModel); + expect(modelFromJson.key, 'ak-test-key-12345'); + expect(modelFromJson.location, 'header'); + expect(modelFromJson.name, 'x-api-key'); + }); + + test("Testing AuthApiKeyModel getters", () { + var authApiKeyModel = authApiKeyModel1; + expect(authApiKeyModel.key, 'ak-test-key-12345'); + expect(authApiKeyModel.location, 'header'); + expect(authApiKeyModel.name, 'x-api-key'); + }); + + test("Testing AuthApiKeyModel default values", () { + const authApiKeyModelMinimal = AuthApiKeyModel(key: 'test-key'); + expect(authApiKeyModelMinimal.key, 'test-key'); + expect(authApiKeyModelMinimal.location, 'header'); // default value + expect(authApiKeyModelMinimal.name, 'x-api-key'); // default value + }); + + test("Testing AuthApiKeyModel equality", () { + const authApiKeyModel1Copy = AuthApiKeyModel( + key: 'ak-test-key-12345', + location: 'header', + name: 'x-api-key', + ); + expect(authApiKeyModel1, authApiKeyModel1Copy); + expect(authApiKeyModel1, isNot(authApiKeyModel2)); + }); + + test("Testing AuthApiKeyModel with different configurations", () { + expect(authApiKeyModel2.key, 'query-api-key-67890'); + expect(authApiKeyModel2.location, 'query'); + expect(authApiKeyModel2.name, 'api_key'); + expect(authApiKeyModel1.location, isNot(authApiKeyModel2.location)); + expect(authApiKeyModel1.name, isNot(authApiKeyModel2.name)); + }); + }); +} diff --git a/packages/better_networking/test/models/auth/auth_basic_model_test.dart b/packages/better_networking/test/models/auth/auth_basic_model_test.dart new file mode 100644 index 000000000..221c9b150 --- /dev/null +++ b/packages/better_networking/test/models/auth/auth_basic_model_test.dart @@ -0,0 +1,53 @@ +import 'package:better_networking/models/auth/auth_basic_model.dart'; +import 'package:test/test.dart'; +import 'auth_models.dart'; + +void main() { + group('Testing AuthBasicAuthModel', () { + test("Testing AuthBasicAuthModel copyWith", () { + var authBasicModel = authBasicModel1; + final authBasicModelCopyWith = authBasicModel.copyWith( + password: 'new_password', + ); + expect(authBasicModelCopyWith.password, 'new_password'); + // original model unchanged + expect(authBasicModel.username, 'john_doe'); + expect(authBasicModel.password, 'secure_password'); + }); + + test("Testing AuthBasicAuthModel toJson", () { + var authBasicModel = authBasicModel1; + expect(authBasicModel.toJson(), authBasicModelJson1); + }); + + test("Testing AuthBasicAuthModel fromJson", () { + var authBasicModel = authBasicModel1; + final modelFromJson = AuthBasicAuthModel.fromJson(authBasicModelJson1); + expect(modelFromJson, authBasicModel); + expect(modelFromJson.username, 'john_doe'); + expect(modelFromJson.password, 'secure_password'); + }); + + test("Testing AuthBasicAuthModel getters", () { + var authBasicModel = authBasicModel1; + expect(authBasicModel.username, 'john_doe'); + expect(authBasicModel.password, 'secure_password'); + }); + + test("Testing AuthBasicAuthModel equality", () { + const authBasicModel1Copy = AuthBasicAuthModel( + username: 'john_doe', + password: 'secure_password', + ); + expect(authBasicModel1, authBasicModel1Copy); + expect(authBasicModel1, isNot(authBasicModel2)); + }); + + test("Testing AuthBasicAuthModel with different values", () { + expect(authBasicModel2.username, 'jane_smith'); + expect(authBasicModel2.password, 'another_password'); + expect(authBasicModel1.username, isNot(authBasicModel2.username)); + expect(authBasicModel1.password, isNot(authBasicModel2.password)); + }); + }); +} diff --git a/packages/better_networking/test/models/auth/auth_bearer_model_test.dart b/packages/better_networking/test/models/auth/auth_bearer_model_test.dart new file mode 100644 index 000000000..389934ed0 --- /dev/null +++ b/packages/better_networking/test/models/auth/auth_bearer_model_test.dart @@ -0,0 +1,57 @@ +import 'package:better_networking/models/auth/auth_bearer_model.dart'; +import 'package:test/test.dart'; +import 'auth_models.dart'; + +void main() { + group('Testing AuthBearerModel', () { + test("Testing AuthBearerModel copyWith", () { + var authBearerModel = authBearerModel1; + final authBearerModelCopyWith = authBearerModel.copyWith( + token: 'new_bearer_token', + ); + expect(authBearerModelCopyWith.token, 'new_bearer_token'); + // original model unchanged + expect( + authBearerModel.token, + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c', + ); + }); + + test("Testing AuthBearerModel toJson", () { + var authBearerModel = authBearerModel1; + expect(authBearerModel.toJson(), authBearerModelJson1); + }); + + test("Testing AuthBearerModel fromJson", () { + var authBearerModel = authBearerModel1; + final modelFromJson = AuthBearerModel.fromJson(authBearerModelJson1); + expect(modelFromJson, authBearerModel); + expect( + modelFromJson.token, + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c', + ); + }); + + test("Testing AuthBearerModel getters", () { + var authBearerModel = authBearerModel1; + expect( + authBearerModel.token, + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c', + ); + }); + + test("Testing AuthBearerModel equality", () { + const authBearerModel1Copy = AuthBearerModel( + token: + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c', + ); + expect(authBearerModel1, authBearerModel1Copy); + expect(authBearerModel1, isNot(authBearerModel2)); + }); + + test("Testing AuthBearerModel with different tokens", () { + expect(authBearerModel2.token, 'different_bearer_token_value'); + expect(authBearerModel1.token, isNot(authBearerModel2.token)); + }); + }); +} diff --git a/packages/better_networking/test/models/auth/auth_digest_model_test.dart b/packages/better_networking/test/models/auth/auth_digest_model_test.dart new file mode 100644 index 000000000..15a31399b --- /dev/null +++ b/packages/better_networking/test/models/auth/auth_digest_model_test.dart @@ -0,0 +1,87 @@ +import 'package:better_networking/models/auth/auth_digest_model.dart'; +import 'package:test/test.dart'; +import 'auth_models.dart'; + +void main() { + group('Testing AuthDigestModel', () { + test("Testing AuthDigestModel copyWith", () { + var authDigestModel = authDigestModel1; + final authDigestModelCopyWith = authDigestModel.copyWith( + username: 'new_user', + algorithm: 'MD5', + qop: 'auth', + ); + expect(authDigestModelCopyWith.username, 'new_user'); + expect(authDigestModelCopyWith.algorithm, 'MD5'); + expect(authDigestModelCopyWith.qop, 'auth'); + // original model unchanged + expect(authDigestModel.username, 'digest_user'); + expect(authDigestModel.algorithm, 'SHA-256'); + expect(authDigestModel.qop, 'auth-int'); + }); + + test("Testing AuthDigestModel toJson", () { + var authDigestModel = authDigestModel1; + expect(authDigestModel.toJson(), authDigestModelJson1); + }); + + test("Testing AuthDigestModel fromJson", () { + var authDigestModel = authDigestModel1; + final modelFromJson = AuthDigestModel.fromJson(authDigestModelJson1); + expect(modelFromJson, authDigestModel); + expect(modelFromJson.username, 'digest_user'); + expect(modelFromJson.password, 'digest_pass'); + expect(modelFromJson.realm, 'protected-area'); + expect(modelFromJson.algorithm, 'SHA-256'); + }); + + test("Testing AuthDigestModel getters", () { + var authDigestModel = authDigestModel1; + expect(authDigestModel.username, 'digest_user'); + expect(authDigestModel.password, 'digest_pass'); + expect(authDigestModel.realm, 'protected-area'); + expect(authDigestModel.nonce, 'dcd98b7102dd2f0e8b11d0f600bfb0c093'); + expect(authDigestModel.algorithm, 'SHA-256'); + expect(authDigestModel.qop, 'auth-int'); + expect(authDigestModel.opaque, '5ccc069c403ebaf9f0171e9517f40e41'); + }); + + test("Testing AuthDigestModel equality", () { + const authDigestModel1Copy = AuthDigestModel( + username: 'digest_user', + password: 'digest_pass', + realm: 'protected-area', + nonce: 'dcd98b7102dd2f0e8b11d0f600bfb0c093', + algorithm: 'SHA-256', + qop: 'auth-int', + opaque: '5ccc069c403ebaf9f0171e9517f40e41', + ); + expect(authDigestModel1, authDigestModel1Copy); + expect(authDigestModel1, isNot(authDigestModel2)); + }); + + test("Testing AuthDigestModel with different configurations", () { + expect(authDigestModel2.username, 'another_digest_user'); + expect(authDigestModel2.password, 'another_digest_pass'); + expect(authDigestModel2.realm, 'different-realm'); + expect(authDigestModel2.nonce, 'abc12345678901234567890abcdef012'); + expect(authDigestModel2.algorithm, 'MD5'); + expect(authDigestModel2.qop, 'auth'); + expect(authDigestModel2.opaque, 'fedcba0987654321098765432109876543'); + + // Compare differences + expect(authDigestModel1.username, isNot(authDigestModel2.username)); + expect(authDigestModel1.algorithm, isNot(authDigestModel2.algorithm)); + expect(authDigestModel1.qop, isNot(authDigestModel2.qop)); + expect(authDigestModel1.realm, isNot(authDigestModel2.realm)); + }); + + test("Testing AuthDigestModel nonce and opaque values", () { + var authDigestModel = authDigestModel1; + expect(authDigestModel.nonce.length, 34); + expect(authDigestModel.opaque.length, 32); + expect(authDigestModel.nonce, matches(RegExp(r'^[a-f0-9]+$'))); + expect(authDigestModel.opaque, matches(RegExp(r'^[a-f0-9]+$'))); + }); + }); +} diff --git a/packages/better_networking/test/models/auth/auth_jwt_model_test.dart b/packages/better_networking/test/models/auth/auth_jwt_model_test.dart new file mode 100644 index 000000000..f6c475272 --- /dev/null +++ b/packages/better_networking/test/models/auth/auth_jwt_model_test.dart @@ -0,0 +1,112 @@ +import 'package:better_networking/models/auth/auth_jwt_model.dart'; +import 'package:test/test.dart'; +import 'auth_models.dart'; + +void main() { + group('Testing AuthJwtModel', () { + test("Testing AuthJwtModel copyWith", () { + var authJwtModel = authJwtModel1; + final authJwtModelCopyWith = authJwtModel.copyWith( + secret: 'new_secret', + algorithm: 'HS256', + isSecretBase64Encoded: false, + ); + expect(authJwtModelCopyWith.secret, 'new_secret'); + expect(authJwtModelCopyWith.algorithm, 'HS256'); + expect(authJwtModelCopyWith.isSecretBase64Encoded, false); + // original model unchanged + expect(authJwtModel.secret, 'jwt-secret-key'); + expect(authJwtModel.algorithm, 'RS256'); + expect(authJwtModel.isSecretBase64Encoded, true); + }); + + test("Testing AuthJwtModel toJson", () { + var authJwtModel = authJwtModel1; + expect(authJwtModel.toJson(), authJwtModelJson1); + }); + + test("Testing AuthJwtModel fromJson", () { + var authJwtModel = authJwtModel1; + final modelFromJson = AuthJwtModel.fromJson(authJwtModelJson1); + expect(modelFromJson, authJwtModel); + expect(modelFromJson.secret, 'jwt-secret-key'); + expect(modelFromJson.algorithm, 'RS256'); + expect(modelFromJson.isSecretBase64Encoded, true); + }); + + test("Testing AuthJwtModel getters", () { + var authJwtModel = authJwtModel1; + expect(authJwtModel.secret, 'jwt-secret-key'); + expect( + authJwtModel.privateKey, + startsWith('-----BEGIN RSA PRIVATE KEY-----'), + ); + expect(authJwtModel.payload, '{"user_id": 123, "exp": 1735689600}'); + expect(authJwtModel.addTokenTo, 'header'); + expect(authJwtModel.algorithm, 'RS256'); + expect(authJwtModel.isSecretBase64Encoded, true); + expect(authJwtModel.headerPrefix, 'JWT'); + expect(authJwtModel.queryParamKey, 'jwt_token'); + expect(authJwtModel.header, 'X-JWT-Token'); + }); + + test("Testing AuthJwtModel equality", () { + const authJwtModel1Copy = AuthJwtModel( + secret: 'jwt-secret-key', + privateKey: '''-----BEGIN RSA PRIVATE KEY----- +MIICWgIBAAKBgHa+iOFqaom/Eg1xlBapqu6JPDHMhsCLy06i4/yZ6KFTz8RWBDG8 +rRdhqSTOWCGtLq+unK/A1lkexaYE3lHBbn/2dzDjaXA48G/B4s4R6ixigQDWnZJd +e4GVKuLOZx82tDSl0yLQOzOzUMygj8IRBgp7CaL4WBRo5DwGRXAON9A7AgMBAAEC +gYAlotZ3u+bwqeLq5+jsFfLbkBvIHO9I8AYMcoyYb5/QImRj8m955Ddohce6prxA +UEfP3yRCgHhv3tT+feSJPSnsbPIpWnmnvDdy+NLij6rYKjga8oYyskg8wpYKSsgO +nNTWI8jLDTM2TFGXAR+Pn+yQ120fmcdhMKsnshnxitHhAQJBAM58Tz/SKb+Hgojs +Le3WJfs1meK0ecEHVZr9p+8mXmn1qUWddG/Mi1m2Zr3ycef+JMDp8CKexa/dacSV +00D+G6ECQQCTN/tEBBia1+eMy3+GKYVH/M7jVSPxjcTQF3qnBnd752AJNqHUpaFO +af8d1omyRY8DdCgTs/JjfesveaL0Uz5bAkB+bVCctBKJye/b5DhO+qLwyCX70CMI +VHRO3Oa5IBYI7LiC/mBvn57nBC6uOMcTk+FvGQ3GNM632mrLSi06CxxhAkA92BeS +xBG+ApL//4DL0GdwDVCwCVU3JTIXpLVeswXApDsgw7WKCiZQNZD5bOWdYUEp10L6 +u+5IQ15oLDX7Y3jfAkBtpWyAuhQwYLpiLPa82U9zus9IxYpfqohVBeiT5UasSssx +OUdMDWRxHzjEexN0nmD1nIPbKNJd0/rvj7jI82Kh +-----END RSA PRIVATE KEY-----''', + payload: '{"user_id": 123, "exp": 1735689600}', + addTokenTo: 'header', + algorithm: 'RS256', + isSecretBase64Encoded: true, + headerPrefix: 'JWT', + queryParamKey: 'jwt_token', + header: 'X-JWT-Token', + ); + expect(authJwtModel1, authJwtModel1Copy); + expect(authJwtModel1, isNot(authJwtModel2)); + }); + + test("Testing AuthJwtModel with different configurations", () { + expect(authJwtModel2.secret, 'different-jwt-secret'); + expect(authJwtModel2.algorithm, 'HS256'); + expect(authJwtModel2.isSecretBase64Encoded, false); + expect(authJwtModel2.addTokenTo, 'query'); + expect(authJwtModel2.headerPrefix, 'Bearer'); + expect(authJwtModel2.header, 'Authorization'); + + // Compare differences + expect(authJwtModel1.secret, isNot(authJwtModel2.secret)); + expect(authJwtModel1.algorithm, isNot(authJwtModel2.algorithm)); + expect( + authJwtModel1.isSecretBase64Encoded, + isNot(authJwtModel2.isSecretBase64Encoded), + ); + expect(authJwtModel1.addTokenTo, isNot(authJwtModel2.addTokenTo)); + }); + + test("Testing AuthJwtModel payload parsing", () { + var authJwtModel = authJwtModel1; + expect(authJwtModel.payload, contains('user_id')); + expect(authJwtModel.payload, contains('exp')); + + var authJwtModel2Local = authJwtModel2; + expect(authJwtModel2Local.payload, contains('sub')); + expect(authJwtModel2Local.payload, contains('name')); + expect(authJwtModel2Local.payload, contains('John Doe')); + }); + }); +} diff --git a/packages/better_networking/test/models/auth/auth_models.dart b/packages/better_networking/test/models/auth/auth_models.dart new file mode 100644 index 000000000..50990796d --- /dev/null +++ b/packages/better_networking/test/models/auth/auth_models.dart @@ -0,0 +1,212 @@ +import 'package:better_networking/models/auth/api_auth_model.dart'; +import 'package:better_networking/models/auth/auth_basic_model.dart'; +import 'package:better_networking/models/auth/auth_bearer_model.dart'; +import 'package:better_networking/models/auth/auth_api_key_model.dart'; +import 'package:better_networking/models/auth/auth_jwt_model.dart'; +import 'package:better_networking/models/auth/auth_digest_model.dart'; +import 'package:better_networking/consts.dart'; + +/// Auth models for testing + +const authBasicModel1 = AuthBasicAuthModel( + username: 'john_doe', + password: 'secure_password', +); + +const authBasicModel2 = AuthBasicAuthModel( + username: 'jane_smith', + password: 'another_password', +); + +const authBearerModel1 = AuthBearerModel( + token: + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c', +); + +const authBearerModel2 = AuthBearerModel(token: 'different_bearer_token_value'); + +const authApiKeyModel1 = AuthApiKeyModel( + key: 'ak-test-key-12345', + location: 'header', + name: 'x-api-key', +); + +const authApiKeyModel2 = AuthApiKeyModel( + key: 'query-api-key-67890', + location: 'query', + name: 'api_key', +); + +const authJwtModel1 = AuthJwtModel( + secret: 'jwt-secret-key', + privateKey: '''-----BEGIN RSA PRIVATE KEY----- +MIICWgIBAAKBgHa+iOFqaom/Eg1xlBapqu6JPDHMhsCLy06i4/yZ6KFTz8RWBDG8 +rRdhqSTOWCGtLq+unK/A1lkexaYE3lHBbn/2dzDjaXA48G/B4s4R6ixigQDWnZJd +e4GVKuLOZx82tDSl0yLQOzOzUMygj8IRBgp7CaL4WBRo5DwGRXAON9A7AgMBAAEC +gYAlotZ3u+bwqeLq5+jsFfLbkBvIHO9I8AYMcoyYb5/QImRj8m955Ddohce6prxA +UEfP3yRCgHhv3tT+feSJPSnsbPIpWnmnvDdy+NLij6rYKjga8oYyskg8wpYKSsgO +nNTWI8jLDTM2TFGXAR+Pn+yQ120fmcdhMKsnshnxitHhAQJBAM58Tz/SKb+Hgojs +Le3WJfs1meK0ecEHVZr9p+8mXmn1qUWddG/Mi1m2Zr3ycef+JMDp8CKexa/dacSV +00D+G6ECQQCTN/tEBBia1+eMy3+GKYVH/M7jVSPxjcTQF3qnBnd752AJNqHUpaFO +af8d1omyRY8DdCgTs/JjfesveaL0Uz5bAkB+bVCctBKJye/b5DhO+qLwyCX70CMI +VHRO3Oa5IBYI7LiC/mBvn57nBC6uOMcTk+FvGQ3GNM632mrLSi06CxxhAkA92BeS +xBG+ApL//4DL0GdwDVCwCVU3JTIXpLVeswXApDsgw7WKCiZQNZD5bOWdYUEp10L6 +u+5IQ15oLDX7Y3jfAkBtpWyAuhQwYLpiLPa82U9zus9IxYpfqohVBeiT5UasSssx +OUdMDWRxHzjEexN0nmD1nIPbKNJd0/rvj7jI82Kh +-----END RSA PRIVATE KEY-----''', + payload: '{"user_id": 123, "exp": 1735689600}', + addTokenTo: 'header', + algorithm: 'RS256', + isSecretBase64Encoded: true, + headerPrefix: 'JWT', + queryParamKey: 'jwt_token', + header: 'X-JWT-Token', +); + +const authJwtModel2 = AuthJwtModel( + secret: 'different-jwt-secret', + payload: '{"sub": "1234567890", "name": "John Doe", "iat": 1516239022}', + addTokenTo: 'query', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: 'Authorization', +); + +const authDigestModel1 = AuthDigestModel( + username: 'digest_user', + password: 'digest_pass', + realm: 'protected-area', + nonce: 'dcd98b7102dd2f0e8b11d0f600bfb0c093', + algorithm: 'SHA-256', + qop: 'auth-int', + opaque: '5ccc069c403ebaf9f0171e9517f40e41', +); + +const authDigestModel2 = AuthDigestModel( + username: 'another_digest_user', + password: 'another_digest_pass', + realm: 'different-realm', + nonce: 'abc12345678901234567890abcdef012', + algorithm: 'MD5', + qop: 'auth', + opaque: 'fedcba0987654321098765432109876543', +); + +const authModel1 = AuthModel(type: APIAuthType.basic, basic: authBasicModel1); + +const authModel2 = AuthModel( + type: APIAuthType.bearer, + bearer: authBearerModel1, +); + +const authModel3 = AuthModel( + type: APIAuthType.apiKey, + apikey: authApiKeyModel1, +); + +const authModel4 = AuthModel(type: APIAuthType.jwt, jwt: authJwtModel1); + +const authModel5 = AuthModel( + type: APIAuthType.digest, + digest: authDigestModel1, +); + +const authModelNone = AuthModel(type: APIAuthType.none); + +/// JSON representations for testing + +final Map authBasicModelJson1 = { + "username": "john_doe", + "password": "secure_password", +}; + +final Map authBearerModelJson1 = { + "token": + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", +}; + +final Map authApiKeyModelJson1 = { + "key": "ak-test-key-12345", + "location": "header", + "name": "x-api-key", +}; + +final Map authJwtModelJson1 = { + "secret": "jwt-secret-key", + "privateKey": '''-----BEGIN RSA PRIVATE KEY----- +MIICWgIBAAKBgHa+iOFqaom/Eg1xlBapqu6JPDHMhsCLy06i4/yZ6KFTz8RWBDG8 +rRdhqSTOWCGtLq+unK/A1lkexaYE3lHBbn/2dzDjaXA48G/B4s4R6ixigQDWnZJd +e4GVKuLOZx82tDSl0yLQOzOzUMygj8IRBgp7CaL4WBRo5DwGRXAON9A7AgMBAAEC +gYAlotZ3u+bwqeLq5+jsFfLbkBvIHO9I8AYMcoyYb5/QImRj8m955Ddohce6prxA +UEfP3yRCgHhv3tT+feSJPSnsbPIpWnmnvDdy+NLij6rYKjga8oYyskg8wpYKSsgO +nNTWI8jLDTM2TFGXAR+Pn+yQ120fmcdhMKsnshnxitHhAQJBAM58Tz/SKb+Hgojs +Le3WJfs1meK0ecEHVZr9p+8mXmn1qUWddG/Mi1m2Zr3ycef+JMDp8CKexa/dacSV +00D+G6ECQQCTN/tEBBia1+eMy3+GKYVH/M7jVSPxjcTQF3qnBnd752AJNqHUpaFO +af8d1omyRY8DdCgTs/JjfesveaL0Uz5bAkB+bVCctBKJye/b5DhO+qLwyCX70CMI +VHRO3Oa5IBYI7LiC/mBvn57nBC6uOMcTk+FvGQ3GNM632mrLSi06CxxhAkA92BeS +xBG+ApL//4DL0GdwDVCwCVU3JTIXpLVeswXApDsgw7WKCiZQNZD5bOWdYUEp10L6 +u+5IQ15oLDX7Y3jfAkBtpWyAuhQwYLpiLPa82U9zus9IxYpfqohVBeiT5UasSssx +OUdMDWRxHzjEexN0nmD1nIPbKNJd0/rvj7jI82Kh +-----END RSA PRIVATE KEY-----''', + "payload": "{\"user_id\": 123, \"exp\": 1735689600}", + "addTokenTo": "header", + "algorithm": "RS256", + "isSecretBase64Encoded": true, + "headerPrefix": "JWT", + "queryParamKey": "jwt_token", + "header": "X-JWT-Token", +}; + +final Map authDigestModelJson1 = { + "username": "digest_user", + "password": "digest_pass", + "realm": "protected-area", + "nonce": "dcd98b7102dd2f0e8b11d0f600bfb0c093", + "algorithm": "SHA-256", + "qop": "auth-int", + "opaque": "5ccc069c403ebaf9f0171e9517f40e41", +}; + +final Map authModelJson1 = { + "type": "basic", + "apikey": null, + "bearer": null, + "basic": {"username": "john_doe", "password": "secure_password"}, + "jwt": null, + "digest": null, +}; + +final Map authModelJson2 = { + "type": "bearer", + "apikey": null, + "bearer": { + "token": + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", + }, + "basic": null, + "jwt": null, + "digest": null, +}; + +final Map authModelJson3 = { + "type": "", + "apikey": null, + "bearer": { + "token": + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", + }, + "basic": null, + "jwt": null, + "digest": null, +}; + +final Map authModelNoneJson = { + "type": "none", + "apikey": null, + "bearer": null, + "basic": null, + "jwt": null, + "digest": null, +}; diff --git a/packages/better_networking/test/utils/auth/auth_handling_test.dart b/packages/better_networking/test/utils/auth/auth_handling_test.dart index b461ea166..905dcf89b 100644 --- a/packages/better_networking/test/utils/auth/auth_handling_test.dart +++ b/packages/better_networking/test/utils/auth/auth_handling_test.dart @@ -51,7 +51,7 @@ void main() { final result = await handleAuth(httpRequestModel, authModel); - expect(result.headers, isEmpty); + expect(result.headers, isNull); expect(result.url, equals('https://api.apidash.dev/users')); }, ); From 739afca856d9517a9545ab7bb479859e85e3aff4 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Mon, 7 Jul 2025 22:08:51 +0530 Subject: [PATCH 39/70] tests: improve auth utils tests(coverage 90%) --- .../test/utils/auth/auth_handling_test.dart | 208 +++++++++ .../utils/auth/digest_auth_utils_test.dart | 424 ++++++++++++++++++ .../test/utils/auth/jwt_auth_utils_test.dart | 120 +++++ 3 files changed, 752 insertions(+) create mode 100644 packages/better_networking/test/utils/auth/digest_auth_utils_test.dart diff --git a/packages/better_networking/test/utils/auth/auth_handling_test.dart b/packages/better_networking/test/utils/auth/auth_handling_test.dart index 905dcf89b..4448da5ae 100644 --- a/packages/better_networking/test/utils/auth/auth_handling_test.dart +++ b/packages/better_networking/test/utils/auth/auth_handling_test.dart @@ -334,5 +334,213 @@ void main() { expect(result.url, equals('https://api.apidash.dev/users')); }, ); + + test( + 'given handleAuth when JWT authentication with query parameter is provided then it should add to query params', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const jwtAuth = AuthJwtModel( + secret: 'jwt-secret', + payload: '{"sub": "1234567890"}', + addTokenTo: 'query', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'access_token', + header: 'Authorization', + ); + const authModel = AuthModel(type: APIAuthType.jwt, jwt: jwtAuth); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.params, isNotEmpty); + expect(result.params?.any((p) => p.name == 'access_token'), isTrue); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when JWT authentication with empty query param key then it should use default "token"', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const jwtAuth = AuthJwtModel( + secret: 'jwt-secret', + payload: '{"sub": "1234567890"}', + addTokenTo: 'query', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: '', + header: 'Authorization', + ); + const authModel = AuthModel(type: APIAuthType.jwt, jwt: jwtAuth); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.params, isNotEmpty); + expect(result.params?.any((p) => p.name == 'token'), isTrue); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when JWT authentication with empty header prefix then it should not add prefix', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const jwtAuth = AuthJwtModel( + secret: 'jwt-secret', + payload: '{"sub": "1234567890"}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: '', + queryParamKey: 'token', + header: 'Authorization', + ); + const authModel = AuthModel(type: APIAuthType.jwt, jwt: jwtAuth); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.headers, isNotEmpty); + final authHeader = result.headers?.firstWhere( + (h) => h.name.toLowerCase() == 'authorization', + ); + expect(authHeader?.value, isNotNull); + expect(authHeader?.value?.startsWith('Bearer '), isFalse); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when OAuth1 authentication is provided then it should throw UnimplementedError', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const authModel = AuthModel(type: APIAuthType.oauth1); + + expect( + () async => await handleAuth(httpRequestModel, authModel), + throwsA(isA()), + ); + }, + ); + + test( + 'given handleAuth when OAuth2 authentication is provided then it should throw UnimplementedError', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const authModel = AuthModel(type: APIAuthType.oauth2); + + expect( + () async => await handleAuth(httpRequestModel, authModel), + throwsA(isA()), + ); + }, + ); + + test( + 'given handleAuth when basic auth model is null then it should not add headers', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const authModel = AuthModel(type: APIAuthType.basic, basic: null); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.headers, isEmpty); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when bearer auth model is null then it should not add headers', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const authModel = AuthModel(type: APIAuthType.bearer, bearer: null); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.headers, isEmpty); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when JWT auth model is null then it should not add headers', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const authModel = AuthModel(type: APIAuthType.jwt, jwt: null); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.headers, isEmpty); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when API key auth model is null then it should not add headers or params', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const authModel = AuthModel(type: APIAuthType.apiKey, apikey: null); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.headers, isEmpty); + expect(result.params, isEmpty); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); + + test( + 'given handleAuth when digest auth model is null then it should not add headers', + () async { + const httpRequestModel = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.apidash.dev/users', + ); + + const authModel = AuthModel(type: APIAuthType.digest, digest: null); + + final result = await handleAuth(httpRequestModel, authModel); + + expect(result.headers, isEmpty); + expect(result.url, equals('https://api.apidash.dev/users')); + }, + ); }); } diff --git a/packages/better_networking/test/utils/auth/digest_auth_utils_test.dart b/packages/better_networking/test/utils/auth/digest_auth_utils_test.dart new file mode 100644 index 000000000..f92deb527 --- /dev/null +++ b/packages/better_networking/test/utils/auth/digest_auth_utils_test.dart @@ -0,0 +1,424 @@ +import 'package:better_networking/utils/auth/digest_auth_utils.dart'; +import 'package:better_networking/better_networking.dart'; +import 'package:test/test.dart'; + +void main() { + group('Digest Auth Utils Tests', () { + group('splitAuthenticateHeader', () { + test('should parse valid Digest header correctly', () { + const header = + 'Digest realm="test", nonce="123", algorithm=MD5, qop="auth"'; + final result = splitAuthenticateHeader(header); + + expect(result, isNotNull); + expect(result!['realm'], equals('test')); + expect(result['nonce'], equals('123')); + expect(result['algorithm'], equals('MD5')); + expect(result['qop'], equals('auth')); + }); + + test('should return null for non-Digest header', () { + const header = 'Basic realm="test"'; + final result = splitAuthenticateHeader(header); + + expect(result, isNull); + }); + + test('should return null for empty header', () { + const header = ''; + final result = splitAuthenticateHeader(header); + + expect(result, isNull); + }); + + test('should return null for header without Digest prefix', () { + const header = 'realm="test", nonce="123"'; + final result = splitAuthenticateHeader(header); + + expect(result, isNull); + }); + + test('should handle header with quotes around values', () { + const header = + 'Digest realm="my realm", nonce="abc123", opaque="xyz789"'; + final result = splitAuthenticateHeader(header); + + expect(result, isNotNull); + expect(result!['realm'], equals('my realm')); + expect(result['nonce'], equals('abc123')); + expect(result['opaque'], equals('xyz789')); + }); + + test('should handle header with equals in values', () { + const header = 'Digest realm="test=value", nonce="123=456"'; + final result = splitAuthenticateHeader(header); + + expect(result, isNotNull); + expect(result!['realm'], equals('test=value')); + expect(result['nonce'], equals('123=456')); + }); + }); + + group('Hash Functions', () { + test('should compute SHA-256 hash correctly', () { + const input = 'test data'; + final result = sha256Hash(input); + + expect(result, isNotEmpty); + expect( + result, + hasLength(64), + ); // SHA-256 produces 64 character hex string + expect( + result, + equals( + '916f0027a575074ce72a331777c3478d6513f786a591bd892da1a577bf2335f9', + ), + ); + }); + + test('should compute MD5 hash correctly', () { + const input = 'test data'; + final result = md5Hash(input); + + expect(result, isNotEmpty); + expect(result, hasLength(32)); // MD5 produces 32 character hex string + expect(result, equals('eb733a00c0c9d336e65691a37ab54293')); + }); + + test('should handle empty string in SHA-256', () { + const input = ''; + final result = sha256Hash(input); + + expect(result, isNotEmpty); + expect( + result, + equals( + 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', + ), + ); + }); + + test('should handle empty string in MD5', () { + const input = ''; + final result = md5Hash(input); + + expect(result, isNotEmpty); + expect(result, equals('d41d8cd98f00b204e9800998ecf8427e')); + }); + }); + + group('computeResponse', () { + test('should compute response with MD5 algorithm and auth qop', () { + final result = computeResponse( + 'GET', + '/api/users', + '', + 'MD5', + 'auth', + 'opaque123', + 'test-realm', + 'cnonce123', + 'nonce123', + 1, + 'testuser', + 'testpass', + ); + + expect(result['username'], equals('testuser')); + expect(result['realm'], equals('test-realm')); + expect(result['nonce'], equals('nonce123')); + expect(result['uri'], equals('/api/users')); + expect(result['qop'], equals('auth')); + expect(result['nc'], equals('00000001')); + expect(result['cnonce'], equals('cnonce123')); + expect(result['opaque'], equals('opaque123')); + expect(result['algorithm'], equals('MD5')); + expect(result['response'], isNotNull); + }); + + test('should compute response with MD5 algorithm and auth-int qop', () { + final result = computeResponse( + 'POST', + '/api/users', + '{"name": "test"}', + 'MD5', + 'auth-int', + null, + 'test-realm', + 'cnonce123', + 'nonce123', + 1, + 'testuser', + 'testpass', + ); + + expect(result['qop'], equals('auth-int')); + expect(result['response'], isNotNull); + expect(result['opaque'], isNull); + }); + + test('should compute response with MD5 algorithm and no qop', () { + final result = computeResponse( + 'GET', + '/api/users', + '', + 'MD5', + null, + null, + 'test-realm', + 'cnonce123', + 'nonce123', + 1, + 'testuser', + 'testpass', + ); + + expect(result['qop'], isNull); + expect(result['response'], isNotNull); + }); + + test('should compute response with SHA-256 algorithm and auth qop', () { + final result = computeResponse( + 'GET', + '/api/users', + '', + 'SHA-256', + 'auth', + null, + 'test-realm', + 'cnonce123', + 'nonce123', + 1, + 'testuser', + 'testpass', + ); + + expect(result['algorithm'], equals('SHA-256')); + expect(result['response'], isNotNull); + }); + + test( + 'should compute response with SHA-256 algorithm and auth-int qop', + () { + final result = computeResponse( + 'POST', + '/api/users', + '{"data": "test"}', + 'SHA-256', + 'auth-int', + null, + 'test-realm', + 'cnonce123', + 'nonce123', + 1, + 'testuser', + 'testpass', + ); + + expect(result['algorithm'], equals('SHA-256')); + expect(result['qop'], equals('auth-int')); + expect(result['response'], isNotNull); + }, + ); + + test('should compute response with SHA-256 algorithm and no qop', () { + final result = computeResponse( + 'GET', + '/api/users', + '', + 'SHA-256', + null, + null, + 'test-realm', + 'cnonce123', + 'nonce123', + 1, + 'testuser', + 'testpass', + ); + + expect(result['algorithm'], equals('SHA-256')); + expect(result['qop'], isNull); + expect(result['response'], isNotNull); + }); + + test('should compute response with MD5-sess algorithm', () { + final result = computeResponse( + 'GET', + '/api/users', + '', + 'MD5-sess', + 'auth', + null, + 'test-realm', + 'cnonce123', + 'nonce123', + 1, + 'testuser', + 'testpass', + ); + + expect(result['algorithm'], equals('MD5-sess')); + expect(result['response'], isNotNull); + }); + + test('should compute response with SHA-256-sess algorithm', () { + final result = computeResponse( + 'GET', + '/api/users', + '', + 'SHA-256-sess', + 'auth', + null, + 'test-realm', + 'cnonce123', + 'nonce123', + 1, + 'testuser', + 'testpass', + ); + + expect(result['algorithm'], equals('SHA-256-sess')); + expect(result['response'], isNotNull); + }); + + test('should throw error for unsupported algorithm', () { + expect( + () => computeResponse( + 'GET', + '/api/users', + '', + 'UNSUPPORTED', + 'auth', + null, + 'test-realm', + 'cnonce123', + 'nonce123', + 1, + 'testuser', + 'testpass', + ), + throwsArgumentError, + ); + }); + }); + + group('DigestAuth class', () { + test('should create DigestAuth from model', () { + const model = AuthDigestModel( + username: 'testuser', + password: 'testpass', + realm: 'test-realm', + nonce: 'test-nonce', + algorithm: 'MD5', + qop: 'auth', + opaque: 'test-opaque', + ); + + final digestAuth = DigestAuth.fromModel(model); + + expect(digestAuth.username, equals('testuser')); + expect(digestAuth.password, equals('testpass')); + }); + + test('should generate auth string correctly', () { + const model = AuthDigestModel( + username: 'testuser', + password: 'testpass', + realm: 'test-realm', + nonce: 'test-nonce', + algorithm: 'MD5', + qop: 'auth', + opaque: 'test-opaque', + ); + + final digestAuth = DigestAuth.fromModel(model); + const httpRequest = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.example.com/users', + ); + + final authString = digestAuth.getAuthString(httpRequest); + + expect(authString, startsWith('Digest ')); + expect(authString, contains('username="testuser"')); + expect(authString, contains('realm="test-realm"')); + expect(authString, contains('nonce="test-nonce"')); + expect(authString, contains('uri="/users"')); + expect(authString, contains('algorithm=MD5')); + expect(authString, contains('qop=auth')); + expect(authString, contains('opaque="test-opaque"')); + expect(authString, contains('response="')); + }); + + test('should handle URL with query parameters', () { + const model = AuthDigestModel( + username: 'testuser', + password: 'testpass', + realm: 'test-realm', + nonce: 'test-nonce', + algorithm: 'MD5', + qop: 'auth', + opaque: '', + ); + + final digestAuth = DigestAuth.fromModel(model); + const httpRequest = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.example.com/users?limit=10&offset=0', + ); + + final authString = digestAuth.getAuthString(httpRequest); + + expect(authString, contains('uri="/users?limit=10&offset=0"')); + }); + + test('should handle empty opaque value', () { + const model = AuthDigestModel( + username: 'testuser', + password: 'testpass', + realm: 'test-realm', + nonce: 'test-nonce', + algorithm: 'MD5', + qop: 'auth', + opaque: '', + ); + + final digestAuth = DigestAuth.fromModel(model); + const httpRequest = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.example.com/users', + ); + + final authString = digestAuth.getAuthString(httpRequest); + + expect(authString, isNot(contains('opaque='))); + }); + + test('should increment nonce count with each call', () { + const model = AuthDigestModel( + username: 'testuser', + password: 'testpass', + realm: 'test-realm', + nonce: 'test-nonce', + algorithm: 'MD5', + qop: 'auth', + opaque: '', + ); + + final digestAuth = DigestAuth.fromModel(model); + const httpRequest = HttpRequestModel( + method: HTTPVerb.get, + url: 'https://api.example.com/users', + ); + + final authString1 = digestAuth.getAuthString(httpRequest); + final authString2 = digestAuth.getAuthString(httpRequest); + + expect(authString1, contains('nc=00000001')); + expect(authString2, contains('nc=00000002')); + }); + }); + }); +} diff --git a/packages/better_networking/test/utils/auth/jwt_auth_utils_test.dart b/packages/better_networking/test/utils/auth/jwt_auth_utils_test.dart index 009560381..7bf43694a 100644 --- a/packages/better_networking/test/utils/auth/jwt_auth_utils_test.dart +++ b/packages/better_networking/test/utils/auth/jwt_auth_utils_test.dart @@ -174,5 +174,125 @@ void main() { throwsA(isA()), ); }); + + test( + 'should throw error when generating JWT fails due to invalid payload', + () { + const jwtAuth = AuthJwtModel( + secret: 'test_secret', + payload: + '{"invalid": json}', // Malformed JSON that will cause parsing to fail but createKey to succeed + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: '', + ); + + // This should not throw since we handle JSON parsing gracefully + expect(() => generateJWT(jwtAuth), returnsNormally); + }, + ); + + test('should throw exception for RSA algorithm without private key', () { + const jwtAuth = AuthJwtModel( + secret: 'test_secret', + payload: '{"user": "test"}', + addTokenTo: 'header', + algorithm: 'RS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: '', + privateKey: null, + ); + + expect(() => generateJWT(jwtAuth), throwsA(isA())); + }); + + test('should throw exception for ECDSA algorithm without private key', () { + const jwtAuth = AuthJwtModel( + secret: 'test_secret', + payload: '{"user": "test"}', + addTokenTo: 'header', + algorithm: 'ES256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: '', + privateKey: null, + ); + + expect(() => generateJWT(jwtAuth), throwsA(isA())); + }); + + test('should throw exception for PS algorithm without private key', () { + const jwtAuth = AuthJwtModel( + secret: 'test_secret', + payload: '{"user": "test"}', + addTokenTo: 'header', + algorithm: 'PS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: '', + privateKey: null, + ); + + expect(() => generateJWT(jwtAuth), throwsA(isA())); + }); + + test('should throw exception for EdDSA algorithm without private key', () { + const jwtAuth = AuthJwtModel( + secret: 'test_secret', + payload: '{"user": "test"}', + addTokenTo: 'header', + algorithm: 'EdDSA', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: '', + privateKey: null, + ); + + expect(() => generateJWT(jwtAuth), throwsA(isA())); + }); + + test('should handle invalid header JSON gracefully', () { + const jwtAuth = AuthJwtModel( + secret: 'test_secret', + payload: '{"user": "test"}', + addTokenTo: 'header', + algorithm: 'HS256', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: '{"invalid": json}', // Invalid JSON + ); + + final token = generateJWT(jwtAuth); + expect(token, isNotEmpty); + expect(token.split('.').length, equals(3)); + + // Should still generate a valid token with empty header + final decoded = JWT.decode(token); + expect(decoded.payload['user'], equals('test')); + }); + + test('should throw exception for unknown algorithm', () { + const jwtAuth = AuthJwtModel( + secret: 'test_secret', + payload: '{"user": "test"}', + addTokenTo: 'header', + algorithm: 'UNKNOWN_ALG', + isSecretBase64Encoded: false, + headerPrefix: 'Bearer', + queryParamKey: 'token', + header: '', + ); + + expect(() => generateJWT(jwtAuth), throwsA(isA())); + }); }); } From e838654b2d65c5342078c7b9a6a7a191e8903bf9 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Mon, 7 Jul 2025 22:25:54 +0530 Subject: [PATCH 40/70] feat: enhance authentication fields with additional info --- .../auth/api_key_auth_fields.dart | 24 +++++----- .../auth/digest_auth_fields.dart | 16 ++++++- .../common_widgets/auth/jwt_auth_fields.dart | 4 +- .../common_widgets/auth_textfield.dart | 44 +++++++++++++------ 4 files changed, 59 insertions(+), 29 deletions(-) diff --git a/lib/screens/common_widgets/auth/api_key_auth_fields.dart b/lib/screens/common_widgets/auth/api_key_auth_fields.dart index 8fd272c92..1bf5a3e72 100644 --- a/lib/screens/common_widgets/auth/api_key_auth_fields.dart +++ b/lib/screens/common_widgets/auth/api_key_auth_fields.dart @@ -75,7 +75,8 @@ class _ApiKeyAuthFieldsState extends State { AuthTextField( readOnly: widget.readOnly, controller: _keyController, - hintText: "API Key", + title: "API Key", + hintText: "Key", isObscureText: true, onChanged: (value) => _updateApiKeyAuth(), ), @@ -84,22 +85,21 @@ class _ApiKeyAuthFieldsState extends State { } void _updateApiKeyAuth() { - widget.updateAuth( - widget.authData?.copyWith( - type: APIAuthType.apiKey, - apikey: AuthApiKeyModel( - key: _keyController.text.trim(), - name: _nameController.text.trim(), - location: _addKeyTo, - ), - ) ?? AuthModel( + widget.updateAuth(widget.authData?.copyWith( type: APIAuthType.apiKey, apikey: AuthApiKeyModel( key: _keyController.text.trim(), name: _nameController.text.trim(), location: _addKeyTo, ), - ) - ); + ) ?? + AuthModel( + type: APIAuthType.apiKey, + apikey: AuthApiKeyModel( + key: _keyController.text.trim(), + name: _nameController.text.trim(), + location: _addKeyTo, + ), + )); } } diff --git a/lib/screens/common_widgets/auth/digest_auth_fields.dart b/lib/screens/common_widgets/auth/digest_auth_fields.dart index 859f3cec7..aa31efa48 100644 --- a/lib/screens/common_widgets/auth/digest_auth_fields.dart +++ b/lib/screens/common_widgets/auth/digest_auth_fields.dart @@ -51,6 +51,8 @@ class _DigestAuthFieldsState extends State { readOnly: widget.readOnly, controller: _usernameController, hintText: "Username", + infoText: + "Your username for digest authentication. This will be sent to the server for credential verification.", onChanged: (_) => _updateDigestAuth(), ), const SizedBox(height: 12), @@ -59,6 +61,8 @@ class _DigestAuthFieldsState extends State { controller: _passwordController, hintText: "Password", isObscureText: true, + infoText: + "Your password for digest authentication. This is hashed and not sent in plain text to the server.", onChanged: (_) => _updateDigestAuth(), ), const SizedBox(height: 12), @@ -66,6 +70,8 @@ class _DigestAuthFieldsState extends State { readOnly: widget.readOnly, controller: _realmController, hintText: "Realm", + infoText: + "Authentication realm as specified by the server. This defines the protection space for the credentials.", onChanged: (_) => _updateDigestAuth(), ), const SizedBox(height: 12), @@ -73,6 +79,8 @@ class _DigestAuthFieldsState extends State { readOnly: widget.readOnly, controller: _nonceController, hintText: "Nonce", + infoText: + "Server-generated random value used to prevent replay attacks.", onChanged: (_) => _updateDigestAuth(), ), const SizedBox(height: 12), @@ -92,7 +100,7 @@ class _DigestAuthFieldsState extends State { ('SHA-256', 'SHA-256'), ('SHA-256-sess', 'SHA-256-sess'), ], - tooltip: "this algorithm will be used to produce the digest", + tooltip: "Algorithm that will be used to produce the digest", isOutlined: true, onChanged: (String? newLocation) { if (newLocation != null) { @@ -107,7 +115,9 @@ class _DigestAuthFieldsState extends State { AuthTextField( readOnly: widget.readOnly, controller: _qopController, - hintText: "QOP (e.g. auth)", + hintText: "QOP", + infoText: + "Quality of Protection. Typically 'auth' for authentication only, or 'auth-int' for authentication with integrity protection.", onChanged: (_) => _updateDigestAuth(), ), const SizedBox(height: 12), @@ -115,6 +125,8 @@ class _DigestAuthFieldsState extends State { readOnly: widget.readOnly, controller: _opaqueController, hintText: "Opaque", + infoText: + "Server-specified data string that should be returned unchanged in the authorization header. Usually obtained from server's 401 response.", onChanged: (_) => _updateDigestAuth(), ), ], diff --git a/lib/screens/common_widgets/auth/jwt_auth_fields.dart b/lib/screens/common_widgets/auth/jwt_auth_fields.dart index 44f97c986..2982ab073 100644 --- a/lib/screens/common_widgets/auth/jwt_auth_fields.dart +++ b/lib/screens/common_widgets/auth/jwt_auth_fields.dart @@ -115,6 +115,8 @@ class _JwtAuthFieldsState extends State { controller: _secretController, isObscureText: true, hintText: "Secret key", + infoText: + "The secret key used to sign the JWT token. Keep this secure and match it with your server configuration.", onChanged: (value) => _updateJwtAuth(), ), const SizedBox(height: 16), @@ -139,7 +141,7 @@ class _JwtAuthFieldsState extends State { ), ] else ...[ Text( - "Private Key (PEM Format)", + "Private Key", style: TextStyle( fontWeight: FontWeight.normal, fontSize: 14, diff --git a/lib/screens/common_widgets/auth_textfield.dart b/lib/screens/common_widgets/auth_textfield.dart index 28610c9bb..754a5d813 100644 --- a/lib/screens/common_widgets/auth_textfield.dart +++ b/lib/screens/common_widgets/auth_textfield.dart @@ -4,19 +4,22 @@ import 'package:flutter/material.dart'; class AuthTextField extends StatefulWidget { final String hintText; + final String? title; final TextEditingController controller; final bool isObscureText; final Function(String)? onChanged; final bool readOnly; + final String? infoText; - const AuthTextField({ - super.key, - required this.hintText, - required this.controller, - required this.onChanged, - this.readOnly = false, - this.isObscureText = false, - }); + const AuthTextField( + {super.key, + this.title, + required this.hintText, + required this.controller, + required this.onChanged, + this.readOnly = false, + this.isObscureText = false, + this.infoText}); @override State createState() => _AuthFieldState(); @@ -44,12 +47,25 @@ class _AuthFieldState extends State { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - widget.hintText, - style: TextStyle( - fontWeight: FontWeight.normal, - fontSize: 14, - ), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text(widget.title ?? widget.hintText), + if (widget.infoText != null) + Tooltip( + message: widget.infoText!, + triggerMode: TooltipTriggerMode.tap, + showDuration: Duration(seconds: 5), + child: Padding( + padding: const EdgeInsets.only(left: 4.0), + child: Icon( + Icons.help_outline_rounded, + color: Theme.of(context).colorScheme.secondary, + size: 18, + ), + ), + ), + ], ), const SizedBox(height: 6), TextFormField( From 38d8e8e76b7ee65543600117081148cfe0327550 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Mon, 7 Jul 2025 22:28:18 +0530 Subject: [PATCH 41/70] fix: update tooltip icon color and size --- lib/screens/common_widgets/auth_textfield.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/screens/common_widgets/auth_textfield.dart b/lib/screens/common_widgets/auth_textfield.dart index 754a5d813..88065673c 100644 --- a/lib/screens/common_widgets/auth_textfield.dart +++ b/lib/screens/common_widgets/auth_textfield.dart @@ -60,8 +60,8 @@ class _AuthFieldState extends State { padding: const EdgeInsets.only(left: 4.0), child: Icon( Icons.help_outline_rounded, - color: Theme.of(context).colorScheme.secondary, - size: 18, + color: Theme.of(context).colorScheme.primaryFixedDim, + size: 14, ), ), ), From 127b2c1efca60723207238a505591dca529a405a Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Mon, 7 Jul 2025 22:32:14 +0530 Subject: [PATCH 42/70] fix: disable onChanged for read-only auth fields --- .../auth/api_key_auth_fields.dart | 18 +++++----- .../auth/digest_auth_fields.dart | 18 +++++----- .../common_widgets/auth/jwt_auth_fields.dart | 36 ++++++++++--------- 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/lib/screens/common_widgets/auth/api_key_auth_fields.dart b/lib/screens/common_widgets/auth/api_key_auth_fields.dart index 1bf5a3e72..aa020f3a0 100644 --- a/lib/screens/common_widgets/auth/api_key_auth_fields.dart +++ b/lib/screens/common_widgets/auth/api_key_auth_fields.dart @@ -55,14 +55,16 @@ class _ApiKeyAuthFieldsState extends State { ], tooltip: "Select where to add API key", isOutlined: true, - onChanged: (String? newLocation) { - if (newLocation != null) { - setState(() { - _addKeyTo = newLocation; - }); - _updateApiKeyAuth(); - } - }, + onChanged: widget.readOnly + ? null + : (String? newLocation) { + if (newLocation != null) { + setState(() { + _addKeyTo = newLocation; + }); + _updateApiKeyAuth(); + } + }, ), const SizedBox(height: 16), AuthTextField( diff --git a/lib/screens/common_widgets/auth/digest_auth_fields.dart b/lib/screens/common_widgets/auth/digest_auth_fields.dart index aa31efa48..eaa4028e2 100644 --- a/lib/screens/common_widgets/auth/digest_auth_fields.dart +++ b/lib/screens/common_widgets/auth/digest_auth_fields.dart @@ -102,14 +102,16 @@ class _DigestAuthFieldsState extends State { ], tooltip: "Algorithm that will be used to produce the digest", isOutlined: true, - onChanged: (String? newLocation) { - if (newLocation != null) { - setState(() { - _algorithmController = newLocation; - }); - _updateDigestAuth(); - } - }, + onChanged: widget.readOnly + ? null + : (String? newLocation) { + if (newLocation != null) { + setState(() { + _algorithmController = newLocation; + }); + _updateDigestAuth(); + } + }, ), const SizedBox(height: 12), AuthTextField( diff --git a/lib/screens/common_widgets/auth/jwt_auth_fields.dart b/lib/screens/common_widgets/auth/jwt_auth_fields.dart index 2982ab073..1637e7f58 100644 --- a/lib/screens/common_widgets/auth/jwt_auth_fields.dart +++ b/lib/screens/common_widgets/auth/jwt_auth_fields.dart @@ -61,14 +61,16 @@ class _JwtAuthFieldsState extends State { ], tooltip: "Select where to add JWT token", isOutlined: true, - onChanged: (String? newAddTokenTo) { - if (newAddTokenTo != null) { - setState(() { - _addTokenTo = newAddTokenTo; - }); - _updateJwtAuth(); - } - }, + onChanged: widget.readOnly + ? null + : (String? newAddTokenTo) { + if (newAddTokenTo != null) { + setState(() { + _addTokenTo = newAddTokenTo; + }); + _updateJwtAuth(); + } + }, ), const SizedBox(height: 16), Text( @@ -99,14 +101,16 @@ class _JwtAuthFieldsState extends State { ], tooltip: "Select JWT algorithm", isOutlined: true, - onChanged: (String? newAlgorithm) { - if (newAlgorithm != null) { - setState(() { - _algorithm = newAlgorithm; - }); - _updateJwtAuth(); - } - }, + onChanged: widget.readOnly + ? null + : (String? newAlgorithm) { + if (newAlgorithm != null) { + setState(() { + _algorithm = newAlgorithm; + }); + _updateJwtAuth(); + } + }, ), const SizedBox(height: 16), if (_algorithm.startsWith('HS')) ...[ From 38eb5277038ef3bbfbbf82aac9863a1e5b5b731c Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Mon, 7 Jul 2025 22:41:25 +0530 Subject: [PATCH 43/70] feat: update APIAuthType enum to include display types for authentication options --- .../details_card/request_pane/request_auth.dart | 16 +++++----------- packages/better_networking/lib/consts.dart | 14 +++++++++++++- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index fd3e63621..0d73f099b 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -55,17 +55,10 @@ class EditAuthType extends ConsumerWidget { height: 8, ), ADPopupMenu( - value: currentAuthType.name.capitalize(), - values: const [ - (APIAuthType.none, 'None'), - (APIAuthType.basic, 'Basic'), - (APIAuthType.apiKey, 'API Key'), - (APIAuthType.bearer, 'Bearer'), - (APIAuthType.jwt, 'JWT'), - (APIAuthType.digest, 'Digest'), - (APIAuthType.oauth1, 'OAuth 1.0'), - (APIAuthType.oauth2, 'OAuth 2.0'), - ], + value: currentAuthType.displayType, + values: APIAuthType.values + .map((type) => (type, type.displayType)) + .toList(), tooltip: "Select Authentication Type", isOutlined: true, onChanged: readOnly @@ -92,6 +85,7 @@ class EditAuthType extends ConsumerWidget { ), ); } + Widget _buildAuthFields( BuildContext context, WidgetRef ref, diff --git a/packages/better_networking/lib/consts.dart b/packages/better_networking/lib/consts.dart index 23038c7ee..8e5c14724 100644 --- a/packages/better_networking/lib/consts.dart +++ b/packages/better_networking/lib/consts.dart @@ -9,7 +9,19 @@ enum APIType { final String abbr; } -enum APIAuthType { none, basic, apiKey, bearer, jwt, digest, oauth1, oauth2 } +enum APIAuthType { + none("None"), + basic("Basic Auth"), + apiKey("API Key"), + bearer("Bearer Token"), + jwt("JWT Bearer"), + digest("Digest Auth"), + oauth1("OAuth 1.0"), + oauth2("OAuth 2.0"); + + const APIAuthType(this.displayType); + final String displayType; +} enum HTTPVerb { get("GET"), From db93e82b5f73fedbd243520f589e2ba430281da0 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sat, 12 Jul 2025 00:34:12 +0530 Subject: [PATCH 44/70] fix: make authModel optional in HistoryRequestModel --- lib/models/history_request_model.dart | 2 +- lib/models/history_request_model.freezed.dart | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/models/history_request_model.dart b/lib/models/history_request_model.dart index 51715f5c6..f46382a72 100644 --- a/lib/models/history_request_model.dart +++ b/lib/models/history_request_model.dart @@ -18,7 +18,7 @@ class HistoryRequestModel with _$HistoryRequestModel { required HttpResponseModel httpResponseModel, String? preRequestScript, String? postRequestScript, - required AuthModel? authModel, + AuthModel? authModel, }) = _HistoryRequestModel; factory HistoryRequestModel.fromJson(Map json) => diff --git a/lib/models/history_request_model.freezed.dart b/lib/models/history_request_model.freezed.dart index b2c9f0ef9..020ea13de 100644 --- a/lib/models/history_request_model.freezed.dart +++ b/lib/models/history_request_model.freezed.dart @@ -251,7 +251,7 @@ class _$HistoryRequestModelImpl implements _HistoryRequestModel { required this.httpResponseModel, this.preRequestScript, this.postRequestScript, - required this.authModel}); + this.authModel}); factory _$HistoryRequestModelImpl.fromJson(Map json) => _$$HistoryRequestModelImplFromJson(json); @@ -334,7 +334,7 @@ abstract class _HistoryRequestModel implements HistoryRequestModel { required final HttpResponseModel httpResponseModel, final String? preRequestScript, final String? postRequestScript, - required final AuthModel? authModel}) = _$HistoryRequestModelImpl; + final AuthModel? authModel}) = _$HistoryRequestModelImpl; factory _HistoryRequestModel.fromJson(Map json) = _$HistoryRequestModelImpl.fromJson; From 20c71073cbd0ebae7a19ce9108da9d2f4374bbec Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sat, 12 Jul 2025 00:42:24 +0530 Subject: [PATCH 45/70] fix: update qop label in DigestAuthFields test --- test/screens/common_widgets/auth/digest_auth_fields_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/screens/common_widgets/auth/digest_auth_fields_test.dart b/test/screens/common_widgets/auth/digest_auth_fields_test.dart index 0c43e9ad2..85844c0ec 100644 --- a/test/screens/common_widgets/auth/digest_auth_fields_test.dart +++ b/test/screens/common_widgets/auth/digest_auth_fields_test.dart @@ -41,7 +41,7 @@ void main() { expect(find.text('Realm'), findsNWidgets(2)); expect(find.text('Nonce'), findsNWidgets(2)); expect(find.text('Algorithm'), findsOneWidget); - expect(find.text('QOP (e.g. auth)'), findsNWidgets(2)); + expect(find.text('QOP'), findsNWidgets(2)); expect(find.text('Opaque'), findsNWidgets(2)); }); From 3ca5255e8f2bcef85eca68b21f1891ab04d02fa0 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sat, 12 Jul 2025 00:43:44 +0530 Subject: [PATCH 46/70] fix: pass null for authData in sendHttpRequest for digest authentication to prevent infinite loop when realm and nonce are empty --- packages/better_networking/lib/utils/auth/handle_auth.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/better_networking/lib/utils/auth/handle_auth.dart b/packages/better_networking/lib/utils/auth/handle_auth.dart index 8228f87e2..b18c3dab4 100644 --- a/packages/better_networking/lib/utils/auth/handle_auth.dart +++ b/packages/better_networking/lib/utils/auth/handle_auth.dart @@ -109,7 +109,7 @@ Future handleAuth( final httpResult = await sendHttpRequest( "digest-${Random.secure()}", APIType.rest, - authData, + null, httpRequestModel, ); final httpResponse = httpResult.$1; From 51c44a3eb7a29587c66aa4515781c3dd0ca0bf49 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sat, 12 Jul 2025 00:47:54 +0530 Subject: [PATCH 47/70] fix: update label for private key field in JWT auth fields test --- test/screens/common_widgets/auth/jwt_auth_fields_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/screens/common_widgets/auth/jwt_auth_fields_test.dart b/test/screens/common_widgets/auth/jwt_auth_fields_test.dart index 7856c43b2..a5db8a6ca 100644 --- a/test/screens/common_widgets/auth/jwt_auth_fields_test.dart +++ b/test/screens/common_widgets/auth/jwt_auth_fields_test.dart @@ -137,7 +137,7 @@ void main() { ), ); - expect(find.text('Private Key (PEM Format)'), findsOneWidget); + expect(find.text('Private Key'), findsOneWidget); expect(find.text('Secret key'), findsNothing); expect(find.byType(TextField), findsNWidgets(2)); // Private key + payload }); From db2f5af773142c373ebf6e8b9d6a4732e7a6d3d5 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sat, 12 Jul 2025 00:49:48 +0530 Subject: [PATCH 48/70] refactor: move auth_textfield to widgets folder --- lib/screens/common_widgets/auth/api_key_auth_fields.dart | 2 +- lib/screens/common_widgets/auth/basic_auth_fields.dart | 2 +- lib/screens/common_widgets/auth/bearer_auth_fields.dart | 2 +- lib/screens/common_widgets/auth/digest_auth_fields.dart | 2 +- lib/screens/common_widgets/auth/jwt_auth_fields.dart | 2 +- lib/{screens/common_widgets => widgets}/auth_textfield.dart | 0 test/screens/common_widgets/auth/api_key_auth_fields_test.dart | 2 +- test/screens/common_widgets/auth/basic_auth_fields_test.dart | 2 +- test/screens/common_widgets/auth/bearer_auth_fields_test.dart | 2 +- test/screens/common_widgets/auth/digest_auth_fields_test.dart | 2 +- test/screens/common_widgets/auth/jwt_auth_fields_test.dart | 2 +- 11 files changed, 10 insertions(+), 10 deletions(-) rename lib/{screens/common_widgets => widgets}/auth_textfield.dart (100%) diff --git a/lib/screens/common_widgets/auth/api_key_auth_fields.dart b/lib/screens/common_widgets/auth/api_key_auth_fields.dart index aa020f3a0..88dd09d97 100644 --- a/lib/screens/common_widgets/auth/api_key_auth_fields.dart +++ b/lib/screens/common_widgets/auth/api_key_auth_fields.dart @@ -1,4 +1,4 @@ -import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash/widgets/auth_textfield.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; diff --git a/lib/screens/common_widgets/auth/basic_auth_fields.dart b/lib/screens/common_widgets/auth/basic_auth_fields.dart index 91f30336b..9a6396ced 100644 --- a/lib/screens/common_widgets/auth/basic_auth_fields.dart +++ b/lib/screens/common_widgets/auth/basic_auth_fields.dart @@ -1,4 +1,4 @@ -import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash/widgets/auth_textfield.dart'; import 'package:flutter/material.dart'; import 'package:apidash_core/apidash_core.dart'; diff --git a/lib/screens/common_widgets/auth/bearer_auth_fields.dart b/lib/screens/common_widgets/auth/bearer_auth_fields.dart index 0569831f1..22b967115 100644 --- a/lib/screens/common_widgets/auth/bearer_auth_fields.dart +++ b/lib/screens/common_widgets/auth/bearer_auth_fields.dart @@ -1,4 +1,4 @@ -import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash/widgets/auth_textfield.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; diff --git a/lib/screens/common_widgets/auth/digest_auth_fields.dart b/lib/screens/common_widgets/auth/digest_auth_fields.dart index eaa4028e2..7fbad306b 100644 --- a/lib/screens/common_widgets/auth/digest_auth_fields.dart +++ b/lib/screens/common_widgets/auth/digest_auth_fields.dart @@ -1,4 +1,4 @@ -import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash/widgets/auth_textfield.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/widgets/widgets.dart'; import 'package:flutter/material.dart'; diff --git a/lib/screens/common_widgets/auth/jwt_auth_fields.dart b/lib/screens/common_widgets/auth/jwt_auth_fields.dart index 1637e7f58..17b310fdf 100644 --- a/lib/screens/common_widgets/auth/jwt_auth_fields.dart +++ b/lib/screens/common_widgets/auth/jwt_auth_fields.dart @@ -1,4 +1,4 @@ -import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash/widgets/auth_textfield.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; import 'package:apidash_core/apidash_core.dart'; diff --git a/lib/screens/common_widgets/auth_textfield.dart b/lib/widgets/auth_textfield.dart similarity index 100% rename from lib/screens/common_widgets/auth_textfield.dart rename to lib/widgets/auth_textfield.dart diff --git a/test/screens/common_widgets/auth/api_key_auth_fields_test.dart b/test/screens/common_widgets/auth/api_key_auth_fields_test.dart index 19f80080c..55ce5cd6e 100644 --- a/test/screens/common_widgets/auth/api_key_auth_fields_test.dart +++ b/test/screens/common_widgets/auth/api_key_auth_fields_test.dart @@ -1,5 +1,5 @@ import 'package:apidash/screens/common_widgets/auth/api_key_auth_fields.dart'; -import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash/widgets/auth_textfield.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; diff --git a/test/screens/common_widgets/auth/basic_auth_fields_test.dart b/test/screens/common_widgets/auth/basic_auth_fields_test.dart index a2ca01bb2..862924086 100644 --- a/test/screens/common_widgets/auth/basic_auth_fields_test.dart +++ b/test/screens/common_widgets/auth/basic_auth_fields_test.dart @@ -1,5 +1,5 @@ import 'package:apidash/screens/common_widgets/auth/basic_auth_fields.dart'; -import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash/widgets/auth_textfield.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/test/screens/common_widgets/auth/bearer_auth_fields_test.dart b/test/screens/common_widgets/auth/bearer_auth_fields_test.dart index 51ef74a94..261e45943 100644 --- a/test/screens/common_widgets/auth/bearer_auth_fields_test.dart +++ b/test/screens/common_widgets/auth/bearer_auth_fields_test.dart @@ -1,5 +1,5 @@ import 'package:apidash/screens/common_widgets/auth/bearer_auth_fields.dart'; -import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash/widgets/auth_textfield.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/test/screens/common_widgets/auth/digest_auth_fields_test.dart b/test/screens/common_widgets/auth/digest_auth_fields_test.dart index 85844c0ec..a7f599493 100644 --- a/test/screens/common_widgets/auth/digest_auth_fields_test.dart +++ b/test/screens/common_widgets/auth/digest_auth_fields_test.dart @@ -1,5 +1,5 @@ import 'package:apidash/screens/common_widgets/auth/digest_auth_fields.dart'; -import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash/widgets/auth_textfield.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/widgets/widgets.dart'; import 'package:flutter/material.dart'; diff --git a/test/screens/common_widgets/auth/jwt_auth_fields_test.dart b/test/screens/common_widgets/auth/jwt_auth_fields_test.dart index a5db8a6ca..5ab9b1b9c 100644 --- a/test/screens/common_widgets/auth/jwt_auth_fields_test.dart +++ b/test/screens/common_widgets/auth/jwt_auth_fields_test.dart @@ -1,5 +1,5 @@ import 'package:apidash/screens/common_widgets/auth/jwt_auth_fields.dart'; -import 'package:apidash/screens/common_widgets/auth_textfield.dart'; +import 'package:apidash/widgets/auth_textfield.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; From 69e7f7bc26f9b7a80e10306cac1ac3ce8e823f39 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Sat, 12 Jul 2025 01:00:41 +0530 Subject: [PATCH 49/70] docs: add authentication testing links --- doc/dev_guide/api_endpoints_for_testing.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/dev_guide/api_endpoints_for_testing.md b/doc/dev_guide/api_endpoints_for_testing.md index 5e0c1378c..ab953ab5a 100644 --- a/doc/dev_guide/api_endpoints_for_testing.md +++ b/doc/dev_guide/api_endpoints_for_testing.md @@ -47,3 +47,14 @@ A List of API endpoints that can be used for testing API Dash ## SSE - https://sse.dev + +## Auth + - **Bearer** + - https://httpbin.org/bearer + + - **Basic Auth** + - https://httpbin.org/basic-auth/{username}/{password} + + - **Digest Auth** + - https://httpbin.org/digest-auth/{qop}/{usenamer}/{password}/{algorithm} + From 9850b7a044404554d49e2c91f76def3c2c461ac9 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Sat, 12 Jul 2025 15:24:57 +0530 Subject: [PATCH 50/70] Update auth widgets export --- lib/screens/common_widgets/auth/auth.dart | 5 +++++ lib/screens/common_widgets/common_widgets.dart | 1 + 2 files changed, 6 insertions(+) create mode 100644 lib/screens/common_widgets/auth/auth.dart diff --git a/lib/screens/common_widgets/auth/auth.dart b/lib/screens/common_widgets/auth/auth.dart new file mode 100644 index 000000000..376feb90d --- /dev/null +++ b/lib/screens/common_widgets/auth/auth.dart @@ -0,0 +1,5 @@ +export 'api_key_auth_fields.dart'; +export 'basic_auth_fields.dart'; +export 'bearer_auth_fields.dart'; +export 'digest_auth_fields.dart'; +export 'jwt_auth_fields.dart'; diff --git a/lib/screens/common_widgets/common_widgets.dart b/lib/screens/common_widgets/common_widgets.dart index fc4c66b84..dcbf9c70f 100644 --- a/lib/screens/common_widgets/common_widgets.dart +++ b/lib/screens/common_widgets/common_widgets.dart @@ -1,3 +1,4 @@ +export 'auth/auth.dart'; export 'api_type_dropdown.dart'; export 'button_navbar.dart'; export 'code_pane.dart'; From 99c38c4f96b2dbf27b32db50b3ccc0b625107ef9 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Sat, 12 Jul 2025 15:52:10 +0530 Subject: [PATCH 51/70] refactor API Key auth --- .../auth/api_key_auth_fields.dart | 40 +++++++++---------- lib/screens/common_widgets/auth/consts.dart | 9 +++++ 2 files changed, 27 insertions(+), 22 deletions(-) create mode 100644 lib/screens/common_widgets/auth/consts.dart diff --git a/lib/screens/common_widgets/auth/api_key_auth_fields.dart b/lib/screens/common_widgets/auth/api_key_auth_fields.dart index 88dd09d97..aca1abaf1 100644 --- a/lib/screens/common_widgets/auth/api_key_auth_fields.dart +++ b/lib/screens/common_widgets/auth/api_key_auth_fields.dart @@ -2,6 +2,7 @@ import 'package:apidash/widgets/auth_textfield.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; +import 'consts.dart'; class ApiKeyAuthFields extends StatefulWidget { final AuthModel? authData; @@ -28,8 +29,9 @@ class _ApiKeyAuthFieldsState extends State { super.initState(); final apiAuth = widget.authData?.apikey; _keyController = TextEditingController(text: apiAuth?.key ?? ''); - _nameController = TextEditingController(text: apiAuth?.name ?? 'x-api-key'); - _addKeyTo = apiAuth?.location ?? 'header'; + _nameController = + TextEditingController(text: apiAuth?.name ?? kApiKeyHeaderName); + _addKeyTo = apiAuth?.location ?? kAddToDefaultLocation; } @override @@ -38,7 +40,7 @@ class _ApiKeyAuthFieldsState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Add to", + kLabelAddTo, style: TextStyle( fontWeight: FontWeight.normal, fontSize: 14, @@ -48,12 +50,9 @@ class _ApiKeyAuthFieldsState extends State { height: 4, ), ADPopupMenu( - value: _addKeyTo == 'header' ? 'Header' : 'Query Params', - values: const [ - ('header', 'Header'), - ('query', 'Query Params'), - ], - tooltip: "Select where to add API key", + value: kAddToLocationsMap[_addKeyTo], + values: kAddToLocations, + tooltip: kTooltipApiKeyAuth, isOutlined: true, onChanged: widget.readOnly ? null @@ -70,15 +69,15 @@ class _ApiKeyAuthFieldsState extends State { AuthTextField( readOnly: widget.readOnly, controller: _nameController, - hintText: "Header/Query Param Name", + hintText: kHintTextFieldName, onChanged: (value) => _updateApiKeyAuth(), ), const SizedBox(height: 16), AuthTextField( readOnly: widget.readOnly, controller: _keyController, - title: "API Key", - hintText: "Key", + title: kLabelApiKey, + hintText: kHintTextKey, isObscureText: true, onChanged: (value) => _updateApiKeyAuth(), ), @@ -87,21 +86,18 @@ class _ApiKeyAuthFieldsState extends State { } void _updateApiKeyAuth() { + final apiKey = AuthApiKeyModel( + key: _keyController.text.trim(), + name: _nameController.text.trim(), + location: _addKeyTo, + ); widget.updateAuth(widget.authData?.copyWith( type: APIAuthType.apiKey, - apikey: AuthApiKeyModel( - key: _keyController.text.trim(), - name: _nameController.text.trim(), - location: _addKeyTo, - ), + apikey: apiKey, ) ?? AuthModel( type: APIAuthType.apiKey, - apikey: AuthApiKeyModel( - key: _keyController.text.trim(), - name: _nameController.text.trim(), - location: _addKeyTo, - ), + apikey: apiKey, )); } } diff --git a/lib/screens/common_widgets/auth/consts.dart b/lib/screens/common_widgets/auth/consts.dart new file mode 100644 index 000000000..139fb40f8 --- /dev/null +++ b/lib/screens/common_widgets/auth/consts.dart @@ -0,0 +1,9 @@ +const kApiKeyHeaderName = 'x-api-key'; +const kAddToLocations = [ + ('header', 'Header'), + ('query', 'Query Params'), +]; +final kAddToDefaultLocation = kAddToLocations[0].$1; +final kAddToLocationsMap = {for (var v in kAddToLocations) v.$1: v.$2}; +const kLabelAddTo = "Add to"; +const kTooltipApiKeyAuth = "Select where to add API key"; From 5afce7438b36fdea4a19e5e1743125ebcfd56b71 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Sat, 12 Jul 2025 15:52:47 +0530 Subject: [PATCH 52/70] Update consts.dart --- lib/screens/common_widgets/auth/consts.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/screens/common_widgets/auth/consts.dart b/lib/screens/common_widgets/auth/consts.dart index 139fb40f8..6328460b4 100644 --- a/lib/screens/common_widgets/auth/consts.dart +++ b/lib/screens/common_widgets/auth/consts.dart @@ -7,3 +7,6 @@ final kAddToDefaultLocation = kAddToLocations[0].$1; final kAddToLocationsMap = {for (var v in kAddToLocations) v.$1: v.$2}; const kLabelAddTo = "Add to"; const kTooltipApiKeyAuth = "Select where to add API key"; +const kHintTextFieldName = "Header/Query Param Name"; +const kLabelApiKey = "API Key"; +const kHintTextKey = "Key"; From 759e90663d0402b813168ea357e6df7d09e88cd3 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Sat, 12 Jul 2025 16:18:19 +0530 Subject: [PATCH 53/70] Update basic_auth_fields.dart --- .../auth/basic_auth_fields.dart | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/screens/common_widgets/auth/basic_auth_fields.dart b/lib/screens/common_widgets/auth/basic_auth_fields.dart index 9a6396ced..64dd58918 100644 --- a/lib/screens/common_widgets/auth/basic_auth_fields.dart +++ b/lib/screens/common_widgets/auth/basic_auth_fields.dart @@ -1,6 +1,7 @@ import 'package:apidash/widgets/auth_textfield.dart'; import 'package:flutter/material.dart'; import 'package:apidash_core/apidash_core.dart'; +import 'consts.dart'; class BasicAuthFields extends StatelessWidget { final AuthModel? authData; @@ -28,7 +29,7 @@ class BasicAuthFields extends StatelessWidget { children: [ AuthTextField( readOnly: readOnly, - hintText: "Username", + hintText: kHintUsername, controller: usernameController, onChanged: (_) => _updateBasicAuth( usernameController, @@ -38,7 +39,7 @@ class BasicAuthFields extends StatelessWidget { const SizedBox(height: 16), AuthTextField( readOnly: readOnly, - hintText: "Password", + hintText: kHintPassword, isObscureText: true, controller: passwordController, onChanged: (_) => _updateBasicAuth( @@ -54,20 +55,17 @@ class BasicAuthFields extends StatelessWidget { TextEditingController usernameController, TextEditingController passwordController, ) { - updateAuth( - authData?.copyWith( - type: APIAuthType.basic, - basic: AuthBasicAuthModel( - username: usernameController.text.trim(), - password: passwordController.text.trim(), - ), - ) ?? AuthModel( - type: APIAuthType.basic, - basic: AuthBasicAuthModel( - username: usernameController.text.trim(), - password: passwordController.text.trim(), - ), - ) + final basicAuth = AuthBasicAuthModel( + username: usernameController.text.trim(), + password: passwordController.text.trim(), ); + updateAuth(authData?.copyWith( + type: APIAuthType.basic, + basic: basicAuth, + ) ?? + AuthModel( + type: APIAuthType.basic, + basic: basicAuth, + )); } } From 7925a385f65f28a1fe69222c200e598ce76ba592 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Sat, 12 Jul 2025 16:18:29 +0530 Subject: [PATCH 54/70] Update bearer_auth_fields.dart --- .../common_widgets/auth/bearer_auth_fields.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/screens/common_widgets/auth/bearer_auth_fields.dart b/lib/screens/common_widgets/auth/bearer_auth_fields.dart index 22b967115..22e238965 100644 --- a/lib/screens/common_widgets/auth/bearer_auth_fields.dart +++ b/lib/screens/common_widgets/auth/bearer_auth_fields.dart @@ -1,6 +1,7 @@ import 'package:apidash/widgets/auth_textfield.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; +import 'consts.dart'; class BearerAuthFields extends StatefulWidget { final AuthModel? authData; @@ -33,24 +34,23 @@ class _BearerAuthFieldsState extends State { return AuthTextField( readOnly: widget.readOnly, controller: _tokenController, - hintText: "Token", + hintText: kHintToken, isObscureText: true, onChanged: (value) => _updateBearerAuth(), ); } void _updateBearerAuth() { + final bearer = AuthBearerModel( + token: _tokenController.text.trim(), + ); widget.updateAuth(widget.authData?.copyWith( type: APIAuthType.bearer, - bearer: AuthBearerModel( - token: _tokenController.text.trim(), - ), + bearer: bearer, ) ?? AuthModel( type: APIAuthType.bearer, - bearer: AuthBearerModel( - token: _tokenController.text.trim(), - ), + bearer: bearer, )); } } From 5d89dfddaa0874192d51713e7eb1b3e35ce5273d Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Sat, 12 Jul 2025 16:18:31 +0530 Subject: [PATCH 55/70] Update consts.dart --- lib/screens/common_widgets/auth/consts.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/screens/common_widgets/auth/consts.dart b/lib/screens/common_widgets/auth/consts.dart index 6328460b4..de0e85c9e 100644 --- a/lib/screens/common_widgets/auth/consts.dart +++ b/lib/screens/common_widgets/auth/consts.dart @@ -1,3 +1,4 @@ +const kEmpty = ''; const kApiKeyHeaderName = 'x-api-key'; const kAddToLocations = [ ('header', 'Header'), @@ -10,3 +11,8 @@ const kTooltipApiKeyAuth = "Select where to add API key"; const kHintTextFieldName = "Header/Query Param Name"; const kLabelApiKey = "API Key"; const kHintTextKey = "Key"; + +const kHintUsername = "Username"; +const kHintPassword = "Password"; + +const kHintToken = "Token"; From 568927b369e63d3553a2782c8f8c3b99c060bab6 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Sat, 12 Jul 2025 16:22:38 +0530 Subject: [PATCH 56/70] rename AuthTextField --- lib/widgets/{auth_textfield.dart => field_auth.dart} | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) rename lib/widgets/{auth_textfield.dart => field_auth.dart} (96%) diff --git a/lib/widgets/auth_textfield.dart b/lib/widgets/field_auth.dart similarity index 96% rename from lib/widgets/auth_textfield.dart rename to lib/widgets/field_auth.dart index 88065673c..ef60bec0e 100644 --- a/lib/widgets/auth_textfield.dart +++ b/lib/widgets/field_auth.dart @@ -1,6 +1,5 @@ -import 'package:apidash_design_system/tokens/measurements.dart'; -import 'package:apidash_design_system/tokens/typography.dart'; import 'package:flutter/material.dart'; +import 'package:apidash_design_system/apidash_design_system.dart'; class AuthTextField extends StatefulWidget { final String hintText; From 13a400056907d9b4b5122136c9d217ddbdb07468 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Sat, 12 Jul 2025 16:22:47 +0530 Subject: [PATCH 57/70] refactor imports --- lib/screens/common_widgets/auth/api_key_auth_fields.dart | 4 ++-- lib/screens/common_widgets/auth/basic_auth_fields.dart | 2 +- lib/screens/common_widgets/auth/bearer_auth_fields.dart | 4 ++-- lib/screens/common_widgets/auth/digest_auth_fields.dart | 6 +++--- lib/screens/common_widgets/auth/jwt_auth_fields.dart | 4 ++-- lib/widgets/widgets.dart | 1 + 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/screens/common_widgets/auth/api_key_auth_fields.dart b/lib/screens/common_widgets/auth/api_key_auth_fields.dart index aca1abaf1..6cfc23617 100644 --- a/lib/screens/common_widgets/auth/api_key_auth_fields.dart +++ b/lib/screens/common_widgets/auth/api_key_auth_fields.dart @@ -1,7 +1,7 @@ -import 'package:apidash/widgets/auth_textfield.dart'; +import 'package:flutter/material.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; -import 'package:flutter/material.dart'; +import 'package:apidash/widgets/widgets.dart'; import 'consts.dart'; class ApiKeyAuthFields extends StatefulWidget { diff --git a/lib/screens/common_widgets/auth/basic_auth_fields.dart b/lib/screens/common_widgets/auth/basic_auth_fields.dart index 64dd58918..7219f1f90 100644 --- a/lib/screens/common_widgets/auth/basic_auth_fields.dart +++ b/lib/screens/common_widgets/auth/basic_auth_fields.dart @@ -1,6 +1,6 @@ -import 'package:apidash/widgets/auth_textfield.dart'; import 'package:flutter/material.dart'; import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash/widgets/widgets.dart'; import 'consts.dart'; class BasicAuthFields extends StatelessWidget { diff --git a/lib/screens/common_widgets/auth/bearer_auth_fields.dart b/lib/screens/common_widgets/auth/bearer_auth_fields.dart index 22e238965..b213e51bc 100644 --- a/lib/screens/common_widgets/auth/bearer_auth_fields.dart +++ b/lib/screens/common_widgets/auth/bearer_auth_fields.dart @@ -1,6 +1,6 @@ -import 'package:apidash/widgets/auth_textfield.dart'; -import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash/widgets/widgets.dart'; import 'consts.dart'; class BearerAuthFields extends StatefulWidget { diff --git a/lib/screens/common_widgets/auth/digest_auth_fields.dart b/lib/screens/common_widgets/auth/digest_auth_fields.dart index 7fbad306b..96a470e97 100644 --- a/lib/screens/common_widgets/auth/digest_auth_fields.dart +++ b/lib/screens/common_widgets/auth/digest_auth_fields.dart @@ -1,7 +1,7 @@ -import 'package:apidash/widgets/auth_textfield.dart'; -import 'package:apidash_core/apidash_core.dart'; -import 'package:apidash_design_system/widgets/widgets.dart'; import 'package:flutter/material.dart'; +import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:apidash/widgets/widgets.dart'; class DigestAuthFields extends StatefulWidget { final AuthModel? authData; diff --git a/lib/screens/common_widgets/auth/jwt_auth_fields.dart b/lib/screens/common_widgets/auth/jwt_auth_fields.dart index 17b310fdf..18812bf83 100644 --- a/lib/screens/common_widgets/auth/jwt_auth_fields.dart +++ b/lib/screens/common_widgets/auth/jwt_auth_fields.dart @@ -1,7 +1,7 @@ -import 'package:apidash/widgets/auth_textfield.dart'; -import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; import 'package:apidash_core/apidash_core.dart'; +import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:apidash/widgets/widgets.dart'; class JwtAuthFields extends StatefulWidget { final AuthModel? authData; diff --git a/lib/widgets/widgets.dart b/lib/widgets/widgets.dart index aea1f5b19..68c12aaf1 100644 --- a/lib/widgets/widgets.dart +++ b/lib/widgets/widgets.dart @@ -28,6 +28,7 @@ export 'editor_code.dart'; export 'editor_json.dart'; export 'editor.dart'; export 'error_message.dart'; +export 'field_auth.dart'; export 'field_cell_obscurable.dart'; export 'field_cell.dart'; export 'field_json_search.dart'; From 4f1118519528543e4432437ff1de6c4280bb8ed7 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Sat, 12 Jul 2025 16:23:46 +0530 Subject: [PATCH 58/70] Update imports in tests --- test/screens/common_widgets/auth/api_key_auth_fields_test.dart | 2 +- test/screens/common_widgets/auth/basic_auth_fields_test.dart | 2 +- test/screens/common_widgets/auth/bearer_auth_fields_test.dart | 2 +- test/screens/common_widgets/auth/digest_auth_fields_test.dart | 2 +- test/screens/common_widgets/auth/jwt_auth_fields_test.dart | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/screens/common_widgets/auth/api_key_auth_fields_test.dart b/test/screens/common_widgets/auth/api_key_auth_fields_test.dart index 55ce5cd6e..1e60cbd60 100644 --- a/test/screens/common_widgets/auth/api_key_auth_fields_test.dart +++ b/test/screens/common_widgets/auth/api_key_auth_fields_test.dart @@ -1,5 +1,5 @@ import 'package:apidash/screens/common_widgets/auth/api_key_auth_fields.dart'; -import 'package:apidash/widgets/auth_textfield.dart'; +import 'package:apidash/widgets/widgets.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; diff --git a/test/screens/common_widgets/auth/basic_auth_fields_test.dart b/test/screens/common_widgets/auth/basic_auth_fields_test.dart index 862924086..8a5d88142 100644 --- a/test/screens/common_widgets/auth/basic_auth_fields_test.dart +++ b/test/screens/common_widgets/auth/basic_auth_fields_test.dart @@ -1,5 +1,5 @@ import 'package:apidash/screens/common_widgets/auth/basic_auth_fields.dart'; -import 'package:apidash/widgets/auth_textfield.dart'; +import 'package:apidash/widgets/widgets.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/test/screens/common_widgets/auth/bearer_auth_fields_test.dart b/test/screens/common_widgets/auth/bearer_auth_fields_test.dart index 261e45943..c8dc13368 100644 --- a/test/screens/common_widgets/auth/bearer_auth_fields_test.dart +++ b/test/screens/common_widgets/auth/bearer_auth_fields_test.dart @@ -1,5 +1,5 @@ import 'package:apidash/screens/common_widgets/auth/bearer_auth_fields.dart'; -import 'package:apidash/widgets/auth_textfield.dart'; +import 'package:apidash/widgets/widgets.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/test/screens/common_widgets/auth/digest_auth_fields_test.dart b/test/screens/common_widgets/auth/digest_auth_fields_test.dart index a7f599493..2eb26a04e 100644 --- a/test/screens/common_widgets/auth/digest_auth_fields_test.dart +++ b/test/screens/common_widgets/auth/digest_auth_fields_test.dart @@ -1,5 +1,5 @@ import 'package:apidash/screens/common_widgets/auth/digest_auth_fields.dart'; -import 'package:apidash/widgets/auth_textfield.dart'; +import 'package:apidash/widgets/widgets.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/widgets/widgets.dart'; import 'package:flutter/material.dart'; diff --git a/test/screens/common_widgets/auth/jwt_auth_fields_test.dart b/test/screens/common_widgets/auth/jwt_auth_fields_test.dart index 5ab9b1b9c..dd83540b8 100644 --- a/test/screens/common_widgets/auth/jwt_auth_fields_test.dart +++ b/test/screens/common_widgets/auth/jwt_auth_fields_test.dart @@ -1,5 +1,5 @@ import 'package:apidash/screens/common_widgets/auth/jwt_auth_fields.dart'; -import 'package:apidash/widgets/auth_textfield.dart'; +import 'package:apidash/widgets/widgets.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; From 33acbc8e5e4301829d3eb670138d9fa314478b21 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Sat, 12 Jul 2025 18:04:11 +0530 Subject: [PATCH 59/70] Update pubspec.yaml --- packages/better_networking/pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/better_networking/pubspec.yaml b/packages/better_networking/pubspec.yaml index 5214f3997..860d3c1c6 100644 --- a/packages/better_networking/pubspec.yaml +++ b/packages/better_networking/pubspec.yaml @@ -18,6 +18,7 @@ dependencies: flutter: sdk: flutter collection: ^1.18.0 + convert: ^3.1.2 freezed_annotation: ^2.4.1 http: ^1.3.0 http_parser: ^4.1.2 From 447cbd4fa79a3e90d9798c149d731d13fd71e106 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Sat, 12 Jul 2025 18:04:19 +0530 Subject: [PATCH 60/70] refactor for digest --- lib/screens/common_widgets/auth/consts.dart | 19 +++++ .../auth/digest_auth_fields.dart | 75 +++++++------------ packages/better_networking/lib/consts.dart | 3 + .../lib/utils/auth/digest_auth_utils.dart | 6 +- 4 files changed, 54 insertions(+), 49 deletions(-) diff --git a/lib/screens/common_widgets/auth/consts.dart b/lib/screens/common_widgets/auth/consts.dart index de0e85c9e..9258471c2 100644 --- a/lib/screens/common_widgets/auth/consts.dart +++ b/lib/screens/common_widgets/auth/consts.dart @@ -16,3 +16,22 @@ const kHintUsername = "Username"; const kHintPassword = "Password"; const kHintToken = "Token"; + +const kInfoDigestUsername = + "Your username for digest authentication. This will be sent to the server for credential verification."; +const kInfoDigestPassword = + "Your password for digest authentication. This is hashed and not sent in plain text to the server."; +const kHintRealm = "Realm"; +const kInfoDigestRealm = + "Authentication realm as specified by the server. This defines the protection space for the credentials."; +const kHintNonce = "Nonce"; +const kInfoDigestNonce = + "Server-generated random value used to prevent replay attacks."; +const kAlgorithm = "Algorithm"; +const kTooltipAlgorithm = "Algorithm that will be used to produce the digest"; +const kHintQop = "QOP"; +const kInfoDigestQop = + "Quality of Protection. Typically 'auth' for authentication only, or 'auth-int' for authentication with integrity protection."; +const kHintDataString = "Opaque"; +const kInfoDigestDataString = + "Server-specified data string that should be returned unchanged in the authorization header. Usually obtained from server's 401 response."; diff --git a/lib/screens/common_widgets/auth/digest_auth_fields.dart b/lib/screens/common_widgets/auth/digest_auth_fields.dart index 96a470e97..ee75a9364 100644 --- a/lib/screens/common_widgets/auth/digest_auth_fields.dart +++ b/lib/screens/common_widgets/auth/digest_auth_fields.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:apidash/widgets/widgets.dart'; +import 'consts.dart'; class DigestAuthFields extends StatefulWidget { final AuthModel? authData; @@ -36,8 +37,8 @@ class _DigestAuthFieldsState extends State { _passwordController = TextEditingController(text: digest?.password ?? ''); _realmController = TextEditingController(text: digest?.realm ?? ''); _nonceController = TextEditingController(text: digest?.nonce ?? ''); - _algorithmController = digest?.algorithm ?? 'MD5'; - _qopController = TextEditingController(text: digest?.qop ?? 'auth'); + _algorithmController = digest?.algorithm ?? kDigestAlgos[0]; + _qopController = TextEditingController(text: digest?.qop ?? kQop[0]); _opaqueController = TextEditingController(text: digest?.opaque ?? ''); } @@ -50,42 +51,38 @@ class _DigestAuthFieldsState extends State { AuthTextField( readOnly: widget.readOnly, controller: _usernameController, - hintText: "Username", - infoText: - "Your username for digest authentication. This will be sent to the server for credential verification.", + hintText: kHintUsername, + infoText: kInfoDigestUsername, onChanged: (_) => _updateDigestAuth(), ), const SizedBox(height: 12), AuthTextField( readOnly: widget.readOnly, controller: _passwordController, - hintText: "Password", + hintText: kHintPassword, isObscureText: true, - infoText: - "Your password for digest authentication. This is hashed and not sent in plain text to the server.", + infoText: kInfoDigestPassword, onChanged: (_) => _updateDigestAuth(), ), const SizedBox(height: 12), AuthTextField( readOnly: widget.readOnly, controller: _realmController, - hintText: "Realm", - infoText: - "Authentication realm as specified by the server. This defines the protection space for the credentials.", + hintText: kHintRealm, + infoText: kInfoDigestRealm, onChanged: (_) => _updateDigestAuth(), ), const SizedBox(height: 12), AuthTextField( readOnly: widget.readOnly, controller: _nonceController, - hintText: "Nonce", - infoText: - "Server-generated random value used to prevent replay attacks.", + hintText: kHintNonce, + infoText: kInfoDigestNonce, onChanged: (_) => _updateDigestAuth(), ), const SizedBox(height: 12), Text( - "Algorithm", + kAlgorithm, style: TextStyle( fontWeight: FontWeight.normal, fontSize: 14, @@ -94,13 +91,8 @@ class _DigestAuthFieldsState extends State { SizedBox(height: 4), ADPopupMenu( value: _algorithmController.trim(), - values: const [ - ('MD5', 'MD5'), - ('MD5-sess', 'MD5-sess'), - ('SHA-256', 'SHA-256'), - ('SHA-256-sess', 'SHA-256-sess'), - ], - tooltip: "Algorithm that will be used to produce the digest", + values: kDigestAlgos.map((i) => (i, null)), + tooltip: kTooltipAlgorithm, isOutlined: true, onChanged: widget.readOnly ? null @@ -117,18 +109,16 @@ class _DigestAuthFieldsState extends State { AuthTextField( readOnly: widget.readOnly, controller: _qopController, - hintText: "QOP", - infoText: - "Quality of Protection. Typically 'auth' for authentication only, or 'auth-int' for authentication with integrity protection.", + hintText: kHintQop, + infoText: kInfoDigestQop, onChanged: (_) => _updateDigestAuth(), ), const SizedBox(height: 12), AuthTextField( readOnly: widget.readOnly, controller: _opaqueController, - hintText: "Opaque", - infoText: - "Server-specified data string that should be returned unchanged in the authorization header. Usually obtained from server's 401 response.", + hintText: kHintDataString, + infoText: kInfoDigestDataString, onChanged: (_) => _updateDigestAuth(), ), ], @@ -137,29 +127,22 @@ class _DigestAuthFieldsState extends State { } void _updateDigestAuth() { + final digest = AuthDigestModel( + username: _usernameController.text.trim(), + password: _passwordController.text.trim(), + realm: _realmController.text.trim(), + nonce: _nonceController.text.trim(), + algorithm: _algorithmController.trim(), + qop: _qopController.text.trim(), + opaque: _opaqueController.text.trim(), + ); widget.updateAuth(widget.authData?.copyWith( type: APIAuthType.digest, - digest: AuthDigestModel( - username: _usernameController.text.trim(), - password: _passwordController.text.trim(), - realm: _realmController.text.trim(), - nonce: _nonceController.text.trim(), - algorithm: _algorithmController.trim(), - qop: _qopController.text.trim(), - opaque: _opaqueController.text.trim(), - ), + digest: digest, ) ?? AuthModel( type: APIAuthType.digest, - digest: AuthDigestModel( - username: _usernameController.text.trim(), - password: _passwordController.text.trim(), - realm: _realmController.text.trim(), - nonce: _nonceController.text.trim(), - algorithm: _algorithmController.trim(), - qop: _qopController.text.trim(), - opaque: _opaqueController.text.trim(), - ), + digest: digest, )); } } diff --git a/packages/better_networking/lib/consts.dart b/packages/better_networking/lib/consts.dart index 8e5c14724..5d1819be1 100644 --- a/packages/better_networking/lib/consts.dart +++ b/packages/better_networking/lib/consts.dart @@ -23,6 +23,9 @@ enum APIAuthType { final String displayType; } +const kDigestAlgos = ['MD5', 'MD5-sess', 'SHA-256', 'SHA-256-sess']; +const kQop = ['auth', 'auth-int']; + enum HTTPVerb { get("GET"), head("HEAD"), diff --git a/packages/better_networking/lib/utils/auth/digest_auth_utils.dart b/packages/better_networking/lib/utils/auth/digest_auth_utils.dart index bfe701580..c6dd34b05 100644 --- a/packages/better_networking/lib/utils/auth/digest_auth_utils.dart +++ b/packages/better_networking/lib/utils/auth/digest_auth_utils.dart @@ -1,8 +1,8 @@ import 'dart:convert'; import 'dart:math' as math; - import 'package:convert/convert.dart'; import 'package:crypto/crypto.dart' as crypto; +import '../../consts.dart'; import '../../models/models.dart'; Map? splitAuthenticateHeader(String header) { @@ -130,7 +130,7 @@ Map computeResponse( if (qop == null) { final token3 = '$ha1:$nonce:$ha2'; ret['response'] = md5Hash(token3); - } else if (qop == 'auth' || qop == 'auth-int') { + } else if (kQop.contains(qop)) { final token3 = '$ha1:$nonce:$nonceCount:$cnonce:$qop:$ha2'; ret['response'] = md5Hash(token3); } @@ -138,7 +138,7 @@ Map computeResponse( if (qop == null) { final token3 = '$ha1:$nonce:$ha2'; ret['response'] = sha256Hash(token3); - } else if (qop == 'auth' || qop == 'auth-int') { + } else if (kQop.contains(qop)) { final token3 = '$ha1:$nonce:$nonceCount:$cnonce:$qop:$ha2'; ret['response'] = sha256Hash(token3); } From 1e10606ebf76891bdc4854eda93127168fdecf62 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Sat, 12 Jul 2025 18:05:40 +0530 Subject: [PATCH 61/70] Remove comments from JWT --- .../common_widgets/auth/jwt_auth_fields.dart | 113 ------------------ 1 file changed, 113 deletions(-) diff --git a/lib/screens/common_widgets/auth/jwt_auth_fields.dart b/lib/screens/common_widgets/auth/jwt_auth_fields.dart index 18812bf83..1adfa6c53 100644 --- a/lib/screens/common_widgets/auth/jwt_auth_fields.dart +++ b/lib/screens/common_widgets/auth/jwt_auth_fields.dart @@ -186,7 +186,6 @@ Private Key in PKCS#8 PEM Format onChanged: (value) => _updateJwtAuth(), ), ], - const SizedBox(height: 16), Text( "Payload (JSON format)", @@ -226,118 +225,6 @@ Private Key in PKCS#8 PEM Format ), onChanged: (value) => _updateJwtAuth(), ), - // const SizedBox(height: 16), - // if (currentAddTokenTo == 'header') ...[ - // Text( - // "Header Prefix", - // style: TextStyle( - // fontWeight: FontWeight.bold, - // ), - // ), - // SizedBox(height: 4), - // TextField( - // controller: jwtHeaderPrefixController, - // decoration: InputDecoration( - // constraints: BoxConstraints( - // maxWidth: MediaQuery.sizeOf(context).width - 100, - // ), - // contentPadding: const EdgeInsets.all(18), - // hintText: "Bearer", - // hintStyle: Theme.of(context).textTheme.bodyMedium, - // border: OutlineInputBorder( - // borderRadius: BorderRadius.circular(8), - // ), - // ), - // onChanged: (value) => updateAuth(ApiAuthModel( - // type: APIAuthType.jwt, - // jwt: AuthJwtModel( - // secret: jwtSecretController.text.trim(), - // payload: jwtPayloadController.text.trim(), - // addTokenTo: currentAddTokenTo, - // algorithm: currentAlgorithm, - // isSecretBase64Encoded: isSecretBase64Encoded, - // headerPrefix: jwtHeaderPrefixController.text.trim(), - // queryParamKey: jwtQueryParamKeyController.text.trim(), - // header: jwtHeaderController.text.trim(), - // ), - // )), - // ), - // const SizedBox(height: 16), - // ], - // if (currentAddTokenTo == 'query') ...[ - // Text( - // "Query Parameter Key", - // style: TextStyle( - // fontWeight: FontWeight.bold, - // ), - // ), - // SizedBox(height: 4), - // TextField( - // controller: jwtQueryParamKeyController, - // decoration: InputDecoration( - // constraints: BoxConstraints( - // maxWidth: MediaQuery.sizeOf(context).width - 100, - // ), - // contentPadding: const EdgeInsets.all(18), - // hintText: "token", - // hintStyle: Theme.of(context).textTheme.bodyMedium, - // border: OutlineInputBorder( - // borderRadius: BorderRadius.circular(8), - // ), - // ), - // onChanged: (value) => updateAuth(ApiAuthModel( - // type: APIAuthType.jwt, - // jwt: AuthJwtModel( - // secret: jwtSecretController.text.trim(), - // payload: jwtPayloadController.text.trim(), - // addTokenTo: currentAddTokenTo, - // algorithm: currentAlgorithm, - // isSecretBase64Encoded: isSecretBase64Encoded, - // headerPrefix: jwtHeaderPrefixController.text.trim(), - // queryParamKey: jwtQueryParamKeyController.text.trim(), - // header: jwtHeaderController.text.trim(), - // ), - // )), - // ), - // const SizedBox(height: 16), - // ], - // Text( - // "JWT Headers (JSON format)", - // style: TextStyle( - // fontWeight: FontWeight.bold, - // ), - // ), - // SizedBox(height: 4), - // TextField( - // controller: jwtHeaderController, - // maxLines: 3, - // decoration: InputDecoration( - // constraints: BoxConstraints( - // maxWidth: MediaQuery.sizeOf(context).width - 100, - // ), - // contentPadding: const EdgeInsets.all(18), - // hintText: '{"typ": "JWT", "alg": "HS256"}', - // hintStyle: Theme.of(context).textTheme.bodyMedium, - // border: OutlineInputBorder( - // borderRadius: BorderRadius.circular(8), - // ), - // ), - // onChanged: (value) => updateAuth( - // ApiAuthModel( - // type: APIAuthType.jwt, - // jwt: AuthJwtModel( - // secret: jwtSecretController.text.trim(), - // payload: jwtPayloadController.text.trim(), - // addTokenTo: currentAddTokenTo, - // algorithm: currentAlgorithm, - // isSecretBase64Encoded: isSecretBase64Encoded, - // headerPrefix: jwtHeaderPrefixController.text.trim(), - // queryParamKey: jwtQueryParamKeyController.text.trim(), - // header: jwtHeaderController.text.trim(), - // ), - // ), - // ), - // ), ], ); } From 32dcbda80346cd4e75f61df47878a7048013a2d1 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Sat, 12 Jul 2025 23:36:27 +0530 Subject: [PATCH 62/70] JWT refactor --- lib/screens/common_widgets/auth/consts.dart | 27 ++++++ .../common_widgets/auth/jwt_auth_fields.dart | 91 ++++++++----------- packages/better_networking/lib/consts.dart | 17 ++++ 3 files changed, 80 insertions(+), 55 deletions(-) diff --git a/lib/screens/common_widgets/auth/consts.dart b/lib/screens/common_widgets/auth/consts.dart index 9258471c2..0670d642d 100644 --- a/lib/screens/common_widgets/auth/consts.dart +++ b/lib/screens/common_widgets/auth/consts.dart @@ -1,4 +1,6 @@ const kEmpty = ''; + +// API Key Auth const kApiKeyHeaderName = 'x-api-key'; const kAddToLocations = [ ('header', 'Header'), @@ -12,11 +14,14 @@ const kHintTextFieldName = "Header/Query Param Name"; const kLabelApiKey = "API Key"; const kHintTextKey = "Key"; +// Username-password auth const kHintUsername = "Username"; const kHintPassword = "Password"; +// Bearer Token AUth const kHintToken = "Token"; +// Digest Auth const kInfoDigestUsername = "Your username for digest authentication. This will be sent to the server for credential verification."; const kInfoDigestPassword = @@ -35,3 +40,25 @@ const kInfoDigestQop = const kHintDataString = "Opaque"; const kInfoDigestDataString = "Server-specified data string that should be returned unchanged in the authorization header. Usually obtained from server's 401 response."; + +// JWT Auth +const kMsgAddToken = "Add JWT token to"; +const kTooltipTokenAddTo = "Select where to add JWT token"; +const kTextAlgo = "Algorithm"; +const kTooltipJWTAlgo = "Select JWT algorithm"; +const kStartAlgo = "HS"; +const kHintSecret = "Secret Key"; +const kInfoSecret = + "The secret key used to sign the JWT token. Keep this secure and match it with your server configuration."; +const kMsgSecret = "Secret is Base64 encoded"; +const kMsgPrivateKey = "Private Key"; +const kHintRSA = ''' +-----BEGIN RSA PRIVATE KEY----- +Private Key in PKCS#8 PEM Format +-----END RSA PRIVATE KEY----- +'''; +const kMsgPayload = "Payload (JSON format)"; +const kHintJson = + '{"sub": "1234567890", "name": "John Doe", "iat": 1516239022}'; +const kHeaderPrefix = 'Bearer'; +const kQueryParamKey = 'token'; diff --git a/lib/screens/common_widgets/auth/jwt_auth_fields.dart b/lib/screens/common_widgets/auth/jwt_auth_fields.dart index 1adfa6c53..146b3e3c6 100644 --- a/lib/screens/common_widgets/auth/jwt_auth_fields.dart +++ b/lib/screens/common_widgets/auth/jwt_auth_fields.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:apidash/widgets/widgets.dart'; +import 'consts.dart'; class JwtAuthFields extends StatefulWidget { final AuthModel? authData; @@ -34,8 +35,8 @@ class _JwtAuthFieldsState extends State { _secretController = TextEditingController(text: jwt?.secret ?? ''); _privateKeyController = TextEditingController(text: jwt?.privateKey ?? ''); _payloadController = TextEditingController(text: jwt?.payload ?? ''); - _addTokenTo = jwt?.addTokenTo ?? 'header'; - _algorithm = jwt?.algorithm ?? 'HS256'; + _addTokenTo = jwt?.addTokenTo ?? kAddToDefaultLocation; + _algorithm = jwt?.algorithm ?? kJwtAlgos[0]; _isSecretBase64Encoded = jwt?.isSecretBase64Encoded ?? false; } @@ -45,7 +46,7 @@ class _JwtAuthFieldsState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Add JWT token to", + kMsgAddToken, style: TextStyle( fontWeight: FontWeight.normal, fontSize: 14, @@ -53,13 +54,9 @@ class _JwtAuthFieldsState extends State { ), SizedBox(height: 4), ADPopupMenu( - value: - _addTokenTo == 'header' ? 'Request Header' : 'Query Parameters', - values: const [ - ('header', 'Request Header'), - ('query', 'Query Parameters'), - ], - tooltip: "Select where to add JWT token", + value: kAddToLocationsMap[_addTokenTo], + values: kAddToLocations, + tooltip: kTooltipTokenAddTo, isOutlined: true, onChanged: widget.readOnly ? null @@ -74,7 +71,7 @@ class _JwtAuthFieldsState extends State { ), const SizedBox(height: 16), Text( - "Algorithm", + kTextAlgo, style: TextStyle( fontWeight: FontWeight.normal, fontSize: 14, @@ -83,23 +80,8 @@ class _JwtAuthFieldsState extends State { SizedBox(height: 4), ADPopupMenu( value: _algorithm, - values: const [ - ('HS256', 'HS256'), - ('HS384', 'HS384'), - ('HS512', 'HS512'), - ('RS256', 'RS256'), - ('RS384', 'RS384'), - ('RS512', 'RS512'), - ('PS256', 'PS256'), - ('PS384', 'PS384'), - ('PS512', 'PS512'), - ('ES256', 'ES256'), - ('ES256K', 'ES256K'), - ('ES384', 'ES384'), - ('ES512', 'ES512'), - ('EdDSA', 'EdDSA'), - ], - tooltip: "Select JWT algorithm", + values: kJwtAlgos.map((i) => (i, null)), + tooltip: kTooltipJWTAlgo, isOutlined: true, onChanged: widget.readOnly ? null @@ -113,20 +95,19 @@ class _JwtAuthFieldsState extends State { }, ), const SizedBox(height: 16), - if (_algorithm.startsWith('HS')) ...[ + if (_algorithm.startsWith(kStartAlgo)) ...[ AuthTextField( readOnly: widget.readOnly, controller: _secretController, isObscureText: true, - hintText: "Secret key", - infoText: - "The secret key used to sign the JWT token. Keep this secure and match it with your server configuration.", + hintText: kHintSecret, + infoText: kInfoSecret, onChanged: (value) => _updateJwtAuth(), ), const SizedBox(height: 16), CheckboxListTile( title: Text( - "Secret is Base64 encoded", + kMsgSecret, style: TextStyle( fontWeight: FontWeight.normal, fontSize: 14, @@ -145,7 +126,7 @@ class _JwtAuthFieldsState extends State { ), ] else ...[ Text( - "Private Key", + kMsgPrivateKey, style: TextStyle( fontWeight: FontWeight.normal, fontSize: 14, @@ -163,11 +144,7 @@ class _JwtAuthFieldsState extends State { maxWidth: MediaQuery.sizeOf(context).width - 100, ), contentPadding: const EdgeInsets.all(18), - hintText: ''' ------BEGIN RSA PRIVATE KEY----- -Private Key in PKCS#8 PEM Format ------END RSA PRIVATE KEY----- -''', + hintText: kHintRSA, hintStyle: Theme.of(context).textTheme.bodyMedium, border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -188,7 +165,7 @@ Private Key in PKCS#8 PEM Format ], const SizedBox(height: 16), Text( - "Payload (JSON format)", + kMsgPayload, style: TextStyle( fontWeight: FontWeight.normal, fontSize: 14, @@ -206,8 +183,7 @@ Private Key in PKCS#8 PEM Format maxWidth: MediaQuery.sizeOf(context).width - 100, ), contentPadding: const EdgeInsets.all(18), - hintText: - '{"sub": "1234567890", "name": "John Doe", "iat": 1516239022}', + hintText: kHintJson, hintStyle: Theme.of(context).textTheme.bodyMedium, border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), @@ -230,21 +206,26 @@ Private Key in PKCS#8 PEM Format } void _updateJwtAuth() { + final jwt = AuthJwtModel( + secret: _secretController.text.trim(), + privateKey: _privateKeyController.text.trim(), + payload: _payloadController.text.trim(), + addTokenTo: _addTokenTo, + algorithm: _algorithm, + isSecretBase64Encoded: _isSecretBase64Encoded, + headerPrefix: kHeaderPrefix, + queryParamKey: kQueryParamKey, + header: '', + ); widget.updateAuth( widget.authData?.copyWith( - type: APIAuthType.jwt, - jwt: AuthJwtModel( - secret: _secretController.text.trim(), - privateKey: _privateKeyController.text.trim(), - payload: _payloadController.text.trim(), - addTokenTo: _addTokenTo, - algorithm: _algorithm, - isSecretBase64Encoded: _isSecretBase64Encoded, - headerPrefix: 'Bearer', - queryParamKey: 'token', - header: '', - ), - ), + type: APIAuthType.jwt, + jwt: jwt, + ) ?? + AuthModel( + type: APIAuthType.jwt, + jwt: jwt, + ), ); } } diff --git a/packages/better_networking/lib/consts.dart b/packages/better_networking/lib/consts.dart index 5d1819be1..778dba2df 100644 --- a/packages/better_networking/lib/consts.dart +++ b/packages/better_networking/lib/consts.dart @@ -26,6 +26,23 @@ enum APIAuthType { const kDigestAlgos = ['MD5', 'MD5-sess', 'SHA-256', 'SHA-256-sess']; const kQop = ['auth', 'auth-int']; +const kJwtAlgos = [ + 'HS256', + 'HS384', + 'HS512', + 'RS256', + 'RS384', + 'RS512', + 'PS256', + 'PS384', + 'PS512', + 'ES256', + 'ES256K', + 'ES384', + 'ES512', + 'EdDSA', +]; + enum HTTPVerb { get("GET"), head("HEAD"), From b8d0d034ebcef89e93d0735b57ea7794a0426dd3 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Sun, 13 Jul 2025 03:26:21 +0530 Subject: [PATCH 63/70] reinstate highlight --- pubspec.lock | 2 +- pubspec.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pubspec.lock b/pubspec.lock index 97b7d5b2c..0536f2ac5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -734,7 +734,7 @@ packages: source: path version: "0.0.1" highlight: - dependency: transitive + dependency: "direct main" description: name: highlight sha256: "5353a83ffe3e3eca7df0abfb72dcf3fa66cc56b953728e7113ad4ad88497cf21" diff --git a/pubspec.yaml b/pubspec.yaml index cf1e4cc5e..0ef4fae78 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,6 +33,7 @@ dependencies: flutter_riverpod: ^2.5.1 flutter_svg: ^2.0.17 fvp: ^0.32.1 + highlight: ^0.7.0 highlighter: ^0.1.1 hive_flutter: ^1.1.0 hooks_riverpod: ^2.5.2 From 394835187a04d7f2b21e691bc4e51479d4125f88 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Mon, 14 Jul 2025 01:00:49 +0530 Subject: [PATCH 64/70] turns fields optional --- lib/screens/common_widgets/auth/api_key_auth_fields.dart | 6 +++--- lib/screens/common_widgets/auth/basic_auth_fields.dart | 6 +++--- lib/screens/common_widgets/auth/bearer_auth_fields.dart | 6 +++--- lib/screens/common_widgets/auth/digest_auth_fields.dart | 6 +++--- lib/screens/common_widgets/auth/jwt_auth_fields.dart | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/screens/common_widgets/auth/api_key_auth_fields.dart b/lib/screens/common_widgets/auth/api_key_auth_fields.dart index 6cfc23617..edf13de99 100644 --- a/lib/screens/common_widgets/auth/api_key_auth_fields.dart +++ b/lib/screens/common_widgets/auth/api_key_auth_fields.dart @@ -7,12 +7,12 @@ import 'consts.dart'; class ApiKeyAuthFields extends StatefulWidget { final AuthModel? authData; final bool readOnly; - final Function(AuthModel?) updateAuth; + final Function(AuthModel?)? updateAuth; const ApiKeyAuthFields( {super.key, required this.authData, - required this.updateAuth, + this.updateAuth, this.readOnly = false}); @override @@ -91,7 +91,7 @@ class _ApiKeyAuthFieldsState extends State { name: _nameController.text.trim(), location: _addKeyTo, ); - widget.updateAuth(widget.authData?.copyWith( + widget.updateAuth?.call(widget.authData?.copyWith( type: APIAuthType.apiKey, apikey: apiKey, ) ?? diff --git a/lib/screens/common_widgets/auth/basic_auth_fields.dart b/lib/screens/common_widgets/auth/basic_auth_fields.dart index 7219f1f90..5be5f1e48 100644 --- a/lib/screens/common_widgets/auth/basic_auth_fields.dart +++ b/lib/screens/common_widgets/auth/basic_auth_fields.dart @@ -5,13 +5,13 @@ import 'consts.dart'; class BasicAuthFields extends StatelessWidget { final AuthModel? authData; - final Function(AuthModel?) updateAuth; + final Function(AuthModel?)? updateAuth; final bool readOnly; const BasicAuthFields({ super.key, required this.authData, - required this.updateAuth, + this.updateAuth, this.readOnly = false, }); @@ -59,7 +59,7 @@ class BasicAuthFields extends StatelessWidget { username: usernameController.text.trim(), password: passwordController.text.trim(), ); - updateAuth(authData?.copyWith( + updateAuth?.call(authData?.copyWith( type: APIAuthType.basic, basic: basicAuth, ) ?? diff --git a/lib/screens/common_widgets/auth/bearer_auth_fields.dart b/lib/screens/common_widgets/auth/bearer_auth_fields.dart index b213e51bc..2ab8cdb1e 100644 --- a/lib/screens/common_widgets/auth/bearer_auth_fields.dart +++ b/lib/screens/common_widgets/auth/bearer_auth_fields.dart @@ -5,13 +5,13 @@ import 'consts.dart'; class BearerAuthFields extends StatefulWidget { final AuthModel? authData; - final Function(AuthModel?) updateAuth; + final Function(AuthModel?)? updateAuth; final bool readOnly; const BearerAuthFields({ super.key, required this.authData, - required this.updateAuth, + this.updateAuth, this.readOnly = false, }); @@ -44,7 +44,7 @@ class _BearerAuthFieldsState extends State { final bearer = AuthBearerModel( token: _tokenController.text.trim(), ); - widget.updateAuth(widget.authData?.copyWith( + widget.updateAuth?.call(widget.authData?.copyWith( type: APIAuthType.bearer, bearer: bearer, ) ?? diff --git a/lib/screens/common_widgets/auth/digest_auth_fields.dart b/lib/screens/common_widgets/auth/digest_auth_fields.dart index ee75a9364..7ddecc4c4 100644 --- a/lib/screens/common_widgets/auth/digest_auth_fields.dart +++ b/lib/screens/common_widgets/auth/digest_auth_fields.dart @@ -7,12 +7,12 @@ import 'consts.dart'; class DigestAuthFields extends StatefulWidget { final AuthModel? authData; final bool readOnly; - final Function(AuthModel?) updateAuth; + final Function(AuthModel?)? updateAuth; const DigestAuthFields({ super.key, required this.authData, - required this.updateAuth, + this.updateAuth, this.readOnly = false, }); @@ -136,7 +136,7 @@ class _DigestAuthFieldsState extends State { qop: _qopController.text.trim(), opaque: _opaqueController.text.trim(), ); - widget.updateAuth(widget.authData?.copyWith( + widget.updateAuth?.call(widget.authData?.copyWith( type: APIAuthType.digest, digest: digest, ) ?? diff --git a/lib/screens/common_widgets/auth/jwt_auth_fields.dart b/lib/screens/common_widgets/auth/jwt_auth_fields.dart index 146b3e3c6..574420c79 100644 --- a/lib/screens/common_widgets/auth/jwt_auth_fields.dart +++ b/lib/screens/common_widgets/auth/jwt_auth_fields.dart @@ -6,13 +6,13 @@ import 'consts.dart'; class JwtAuthFields extends StatefulWidget { final AuthModel? authData; - final Function(AuthModel?) updateAuth; + final Function(AuthModel?)? updateAuth; final bool readOnly; const JwtAuthFields({ super.key, required this.authData, - required this.updateAuth, + this.updateAuth, this.readOnly = false, }); @@ -217,7 +217,7 @@ class _JwtAuthFieldsState extends State { queryParamKey: kQueryParamKey, header: '', ); - widget.updateAuth( + widget.updateAuth?.call( widget.authData?.copyWith( type: APIAuthType.jwt, jwt: jwt, From 972d8be6b03ed715fd93cde47ace36f00e482cb0 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Mon, 14 Jul 2025 01:01:21 +0530 Subject: [PATCH 65/70] Add AuthPage --- lib/screens/common_widgets/auth/auth.dart | 1 + .../common_widgets/auth/auth_page.dart | 89 ++++++++++ lib/screens/common_widgets/auth/consts.dart | 9 + .../request_pane/request_auth.dart | 155 ++++-------------- 4 files changed, 130 insertions(+), 124 deletions(-) create mode 100644 lib/screens/common_widgets/auth/auth_page.dart diff --git a/lib/screens/common_widgets/auth/auth.dart b/lib/screens/common_widgets/auth/auth.dart index 376feb90d..0ea643fd5 100644 --- a/lib/screens/common_widgets/auth/auth.dart +++ b/lib/screens/common_widgets/auth/auth.dart @@ -1,4 +1,5 @@ export 'api_key_auth_fields.dart'; +export 'auth_page.dart'; export 'basic_auth_fields.dart'; export 'bearer_auth_fields.dart'; export 'digest_auth_fields.dart'; diff --git a/lib/screens/common_widgets/auth/auth_page.dart b/lib/screens/common_widgets/auth/auth_page.dart new file mode 100644 index 000000000..e34b9f06f --- /dev/null +++ b/lib/screens/common_widgets/auth/auth_page.dart @@ -0,0 +1,89 @@ +import 'package:apidash_design_system/apidash_design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:apidash_core/apidash_core.dart'; +import 'api_key_auth_fields.dart'; +import 'basic_auth_fields.dart'; +import 'bearer_auth_fields.dart'; +import 'digest_auth_fields.dart'; +import 'jwt_auth_fields.dart'; +import 'consts.dart'; + +class AuthPage extends StatelessWidget { + final AuthModel? authModel; + final bool readOnly; + final Function(APIAuthType? newType)? onChangedAuthType; + final Function(AuthModel? model)? updateAuthData; + + const AuthPage({ + super.key, + this.authModel, + this.readOnly = false, + this.onChangedAuthType, + this.updateAuthData, + }); + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + kLabelSelectAuthType, + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox( + height: 8, + ), + ADPopupMenu( + value: authModel?.type.displayType, + values: APIAuthType.values + .map((type) => (type, type.displayType)) + .toList(), + tooltip: kTooltipSelectAuth, + isOutlined: true, + onChanged: readOnly ? null : onChangedAuthType, + ), + const SizedBox(height: 48), + switch (authModel?.type) { + APIAuthType.basic => BasicAuthFields( + readOnly: readOnly, + authData: authModel, + updateAuth: updateAuthData, + ), + APIAuthType.bearer => BearerAuthFields( + readOnly: readOnly, + authData: authModel, + updateAuth: updateAuthData, + ), + APIAuthType.apiKey => ApiKeyAuthFields( + readOnly: readOnly, + authData: authModel, + updateAuth: updateAuthData, + ), + APIAuthType.jwt => JwtAuthFields( + readOnly: readOnly, + authData: authModel, + updateAuth: updateAuthData, + ), + APIAuthType.digest => DigestAuthFields( + readOnly: readOnly, + authData: authModel, + updateAuth: updateAuthData, + ), + APIAuthType.none => + Text(readOnly ? kMsgNoAuth : kMsgNoAuthSelected), + _ => Text(readOnly + ? "${authModel?.type.name} $kMsgAuthNotSupported" + : kMsgNotImplemented), + } + ], + ), + ), + ); + } +} diff --git a/lib/screens/common_widgets/auth/consts.dart b/lib/screens/common_widgets/auth/consts.dart index 0670d642d..479f09801 100644 --- a/lib/screens/common_widgets/auth/consts.dart +++ b/lib/screens/common_widgets/auth/consts.dart @@ -62,3 +62,12 @@ const kHintJson = '{"sub": "1234567890", "name": "John Doe", "iat": 1516239022}'; const kHeaderPrefix = 'Bearer'; const kQueryParamKey = 'token'; + +//AuthPAge +const kLabelSelectAuthType = "Authentication Type"; +const kTooltipSelectAuth = "Select Authentication Type"; +const kMsgNoAuth = "No authentication was used for this request."; +const kMsgNoAuthSelected = "No authentication selected."; +const kMsgAuthNotSupported = + "authentication details are not yet supported in history view."; +const kMsgNotImplemented = "This auth type is not implemented yet."; diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart index 0d73f099b..daf0e0d10 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart @@ -1,146 +1,53 @@ -import 'package:apidash/screens/common_widgets/auth/api_key_auth_fields.dart'; -import 'package:apidash/screens/common_widgets/auth/basic_auth_fields.dart'; -import 'package:apidash/screens/common_widgets/auth/bearer_auth_fields.dart'; -import 'package:apidash/screens/common_widgets/auth/digest_auth_fields.dart'; -import 'package:apidash/screens/common_widgets/auth/jwt_auth_fields.dart'; -import 'package:apidash_design_system/widgets/popup_menu.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash/providers/providers.dart'; +import '../../../../common_widgets/common_widgets.dart'; class EditAuthType extends ConsumerWidget { - final AuthModel? authModel; final bool readOnly; const EditAuthType({ super.key, - this.authModel, this.readOnly = false, }); @override Widget build(BuildContext context, WidgetRef ref) { - final AuthModel? currentAuthData; - final APIAuthType currentAuthType; - - if (authModel != null) { - currentAuthData = authModel; - currentAuthType = authModel!.type; - } else { - final selectedRequest = ref.read(selectedRequestModelProvider); - if (selectedRequest == null) { - return const SizedBox.shrink(); - } - - currentAuthType = ref.watch( - selectedRequestModelProvider.select((request) => - request?.httpRequestModel?.authModel?.type ?? APIAuthType.none), - ); - currentAuthData = selectedRequest.httpRequestModel?.authModel; + final selectedRequest = ref.read(selectedRequestModelProvider); + if (selectedRequest == null) { + return const SizedBox.shrink(); } - return SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Authentication Type", - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - SizedBox( - height: 8, - ), - ADPopupMenu( - value: currentAuthType.displayType, - values: APIAuthType.values - .map((type) => (type, type.displayType)) - .toList(), - tooltip: "Select Authentication Type", - isOutlined: true, - onChanged: readOnly - ? null - : (APIAuthType? newType) { - final selectedRequest = - ref.read(selectedRequestModelProvider); - if (newType != null) { - ref - .read(collectionStateNotifierProvider.notifier) - .update( - authModel: selectedRequest - ?.httpRequestModel?.authModel - ?.copyWith(type: newType) ?? - AuthModel(type: newType), - ); - } - }, - ), - const SizedBox(height: 48), - _buildAuthFields(context, ref, currentAuthData), - ], - ), - ), + + ref.watch( + selectedRequestModelProvider.select((request) => + request?.httpRequestModel?.authModel?.type ?? APIAuthType.none), ); - } + final currentAuthData = selectedRequest.httpRequestModel?.authModel; - Widget _buildAuthFields( - BuildContext context, - WidgetRef ref, - AuthModel? authData, - ) { - void updateAuth(AuthModel? model) { - if (model == null) { + return AuthPage( + authModel: currentAuthData, + readOnly: readOnly, + onChangedAuthType: (newType) { + final selectedRequest = ref.read(selectedRequestModelProvider); + if (newType != null) { + ref.read(collectionStateNotifierProvider.notifier).update( + authModel: selectedRequest?.httpRequestModel?.authModel + ?.copyWith(type: newType) ?? + AuthModel(type: newType), + ); + } + }, + updateAuthData: (model) { + if (model == null) { + ref.read(collectionStateNotifierProvider.notifier).update( + authModel: AuthModel(type: APIAuthType.none), + ); + } ref.read(collectionStateNotifierProvider.notifier).update( - authModel: AuthModel(type: APIAuthType.none), + authModel: model, ); - } - ref.read(collectionStateNotifierProvider.notifier).update( - authModel: model, - ); - } - - switch (authData?.type) { - case APIAuthType.basic: - return BasicAuthFields( - readOnly: readOnly, - authData: authData, - updateAuth: updateAuth, - ); - case APIAuthType.bearer: - return BearerAuthFields( - readOnly: readOnly, - authData: authData, - updateAuth: updateAuth, - ); - case APIAuthType.apiKey: - return ApiKeyAuthFields( - readOnly: readOnly, - authData: authData, - updateAuth: updateAuth, - ); - case APIAuthType.jwt: - return JwtAuthFields( - readOnly: readOnly, - authData: authData, - updateAuth: updateAuth, - ); - case APIAuthType.digest: - return DigestAuthFields( - readOnly: readOnly, - authData: authData, - updateAuth: updateAuth, - ); - case APIAuthType.none: - return Text(readOnly - ? "No authentication was used for this request." - : "No authentication selected."); - default: - return Text(readOnly - ? "Authentication details for ${authData?.type.name} are not yet supported in history view." - : "This auth type is not implemented yet."); - } + }, + ); } } From 862319b3df3c197847d4797ceb7f29c80b15c0f4 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Mon, 14 Jul 2025 01:01:44 +0530 Subject: [PATCH 66/70] Update hisotry rwquest pane auth --- lib/screens/history/history_widgets/his_request_pane.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/screens/history/history_widgets/his_request_pane.dart b/lib/screens/history/history_widgets/his_request_pane.dart index 05266ebfc..6766ad1b0 100644 --- a/lib/screens/history/history_widgets/his_request_pane.dart +++ b/lib/screens/history/history_widgets/his_request_pane.dart @@ -1,4 +1,3 @@ -import 'package:apidash/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart'; import 'package:apidash_core/apidash_core.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; @@ -6,6 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/providers/providers.dart'; import 'package:apidash/widgets/widgets.dart'; import 'package:apidash/consts.dart'; +import '../../common_widgets/common_widgets.dart'; import 'his_scripts_tab.dart'; class HistoryRequestPane extends ConsumerWidget { @@ -81,7 +81,7 @@ class HistoryRequestPane extends ConsumerWidget { rows: paramsMap, keyName: kNameURLParam, ), - EditAuthType( + AuthPage( authModel: authModel, readOnly: true, ), @@ -119,7 +119,7 @@ class HistoryRequestPane extends ConsumerWidget { rows: headersMap, keyName: kNameHeader, ), - EditAuthType( + AuthPage( authModel: authModel, readOnly: true, ), From 245a7b79ac876dd308b2d0a3de7beaab6b64f984 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Mon, 14 Jul 2025 01:09:54 +0530 Subject: [PATCH 67/70] Fix EditGraphQLRequestPane provider --- .../request_pane/request_pane_graphql.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart index 91be2b7b7..87ed31040 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_pane_graphql.dart @@ -1,10 +1,10 @@ import 'package:apidash/consts.dart'; -import 'package:apidash/screens/home_page/editor_pane/details_card/request_pane/request_auth.dart'; -import 'package:apidash_core/apidash_core.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:apidash_core/apidash_core.dart'; import 'package:apidash/providers/providers.dart'; import 'package:apidash/widgets/widgets.dart'; +import 'request_auth.dart'; import 'request_headers.dart'; import 'request_body.dart'; import 'request_scripts.dart'; @@ -25,15 +25,15 @@ class EditGraphQLRequestPane extends ConsumerWidget { .select((value) => value?.httpRequestModel?.hasQuery)) ?? false; - final hasAuth = ref.watch(selectedRequestModelProvider - .select((value) => value?.httpRequestModel?.authModel?.type != APIAuthType.none)); - - final scriptsLength = ref.watch(selectedHistoryRequestModelProvider + final scriptsLength = ref.watch(selectedRequestModelProvider .select((value) => value?.preRequestScript?.length)) ?? - ref.watch(selectedHistoryRequestModelProvider + ref.watch(selectedRequestModelProvider .select((value) => value?.postRequestScript?.length)) ?? 0; + final hasAuth = ref.watch(selectedRequestModelProvider.select((value) => + value?.httpRequestModel?.authModel?.type != APIAuthType.none)); + if (tabIndex >= 3) { tabIndex = 0; } From 351131f99d074381772404079d5aeb3e612c7119 Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Mon, 14 Jul 2025 01:19:54 +0530 Subject: [PATCH 68/70] Update pubspec.yaml --- packages/better_networking/pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/better_networking/pubspec.yaml b/packages/better_networking/pubspec.yaml index 860d3c1c6..50caa33fa 100644 --- a/packages/better_networking/pubspec.yaml +++ b/packages/better_networking/pubspec.yaml @@ -19,6 +19,8 @@ dependencies: sdk: flutter collection: ^1.18.0 convert: ^3.1.2 + crypto: ^3.0.6 + dart_jsonwebtoken: ^3.2.0 freezed_annotation: ^2.4.1 http: ^1.3.0 http_parser: ^4.1.2 @@ -26,8 +28,6 @@ dependencies: json_annotation: ^4.9.0 seed: ^0.0.3 xml: ^6.3.0 - crypto: ^3.0.6 - dart_jsonwebtoken: ^3.2.0 dev_dependencies: flutter_test: From 744b8c099439f7f37905e7d4fff27c03ef2c8d2d Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Mon, 14 Jul 2025 01:51:50 +0530 Subject: [PATCH 69/70] Fix dropdown labels --- lib/screens/common_widgets/auth/digest_auth_fields.dart | 2 +- lib/screens/common_widgets/auth/jwt_auth_fields.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/screens/common_widgets/auth/digest_auth_fields.dart b/lib/screens/common_widgets/auth/digest_auth_fields.dart index 7ddecc4c4..8b060ccca 100644 --- a/lib/screens/common_widgets/auth/digest_auth_fields.dart +++ b/lib/screens/common_widgets/auth/digest_auth_fields.dart @@ -91,7 +91,7 @@ class _DigestAuthFieldsState extends State { SizedBox(height: 4), ADPopupMenu( value: _algorithmController.trim(), - values: kDigestAlgos.map((i) => (i, null)), + values: kDigestAlgos.map((i) => (i, i)), tooltip: kTooltipAlgorithm, isOutlined: true, onChanged: widget.readOnly diff --git a/lib/screens/common_widgets/auth/jwt_auth_fields.dart b/lib/screens/common_widgets/auth/jwt_auth_fields.dart index 574420c79..bff161575 100644 --- a/lib/screens/common_widgets/auth/jwt_auth_fields.dart +++ b/lib/screens/common_widgets/auth/jwt_auth_fields.dart @@ -80,7 +80,7 @@ class _JwtAuthFieldsState extends State { SizedBox(height: 4), ADPopupMenu( value: _algorithm, - values: kJwtAlgos.map((i) => (i, null)), + values: kJwtAlgos.map((i) => (i, i)), tooltip: kTooltipJWTAlgo, isOutlined: true, onChanged: widget.readOnly From 1dea1b442ebb0d356db90b2a780118d137b1075b Mon Sep 17 00:00:00 2001 From: Ankit Mahato Date: Mon, 14 Jul 2025 01:52:01 +0530 Subject: [PATCH 70/70] Fix test --- .../common_widgets/auth/jwt_auth_fields_test.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/screens/common_widgets/auth/jwt_auth_fields_test.dart b/test/screens/common_widgets/auth/jwt_auth_fields_test.dart index dd83540b8..ff02166bf 100644 --- a/test/screens/common_widgets/auth/jwt_auth_fields_test.dart +++ b/test/screens/common_widgets/auth/jwt_auth_fields_test.dart @@ -37,7 +37,7 @@ void main() { expect(find.text('Algorithm'), findsOneWidget); expect(find.text('Payload (JSON format)'), findsOneWidget); expect(find.byType(ADPopupMenu), findsNWidgets(2)); - expect(find.text('Request Header'), findsOneWidget); + expect(find.text('Header'), findsOneWidget); expect(find.text('HS256'), findsOneWidget); }); @@ -71,7 +71,7 @@ void main() { expect(find.text('Add JWT token to'), findsOneWidget); expect(find.text('Algorithm'), findsOneWidget); - expect(find.text('Request Header'), findsOneWidget); + expect(find.text('Header'), findsOneWidget); expect(find.text('HS256'), findsOneWidget); }); @@ -103,7 +103,7 @@ void main() { ), ); - expect(find.text('Secret key'), findsExactly(2)); + expect(find.text('Secret Key'), findsExactly(2)); expect(find.text('Secret is Base64 encoded'), findsOneWidget); expect(find.byType(AuthTextField), findsOneWidget); expect(find.byType(CheckboxListTile), findsOneWidget); @@ -138,7 +138,7 @@ void main() { ); expect(find.text('Private Key'), findsOneWidget); - expect(find.text('Secret key'), findsNothing); + expect(find.text('Secret Key'), findsNothing); expect(find.byType(TextField), findsNWidgets(2)); // Private key + payload }); @@ -175,7 +175,7 @@ void main() { await tester.pumpAndSettle(); // Select Query Parameters option - await tester.tap(find.text('Query Parameters').last); + await tester.tap(find.text('Query Params').last); await tester.pumpAndSettle(); // Verify that updateAuth was called @@ -360,7 +360,7 @@ void main() { ); // Default token location should be header - expect(find.text('Request Header'), findsOneWidget); + expect(find.text('Header'), findsOneWidget); // Default algorithm should be HS256 expect(find.text('HS256'), findsOneWidget);