Added auth token to server modal and dns statistics request

This commit is contained in:
Juan Gilsanz Polo 2022-09-27 02:38:59 +02:00
parent 360b6865be
commit 97e4fea015
9 changed files with 171 additions and 15 deletions

View file

@ -0,0 +1,7 @@
import 'dart:convert';
String encodeBase64UserPass(String user, String pass) {
String credentials = "$user:$pass";
Codec<String, String> stringToBase64 = utf8.fuse(base64);
return stringToBase64.encode(credentials);
}

View file

@ -0,0 +1,73 @@
import 'dart:convert';
DnsStatistics dnsStatisticsFromJson(String str) => DnsStatistics.fromJson(json.decode(str));
String dnsStatisticsToJson(DnsStatistics data) => json.encode(data.toJson());
class DnsStatistics {
final String timeUnits;
final List<Map<String, int>> topQueriedDomains;
final List<Map<String, int>> topClients;
final List<Map<String, int>> topBlockedDomains;
final List<int> dnsQueries;
final List<int> blockedFiltering;
final List<int> replacedSafebrowsing;
final List<int> replacedParental;
final int numDnsQueries;
final int numBlockedFiltering;
final int numReplacedSafebrowsing;
final int numReplacedSafesearch;
final int numReplacedParental;
final double avgProcessingTime;
DnsStatistics({
required this.timeUnits,
required this.topQueriedDomains,
required this.topClients,
required this.topBlockedDomains,
required this.dnsQueries,
required this.blockedFiltering,
required this.replacedSafebrowsing,
required this.replacedParental,
required this.numDnsQueries,
required this.numBlockedFiltering,
required this.numReplacedSafebrowsing,
required this.numReplacedSafesearch,
required this.numReplacedParental,
required this.avgProcessingTime,
});
factory DnsStatistics.fromJson(Map<String, dynamic> json) => DnsStatistics(
timeUnits: json["time_units"],
topQueriedDomains: List<Map<String, int>>.from(json["top_queried_domains"].map((x) => Map.from(x).map((k, v) => MapEntry<String, int>(k, v)))),
topClients: List<Map<String, int>>.from(json["top_clients"].map((x) => Map.from(x).map((k, v) => MapEntry<String, int>(k, v)))),
topBlockedDomains: List<Map<String, int>>.from(json["top_blocked_domains"].map((x) => Map.from(x).map((k, v) => MapEntry<String, int>(k, v)))),
dnsQueries: List<int>.from(json["dns_queries"].map((x) => x)),
blockedFiltering: List<int>.from(json["blocked_filtering"].map((x) => x)),
replacedSafebrowsing: List<int>.from(json["replaced_safebrowsing"].map((x) => x)),
replacedParental: List<int>.from(json["replaced_parental"].map((x) => x)),
numDnsQueries: json["num_dns_queries"],
numBlockedFiltering: json["num_blocked_filtering"],
numReplacedSafebrowsing: json["num_replaced_safebrowsing"],
numReplacedSafesearch: json["num_replaced_safesearch"],
numReplacedParental: json["num_replaced_parental"],
avgProcessingTime: json["avg_processing_time"].toDouble(),
);
Map<String, dynamic> toJson() => {
"time_units": timeUnits,
"top_queried_domains": List<dynamic>.from(topQueriedDomains.map((x) => Map.from(x).map((k, v) => MapEntry<String, dynamic>(k, v)))),
"top_clients": List<dynamic>.from(topClients.map((x) => Map.from(x).map((k, v) => MapEntry<String, dynamic>(k, v)))),
"top_blocked_domains": List<dynamic>.from(topBlockedDomains.map((x) => Map.from(x).map((k, v) => MapEntry<String, dynamic>(k, v)))),
"dns_queries": List<dynamic>.from(dnsQueries.map((x) => x)),
"blocked_filtering": List<dynamic>.from(blockedFiltering.map((x) => x)),
"replaced_safebrowsing": List<dynamic>.from(replacedSafebrowsing.map((x) => x)),
"replaced_parental": List<dynamic>.from(replacedParental.map((x) => x)),
"num_dns_queries": numDnsQueries,
"num_blocked_filtering": numBlockedFiltering,
"num_replaced_safebrowsing": numReplacedSafebrowsing,
"num_replaced_safesearch": numReplacedSafesearch,
"num_replaced_parental": numReplacedParental,
"avg_processing_time": avgProcessingTime,
};
}

View file

@ -8,6 +8,7 @@ class Server {
String user;
String password;
bool defaultServer;
String authToken;
Server({
required this.id,
@ -18,6 +19,7 @@ class Server {
this.port,
required this.user,
required this.password,
required this.defaultServer
required this.defaultServer,
required this.authToken
});
}

View file

@ -1,3 +1,5 @@
import 'package:adguard_home_manager/models/dns_statistics.dart';
import 'package:adguard_home_manager/services/http_requests.dart';
import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart';
@ -10,6 +12,7 @@ class ServersProvider with ChangeNotifier {
List<Server> _serversList = [];
Server? _selectedServer;
bool? _isServerConnected;
DnsStatistics? _dnsStatistics;
List<Server> get serversList {
return _serversList;
@ -23,6 +26,10 @@ class ServersProvider with ChangeNotifier {
return _isServerConnected;
}
DnsStatistics? get dnsStatistics {
return _dnsStatistics;
}
void setDbInstance(Database db) {
_dbInstance = db;
}
@ -42,6 +49,11 @@ class ServersProvider with ChangeNotifier {
notifyListeners();
}
void setDnsStatistics(DnsStatistics data) {
_dnsStatistics = data;
notifyListeners();
}
Future<bool> createServer(Server server) async {
final saved = await saveServerIntoDb(server);
if (saved == true) {
@ -127,7 +139,7 @@ class ServersProvider with ChangeNotifier {
try {
return await _dbInstance!.transaction((txn) async {
await txn.rawInsert(
'INSERT INTO servers (id, name, connectionMethod, domain, path, port, user, password, defaultServer) VALUES ("${server.id}", "${server.name}", "${server.connectionMethod}", "${server.domain}", ${server.path != null ? "${server.path}" : null}, ${server.port}, "${server.user}", "${server.password}", 0)',
'INSERT INTO servers (id, name, connectionMethod, domain, path, port, user, password, defaultServer, authToken) VALUES ("${server.id}", "${server.name}", "${server.connectionMethod}", "${server.domain}", ${server.path != null ? "${server.path}" : null}, ${server.port}, "${server.user}", "${server.password}", 0, "${server.authToken}")',
);
return true;
});
@ -140,7 +152,7 @@ class ServersProvider with ChangeNotifier {
try {
return await _dbInstance!.transaction((txn) async {
await txn.rawUpdate(
'UPDATE servers SET name = "${server.name}", connectionMethod = "${server.connectionMethod}", domain = "${server.domain}", path = ${server.path != null ? "${server.path}" : null}, port = ${server.port}, user = "${server.user}", password = "${server.password}" WHERE id = "${server.id}"',
'UPDATE servers SET name = "${server.name}", connectionMethod = "${server.connectionMethod}", domain = "${server.domain}", path = ${server.path != null ? "${server.path}" : null}, port = ${server.port}, user = "${server.user}", password = "${server.password}", authToken = "${server.authToken}" WHERE id = "${server.id}"',
);
return true;
});
@ -191,10 +203,19 @@ class ServersProvider with ChangeNotifier {
user: server['user'],
password: server['password'],
defaultServer: convertFromIntToBool(server['defaultServer'])!,
authToken: server['authToken']
);
_serversList.add(serverObj);
if (convertFromIntToBool(server['defaultServer']) == true) {
_selectedServer = serverObj;
final dnsStatistics = await getDnsStatistics(serverObj);
if (dnsStatistics['result'] == 'success') {
_dnsStatistics = dnsStatistics['data'];
_isServerConnected = true;
}
else {
_isServerConnected = false;
}
}
}
}

View file

@ -1,10 +1,15 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:adguard_home_manager/providers/servers_provider.dart';
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final serversProvider = Provider.of<ServersProvider>(context);
return Container();
}
}

View file

@ -8,7 +8,7 @@ Future<Map<String, dynamic>> loadDb() async {
'adguard_home_manager.db',
version: 1,
onCreate: (Database db, int version) async {
await db.execute("CREATE TABLE servers (id TEXT PRIMARY KEY, name TEXT, connectionMethod TEXT, domain TEXT, path TEXT, port INTEGER, user TEXT, password TEXT, defaultServer INTEGER)");
await db.execute("CREATE TABLE servers (id TEXT PRIMARY KEY, name TEXT, connectionMethod TEXT, domain TEXT, path TEXT, port INTEGER, user TEXT, password TEXT, defaultServer INTEGER, authToken TEXT)");
},
onUpgrade: (Database db, int oldVersion, int newVersion) async {

View file

@ -6,6 +6,7 @@ import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:adguard_home_manager/models/dns_statistics.dart';
import 'package:adguard_home_manager/models/server.dart';
Future login(Server server) async {
@ -44,4 +45,32 @@ Future login(Server server) async {
} catch (e) {
return {'result': 'error'};
}
}
Future getDnsStatistics(Server server) async {
try {
final result = await http.get(
Uri.parse("${server.connectionMethod}://${server.domain}${server.path ?? ""}${server.port != null ? ':${server.port}' : ""}/control/stats"),
headers: {
'Authorization': 'Basic ${server.authToken}'
}
);
if (result.statusCode == 200) {
return {
'result': 'success',
'data': DnsStatistics.fromJson(jsonDecode(result.body))
};
}
else {
return {'result': 'error'};
}
} on SocketException {
return {'result': 'no_connection'};
} on TimeoutException {
return {'result': 'no_connection'};
} on HandshakeException {
return {'result': 'ssl_error'};
} catch (e) {
return {'result': 'error'};
}
}

View file

@ -1,5 +1,6 @@
// ignore_for_file: use_build_context_synchronously
import 'package:adguard_home_manager/functions/encode_base64.dart';
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
import 'package:uuid/uuid.dart';
@ -206,7 +207,7 @@ class _AddServerModalState extends State<AddServerModal> {
final mediaQuery = MediaQuery.of(context);
void connect() async {
final Server serverObj = Server(
Server serverObj = Server(
id: uuid.v4(),
name: nameController.text,
connectionMethod: connectionType,
@ -214,14 +215,24 @@ class _AddServerModalState extends State<AddServerModal> {
port: int.parse(portController.text),
user: userController.text,
password: passwordController.text,
defaultServer: defaultServer
defaultServer: defaultServer,
authToken: ''
);
setState(() => isConnecting = true);
final result = await login(serverObj);
setState(() => isConnecting = false);
if (result['result'] == 'success') {
serverObj.authToken = encodeBase64UserPass(serverObj.user, serverObj.password);
final serverCreated = await serversProvider.createServer(serverObj);
if (serverCreated == true) {
final dnsStatistics = await getDnsStatistics(serverObj);
if (dnsStatistics['result'] == 'success') {
serversProvider.setDnsStatistics(dnsStatistics['data']);
serversProvider.setIsServerConnected(true);
}
else {
serversProvider.setIsServerConnected(false);
}
Navigator.pop(context);
}
else {
@ -284,10 +295,12 @@ class _AddServerModalState extends State<AddServerModal> {
port: int.parse(portController.text),
user: userController.text,
password: passwordController.text,
defaultServer: defaultServer
defaultServer: defaultServer,
authToken: ''
);
final result = await login(serverObj);
if (result['result'] == 'success') {
serverObj.authToken = encodeBase64UserPass(serverObj.user, serverObj.password);
final serverSaved = await serversProvider.editServer(serverObj);
if (serverSaved == true) {
Navigator.pop(context);

View file

@ -1,11 +1,11 @@
// ignore_for_file: use_build_context_synchronously
import 'package:adguard_home_manager/widgets/add_server_modal.dart';
import 'package:flutter/material.dart';
import 'package:expandable/expandable.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/widgets/servers_list/delete_modal.dart';
import 'package:adguard_home_manager/widgets/add_server_modal.dart';
import 'package:adguard_home_manager/classes/process_modal.dart';
import 'package:adguard_home_manager/models/server.dart';
@ -54,21 +54,27 @@ class ServersList extends StatelessWidget {
}
void connectToServer(Server server) async {
Future connectSuccess(result) async {
serversProvider.setSelectedServer(server);
}
final ProcessModal process = ProcessModal(context: context);
process.open(AppLocalizations.of(context)!.connecting);
final result = await login(server);
process.close();
if (result['result'] == 'success') {
await connectSuccess(result);
serversProvider.setSelectedServer(server);
final dnsStatistics = await getDnsStatistics(server);
if (dnsStatistics['result'] == 'success') {
serversProvider.setDnsStatistics(dnsStatistics['data']);
serversProvider.setIsServerConnected(true);
}
else {
serversProvider.setIsServerConnected(false);
}
process.close();
}
else {
process.close();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.cannotConnect),