* [pve-devel] [PATCH proxmox_dart_api_client v2 1/2] fix: android: use `cronet_http` package to honor custom certificates
2025-09-04 10:09 [pve-devel] [PATCH proxmox_dart_api_client/pve_flutter_frontend v2 0/3] fix: android: add support to honor user installed certificate Shan Shaji
2025-09-04 10:09 ` [pve-devel] [PATCH pve_flutter_frontend v2 1/1] fix: android: add network config to support custom certificates Shan Shaji
@ 2025-09-04 10:09 ` Shan Shaji
2025-09-04 10:09 ` [pve-devel] [PATCH proxmox_dart_api_client v2 2/2] fix: add explicit throw of `HandShakeException` Shan Shaji
2025-09-05 8:43 ` [pve-devel] [PATCH proxmox_dart_api_client/pve_flutter_frontend v2 0/3] fix: android: add support to honor user installed certificate Michael Köppl
3 siblings, 0 replies; 5+ messages in thread
From: Shan Shaji @ 2025-09-04 10:09 UTC (permalink / raw)
To: pve-devel
In android when a user installs a custom certificate the app was not
honoring the installed certificate and was still throwing
`HandShakeException`.
The issue is because the `IOClient` doesn't by default honor user
installed certificate [0].
To fix the issue, used the `cronet_http` [1] package which will honor
the user installed certificates. Used the standalone embedded
library [2] of cronet inorder to avoid the dependency on
Google Play Services.
[0] - https://github.com/dart-lang/sdk/issues/50435
[1] - https://pub.dev/packages/cronet_http
[2] - https://pub.dev/packages/cronet_http#use-embedded-cronet
Signed-off-by: Shan Shaji <s.shaji@proxmox.com>
---
changes since v1:
- Update commit message with more details and links.
- Fixed wrong package name in the commit message.
lib/src/utils_native.dart | 12 ++++++
pubspec.lock | 89 ++++++++++++++++++++++++++++++++++++---
pubspec.yaml | 1 +
3 files changed, 95 insertions(+), 7 deletions(-)
diff --git a/lib/src/utils_native.dart b/lib/src/utils_native.dart
index 2ece3a3..a4b7397 100644
--- a/lib/src/utils_native.dart
+++ b/lib/src/utils_native.dart
@@ -1,3 +1,4 @@
+import 'package:cronet_http/cronet_http.dart';
import 'package:http/http.dart' as http;
import 'package:http/io_client.dart' as http_io;
import 'dart:io';
@@ -5,6 +6,17 @@ import 'dart:io';
http.Client getCustomIOHttpClient({bool validateSSL = true}) {
var ioClient = HttpClient();
+ if (Platform.isAndroid && validateSSL) {
+ final engine = CronetEngine.build(
+ cacheMaxSize: 1024 * 1024,
+ cacheMode: CacheMode.memory,
+ );
+ return CronetClient.fromCronetEngine(
+ engine,
+ closeEngine: true,
+ );
+ }
+
if (!validateSSL) {
ioClient.badCertificateCallback =
((X509Certificate cert, String host, int port) {
diff --git a/pubspec.lock b/pubspec.lock
index 857f2bc..6496e27 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -113,6 +113,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "8.9.2"
+ characters:
+ dependency: transitive
+ description:
+ name: characters
+ sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.4.0"
checked_yaml:
dependency: transitive
description:
@@ -133,10 +141,10 @@ packages:
dependency: transitive
description:
name: collection
- sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
+ sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
- version: "1.18.0"
+ version: "1.19.1"
convert:
dependency: transitive
description:
@@ -153,6 +161,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.7.2"
+ cronet_http:
+ dependency: "direct main"
+ description:
+ name: cronet_http
+ sha256: "1b99ad5ae81aa9d2f12900e5f17d3681f3828629bb7f7fe7ad88076a34209840"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.5.0"
crypto:
dependency: transitive
description:
@@ -169,6 +185,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.6"
+ ffi:
+ dependency: transitive
+ description:
+ name: ffi
+ sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.4"
file:
dependency: transitive
description:
@@ -185,6 +209,11 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.0"
+ flutter:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.0"
frontend_server_client:
dependency: transitive
description:
@@ -213,10 +242,10 @@ packages:
dependency: "direct main"
description:
name: http
- sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
+ sha256: bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007
url: "https://pub.dev"
source: hosted
- version: "1.2.1"
+ version: "1.5.0"
http_multi_server:
dependency: transitive
description:
@@ -233,6 +262,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.2"
+ http_profile:
+ dependency: transitive
+ description:
+ name: http_profile
+ sha256: "7e679e355b09aaee2ab5010915c932cce3f2d1c11c3b2dc177891687014ffa78"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.1.0"
io:
dependency: transitive
description:
@@ -241,6 +278,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.4"
+ jni:
+ dependency: transitive
+ description:
+ name: jni
+ sha256: d2c361082d554d4593c3012e26f6b188f902acd291330f13d6427641a92b3da1
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.14.2"
js:
dependency: transitive
description:
@@ -281,14 +326,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
+ material_color_utilities:
+ dependency: transitive
+ description:
+ name: material_color_utilities
+ sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.11.1"
meta:
dependency: transitive
description:
name: meta
- sha256: "25dfcaf170a0190f47ca6355bdd4552cb8924b430512ff0cafb8db9bd41fe33b"
+ sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
url: "https://pub.dev"
source: hosted
- version: "1.14.0"
+ version: "1.16.0"
mime:
dependency: transitive
description:
@@ -321,6 +374,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.0"
+ plugin_platform_interface:
+ dependency: transitive
+ description:
+ name: plugin_platform_interface
+ sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.8"
pool:
dependency: transitive
description:
@@ -385,6 +446,11 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.4"
+ sky_engine:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.0"
source_gen:
dependency: transitive
description:
@@ -497,6 +563,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.2"
+ vector_math:
+ dependency: transitive
+ description:
+ name: vector_math
+ sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.4"
vm_service:
dependency: transitive
description:
@@ -546,4 +620,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
- dart: ">=3.3.0 <4.0.0"
+ dart: ">=3.7.0 <4.0.0"
+ flutter: ">=3.22.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index 7b61edc..3aa881b 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -10,6 +10,7 @@ dependencies:
built_value: ^8.4.2
built_collection: ^5.1.1
retry: ^3.1.0
+ cronet_http: ^1.5.0
dev_dependencies:
lints: ^3.0.0
--
2.47.2
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 5+ messages in thread
* [pve-devel] [PATCH proxmox_dart_api_client v2 2/2] fix: add explicit throw of `HandShakeException`
2025-09-04 10:09 [pve-devel] [PATCH proxmox_dart_api_client/pve_flutter_frontend v2 0/3] fix: android: add support to honor user installed certificate Shan Shaji
2025-09-04 10:09 ` [pve-devel] [PATCH pve_flutter_frontend v2 1/1] fix: android: add network config to support custom certificates Shan Shaji
2025-09-04 10:09 ` [pve-devel] [PATCH proxmox_dart_api_client v2 1/2] fix: android: use `cronet_http` package to honor " Shan Shaji
@ 2025-09-04 10:09 ` Shan Shaji
2025-09-05 8:43 ` [pve-devel] [PATCH proxmox_dart_api_client/pve_flutter_frontend v2 0/3] fix: android: add support to honor user installed certificate Michael Köppl
3 siblings, 0 replies; 5+ messages in thread
From: Shan Shaji @ 2025-09-04 10:09 UTC (permalink / raw)
To: pve-devel
The `cronet_http` is throwing `ClientException` [0] instead of
`HandShakeException` when the certificate is not valid.
Due to this the exception was directly shown in the UI. Inorder to make
the error more user friendly catch the `ClientException` and rethrow
`HandShakeException` if the certificate is not valid.
[0] - https://github.com/dart-lang/http/blob/ef05b3744424885d93f88a6a50664fb5b7d5cbdb/pkgs/cronet_http/lib/src/cronet_client.dart#L327
Signed-off-by: Shan Shaji <s.shaji@proxmox.com>
---
lib/src/authenticate.dart | 31 ++++++++++++++++++++++---------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/lib/src/authenticate.dart b/lib/src/authenticate.dart
index 118408f..a142a4c 100644
--- a/lib/src/authenticate.dart
+++ b/lib/src/authenticate.dart
@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:convert';
+import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:proxmox_dart_api_client/proxmox_dart_api_client.dart';
@@ -56,6 +57,11 @@ Future<ProxmoxApiClient> authenticate(
} on TimeoutException catch (_) {
throw ProxmoxApiException(
'Authentication takes unusually long, check network connection', 408);
+ } on http.ClientException catch (e) {
+ if (e.message.contains('net::ERR_CERT_AUTHORITY_INVALID')) {
+ throw HandshakeException(e.message);
+ }
+ rethrow;
}
}
@@ -64,14 +70,21 @@ Future<List<PveAccessDomainModel?>> accessDomains(
bool validateSSL, {
http.Client? httpClient,
}) async {
- httpClient ??= getCustomIOHttpClient(validateSSL: validateSSL);
+ try {
+ httpClient ??= getCustomIOHttpClient(validateSSL: validateSSL);
- final path = '/api2/json/access/domains';
- final response = await httpClient
- .get(apiBaseUrl.replace(path: path))
- .timeout(Duration(seconds: 25));
- var data = (json.decode(response.body)['data'] as List).map((f) {
- return serializers.deserializeWith(PveAccessDomainModel.serializer, f);
- });
- return data.toList();
+ final path = '/api2/json/access/domains';
+ final response = await httpClient
+ .get(apiBaseUrl.replace(path: path))
+ .timeout(Duration(seconds: 25));
+ var data = (json.decode(response.body)['data'] as List).map((f) {
+ return serializers.deserializeWith(PveAccessDomainModel.serializer, f);
+ });
+ return data.toList();
+ } on http.ClientException catch (e) {
+ if (e.message.contains('net::ERR_CERT_AUTHORITY_INVALID')) {
+ throw HandshakeException(e.message);
+ }
+ rethrow;
+ }
}
--
2.47.2
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
^ permalink raw reply [flat|nested] 5+ messages in thread