mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-05-25 11:22:23 +00:00
Created config encryption UI
This commit is contained in:
parent
e0edcb67fa
commit
137a976a36
7 changed files with 687 additions and 5 deletions
|
@ -490,5 +490,30 @@
|
||||||
"dnsCacheConfigDescription": "Configure how the server should manage the DNS cache",
|
"dnsCacheConfigDescription": "Configure how the server should manage the DNS cache",
|
||||||
"comment": "Comment",
|
"comment": "Comment",
|
||||||
"address": "Address",
|
"address": "Address",
|
||||||
"commentsDescription": "Comments are always preceded by #. You don't have to add it, it will be added automatically."
|
"commentsDescription": "Comments are always preceded by #. You don't have to add it, it will be added automatically.",
|
||||||
|
"encryptionSettings": "Encryption settings",
|
||||||
|
"encryptionSettingsDescription": "Encryption (HTTPS/QUIC/TLS) support",
|
||||||
|
"loadingEncryptionSettings": "Loading encryption settings...",
|
||||||
|
"encryptionSettingsNotLoaded": "Encryption settings couldn't be loaded.",
|
||||||
|
"enableEncryption": "Enable encryption",
|
||||||
|
"enableEncryptionTypes": "HTTPS, DNS-over-HTTPS, and DNS-over-TLS",
|
||||||
|
"enableEncryptionDescription": "If encryption is enabled, AdGuard Home admin interface will work over HTTPS, and the DNS server will listen for requests over DNS-over-HTTPS and DNS-over-TLS.",
|
||||||
|
"serverConfiguration": "Server configuration",
|
||||||
|
"domainName": "Domain name",
|
||||||
|
"domainNameDescription": "If set, AdGuard Home detects ClientIDs, responds to DDR queries, and performs additional connection validations. If not set, these features are disabled. Must match one of the DNS Names in the certificate.",
|
||||||
|
"redirectHttps": "Redirect to HTTPS automatically",
|
||||||
|
"httpsPort": "HTTPS port",
|
||||||
|
"tlsPort": "DNS-over-TLS port",
|
||||||
|
"dnsOverQuicPort": "DNS-over-QUIC port",
|
||||||
|
"certificates": "Certificates",
|
||||||
|
"certificatesDescription": "In order to use encryption, you need to provide a valid SSL certificates chain for your domain. You can get a free certificate on letsencrypt.org or you can buy it from one of the trusted Certificate Authorities.",
|
||||||
|
"certificateFilePath": "Set a certificates file path",
|
||||||
|
"pasteCertificateContent": "Paste the certificates contents",
|
||||||
|
"certificatePath": "Certificate path",
|
||||||
|
"certificateContent": "Certificate content",
|
||||||
|
"privateKey": "Private key",
|
||||||
|
"privateKeyFile": "Set a private key file",
|
||||||
|
"pastePrivateKey": "Paste the private key contents",
|
||||||
|
"usePreviousKey": "Use the previously saved key",
|
||||||
|
"privateKeyPath": "Private key path"
|
||||||
}
|
}
|
|
@ -490,5 +490,30 @@
|
||||||
"dnsCacheConfigDescription": "Configura cómo el servidor debe manejar la caché del DNS",
|
"dnsCacheConfigDescription": "Configura cómo el servidor debe manejar la caché del DNS",
|
||||||
"comment": "Comentario",
|
"comment": "Comentario",
|
||||||
"address": "Dirección",
|
"address": "Dirección",
|
||||||
"commentsDescription": "Los comentarios siempre van precedidos por #. No necesitas añadirlo. Se añadirá automáticamente."
|
"commentsDescription": "Los comentarios siempre van precedidos por #. No necesitas añadirlo. Se añadirá automáticamente.",
|
||||||
|
"encryptionSettings": "Configuración de cifrado",
|
||||||
|
"encryptionSettingsDescription": "Soporte de cifrado (HTTPS/QUIC/TLS)",
|
||||||
|
"loadingEncryptionSettings": "Cargando configuración de cifrado...",
|
||||||
|
"encryptionSettingsNotLoaded": "No se ha podido cargar la configuración de cifrado.",
|
||||||
|
"enableEncryption": "Habilitar cifrado",
|
||||||
|
"enableEncryptionTypes": "HTTPS, DNS mediante HTTPS y DNS mediante TLS",
|
||||||
|
"enableEncryptionDescription": "Si el cifrado está habilitado, la interfaz de administración de AdGuard Home funcionará a través de HTTPS, y el servidor DNS escuchará las peticiones DNS mediante HTTPS y DNS mediante TLS.",
|
||||||
|
"serverConfiguration": "Configuración del servidor",
|
||||||
|
"domainName": "Nombre de dominio",
|
||||||
|
"domainNameDescription": "Si se configura, AdGuard Home detecta los ID de clientes, responde a las consultas DDR y realiza validaciones de conexión adicionales. Si no se configura, estas funciones se deshabilitarán. Debe coincidir con uno de los nombres DNS del certificado.",
|
||||||
|
"redirectHttps": "Redireccionar automáticamente a HTTPS",
|
||||||
|
"httpsPort": "Puerto HTTPS",
|
||||||
|
"tlsPort": "Puerto DNS sobre TLS",
|
||||||
|
"dnsOverQuicPort": "Puerto DNS sobre QUIC",
|
||||||
|
"certificates": "Certificados",
|
||||||
|
"certificatesDescription": "Para utilizar el cifrado, debes proporcionar una cadena de certificado SSL válida para tu dominio. Puedes obtener un certificado gratuito en letsencrypt.org o puedes comprarlo en una de las autoridades de certificación de confianza.",
|
||||||
|
"certificateFilePath": "Establecer una ruta para el archivo de certificado",
|
||||||
|
"pasteCertificateContent": "Pegar el contenido del certificado",
|
||||||
|
"certificatePath": "Ruta de acceso al certificado",
|
||||||
|
"certificateContent": "Contenido del certificado",
|
||||||
|
"privateKey": "Clave privada",
|
||||||
|
"privateKeyFile": "Establecer un archivo de clave privada",
|
||||||
|
"pastePrivateKey": "Pegar el contenido de la clave privada",
|
||||||
|
"usePreviousKey": "Usar la clave privada guardada previamente",
|
||||||
|
"privateKeyPath": "Ruta de la clave privada"
|
||||||
}
|
}
|
108
lib/models/encryption.dart
Normal file
108
lib/models/encryption.dart
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
class Encryption {
|
||||||
|
int loadStatus = 0;
|
||||||
|
EncryptionData? data;
|
||||||
|
|
||||||
|
Encryption({
|
||||||
|
required this.loadStatus,
|
||||||
|
this.data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
EncryptionData encryptionDataFromJson(String str) => EncryptionData.fromJson(json.decode(str));
|
||||||
|
|
||||||
|
String encryptionDataToJson(EncryptionData data) => json.encode(data.toJson());
|
||||||
|
|
||||||
|
class EncryptionData {
|
||||||
|
final bool validCert;
|
||||||
|
final bool validChain;
|
||||||
|
final DateTime notBefore;
|
||||||
|
final DateTime notAfter;
|
||||||
|
final dynamic dnsNames;
|
||||||
|
final bool validKey;
|
||||||
|
final bool validPair;
|
||||||
|
final bool enabled;
|
||||||
|
final bool forceHttps;
|
||||||
|
final int portHttps;
|
||||||
|
final int portDnsOverTls;
|
||||||
|
final int portDnsOverQuic;
|
||||||
|
final int portDnscrypt;
|
||||||
|
final String dnscryptConfigFile;
|
||||||
|
final bool allowUnencryptedDoh;
|
||||||
|
final String certificateChain;
|
||||||
|
final String privateKey;
|
||||||
|
final String certificatePath;
|
||||||
|
final String privateKeyPath;
|
||||||
|
final bool privateKeySaved;
|
||||||
|
|
||||||
|
EncryptionData({
|
||||||
|
required this.validCert,
|
||||||
|
required this.validChain,
|
||||||
|
required this.notBefore,
|
||||||
|
required this.notAfter,
|
||||||
|
required this.dnsNames,
|
||||||
|
required this.validKey,
|
||||||
|
required this.validPair,
|
||||||
|
required this.enabled,
|
||||||
|
required this.forceHttps,
|
||||||
|
required this.portHttps,
|
||||||
|
required this.portDnsOverTls,
|
||||||
|
required this.portDnsOverQuic,
|
||||||
|
required this.portDnscrypt,
|
||||||
|
required this.dnscryptConfigFile,
|
||||||
|
required this.allowUnencryptedDoh,
|
||||||
|
required this.certificateChain,
|
||||||
|
required this.privateKey,
|
||||||
|
required this.certificatePath,
|
||||||
|
required this.privateKeyPath,
|
||||||
|
required this.privateKeySaved,
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
factory EncryptionData.fromJson(Map<String, dynamic> json) => EncryptionData(
|
||||||
|
validCert: json["valid_cert"],
|
||||||
|
validChain: json["valid_chain"],
|
||||||
|
notBefore: DateTime.parse(json["not_before"]),
|
||||||
|
notAfter: DateTime.parse(json["not_after"]),
|
||||||
|
dnsNames: json["dns_names"],
|
||||||
|
validKey: json["valid_key"],
|
||||||
|
validPair: json["valid_pair"],
|
||||||
|
enabled: json["enabled"],
|
||||||
|
forceHttps: json["force_https"],
|
||||||
|
portHttps: json["port_https"],
|
||||||
|
portDnsOverTls: json["port_dns_over_tls"],
|
||||||
|
portDnsOverQuic: json["port_dns_over_quic"],
|
||||||
|
portDnscrypt: json["port_dnscrypt"],
|
||||||
|
dnscryptConfigFile: json["dnscrypt_config_file"],
|
||||||
|
allowUnencryptedDoh: json["allow_unencrypted_doh"],
|
||||||
|
certificateChain: json["certificate_chain"],
|
||||||
|
privateKey: json["private_key"],
|
||||||
|
certificatePath: json["certificate_path"],
|
||||||
|
privateKeyPath: json["private_key_path"],
|
||||||
|
privateKeySaved: json["private_key_saved"],
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
"valid_cert": validCert,
|
||||||
|
"valid_chain": validChain,
|
||||||
|
"not_before": notBefore.toIso8601String(),
|
||||||
|
"not_after": notAfter.toIso8601String(),
|
||||||
|
"dns_names": dnsNames,
|
||||||
|
"valid_key": validKey,
|
||||||
|
"valid_pair": validPair,
|
||||||
|
"enabled": enabled,
|
||||||
|
"force_https": forceHttps,
|
||||||
|
"port_https": portHttps,
|
||||||
|
"port_dns_over_tls": portDnsOverTls,
|
||||||
|
"port_dns_over_quic": portDnsOverQuic,
|
||||||
|
"port_dnscrypt": portDnscrypt,
|
||||||
|
"dnscrypt_config_file": dnscryptConfigFile,
|
||||||
|
"allow_unencrypted_doh": allowUnencryptedDoh,
|
||||||
|
"certificate_chain": certificateChain,
|
||||||
|
"private_key": privateKey,
|
||||||
|
"certificate_path": certificatePath,
|
||||||
|
"private_key_path": privateKeyPath,
|
||||||
|
"private_key_saved": privateKeySaved,
|
||||||
|
};
|
||||||
|
}
|
|
@ -7,11 +7,12 @@ import 'package:adguard_home_manager/models/dns_info.dart';
|
||||||
import 'package:adguard_home_manager/models/rewrite_rules.dart';
|
import 'package:adguard_home_manager/models/rewrite_rules.dart';
|
||||||
import 'package:adguard_home_manager/models/filtering_status.dart';
|
import 'package:adguard_home_manager/models/filtering_status.dart';
|
||||||
import 'package:adguard_home_manager/models/clients_allowed_blocked.dart';
|
import 'package:adguard_home_manager/models/clients_allowed_blocked.dart';
|
||||||
|
import 'package:adguard_home_manager/models/encryption.dart';
|
||||||
import 'package:adguard_home_manager/models/clients.dart';
|
import 'package:adguard_home_manager/models/clients.dart';
|
||||||
import 'package:adguard_home_manager/services/http_requests.dart';
|
|
||||||
import 'package:adguard_home_manager/models/server_status.dart';
|
import 'package:adguard_home_manager/models/server_status.dart';
|
||||||
import 'package:adguard_home_manager/functions/conversions.dart';
|
|
||||||
import 'package:adguard_home_manager/models/server.dart';
|
import 'package:adguard_home_manager/models/server.dart';
|
||||||
|
import 'package:adguard_home_manager/services/http_requests.dart';
|
||||||
|
import 'package:adguard_home_manager/functions/conversions.dart';
|
||||||
|
|
||||||
class ServersProvider with ChangeNotifier {
|
class ServersProvider with ChangeNotifier {
|
||||||
Database? _dbInstance;
|
Database? _dbInstance;
|
||||||
|
@ -49,6 +50,11 @@ class ServersProvider with ChangeNotifier {
|
||||||
data: null
|
data: null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final Encryption _encryptionSettings = Encryption(
|
||||||
|
loadStatus: 0, // 0 = loading, 1 = loaded, 2 = error,
|
||||||
|
data: null
|
||||||
|
);
|
||||||
|
|
||||||
FilteringStatus? _filteringStatus;
|
FilteringStatus? _filteringStatus;
|
||||||
|
|
||||||
List<Server> get serversList {
|
List<Server> get serversList {
|
||||||
|
@ -91,6 +97,10 @@ class ServersProvider with ChangeNotifier {
|
||||||
return _dnsInfo;
|
return _dnsInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Encryption get encryptionSettings {
|
||||||
|
return _encryptionSettings;
|
||||||
|
}
|
||||||
|
|
||||||
void setDbInstance(Database db) {
|
void setDbInstance(Database db) {
|
||||||
_dbInstance = db;
|
_dbInstance = db;
|
||||||
}
|
}
|
||||||
|
@ -201,6 +211,18 @@ class ServersProvider with ChangeNotifier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setEncryptionSettings(EncryptionData data) {
|
||||||
|
_encryptionSettings.data = data;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setEncryptionSettingsLoadStatus(int status, bool notify) {
|
||||||
|
_encryptionSettings.loadStatus = status;
|
||||||
|
if (notify == true) {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> createServer(Server server) async {
|
Future<bool> createServer(Server server) async {
|
||||||
final saved = await saveServerIntoDb(server);
|
final saved = await saveServerIntoDb(server);
|
||||||
if (saved == true) {
|
if (saved == true) {
|
||||||
|
|
452
lib/screens/settings/encryption/encryption.dart
Normal file
452
lib/screens/settings/encryption/encryption.dart
Normal file
|
@ -0,0 +1,452 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/screens/settings/section_label.dart';
|
||||||
|
import 'package:adguard_home_manager/widgets/custom_switch_list_tile.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/services/http_requests.dart';
|
||||||
|
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||||
|
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||||
|
|
||||||
|
class EncryptionSettings extends StatelessWidget {
|
||||||
|
const EncryptionSettings({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final serversProvider = Provider.of<ServersProvider>(context);
|
||||||
|
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||||
|
|
||||||
|
return EncryptionSettingsWidget(
|
||||||
|
serversProvider: serversProvider,
|
||||||
|
appConfigProvider: appConfigProvider,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EncryptionSettingsWidget extends StatefulWidget {
|
||||||
|
final ServersProvider serversProvider;
|
||||||
|
final AppConfigProvider appConfigProvider;
|
||||||
|
|
||||||
|
const EncryptionSettingsWidget({
|
||||||
|
Key? key,
|
||||||
|
required this.serversProvider,
|
||||||
|
required this.appConfigProvider,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<EncryptionSettingsWidget> createState() => _EncryptionSettingsWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
|
||||||
|
bool enabled = false;
|
||||||
|
|
||||||
|
final TextEditingController domainNameController = TextEditingController();
|
||||||
|
String? domainError;
|
||||||
|
|
||||||
|
bool redirectHttps = false;
|
||||||
|
|
||||||
|
final TextEditingController httpsPortController = TextEditingController();
|
||||||
|
String? httpsPortError;
|
||||||
|
|
||||||
|
final TextEditingController tlsPortController = TextEditingController();
|
||||||
|
String? tlsPortError;
|
||||||
|
|
||||||
|
final TextEditingController dnsOverQuicPortController = TextEditingController();
|
||||||
|
String? dnsOverQuicPortError;
|
||||||
|
|
||||||
|
int certificateOption = 0;
|
||||||
|
|
||||||
|
final TextEditingController certificatePathController = TextEditingController();
|
||||||
|
String? certificatePathError;
|
||||||
|
|
||||||
|
final TextEditingController certificateContentController = TextEditingController();
|
||||||
|
String? certificateContentError;
|
||||||
|
|
||||||
|
int privateKeyOption = 0;
|
||||||
|
|
||||||
|
bool usePreviouslySavedKey = false;
|
||||||
|
|
||||||
|
final TextEditingController privateKeyPathController = TextEditingController();
|
||||||
|
String? privateKeyPathError;
|
||||||
|
|
||||||
|
final TextEditingController pastePrivateKeyController = TextEditingController();
|
||||||
|
String? pastePrivateKeyError;
|
||||||
|
|
||||||
|
|
||||||
|
void fetchData({bool? showRefreshIndicator}) async {
|
||||||
|
widget.serversProvider.setEncryptionSettingsLoadStatus(0, showRefreshIndicator ?? false);
|
||||||
|
|
||||||
|
final result = await getEncryptionSettings(server: widget.serversProvider.selectedServer!);
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
if (result['result'] == 'success') {
|
||||||
|
widget.serversProvider.setEncryptionSettings(result['data']);
|
||||||
|
widget.serversProvider.setEncryptionSettingsLoadStatus(1, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
widget.appConfigProvider.addLog(result['log']);
|
||||||
|
widget.serversProvider.setEncryptionSettingsLoadStatus(2, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
fetchData();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final serversProvider = Provider.of<ServersProvider>(context);
|
||||||
|
final appConfigProvider = Provider.of<AppConfigProvider>(context);
|
||||||
|
|
||||||
|
Widget generateBody() {
|
||||||
|
switch (widget.serversProvider.encryptionSettings.loadStatus) {
|
||||||
|
case 0:
|
||||||
|
return SizedBox(
|
||||||
|
width: double.maxFinite,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const CircularProgressIndicator(),
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.loadingEncryptionSettings,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return ListView(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 10,
|
||||||
|
left: 12,
|
||||||
|
right: 12
|
||||||
|
),
|
||||||
|
child: Material(
|
||||||
|
color: Theme.of(context).primaryColor.withOpacity(0.1),
|
||||||
|
borderRadius: BorderRadius.circular(28),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () => setState(() => enabled = !enabled),
|
||||||
|
borderRadius: BorderRadius.circular(28),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 20,
|
||||||
|
vertical: 12
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.enableEncryption,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 3),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.enableEncryptionTypes,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Theme.of(context).listTileTheme.iconColor,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Switch(
|
||||||
|
value: enabled,
|
||||||
|
onChanged: (value) => setState(() => enabled = value),
|
||||||
|
activeColor: Theme.of(context).primaryColor,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SectionLabel(label: AppLocalizations.of(context)!.serverConfiguration),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
child: TextFormField(
|
||||||
|
controller: domainNameController,
|
||||||
|
// onChanged:
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: const Icon(Icons.link_rounded),
|
||||||
|
border: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(10)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
errorText: domainError,
|
||||||
|
labelText: AppLocalizations.of(context)!.domainName,
|
||||||
|
helperText: AppLocalizations.of(context)!.domainNameDescription,
|
||||||
|
helperMaxLines: 10
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
CustomSwitchListTile(
|
||||||
|
value: redirectHttps,
|
||||||
|
onChanged: (value) => setState(() => redirectHttps = value),
|
||||||
|
title: AppLocalizations.of(context)!.redirectHttps,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
child: TextFormField(
|
||||||
|
controller: httpsPortController,
|
||||||
|
// onChanged:
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: const Icon(Icons.numbers_rounded),
|
||||||
|
border: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(10)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
errorText: httpsPortError,
|
||||||
|
labelText: AppLocalizations.of(context)!.httpsPort,
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
child: TextFormField(
|
||||||
|
controller: tlsPortController,
|
||||||
|
// onChanged:
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: const Icon(Icons.numbers_rounded),
|
||||||
|
border: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(10)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
errorText: tlsPortError,
|
||||||
|
labelText: AppLocalizations.of(context)!.tlsPort,
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
child: TextFormField(
|
||||||
|
controller: dnsOverQuicPortController,
|
||||||
|
// onChanged:
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: const Icon(Icons.numbers_rounded),
|
||||||
|
border: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(10)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
errorText: dnsOverQuicPortError,
|
||||||
|
labelText: AppLocalizations.of(context)!.dnsOverQuicPort,
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SectionLabel(label: AppLocalizations.of(context)!.certificates),
|
||||||
|
Card(
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.info_rounded),
|
||||||
|
const SizedBox(width: 20),
|
||||||
|
Flexible(
|
||||||
|
child: Text(AppLocalizations.of(context)!.certificatesDescription)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
RadioListTile(
|
||||||
|
value: 0,
|
||||||
|
groupValue: certificateOption,
|
||||||
|
onChanged: (value) => setState(() => certificateOption = value!),
|
||||||
|
title: Text(
|
||||||
|
AppLocalizations.of(context)!.certificateFilePath,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.normal
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
RadioListTile(
|
||||||
|
value: 1,
|
||||||
|
groupValue: certificateOption,
|
||||||
|
onChanged: (value) => setState(() => certificateOption = value!),
|
||||||
|
title: Text(
|
||||||
|
AppLocalizations.of(context)!.pasteCertificateContent,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.normal
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
if (certificateOption == 0) Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
child: TextFormField(
|
||||||
|
controller: certificatePathController,
|
||||||
|
// onChanged:
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: const Icon(Icons.description_rounded),
|
||||||
|
border: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(10)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
errorText: certificatePathError,
|
||||||
|
labelText: AppLocalizations.of(context)!.certificatePath,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (certificateOption == 1) Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
child: TextFormField(
|
||||||
|
controller: certificateContentController,
|
||||||
|
// onChanged:
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: const Icon(Icons.description_rounded),
|
||||||
|
border: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(10)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
errorText: certificateContentError,
|
||||||
|
labelText: AppLocalizations.of(context)!.certificateContent,
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.multiline,
|
||||||
|
maxLines: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SectionLabel(label: AppLocalizations.of(context)!.privateKey),
|
||||||
|
RadioListTile(
|
||||||
|
value: 0,
|
||||||
|
groupValue: privateKeyOption,
|
||||||
|
onChanged: (value) => setState(() => privateKeyOption = value!),
|
||||||
|
title: Text(
|
||||||
|
AppLocalizations.of(context)!.privateKeyFile,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.normal
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
RadioListTile(
|
||||||
|
value: 1,
|
||||||
|
groupValue: privateKeyOption,
|
||||||
|
onChanged: (value) => setState(() => privateKeyOption = value!),
|
||||||
|
title: Text(
|
||||||
|
AppLocalizations.of(context)!.pastePrivateKey,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.normal
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (privateKeyOption == 0) const SizedBox(height: 10),
|
||||||
|
if (privateKeyOption == 1) ...[
|
||||||
|
CustomSwitchListTile(
|
||||||
|
value: usePreviouslySavedKey,
|
||||||
|
onChanged: (value) => setState(() => usePreviouslySavedKey = value),
|
||||||
|
title: AppLocalizations.of(context)!.usePreviousKey,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10)
|
||||||
|
],
|
||||||
|
if (privateKeyOption == 0) Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
child: TextFormField(
|
||||||
|
controller: privateKeyPathController,
|
||||||
|
// onChanged:
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: const Icon(Icons.description_rounded),
|
||||||
|
border: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(10)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
errorText: privateKeyPathError,
|
||||||
|
labelText: AppLocalizations.of(context)!.privateKeyPath,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (privateKeyOption == 1) Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
|
child: TextFormField(
|
||||||
|
enabled: !usePreviouslySavedKey,
|
||||||
|
controller: pastePrivateKeyController,
|
||||||
|
// onChanged:
|
||||||
|
decoration: InputDecoration(
|
||||||
|
prefixIcon: const Icon(Icons.description_rounded),
|
||||||
|
border: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(10)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
errorText: pastePrivateKeyError,
|
||||||
|
labelText: AppLocalizations.of(context)!.pastePrivateKey,
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.multiline,
|
||||||
|
maxLines: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return SizedBox(
|
||||||
|
width: double.maxFinite,
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const Icon(
|
||||||
|
Icons.error,
|
||||||
|
color: Colors.red,
|
||||||
|
size: 50,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.encryptionSettingsNotLoaded,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(AppLocalizations.of(context)!.encryptionSettings),
|
||||||
|
),
|
||||||
|
body: generateBody(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/screens/settings/theme_modal.dart';
|
import 'package:adguard_home_manager/screens/settings/theme_modal.dart';
|
||||||
import 'package:adguard_home_manager/screens/settings/server_info/server_info.dart';
|
import 'package:adguard_home_manager/screens/settings/server_info/server_info.dart';
|
||||||
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
import 'package:adguard_home_manager/screens/settings/encryption/encryption.dart';
|
||||||
import 'package:adguard_home_manager/screens/settings/access_settings/access_settings.dart';
|
import 'package:adguard_home_manager/screens/settings/access_settings/access_settings.dart';
|
||||||
import 'package:adguard_home_manager/screens/settings/dhcp/dhcp.dart';
|
import 'package:adguard_home_manager/screens/settings/dhcp/dhcp.dart';
|
||||||
import 'package:adguard_home_manager/screens/settings/section_label.dart';
|
import 'package:adguard_home_manager/screens/settings/section_label.dart';
|
||||||
|
@ -17,6 +17,8 @@ import 'package:adguard_home_manager/screens/servers/servers.dart';
|
||||||
import 'package:adguard_home_manager/screens/settings/advanced_setings.dart';
|
import 'package:adguard_home_manager/screens/settings/advanced_setings.dart';
|
||||||
import 'package:adguard_home_manager/screens/settings/general_settings.dart';
|
import 'package:adguard_home_manager/screens/settings/general_settings.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/widgets/custom_list_tile.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/constants/strings.dart';
|
import 'package:adguard_home_manager/constants/strings.dart';
|
||||||
import 'package:adguard_home_manager/constants/urls.dart';
|
import 'package:adguard_home_manager/constants/urls.dart';
|
||||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||||
|
@ -126,6 +128,18 @@ class Settings extends StatelessWidget {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
CustomListTile(
|
||||||
|
icon: Icons.security_rounded,
|
||||||
|
title: AppLocalizations.of(context)!.encryptionSettings,
|
||||||
|
subtitle: AppLocalizations.of(context)!.encryptionSettingsDescription,
|
||||||
|
onTap: () => {
|
||||||
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => const EncryptionSettings()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
),
|
||||||
CustomListTile(
|
CustomListTile(
|
||||||
icon: Icons.route_rounded,
|
icon: Icons.route_rounded,
|
||||||
title: AppLocalizations.of(context)!.dnsRewrites,
|
title: AppLocalizations.of(context)!.dnsRewrites,
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'dart:io';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/models/dhcp.dart';
|
import 'package:adguard_home_manager/models/dhcp.dart';
|
||||||
import 'package:adguard_home_manager/models/dns_info.dart';
|
import 'package:adguard_home_manager/models/dns_info.dart';
|
||||||
|
import 'package:adguard_home_manager/models/encryption.dart';
|
||||||
import 'package:adguard_home_manager/models/filtering.dart';
|
import 'package:adguard_home_manager/models/filtering.dart';
|
||||||
import 'package:adguard_home_manager/models/logs.dart';
|
import 'package:adguard_home_manager/models/logs.dart';
|
||||||
import 'package:adguard_home_manager/models/filtering_status.dart';
|
import 'package:adguard_home_manager/models/filtering_status.dart';
|
||||||
|
@ -1704,4 +1705,39 @@ Future setDnsConfig({
|
||||||
else {
|
else {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future getEncryptionSettings({
|
||||||
|
required Server server,
|
||||||
|
}) async {
|
||||||
|
final result = await apiRequest(
|
||||||
|
urlPath: '/tls/status',
|
||||||
|
method: 'get',
|
||||||
|
server: server,
|
||||||
|
type: 'get_encryption_settings'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result['hasResponse'] == true) {
|
||||||
|
if (result['statusCode'] == 200) {
|
||||||
|
return {
|
||||||
|
'result': 'success',
|
||||||
|
'data': EncryptionData.fromJson(jsonDecode(result['body']))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return {
|
||||||
|
'result': 'error',
|
||||||
|
'log': AppLog(
|
||||||
|
type: 'get_encryption_settings',
|
||||||
|
dateTime: DateTime.now(),
|
||||||
|
message: 'error_code_not_expected',
|
||||||
|
statusCode: result['statusCode'].toString(),
|
||||||
|
resBody: result['body'],
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue