chore(http): add new package
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:wyatt_http_client/src/authentication/interfaces/header_authentication_client.dart';
|
||||
import 'package:wyatt_http_client/src/utils/authentication_methods.dart';
|
||||
import 'package:wyatt_http_client/src/utils/header_keys.dart';
|
||||
import 'package:wyatt_http_client/src/utils/utils.dart';
|
||||
|
||||
class BasicAuthenticationClient extends HeaderAuthenticationClient {
|
||||
final String username;
|
||||
final String password;
|
||||
final bool preemptive;
|
||||
|
||||
late String authenticationHeader;
|
||||
|
||||
BasicAuthenticationClient({
|
||||
required this.username,
|
||||
required this.password,
|
||||
this.preemptive = true,
|
||||
String? authenticationHeader,
|
||||
BaseClient? inner,
|
||||
}) : super(inner) {
|
||||
this.authenticationHeader =
|
||||
authenticationHeader ?? HeaderKeys.authorization.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, String> modifyHeader(
|
||||
Map<String, String> header, [
|
||||
BaseRequest? request,
|
||||
]) {
|
||||
header[authenticationHeader] = '${AuthenticationMethods.basic} '
|
||||
'${base64Encode(utf8.encode('$username:$password'))}';
|
||||
return header;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<StreamedResponse> send(BaseRequest request) async {
|
||||
if (preemptive) {
|
||||
// Just send request with modified header.
|
||||
return super.send(request);
|
||||
}
|
||||
|
||||
// Try to send request without modified header,
|
||||
// and if it fails, send it with.
|
||||
final response = await inner.send(request);
|
||||
if (response.statusCode == HttpStatus.unauthorized) {
|
||||
// TODO(hpcl): save realm.
|
||||
final newRequest = Utils.copyRequest(request);
|
||||
return super.send(newRequest);
|
||||
} else {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:http/http.dart';
|
||||
import 'package:wyatt_http_client/src/authentication/interfaces/header_authentication_client.dart';
|
||||
import 'package:wyatt_http_client/src/utils/authentication_methods.dart';
|
||||
import 'package:wyatt_http_client/src/utils/header_keys.dart';
|
||||
import 'package:wyatt_http_client/src/utils/utils.dart';
|
||||
|
||||
class BearerAuthenticationClient extends HeaderAuthenticationClient {
|
||||
final String token;
|
||||
final bool preemptive;
|
||||
|
||||
late String authenticationHeader;
|
||||
late String authenticationMethod;
|
||||
|
||||
BearerAuthenticationClient({
|
||||
required this.token,
|
||||
this.preemptive = true,
|
||||
String? authenticationHeader,
|
||||
String? authenticationMethod,
|
||||
BaseClient? inner,
|
||||
}) : super(inner) {
|
||||
this.authenticationHeader =
|
||||
authenticationHeader ?? HeaderKeys.authorization.toString();
|
||||
this.authenticationMethod =
|
||||
authenticationMethod ?? AuthenticationMethods.bearer.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, String> modifyHeader(
|
||||
Map<String, String> header, [
|
||||
BaseRequest? request,
|
||||
]) {
|
||||
header[authenticationHeader] = '$authenticationMethod $token';
|
||||
return header;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<StreamedResponse> send(BaseRequest request) async {
|
||||
if (preemptive) {
|
||||
// Just send request with modified header.
|
||||
return super.send(request);
|
||||
}
|
||||
|
||||
// Try to send request without modified header,
|
||||
final response = await inner.send(request);
|
||||
if (response.statusCode == HttpStatus.unauthorized) {
|
||||
final newRequest = Utils.copyRequest(request);
|
||||
return super.send(newRequest);
|
||||
} else {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:http/http.dart';
|
||||
import 'package:wyatt_http_client/src/authentication/interfaces/header_authentication_client.dart';
|
||||
import 'package:wyatt_http_client/src/utils/digest_auth.dart';
|
||||
import 'package:wyatt_http_client/src/utils/header_keys.dart';
|
||||
import 'package:wyatt_http_client/src/utils/utils.dart';
|
||||
|
||||
class DigestAuthenticationClient extends HeaderAuthenticationClient {
|
||||
final String username;
|
||||
final String password;
|
||||
final DigestAuth _digestAuth;
|
||||
|
||||
late String authenticationHeader;
|
||||
late String wwwAuthenticateHeader;
|
||||
|
||||
DigestAuthenticationClient({
|
||||
required this.username,
|
||||
required this.password,
|
||||
String? authenticationHeader,
|
||||
String? wwwAuthenticateHeader,
|
||||
BaseClient? inner,
|
||||
}) : _digestAuth = DigestAuth(username, password),
|
||||
super(inner) {
|
||||
this.authenticationHeader =
|
||||
authenticationHeader ?? HeaderKeys.authorization.toString();
|
||||
this.wwwAuthenticateHeader =
|
||||
wwwAuthenticateHeader ?? HeaderKeys.wwwAuthenticate.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, String> modifyHeader(
|
||||
Map<String, String> header, [
|
||||
BaseRequest? request,
|
||||
]) {
|
||||
if ((_digestAuth.isReady()) && request != null) {
|
||||
header[authenticationHeader] = _digestAuth.getAuthString(
|
||||
request.method,
|
||||
request.url,
|
||||
);
|
||||
}
|
||||
return header;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<StreamedResponse> send(BaseRequest request) async {
|
||||
// Check if our DigestAuth is ready.
|
||||
if (_digestAuth.isReady()) {
|
||||
// If it is, try to send the request with the modified header.
|
||||
return super.send(request);
|
||||
}
|
||||
|
||||
// If it isn't, try to send the request without the modified header.
|
||||
final response = await inner.send(request);
|
||||
|
||||
if (response.statusCode == HttpStatus.unauthorized) {
|
||||
final newRequest = Utils.copyRequest(request);
|
||||
final authInfo =
|
||||
response.headers[HeaderKeys.wwwAuthenticate.toString().toLowerCase()];
|
||||
_digestAuth.initFromAuthenticateHeader(authInfo);
|
||||
return super.send(newRequest);
|
||||
} else {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:http/http.dart';
|
||||
import 'package:wyatt_http_client/src/rest_client.dart';
|
||||
|
||||
abstract class AuthenticationClient extends BaseClient {
|
||||
final BaseClient _inner;
|
||||
|
||||
BaseClient get inner => _inner;
|
||||
|
||||
AuthenticationClient(BaseClient? inner) : _inner = inner ?? RestClient();
|
||||
|
||||
@override
|
||||
Future<StreamedResponse> send(BaseRequest request) {
|
||||
return _inner.send(request);
|
||||
}
|
||||
|
||||
@override
|
||||
void close() {
|
||||
_inner.close();
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:http/http.dart';
|
||||
import 'package:wyatt_http_client/src/authentication/interfaces/authentication_client.dart';
|
||||
|
||||
abstract class HeaderAuthenticationClient extends AuthenticationClient {
|
||||
HeaderAuthenticationClient(super.inner);
|
||||
|
||||
Map<String, String> modifyHeader(
|
||||
Map<String, String> header, [
|
||||
BaseRequest? request,
|
||||
]) =>
|
||||
header;
|
||||
|
||||
@override
|
||||
Future<StreamedResponse> send(BaseRequest request) {
|
||||
final newHeader = modifyHeader(Map.from(request.headers), request);
|
||||
request.headers.clear();
|
||||
request.headers.addAll(newHeader);
|
||||
return super.send(request);
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:http/http.dart';
|
||||
import 'package:wyatt_http_client/src/authentication/interfaces/authentication_client.dart';
|
||||
|
||||
abstract class UrlAuthenticationClient extends AuthenticationClient {
|
||||
UrlAuthenticationClient(super.inner);
|
||||
|
||||
BaseRequest modifyRequest(BaseRequest request) => request;
|
||||
|
||||
@override
|
||||
Future<StreamedResponse> send(BaseRequest request) {
|
||||
final newRequest = modifyRequest(request);
|
||||
return super.send(newRequest);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:http/http.dart';
|
||||
import 'package:wyatt_http_client/src/authentication/interfaces/url_authentication_client.dart';
|
||||
import 'package:wyatt_http_client/src/utils/convert.dart';
|
||||
import 'package:wyatt_http_client/src/utils/utils.dart';
|
||||
|
||||
class UnsafeAuthenticationClient extends UrlAuthenticationClient {
|
||||
final String username;
|
||||
final String password;
|
||||
|
||||
final String usernameField;
|
||||
final String passwordField;
|
||||
|
||||
UnsafeAuthenticationClient({
|
||||
required this.username,
|
||||
required this.password,
|
||||
this.usernameField = 'username',
|
||||
this.passwordField = 'password',
|
||||
BaseClient? inner,
|
||||
}) : super(inner);
|
||||
|
||||
@override
|
||||
BaseRequest modifyRequest(BaseRequest request) {
|
||||
final url =
|
||||
request.url + '?$usernameField=$username&$passwordField=$password';
|
||||
return Utils.copyRequestWith(request, url: url);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:http/http.dart';
|
||||
import 'package:wyatt_http_client/src/utils/protocols.dart';
|
||||
import 'package:wyatt_http_client/src/utils/utils.dart';
|
||||
|
||||
class RestClient extends BaseClient {
|
||||
final Protocols protocol;
|
||||
final String? authority;
|
||||
|
||||
final Client _inner;
|
||||
|
||||
RestClient({
|
||||
this.protocol = Protocols.https,
|
||||
this.authority = '',
|
||||
Client? inner,
|
||||
}) : _inner = inner ?? Client();
|
||||
|
||||
@override
|
||||
Future<StreamedResponse> send(BaseRequest request) {
|
||||
final Uri uri = Uri.parse('${protocol.scheme}$authority${request.url}');
|
||||
return _inner.send(Utils.copyRequestWith(request, url: uri));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
enum AuthenticationMethods {
|
||||
basic('Basic'),
|
||||
bearer('Bearer'),
|
||||
digest('Digest'),
|
||||
apiKey('ApiKey');
|
||||
|
||||
final String name;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
const AuthenticationMethods(this.name);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
class Convert {
|
||||
static String toHex(List<int> bytes, {bool upperCase = false}) {
|
||||
final buffer = StringBuffer();
|
||||
for (final int part in bytes) {
|
||||
if (part & 0xff != part) {
|
||||
throw FormatException('Non-byte integer detected');
|
||||
}
|
||||
buffer.write('${part < 16 ? '0' : ''}${part.toRadixString(16)}');
|
||||
}
|
||||
if (upperCase) {
|
||||
return buffer.toString().toUpperCase();
|
||||
} else {
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension UriX on Uri {
|
||||
Uri operator +(String path) {
|
||||
final thisPath = toString();
|
||||
return Uri.parse(thisPath + path);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:crypto/crypto.dart';
|
||||
|
||||
class Crypto {
|
||||
/// Hash a string using MD5
|
||||
static String md5Hash(String data) {
|
||||
final content = Utf8Encoder().convert(data);
|
||||
final md5Crypto = md5;
|
||||
final digest = md5Crypto.convert(content).toString();
|
||||
return digest;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:wyatt_http_client/src/utils/convert.dart';
|
||||
import 'package:wyatt_http_client/src/utils/crypto.dart';
|
||||
|
||||
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);
|
||||
|
||||
/// Splits WWW-Authenticate header into a map.
|
||||
Map<String, String>? splitWWWAuthenticateHeader(String header) {
|
||||
if (!header.startsWith('Digest ')) {
|
||||
throw ArgumentError.value(
|
||||
header,
|
||||
'header',
|
||||
'Header must start with "Digest "',
|
||||
);
|
||||
}
|
||||
final h = header.substring(7); // remove 'Digest '
|
||||
final ret = <String, String>{};
|
||||
|
||||
final components = h.split(',').map((token) => token.trim());
|
||||
for (final component in components) {
|
||||
final kv = component.split('=');
|
||||
ret[kv[0]] = kv.getRange(1, kv.length).join('=').replaceAll('"', '');
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
String _computeNonce() {
|
||||
final rnd = Random.secure();
|
||||
final values = List<int>.generate(16, (i) => rnd.nextInt(256));
|
||||
|
||||
return Convert.toHex(values);
|
||||
}
|
||||
|
||||
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 == null || algorithm == 'MD5') {
|
||||
final token1 = '$username:$realm:$password';
|
||||
return Crypto.md5Hash(token1);
|
||||
} else if (algorithm == 'MD5-sess') {
|
||||
final token1 = '$username:$realm:$password';
|
||||
final md51 = Crypto.md5Hash(token1);
|
||||
final token2 = '$md51:$nonce:$cnonce';
|
||||
return Crypto.md5Hash(token2);
|
||||
} else {
|
||||
throw ArgumentError.value(
|
||||
algorithm,
|
||||
'algorithm',
|
||||
'Unsupported algorithm',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String?> _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,
|
||||
) {
|
||||
final ret = <String, String?>{};
|
||||
|
||||
final ha1 =
|
||||
_computeHA1(realm, algorithm, username, password, nonce, cnonce);
|
||||
|
||||
String ha2;
|
||||
|
||||
if (qop == 'auth-int') {
|
||||
final bodyHash = Crypto.md5Hash(body);
|
||||
final token2 = '$method:$path:$bodyHash';
|
||||
ha2 = Crypto.md5Hash(token2);
|
||||
} else {
|
||||
// qop in [null, auth]
|
||||
final token2 = '$method:$path';
|
||||
ha2 = Crypto.md5Hash(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 (qop == null) {
|
||||
final token3 = '$ha1:$nonce:$ha2';
|
||||
ret['response'] = Crypto.md5Hash(token3);
|
||||
} else if (qop == 'auth' || qop == 'auth-int') {
|
||||
final token3 = '$ha1:$nonce:$nonceCount:$cnonce:$qop:$ha2';
|
||||
ret['response'] = Crypto.md5Hash(token3);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
String getAuthString(String method, Uri url) {
|
||||
final _cnonce = _computeNonce();
|
||||
_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,
|
||||
'',
|
||||
_algorithm,
|
||||
_qop,
|
||||
_opaque,
|
||||
_realm!,
|
||||
_cnonce,
|
||||
_nonce,
|
||||
_nc,
|
||||
username,
|
||||
password,
|
||||
);
|
||||
final authValuesString = authValues.entries
|
||||
.where((e) => e.value != null)
|
||||
.map((e) => [e.key, '="', e.value, '"'].join())
|
||||
.toList()
|
||||
.join(', ');
|
||||
final authString = 'Digest $authValuesString';
|
||||
return authString;
|
||||
}
|
||||
|
||||
void initFromAuthenticateHeader(String? authInfo) {
|
||||
if (authInfo == null) {
|
||||
throw ArgumentError.notNull('authInfo');
|
||||
}
|
||||
final values = splitWWWAuthenticateHeader(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;
|
||||
}
|
||||
}
|
||||
|
||||
bool isReady() {
|
||||
return _nonce != null && (_nc == 0 || _qop != null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
enum HeaderKeys {
|
||||
authorization('Authorization'),
|
||||
wwwAuthenticate('WWW-Authenticate'),
|
||||
contentType('Content-Type');
|
||||
|
||||
final String name;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
const HeaderKeys(this.name);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
enum Protocols {
|
||||
http,
|
||||
https;
|
||||
|
||||
String get name => toString().split('.').last;
|
||||
String get scheme => '$name://';
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:http/http.dart';
|
||||
|
||||
abstract class Utils {
|
||||
static Request _copyNormalRequest(Request original) {
|
||||
final request = Request(original.method, original.url)
|
||||
..followRedirects = original.followRedirects
|
||||
..headers.addAll(original.headers)
|
||||
..maxRedirects = original.maxRedirects
|
||||
..persistentConnection = original.persistentConnection
|
||||
..body = original.body;
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
static Request _copyNormalRequestWith(
|
||||
Request original, {
|
||||
String? method,
|
||||
Uri? url,
|
||||
Map<String, String>? headers,
|
||||
int? maxRedirects,
|
||||
bool? followRedirects,
|
||||
bool? persistentConnection,
|
||||
String? body,
|
||||
}) {
|
||||
final request = Request(method ?? original.method, url ?? original.url)
|
||||
..followRedirects = followRedirects ?? original.followRedirects
|
||||
..headers.addAll(headers ?? original.headers)
|
||||
..maxRedirects = maxRedirects ?? original.maxRedirects
|
||||
..persistentConnection =
|
||||
persistentConnection ?? original.persistentConnection
|
||||
..body = body ?? original.body;
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
static BaseRequest copyRequest(BaseRequest original) {
|
||||
if (original is Request) {
|
||||
return _copyNormalRequest(original);
|
||||
} else {
|
||||
throw UnimplementedError(
|
||||
'Cannot handle requests of type ${original.runtimeType}',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static BaseRequest copyRequestWith(
|
||||
BaseRequest original, {
|
||||
String? method,
|
||||
Uri? url,
|
||||
Map<String, String>? headers,
|
||||
int? maxRedirects,
|
||||
bool? followRedirects,
|
||||
bool? persistentConnection,
|
||||
String? body,
|
||||
}) {
|
||||
if (original is Request) {
|
||||
return _copyNormalRequestWith(
|
||||
original,
|
||||
method: method,
|
||||
url: url,
|
||||
headers: headers,
|
||||
maxRedirects: maxRedirects,
|
||||
followRedirects: followRedirects,
|
||||
persistentConnection: persistentConnection,
|
||||
body: body,
|
||||
);
|
||||
} else {
|
||||
throw UnimplementedError(
|
||||
'Cannot handle requests of type ${original.runtimeType}',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
library wyatt_http_client;
|
||||
Reference in New Issue
Block a user