2020-01-04 19:31:52 +00:00
|
|
|
import 'dart:convert';
|
2020-01-08 12:26:34 +00:00
|
|
|
import 'package:dio/dio.dart' as __dio;
|
2020-01-04 19:31:52 +00:00
|
|
|
import 'package:crypto/crypto.dart' as crypto;
|
|
|
|
import 'dart:math' as math;
|
|
|
|
|
|
|
|
class DigestRequest {
|
|
|
|
final md5 = crypto.md5;
|
|
|
|
|
|
|
|
String generateCnonce() {
|
|
|
|
final rnd = math.Random.secure();
|
2020-01-08 12:26:34 +00:00
|
|
|
final values = List<int>.generate(32, (i) => rnd.nextInt(256));
|
2020-01-04 19:31:52 +00:00
|
|
|
return base64Url.encode(values).substring(0, 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
String generateHA1({String realm, String username, String password}) {
|
|
|
|
final ha1CredentialsData =
|
2020-01-08 12:26:34 +00:00
|
|
|
Utf8Encoder().convert('$username:$realm:$password');
|
2020-01-04 19:31:52 +00:00
|
|
|
final ha1 = md5.convert(ha1CredentialsData).toString();
|
|
|
|
|
|
|
|
return ha1;
|
|
|
|
}
|
|
|
|
|
|
|
|
String generateHA2({String method, String uri}) {
|
|
|
|
final ha2Data = Utf8Encoder().convert('$method:$uri');
|
|
|
|
final ha2 = md5.convert(ha2Data).toString();
|
|
|
|
|
|
|
|
return ha2;
|
|
|
|
}
|
|
|
|
|
|
|
|
String generateResponseString(
|
|
|
|
{String ha1,
|
2020-01-08 12:26:34 +00:00
|
|
|
String ha2,
|
|
|
|
String nonce,
|
|
|
|
String nonceCount,
|
|
|
|
String cnonce,
|
|
|
|
String qop}) {
|
2020-01-04 19:31:52 +00:00
|
|
|
final responseData =
|
2020-01-08 12:26:34 +00:00
|
|
|
Utf8Encoder().convert('$ha1:$nonce:$nonceCount:$cnonce:$qop:$ha2');
|
2020-01-04 19:31:52 +00:00
|
|
|
final response = md5.convert(responseData).toString();
|
|
|
|
|
|
|
|
return response;
|
|
|
|
}
|
|
|
|
|
|
|
|
Map<String, String> parsetAuthorizationHeader({String source}) {
|
|
|
|
final authHeaderParts =
|
2020-01-08 12:26:34 +00:00
|
|
|
source.substring(7).split(',').map((item) => item.trim());
|
|
|
|
final authenticate = Map<String, String>();
|
2020-01-04 19:31:52 +00:00
|
|
|
|
|
|
|
for (final part in authHeaderParts) {
|
|
|
|
final kv = part.split('=');
|
|
|
|
authenticate[kv[0]] =
|
|
|
|
kv.getRange(1, kv.length).join('=').replaceAll('"', '');
|
|
|
|
}
|
|
|
|
|
|
|
|
return authenticate;
|
|
|
|
}
|
|
|
|
|
2020-01-08 12:26:34 +00:00
|
|
|
Future<__dio.Response> request(
|
2020-01-04 19:31:52 +00:00
|
|
|
{String uri, String login, String password}) async {
|
2020-01-08 12:26:34 +00:00
|
|
|
const path = '/json_rpc';
|
|
|
|
const method = 'POST';
|
2020-01-04 19:31:52 +00:00
|
|
|
final url = Uri.http(uri, path);
|
2020-01-08 12:26:34 +00:00
|
|
|
final dio = __dio.Dio();
|
|
|
|
final headers = {'Content-type': 'application/json'};
|
|
|
|
final body =
|
|
|
|
json.encode({"jsonrpc": "2.0", "id": "0", "method": "get_info"});
|
|
|
|
final credentialsResponse = await dio.post<Object>(url.toString(),
|
|
|
|
options: __dio.Options(headers: headers, validateStatus: (_) => true));
|
|
|
|
final authenticate = parsetAuthorizationHeader(
|
|
|
|
source: credentialsResponse.headers['www-authenticate'].first);
|
2020-01-04 19:31:52 +00:00
|
|
|
final qop = authenticate['qop'];
|
|
|
|
final algorithm = 'MD5';
|
|
|
|
final realm = 'monero-rpc';
|
|
|
|
final nonce = authenticate['nonce'];
|
|
|
|
final cnonce = generateCnonce();
|
2020-01-08 12:26:34 +00:00
|
|
|
final nonceCount = '00000001';
|
2020-01-04 19:31:52 +00:00
|
|
|
final ha1 = generateHA1(realm: realm, username: login, password: password);
|
|
|
|
final ha2 = generateHA2(method: method, uri: path);
|
|
|
|
final response = generateResponseString(
|
|
|
|
ha1: ha1,
|
|
|
|
ha2: ha2,
|
|
|
|
nonce: nonce,
|
|
|
|
nonceCount: nonceCount,
|
|
|
|
cnonce: cnonce,
|
|
|
|
qop: qop);
|
|
|
|
|
|
|
|
final authorizationHeaders = {
|
|
|
|
'Content-type': 'application/json',
|
|
|
|
'Authorization':
|
2020-01-08 12:26:34 +00:00
|
|
|
'Digest username="$login",realm="$realm",nonce="$nonce",uri="$path",algorithm="$algorithm",qop=$qop,nc=$nonceCount,cnonce="$cnonce",response="$response"'
|
2020-01-04 19:31:52 +00:00
|
|
|
};
|
|
|
|
|
2020-01-08 12:26:34 +00:00
|
|
|
return await dio.post<Object>(url.toString(),
|
|
|
|
options: __dio.Options(headers: authorizationHeaders), data: body);
|
2020-01-04 19:31:52 +00:00
|
|
|
}
|
2020-01-08 12:26:34 +00:00
|
|
|
}
|