diff --git a/app/lib/features/geckoview/features/browser/domain/services/browser_addon.dart b/app/lib/features/geckoview/features/browser/domain/services/browser_addon.dart index bc46df40..a78d2dd4 100644 --- a/app/lib/features/geckoview/features/browser/domain/services/browser_addon.dart +++ b/app/lib/features/geckoview/features/browser/domain/services/browser_addon.dart @@ -29,6 +29,9 @@ import 'package:weblibre/features/geckoview/domain/providers.dart'; part 'browser_addon.g.dart'; const _signatureRequiredPref = 'xpinstall.signatures.required'; +const _installRequireBuiltInCertsPref = + 'extensions.install.requireBuiltInCerts'; +const _updateRequireBuiltInCertsPref = 'extensions.update.requireBuiltInCerts'; @Riverpod(keepAlive: true) class BrowserAddonService extends _$BrowserAddonService { @@ -73,6 +76,13 @@ class BrowserAddonService extends _$BrowserAddonService { bool allowUnsigned = false, }) async { final prefService = GeckoPrefService(); + final unsignedInstallPrefs = { + _signatureRequiredPref: false, + _installRequireBuiltInCertsPref: false, + _updateRequireBuiltInCertsPref: false, + }; + + Map? previousUnsignedInstallPrefs; try { // Validate file exists and has .xpi extension @@ -88,7 +98,25 @@ class BrowserAddonService extends _$BrowserAddonService { // Temporarily disable signature requirement if user allows unsigned if (allowUnsigned) { - await prefService.applyPrefs({_signatureRequiredPref: false}); + final existingPrefs = await prefService.getPrefs( + unsignedInstallPrefs.keys.toList(), + ); + + previousUnsignedInstallPrefs = { + for (final entry in existingPrefs.entries) + if (entry.value.value case final Object value) entry.key: value, + }; + + await prefService.applyPrefs(unsignedInstallPrefs); + + final appliedPrefs = await prefService.getPrefs( + unsignedInstallPrefs.keys.toList(), + ); + + logger.i( + 'Prepared unsigned add-on install prefs: ' + '${appliedPrefs.map((key, value) => MapEntry(key, value.value))}', + ); } try { @@ -101,8 +129,8 @@ class BrowserAddonService extends _$BrowserAddonService { return true; } finally { // Always restore signature requirement - if (allowUnsigned) { - await prefService.applyPrefs({_signatureRequiredPref: true}); + if (allowUnsigned && previousUnsignedInstallPrefs != null) { + await prefService.applyPrefs(previousUnsignedInstallPrefs); } } } catch (e, s) { diff --git a/app/lib/features/geckoview/features/browser/presentation/dialogs/install_local_addon_dialog.dart b/app/lib/features/geckoview/features/browser/presentation/dialogs/install_local_addon_dialog.dart index 99b070c3..ff235fe7 100644 --- a/app/lib/features/geckoview/features/browser/presentation/dialogs/install_local_addon_dialog.dart +++ b/app/lib/features/geckoview/features/browser/presentation/dialogs/install_local_addon_dialog.dart @@ -88,7 +88,7 @@ class _InstallLocalAddonSheet extends HookConsumerWidget { if (errorString.contains('NotSigned') || errorString.contains('SIGNEDSTATE')) { errorMessage.value = - 'This extension is not signed by Mozilla. Enable "Allow unsigned extensions" to install it.'; + 'This extension is not signed by Mozilla. Enable "Allow unsigned extensions" to retry.'; } else { errorMessage.value = 'Installation failed: $errorString'; }