mirror of
https://github.com/foss42/apidash.git
synced 2025-08-18 17:34:18 +08:00

Removed redundant AuthModel parameter from sendHttpRequest and streamHttpRequest functions, now using authModel from HttpRequestModel directly. Updated all usages, tests, and related logic to reflect this change. Improved streaming response handling in CollectionStateNotifier and HttpResponseModel.
170 lines
5.5 KiB
Dart
170 lines
5.5 KiB
Dart
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<HttpRequestModel> handleAuth(
|
|
HttpRequestModel httpRequestModel,
|
|
AuthModel? authData,
|
|
) async {
|
|
if (authData == null || authData.type == APIAuthType.none) {
|
|
return httpRequestModel;
|
|
}
|
|
|
|
List<NameValueModel> updatedHeaders = List.from(
|
|
httpRequestModel.headers ?? [],
|
|
);
|
|
List<NameValueModel> updatedParams = List.from(httpRequestModel.params ?? []);
|
|
List<bool> updatedHeaderEnabledList = List.from(
|
|
httpRequestModel.isHeaderEnabledList ?? [],
|
|
);
|
|
List<bool> 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!;
|
|
final jwtToken = generateJWT(jwtAuth);
|
|
|
|
if (jwtAuth.addTokenTo == 'header') {
|
|
final headerValue = jwtAuth.headerPrefix.isNotEmpty
|
|
? '${jwtAuth.headerPrefix} $jwtToken'
|
|
: jwtToken;
|
|
updatedHeaders.add(
|
|
NameValueModel(name: 'Authorization', value: headerValue),
|
|
);
|
|
updatedHeaderEnabledList.add(true);
|
|
} else if (jwtAuth.addTokenTo == 'query') {
|
|
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,
|
|
httpRequestModel,
|
|
);
|
|
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,
|
|
);
|
|
}
|