mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-05-25 11:22:23 +00:00
Added validation
This commit is contained in:
parent
ea1cb6165c
commit
bfe2572e04
7 changed files with 257 additions and 22 deletions
|
@ -468,5 +468,6 @@
|
||||||
"blockingIpv4": "Blocking IPv4",
|
"blockingIpv4": "Blocking IPv4",
|
||||||
"blockingIpv4Description": "IP address to be returned for a blocked A request",
|
"blockingIpv4Description": "IP address to be returned for a blocked A request",
|
||||||
"blockingIpv6": "Blocking IPv6",
|
"blockingIpv6": "Blocking IPv6",
|
||||||
"blockingIpv6Description": "IP address to be returned for a blocked AAAA request"
|
"blockingIpv6Description": "IP address to be returned for a blocked AAAA request",
|
||||||
|
"invalidIp": "Invalid IP address"
|
||||||
}
|
}
|
|
@ -468,5 +468,6 @@
|
||||||
"blockingIpv4": "Bloqueo de IPv4",
|
"blockingIpv4": "Bloqueo de IPv4",
|
||||||
"blockingIpv4Description": "Dirección IP devolverá una petición A bloqueada",
|
"blockingIpv4Description": "Dirección IP devolverá una petición A bloqueada",
|
||||||
"blockingIpv6": "Bloqueo de IPv6",
|
"blockingIpv6": "Bloqueo de IPv6",
|
||||||
"blockingIpv6Description": "Dirección IP devolverá una petición AAAA bloqueada"
|
"blockingIpv6Description": "Dirección IP devolverá una petición AAAA bloqueada",
|
||||||
|
"invalidIp": "Dirección IP no válida"
|
||||||
}
|
}
|
|
@ -16,15 +16,45 @@ class BootstrapDnsScreen extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
|
class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
|
||||||
List<TextEditingController> bootstrapControllers = [];
|
List<Map<String, dynamic>> bootstrapControllers = [];
|
||||||
|
|
||||||
|
bool validValues = false;
|
||||||
|
|
||||||
|
void validateIp(Map<String, dynamic> field, String value) {
|
||||||
|
RegExp ipAddress = RegExp(r'(?:^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$)|(?:^(?:(?:[a-fA-F\d]{1,4}:){7}(?:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,2}|:)|(?:[a-fA-F\d]{1,4}:){4}(?:(?::[a-fA-F\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,3}|:)|(?:[a-fA-F\d]{1,4}:){3}(?:(?::[a-fA-F\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,4}|:)|(?:[a-fA-F\d]{1,4}:){2}(?:(?::[a-fA-F\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,5}|:)|(?:[a-fA-F\d]{1,4}:){1}(?:(?::[a-fA-F\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?$)');
|
||||||
|
if (ipAddress.hasMatch(value) == true) {
|
||||||
|
setState(() => field['error'] = null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() => field['error'] = AppLocalizations.of(context)!.invalidIp);
|
||||||
|
}
|
||||||
|
checkValidValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkValidValues() {
|
||||||
|
if (
|
||||||
|
bootstrapControllers.isNotEmpty &&
|
||||||
|
bootstrapControllers.every((element) => element['controller'].text != '') &&
|
||||||
|
bootstrapControllers.every((element) => element['error'] == null)
|
||||||
|
) {
|
||||||
|
setState(() => validValues = true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() => validValues = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
for (var item in widget.serversProvider.dnsInfo.data!.bootstrapDns) {
|
for (var item in widget.serversProvider.dnsInfo.data!.bootstrapDns) {
|
||||||
final controller = TextEditingController();
|
final controller = TextEditingController();
|
||||||
controller.text = item;
|
controller.text = item;
|
||||||
bootstrapControllers.add(controller);
|
bootstrapControllers.add({
|
||||||
|
'controller': controller,
|
||||||
|
'error': null
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
validValues = true;
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +63,16 @@ class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(AppLocalizations.of(context)!.bootstrapDns),
|
title: Text(AppLocalizations.of(context)!.bootstrapDns),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: validValues == true
|
||||||
|
? () => {}
|
||||||
|
: null,
|
||||||
|
icon: const Icon(Icons.save_rounded),
|
||||||
|
tooltip: AppLocalizations.of(context)!.save,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: ListView(
|
body: ListView(
|
||||||
padding: const EdgeInsets.only(top: 10),
|
padding: const EdgeInsets.only(top: 10),
|
||||||
|
@ -83,8 +123,8 @@ class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: MediaQuery.of(context).size.width-90,
|
width: MediaQuery.of(context).size.width-90,
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: c,
|
controller: c['controller'],
|
||||||
// onChanged: (_) => checkValidValues(),
|
onChanged: (value) => validateIp(c, value),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
prefixIcon: const Icon(Icons.dns_rounded),
|
prefixIcon: const Icon(Icons.dns_rounded),
|
||||||
border: const OutlineInputBorder(
|
border: const OutlineInputBorder(
|
||||||
|
@ -92,12 +132,16 @@ class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
|
||||||
Radius.circular(10)
|
Radius.circular(10)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
errorText: c['error'],
|
||||||
labelText: AppLocalizations.of(context)!.dnsServer,
|
labelText: AppLocalizations.of(context)!.dnsServer,
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () => setState(() => bootstrapControllers = bootstrapControllers.where((con) => con != c).toList()),
|
onPressed: () {
|
||||||
|
setState(() => bootstrapControllers = bootstrapControllers.where((con) => con != c).toList());
|
||||||
|
checkValidValues();
|
||||||
|
},
|
||||||
icon: const Icon(Icons.remove_circle_outline)
|
icon: const Icon(Icons.remove_circle_outline)
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -108,7 +152,13 @@ class _BootstrapDnsScreenState extends State<BootstrapDnsScreen> {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
onPressed: () => setState(() => bootstrapControllers.add(TextEditingController())),
|
onPressed: () {
|
||||||
|
setState(() => bootstrapControllers.add({
|
||||||
|
'controller': TextEditingController(),
|
||||||
|
'error': null
|
||||||
|
}));
|
||||||
|
checkValidValues();
|
||||||
|
},
|
||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
label: Text(AppLocalizations.of(context)!.addItem)
|
label: Text(AppLocalizations.of(context)!.addItem)
|
||||||
),
|
),
|
||||||
|
|
|
@ -29,12 +29,31 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
|
||||||
|
|
||||||
bool optimisticCache = false;
|
bool optimisticCache = false;
|
||||||
|
|
||||||
|
bool validData = false;
|
||||||
|
|
||||||
|
void checkValidData() {
|
||||||
|
if (
|
||||||
|
cacheSizeController.text != '' &&
|
||||||
|
cacheSizeError == null &&
|
||||||
|
overrideMinTtlController.text != '' &&
|
||||||
|
overrideMinTtlError == null &&
|
||||||
|
overrideMaxTtlController.text != '' &&
|
||||||
|
overrideMaxTtlError == null
|
||||||
|
) {
|
||||||
|
setState(() => validData = true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() => validData = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
cacheSizeController.text = widget.serversProvider.dnsInfo.data!.cacheSize.toString();
|
cacheSizeController.text = widget.serversProvider.dnsInfo.data!.cacheSize.toString();
|
||||||
overrideMinTtlController.text = widget.serversProvider.dnsInfo.data!.cacheTtlMin.toString();
|
overrideMinTtlController.text = widget.serversProvider.dnsInfo.data!.cacheTtlMin.toString();
|
||||||
overrideMaxTtlController.text = widget.serversProvider.dnsInfo.data!.cacheTtlMax.toString();
|
overrideMaxTtlController.text = widget.serversProvider.dnsInfo.data!.cacheTtlMax.toString();
|
||||||
optimisticCache = widget.serversProvider.dnsInfo.data!.cacheOptimistic;
|
optimisticCache = widget.serversProvider.dnsInfo.data!.cacheOptimistic;
|
||||||
|
validData = true;
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +92,16 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(AppLocalizations.of(context)!.dnsCacheConfig),
|
title: Text(AppLocalizations.of(context)!.dnsCacheConfig),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: validData == true
|
||||||
|
? () => {}
|
||||||
|
: null,
|
||||||
|
icon: const Icon(Icons.save_rounded),
|
||||||
|
tooltip: AppLocalizations.of(context)!.save,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: ListView(
|
body: ListView(
|
||||||
padding: const EdgeInsets.only(top: 10),
|
padding: const EdgeInsets.only(top: 10),
|
||||||
|
@ -89,6 +118,7 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
|
||||||
else {
|
else {
|
||||||
setState(() => cacheSizeError = AppLocalizations.of(context)!.valueNotNumber);
|
setState(() => cacheSizeError = AppLocalizations.of(context)!.valueNotNumber);
|
||||||
}
|
}
|
||||||
|
checkValidData();
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
|
@ -104,6 +134,7 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
|
||||||
else {
|
else {
|
||||||
setState(() => overrideMinTtlError = AppLocalizations.of(context)!.valueNotNumber);
|
setState(() => overrideMinTtlError = AppLocalizations.of(context)!.valueNotNumber);
|
||||||
}
|
}
|
||||||
|
checkValidData();
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
|
@ -119,6 +150,7 @@ class _CacheConfigDnsScreenState extends State<CacheConfigDnsScreen> {
|
||||||
else {
|
else {
|
||||||
setState(() => overrideMaxTtlError = AppLocalizations.of(context)!.valueNotNumber);
|
setState(() => overrideMaxTtlError = AppLocalizations.of(context)!.valueNotNumber);
|
||||||
}
|
}
|
||||||
|
checkValidData();
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
|
|
|
@ -33,6 +33,52 @@ class _DnsServerSettingsScreenState extends State<DnsServerSettingsScreen> {
|
||||||
final TextEditingController ipv6controller = TextEditingController();
|
final TextEditingController ipv6controller = TextEditingController();
|
||||||
String? ipv6error;
|
String? ipv6error;
|
||||||
|
|
||||||
|
bool isDataValid = false;
|
||||||
|
|
||||||
|
void validateIpv4(String value) {
|
||||||
|
RegExp ipAddress = RegExp(r'^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$');
|
||||||
|
if (ipAddress.hasMatch(value) == true) {
|
||||||
|
setState(() => ipv4error = null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() => ipv4error = AppLocalizations.of(context)!.invalidIp);
|
||||||
|
}
|
||||||
|
validateData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void validateIpv6(String value) {
|
||||||
|
RegExp ipAddress = RegExp(r'(?:^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$)|(?:^(?:(?:[a-fA-F\d]{1,4}:){7}(?:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,2}|:)|(?:[a-fA-F\d]{1,4}:){4}(?:(?::[a-fA-F\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,3}|:)|(?:[a-fA-F\d]{1,4}:){3}(?:(?::[a-fA-F\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,4}|:)|(?:[a-fA-F\d]{1,4}:){2}(?:(?::[a-fA-F\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,5}|:)|(?:[a-fA-F\d]{1,4}:){1}(?:(?::[a-fA-F\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?$)');
|
||||||
|
if (ipAddress.hasMatch(value) == true) {
|
||||||
|
setState(() => ipv6error = null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() => ipv6error = AppLocalizations.of(context)!.invalidIp);
|
||||||
|
}
|
||||||
|
validateData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void validateData() {
|
||||||
|
if (
|
||||||
|
limitRequestsController.text != '' &&
|
||||||
|
limitRequestsError == null &&
|
||||||
|
(
|
||||||
|
blockingMode != 'custom_ip' ||
|
||||||
|
(
|
||||||
|
blockingMode == 'custom_ip' &&
|
||||||
|
ipv4controller.text != '' &&
|
||||||
|
ipv4error == null &&
|
||||||
|
ipv6controller.text != '' &&
|
||||||
|
ipv6error == null
|
||||||
|
)
|
||||||
|
) == true
|
||||||
|
) {
|
||||||
|
setState(() => isDataValid = true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() => isDataValid = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
limitRequestsController.text = widget.serversProvider.dnsInfo.data!.ratelimit.toString();
|
limitRequestsController.text = widget.serversProvider.dnsInfo.data!.ratelimit.toString();
|
||||||
|
@ -42,6 +88,7 @@ class _DnsServerSettingsScreenState extends State<DnsServerSettingsScreen> {
|
||||||
blockingMode = widget.serversProvider.dnsInfo.data!.blockingMode;
|
blockingMode = widget.serversProvider.dnsInfo.data!.blockingMode;
|
||||||
ipv4controller.text = widget.serversProvider.dnsInfo.data!.blockingIpv4;
|
ipv4controller.text = widget.serversProvider.dnsInfo.data!.blockingIpv4;
|
||||||
ipv6controller.text = widget.serversProvider.dnsInfo.data!.blockingIpv6;
|
ipv6controller.text = widget.serversProvider.dnsInfo.data!.blockingIpv6;
|
||||||
|
isDataValid = true;
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,11 +103,22 @@ class _DnsServerSettingsScreenState extends State<DnsServerSettingsScreen> {
|
||||||
ipv6error = null;
|
ipv6error = null;
|
||||||
}
|
}
|
||||||
setState(() => blockingMode = mode);
|
setState(() => blockingMode = mode);
|
||||||
|
validateData();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(AppLocalizations.of(context)!.dnsServerSettings),
|
title: Text(AppLocalizations.of(context)!.dnsServerSettings),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: isDataValid == true
|
||||||
|
? () => {}
|
||||||
|
: null,
|
||||||
|
icon: const Icon(Icons.save_rounded),
|
||||||
|
tooltip: AppLocalizations.of(context)!.save,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: ListView(
|
body: ListView(
|
||||||
padding: const EdgeInsets.only(top: 10),
|
padding: const EdgeInsets.only(top: 10),
|
||||||
|
@ -76,6 +134,7 @@ class _DnsServerSettingsScreenState extends State<DnsServerSettingsScreen> {
|
||||||
else {
|
else {
|
||||||
setState(() => limitRequestsError = AppLocalizations.of(context)!.valueNotNumber);
|
setState(() => limitRequestsError = AppLocalizations.of(context)!.valueNotNumber);
|
||||||
}
|
}
|
||||||
|
validateData();
|
||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
prefixIcon: const Icon(Icons.looks_one_rounded),
|
prefixIcon: const Icon(Icons.looks_one_rounded),
|
||||||
|
@ -156,7 +215,7 @@ class _DnsServerSettingsScreenState extends State<DnsServerSettingsScreen> {
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: ipv4controller,
|
controller: ipv4controller,
|
||||||
// onChanged: onChanged,
|
onChanged: validateIpv4,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
prefixIcon: const Icon(Icons.link_rounded),
|
prefixIcon: const Icon(Icons.link_rounded),
|
||||||
border: const OutlineInputBorder(
|
border: const OutlineInputBorder(
|
||||||
|
@ -177,7 +236,7 @@ class _DnsServerSettingsScreenState extends State<DnsServerSettingsScreen> {
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: ipv6controller,
|
controller: ipv6controller,
|
||||||
// onChanged: onChanged,
|
onChanged: validateIpv6,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
prefixIcon: const Icon(Icons.link_rounded),
|
prefixIcon: const Icon(Icons.link_rounded),
|
||||||
border: const OutlineInputBorder(
|
border: const OutlineInputBorder(
|
||||||
|
|
|
@ -20,12 +20,46 @@ class PrivateReverseDnsServersScreen extends StatefulWidget {
|
||||||
class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServersScreen> {
|
class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServersScreen> {
|
||||||
List<String> defaultReverseResolvers = [];
|
List<String> defaultReverseResolvers = [];
|
||||||
bool editReverseResolvers = false;
|
bool editReverseResolvers = false;
|
||||||
List<TextEditingController> reverseResolversControllers = [
|
List<Map<String, dynamic>> reverseResolversControllers = [
|
||||||
TextEditingController()
|
{
|
||||||
|
'controller': TextEditingController(),
|
||||||
|
'error': null
|
||||||
|
}
|
||||||
];
|
];
|
||||||
bool usePrivateReverseDnsResolvers = false;
|
bool usePrivateReverseDnsResolvers = false;
|
||||||
bool enableReverseResolve = false;
|
bool enableReverseResolve = false;
|
||||||
|
|
||||||
|
bool validValues = false;
|
||||||
|
|
||||||
|
void validateAddress(Map<String, dynamic> item ,String value) {
|
||||||
|
RegExp ipAddress = RegExp(r'(?:^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$)|(?:^(?:(?:[a-fA-F\d]{1,4}:){7}(?:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,2}|:)|(?:[a-fA-F\d]{1,4}:){4}(?:(?::[a-fA-F\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,3}|:)|(?:[a-fA-F\d]{1,4}:){3}(?:(?::[a-fA-F\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,4}|:)|(?:[a-fA-F\d]{1,4}:){2}(?:(?::[a-fA-F\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,5}|:)|(?:[a-fA-F\d]{1,4}:){1}(?:(?::[a-fA-F\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?$)');
|
||||||
|
RegExp domain = RegExp(r'^((http|https|tls|udp|tcp|quic|sdns):\/\/)?([a-z0-9|-]+\.)*[a-z0-9|-]+\.[a-z]+$');
|
||||||
|
if (ipAddress.hasMatch(value) == true || domain.hasMatch(value) == true) {
|
||||||
|
setState(() => item['error'] = null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() => item['error'] = AppLocalizations.of(context)!.invalidIpDomain);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkDataValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkDataValid() {
|
||||||
|
if (
|
||||||
|
(
|
||||||
|
editReverseResolvers == true &&
|
||||||
|
reverseResolversControllers.isNotEmpty &&
|
||||||
|
reverseResolversControllers.every((element) => element['controller'].text != '') &&
|
||||||
|
reverseResolversControllers.every((element) => element['error'] == null)
|
||||||
|
) == true
|
||||||
|
) {
|
||||||
|
setState(() => validValues = true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() => validValues = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
for (var item in widget.serversProvider.dnsInfo.data!.defaultLocalPtrUpstreams) {
|
for (var item in widget.serversProvider.dnsInfo.data!.defaultLocalPtrUpstreams) {
|
||||||
|
@ -34,13 +68,17 @@ class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServer
|
||||||
for (var item in widget.serversProvider.dnsInfo.data!.localPtrUpstreams) {
|
for (var item in widget.serversProvider.dnsInfo.data!.localPtrUpstreams) {
|
||||||
final controller = TextEditingController();
|
final controller = TextEditingController();
|
||||||
controller.text = item;
|
controller.text = item;
|
||||||
reverseResolversControllers.add(controller);
|
reverseResolversControllers.add({
|
||||||
|
'controller': controller,
|
||||||
|
'error': null
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (widget.serversProvider.dnsInfo.data!.localPtrUpstreams.isNotEmpty) {
|
if (widget.serversProvider.dnsInfo.data!.localPtrUpstreams.isNotEmpty) {
|
||||||
editReverseResolvers = true;
|
editReverseResolvers = true;
|
||||||
}
|
}
|
||||||
usePrivateReverseDnsResolvers = widget.serversProvider.dnsInfo.data!.usePrivatePtrResolvers;
|
usePrivateReverseDnsResolvers = widget.serversProvider.dnsInfo.data!.usePrivatePtrResolvers;
|
||||||
enableReverseResolve = widget.serversProvider.dnsInfo.data!.resolveClients;
|
enableReverseResolve = widget.serversProvider.dnsInfo.data!.resolveClients;
|
||||||
|
validValues = true;
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +87,16 @@ class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServer
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(AppLocalizations.of(context)!.privateReverseDnsServers),
|
title: Text(AppLocalizations.of(context)!.privateReverseDnsServers),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: validValues == true
|
||||||
|
? () => {}
|
||||||
|
: null,
|
||||||
|
icon: const Icon(Icons.save_rounded),
|
||||||
|
tooltip: AppLocalizations.of(context)!.save,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: ListView(
|
body: ListView(
|
||||||
padding: const EdgeInsets.only(top: 10),
|
padding: const EdgeInsets.only(top: 10),
|
||||||
|
@ -90,7 +138,10 @@ class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServer
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
onPressed: () => setState(() => editReverseResolvers = true),
|
onPressed: () {
|
||||||
|
setState(() => editReverseResolvers = true);
|
||||||
|
checkDataValid();
|
||||||
|
},
|
||||||
icon: const Icon(Icons.edit),
|
icon: const Icon(Icons.edit),
|
||||||
label: Text(AppLocalizations.of(context)!.edit)
|
label: Text(AppLocalizations.of(context)!.edit)
|
||||||
),
|
),
|
||||||
|
@ -110,8 +161,8 @@ class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServer
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: MediaQuery.of(context).size.width-90,
|
width: MediaQuery.of(context).size.width-90,
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: c,
|
controller: c['controller'],
|
||||||
// onChanged: (_) => checkValidValues(),
|
onChanged: (value) => validateAddress(c, value),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
prefixIcon: const Icon(Icons.dns_rounded),
|
prefixIcon: const Icon(Icons.dns_rounded),
|
||||||
border: const OutlineInputBorder(
|
border: const OutlineInputBorder(
|
||||||
|
@ -119,12 +170,16 @@ class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServer
|
||||||
Radius.circular(10)
|
Radius.circular(10)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
errorText: c['error'],
|
||||||
labelText: AppLocalizations.of(context)!.serverAddress,
|
labelText: AppLocalizations.of(context)!.serverAddress,
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () => setState(() => reverseResolversControllers = reverseResolversControllers.where((con) => con != c).toList()),
|
onPressed: () {
|
||||||
|
setState(() => reverseResolversControllers = reverseResolversControllers.where((con) => con != c).toList());
|
||||||
|
checkDataValid();
|
||||||
|
},
|
||||||
icon: const Icon(Icons.remove_circle_outline)
|
icon: const Icon(Icons.remove_circle_outline)
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -152,7 +207,13 @@ class _PrivateReverseDnsServersScreenState extends State<PrivateReverseDnsServer
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
onPressed: () => setState(() => reverseResolversControllers.add(TextEditingController())),
|
onPressed: () {
|
||||||
|
setState(() => reverseResolversControllers.add({
|
||||||
|
'controller': TextEditingController(),
|
||||||
|
'error': null
|
||||||
|
}));
|
||||||
|
checkDataValid();
|
||||||
|
},
|
||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
label: Text(AppLocalizations.of(context)!.addItem)
|
label: Text(AppLocalizations.of(context)!.addItem)
|
||||||
),
|
),
|
||||||
|
|
|
@ -21,7 +21,21 @@ class UpstreamDnsScreen extends StatefulWidget {
|
||||||
class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
|
class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
|
||||||
List<TextEditingController> upstreamControllers = [];
|
List<TextEditingController> upstreamControllers = [];
|
||||||
|
|
||||||
String upstreamMode = "load_balancing";
|
String upstreamMode = "";
|
||||||
|
|
||||||
|
bool validValues = false;
|
||||||
|
|
||||||
|
checkValidValues() {
|
||||||
|
if (
|
||||||
|
upstreamControllers.isNotEmpty &&
|
||||||
|
upstreamControllers.every((element) => element.text != '')
|
||||||
|
) {
|
||||||
|
setState(() => validValues = true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() => validValues = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -31,6 +45,7 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
|
||||||
upstreamControllers.add(controller);
|
upstreamControllers.add(controller);
|
||||||
}
|
}
|
||||||
upstreamMode = widget.serversProvider.dnsInfo.data!.upstreamMode;
|
upstreamMode = widget.serversProvider.dnsInfo.data!.upstreamMode;
|
||||||
|
validValues = true;
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +54,16 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(AppLocalizations.of(context)!.upstreamDns),
|
title: Text(AppLocalizations.of(context)!.upstreamDns),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: validValues == true
|
||||||
|
? () => {}
|
||||||
|
: null,
|
||||||
|
icon: const Icon(Icons.save_rounded),
|
||||||
|
tooltip: AppLocalizations.of(context)!.save,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10)
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: ListView(
|
body: ListView(
|
||||||
padding: const EdgeInsets.only(top: 10),
|
padding: const EdgeInsets.only(top: 10),
|
||||||
|
@ -71,7 +96,7 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
|
||||||
width: MediaQuery.of(context).size.width-90,
|
width: MediaQuery.of(context).size.width-90,
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: c,
|
controller: c,
|
||||||
// onChanged: (_) => checkValidValues(),
|
onChanged: (_) => checkValidValues(),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
prefixIcon: const Icon(Icons.dns_rounded),
|
prefixIcon: const Icon(Icons.dns_rounded),
|
||||||
border: const OutlineInputBorder(
|
border: const OutlineInputBorder(
|
||||||
|
@ -84,7 +109,10 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () => setState(() => upstreamControllers = upstreamControllers.where((con) => con != c).toList()),
|
onPressed: () {
|
||||||
|
setState(() => upstreamControllers = upstreamControllers.where((con) => con != c).toList());
|
||||||
|
checkValidValues();
|
||||||
|
},
|
||||||
icon: const Icon(Icons.remove_circle_outline)
|
icon: const Icon(Icons.remove_circle_outline)
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -95,7 +123,10 @@ class _UpstreamDnsScreenState extends State<UpstreamDnsScreen> {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
onPressed: () => setState(() => upstreamControllers.add(TextEditingController())),
|
onPressed: () {
|
||||||
|
setState(() => upstreamControllers.add(TextEditingController()));
|
||||||
|
checkValidValues();
|
||||||
|
},
|
||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
label: Text(AppLocalizations.of(context)!.addItem)
|
label: Text(AppLocalizations.of(context)!.addItem)
|
||||||
),
|
),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue