import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/theme_extensions.dart'; import 'package:immich_mobile/platform/network_api.g.dart'; import 'package:immich_mobile/providers/infrastructure/platform.provider.dart'; import 'package:immich_mobile/utils/http_ssl_options.dart'; import 'package:logging/logging.dart'; class SslClientCertSettings extends StatefulWidget { const SslClientCertSettings({super.key, required this.isLoggedIn}); final bool isLoggedIn; @override State createState() => _SslClientCertSettingsState(); } class _SslClientCertSettingsState extends State { final _log = Logger("SslClientCertSettings"); bool isCertExist; _SslClientCertSettingsState() : isCertExist = SSLClientCertStoreVal.load() != null; @override Widget build(BuildContext context) { return ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 20), horizontalTitleGap: 20, isThreeLine: true, title: Text("client_cert_title".tr(), style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500)), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "client_cert_subtitle".tr(), style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary), ), const SizedBox(height: 6), Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, children: [ ElevatedButton(onPressed: widget.isLoggedIn ? null : importCert, child: Text("client_cert_import".tr())), ElevatedButton( onPressed: widget.isLoggedIn || !isCertExist ? null : removeCert, child: Text("remove".tr()), ), ], ), ], ), ); } void showMessage(String message) { context.showSnackBar( SnackBar( duration: const Duration(seconds: 3), content: Text(message, style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor)), ), ); } Future importCert() async { try { final styling = ClientCertPrompt( title: "client_cert_password_title".tr(), message: "client_cert_password_message".tr(), cancel: "cancel".tr(), confirm: "confirm".tr(), ); final cert = await networkApi.selectCertificate(styling); await SSLClientCertStoreVal(cert.data, cert.password).save(); HttpSSLOptions.apply(); setState(() => isCertExist = true); showMessage("client_cert_import_success_msg".tr()); } catch (e) { if (_isCancellation(e)) { return; } _log.severe("Error importing client cert", e); showMessage("client_cert_invalid_msg".tr()); } } Future removeCert() async { try { await networkApi.removeCertificate(); await SSLClientCertStoreVal.delete(); HttpSSLOptions.apply(); setState(() => isCertExist = false); showMessage("client_cert_remove_msg".tr()); } catch (e) { if (_isCancellation(e)) { return; } _log.severe("Error removing client cert", e); showMessage("client_cert_invalid_msg".tr()); } } bool _isCancellation(Object e) => e is PlatformException && e.code.toLowerCase().contains("cancel"); }