From 85030c72a6109276e65ec31a6c6bd203297d2294 Mon Sep 17 00:00:00 2001 From: Udhay-Adithya Date: Mon, 21 Jul 2025 23:34:26 +0530 Subject: [PATCH] feat: implement oauth1 authentication fields in AuthPage --- .../common_widgets/auth/auth_page.dart | 6 + .../common_widgets/auth/oauth1_fields.dart | 227 ++++++++++++++++++ .../better_networking/lib/models/models.dart | 3 +- 3 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 lib/screens/common_widgets/auth/oauth1_fields.dart diff --git a/lib/screens/common_widgets/auth/auth_page.dart b/lib/screens/common_widgets/auth/auth_page.dart index fa24da72..65d96259 100644 --- a/lib/screens/common_widgets/auth/auth_page.dart +++ b/lib/screens/common_widgets/auth/auth_page.dart @@ -7,6 +7,7 @@ import 'bearer_auth_fields.dart'; import 'digest_auth_fields.dart'; import 'jwt_auth_fields.dart'; import 'consts.dart'; +import 'oauth1_fields.dart'; import 'oauth2_field.dart'; class AuthPage extends StatelessWidget { @@ -76,6 +77,11 @@ class AuthPage extends StatelessWidget { authData: authModel, updateAuth: updateAuthData, ), + APIAuthType.oauth1 => OAuth1Fields( + readOnly: readOnly, + authData: authModel, + updateAuth: updateAuthData, + ), APIAuthType.oauth2 => OAuth2Fields( readOnly: readOnly, authData: authModel, diff --git a/lib/screens/common_widgets/auth/oauth1_fields.dart b/lib/screens/common_widgets/auth/oauth1_fields.dart new file mode 100644 index 00000000..7de37043 --- /dev/null +++ b/lib/screens/common_widgets/auth/oauth1_fields.dart @@ -0,0 +1,227 @@ +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'; + +class OAuth1Fields extends StatefulWidget { + final AuthModel? authData; + + final bool readOnly; + + final Function(AuthModel?)? updateAuth; + + const OAuth1Fields({ + super.key, + required this.authData, + required this.updateAuth, + this.readOnly = false, + }); + + @override + State createState() => _OAuth1FieldsState(); +} + +class _OAuth1FieldsState extends State { + late TextEditingController _consumerKeyController; + late TextEditingController _consumerSecretController; + late TextEditingController _accessTokenController; + late TextEditingController _tokenSecretController; + late TextEditingController _callbackUrlController; + late TextEditingController _verifierController; + late TextEditingController _timestampController; + late TextEditingController _realmController; + late TextEditingController _nonceController; + late String _signatureMethodController; + late String _addAuthDataTo; + + @override + void initState() { + super.initState(); + final oauth1 = widget.authData?.oauth1; + _consumerKeyController = + TextEditingController(text: oauth1?.consumerKey ?? ''); + _consumerSecretController = + TextEditingController(text: oauth1?.consumerSecret ?? ''); + _accessTokenController = + TextEditingController(text: oauth1?.accessToken ?? ''); + _tokenSecretController = + TextEditingController(text: oauth1?.tokenSecret ?? ''); + _callbackUrlController = + TextEditingController(text: oauth1?.callbackUrl ?? ''); + _verifierController = TextEditingController(text: oauth1?.verifier ?? ''); + _timestampController = TextEditingController(text: oauth1?.timestamp ?? ''); + _realmController = TextEditingController(text: oauth1?.realm ?? ''); + _nonceController = TextEditingController(text: oauth1?.nonce ?? ''); + _signatureMethodController = oauth1?.signatureMethod ?? 'hmacsha1'; + _addAuthDataTo = oauth1?.parameterLocation ?? 'url'; + } + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Add auth data to", + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: 14, + ), + ), + SizedBox( + height: 4, + ), + ADPopupMenu( + value: _addAuthDataTo, + values: const [ + ('URL', 'url'), + ('Header', 'header'), + ('Body', 'body'), + ], + tooltip: "Select where to add API key", + isOutlined: true, + onChanged: (String? newLocation) { + if (newLocation != null) { + setState(() { + _addAuthDataTo = newLocation; + }); + + _updateOAuth1(); + } + }, + ), + const SizedBox(height: 16), + AuthTextField( + readOnly: widget.readOnly, + controller: _consumerKeyController, + hintText: "Consumer Key", + onChanged: (_) => _updateOAuth1(), + ), + const SizedBox(height: 16), + AuthTextField( + readOnly: widget.readOnly, + controller: _consumerSecretController, + hintText: "Consumer Secret", + isObscureText: true, + onChanged: (_) => _updateOAuth1(), + ), + const SizedBox(height: 16), + Text( + "Signature Method", + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: 14, + ), + ), + const SizedBox(height: 4), + ADPopupMenu( + value: _signatureMethodController.trim(), + values: const [ + ('HMAC-SHA1', 'hmacsha1'), + ('HMAC-SHA256', 'hmacsha256'), + ('HMAC-SHA512', 'hmacsha512'), + ('Plaintext', 'plaintext'), + ], + tooltip: "this algorithm will be used to produce the digest", + isOutlined: true, + onChanged: (String? newAlgo) { + if (newAlgo != null) { + setState(() { + _signatureMethodController = newAlgo; + }); + + _updateOAuth1(); + } + }, + ), + const SizedBox(height: 16), + AuthTextField( + readOnly: widget.readOnly, + controller: _accessTokenController, + hintText: "Access Token", + onChanged: (_) => _updateOAuth1(), + ), + const SizedBox(height: 16), + AuthTextField( + readOnly: widget.readOnly, + controller: _tokenSecretController, + hintText: "Token Secret", + onChanged: (_) => _updateOAuth1(), + ), + const SizedBox(height: 16), + AuthTextField( + readOnly: widget.readOnly, + controller: _callbackUrlController, + hintText: "Callback URL", + onChanged: (_) => _updateOAuth1(), + ), + const SizedBox(height: 16), + AuthTextField( + readOnly: widget.readOnly, + controller: _verifierController, + hintText: "Verifier", + onChanged: (_) => _updateOAuth1(), + ), + const SizedBox(height: 16), + AuthTextField( + readOnly: widget.readOnly, + controller: _timestampController, + hintText: "Timestamp", + onChanged: (_) => _updateOAuth1(), + ), + const SizedBox(height: 16), + AuthTextField( + readOnly: widget.readOnly, + controller: _nonceController, + hintText: "Nonce", + onChanged: (_) => _updateOAuth1(), + ), + const SizedBox(height: 16), + AuthTextField( + readOnly: widget.readOnly, + controller: _realmController, + hintText: "Realm", + onChanged: (_) => _updateOAuth1(), + ), + const SizedBox(height: 16), + ], + ); + } + + void _updateOAuth1() { + widget.updateAuth?.call( + widget.authData?.copyWith( + type: APIAuthType.oauth1, + oauth1: AuthOAuth1Model( + consumerKey: _consumerKeyController.text.trim(), + consumerSecret: _consumerSecretController.text.trim(), + accessToken: _accessTokenController.text.trim(), + tokenSecret: _tokenSecretController.text.trim(), + signatureMethod: _signatureMethodController, + parameterLocation: _addAuthDataTo, + callbackUrl: _callbackUrlController.text.trim(), + verifier: _verifierController.text.trim(), + timestamp: _timestampController.text.trim(), + nonce: _nonceController.text.trim(), + realm: _realmController.text.trim(), + ), + ) ?? + AuthModel( + type: APIAuthType.oauth1, + oauth1: AuthOAuth1Model( + consumerKey: _consumerKeyController.text.trim(), + consumerSecret: _consumerSecretController.text.trim(), + accessToken: _accessTokenController.text.trim(), + tokenSecret: _tokenSecretController.text.trim(), + signatureMethod: _signatureMethodController, + parameterLocation: _addAuthDataTo, + callbackUrl: _callbackUrlController.text.trim(), + verifier: _verifierController.text.trim(), + timestamp: _timestampController.text.trim(), + nonce: _nonceController.text.trim(), + realm: _realmController.text.trim(), + ), + ), + ); + } +} diff --git a/packages/better_networking/lib/models/models.dart b/packages/better_networking/lib/models/models.dart index 6f559000..5974ac9b 100644 --- a/packages/better_networking/lib/models/models.dart +++ b/packages/better_networking/lib/models/models.dart @@ -6,4 +6,5 @@ export 'auth/auth_basic_model.dart'; export 'auth/auth_bearer_model.dart'; export 'auth/auth_jwt_model.dart'; export 'auth/auth_digest_model.dart'; -export 'auth/auth_oauth2_model.dart'; \ No newline at end of file +export 'auth/auth_oauth2_model.dart'; +export 'auth/auth_oauth1_model.dart';