From 68f0f6526f0d44f0e5e4734ad58705bf2f8a060c Mon Sep 17 00:00:00 2001 From: Addison Schuhardt Date: Mon, 3 Jun 2024 10:49:08 -0700 Subject: [PATCH 1/7] Log fatal exceptions that occur while sending or receiving request traffic BubbleID #46 --- Resources/Localization/Text.Designer.cs | 10 ++++++++++ Resources/Localization/Text.resx | 3 +++ Views/BrowserView.xaml.cs | 10 ++++++++++ 3 files changed, 23 insertions(+) diff --git a/Resources/Localization/Text.Designer.cs b/Resources/Localization/Text.Designer.cs index cc29d2c..19400af 100644 --- a/Resources/Localization/Text.Designer.cs +++ b/Resources/Localization/Text.Designer.cs @@ -339,6 +339,16 @@ internal static string BrowserView_FindNext_No_instances_found { } } + /// + /// Looks up a localized string similar to A fatal error occurred when requesting the page: {0}. + /// + internal static string BrowserView_HandleGeminiResponse_A_fatal_error_occurred_when_requesting_the_page___0_ { + get { + return ResourceManager.GetString("BrowserView_HandleGeminiResponse_A_fatal_error_occurred_when_requesting_the_page_" + + "__0_", resourceCulture); + } + } + /// /// Looks up a localized string similar to Error. /// diff --git a/Resources/Localization/Text.resx b/Resources/Localization/Text.resx index a5d04e1..db05cf4 100644 --- a/Resources/Localization/Text.resx +++ b/Resources/Localization/Text.resx @@ -704,4 +704,7 @@ Try again after you've granted the app permission to do so. Annotate non-Gemini links + + A fatal error occurred when requesting the page: {0} + \ No newline at end of file diff --git a/Views/BrowserView.xaml.cs b/Views/BrowserView.xaml.cs index 5ce3625..9732d54 100644 --- a/Views/BrowserView.xaml.cs +++ b/Views/BrowserView.xaml.cs @@ -448,6 +448,16 @@ private async Task HandleGeminiResponse(IGeminiResponse response // // Currently this only happens in the case of invalid or rejected remote // certificates, where re-sending the request would not make sense + + if (_tab.ParentPage != null) + { + await _tab.ParentPage.DisplayAlertOnMainThread(Text.BrowserView_LoadPage_Error, + string.Format(Text.BrowserView_HandleGeminiResponse_A_fatal_error_occurred_when_requesting_the_page___0_, error.Message), + Text.BrowserView_LoadPage_OK); + } + + _logger.LogError(@"A fatal exception occurred when sending the request: {Message}", error.Message); + return ResponseAction.Finished; } From 2e46a429b517fc0245f27f8ce8049af25bc5e604 Mon Sep 17 00:00:00 2001 From: Addison Schuhardt Date: Sun, 28 Jul 2024 14:11:43 -0700 Subject: [PATCH 2/7] Fixing the unrecognized certificate approval flow so that it clears the existing cert metadata and re-sends the request after the user consents to accepting the new cert. Also a minor refactor to prevent an Android SslException from being shown if the user does *not* consent. Fixes BubbleID #26 and BubbleID #48 --- Database/BrowsingDatabase.cs | 12 +++--- Interfaces/IBrowsingDatabase.cs | 2 +- Resources/Localization/Text.Designer.cs | 10 ----- Resources/Localization/Text.resx | 49 ++++++++++++------------- Views/BrowserView.xaml.cs | 27 +++++++++++--- 5 files changed, 51 insertions(+), 49 deletions(-) diff --git a/Database/BrowsingDatabase.cs b/Database/BrowsingDatabase.cs index f380406..db9b58c 100644 --- a/Database/BrowsingDatabase.cs +++ b/Database/BrowsingDatabase.cs @@ -236,25 +236,23 @@ public bool TryGetCapsule(string hostname, out Capsule capsule) return capsule != null; } - public void AcceptHostCertificate(string host) + public void RemoveHostCertificate(string host) { if (!TryGetHostCertificate(host, out var cert)) { - _logger.LogWarning(@"Cannot accept a host certificate for {Host} that has not yet been stored", host); + _logger.LogWarning(@"Cannot removed stored certificate metadata for unknown host {Host}", host); return; } - _logger.LogDebug(@"Accepting new certificate for host {Host}", host); - - cert.Accepted = true; + _logger.LogDebug(@"Removing certificate metadata for host {Host}", host); try { - _database.Update(cert); + _database.Delete(cert); } catch (Exception e) { - _logger.LogError(e, @"Exception thrown while accepting a new host certificate"); + _logger.LogError(e, @"Exception thrown while removing a host certificate"); } } diff --git a/Interfaces/IBrowsingDatabase.cs b/Interfaces/IBrowsingDatabase.cs index 340a42d..83ce60f 100644 --- a/Interfaces/IBrowsingDatabase.cs +++ b/Interfaces/IBrowsingDatabase.cs @@ -19,7 +19,7 @@ public interface IBrowsingDatabase : INotifyPropertyChanged, ICertificateDatabas IEnumerable GetVisitedPage(int page, out bool lastPage); void AddVisitedPage(Visited visited); bool TryGetHostCertificate(string host, out HostCertificate certificate); - void AcceptHostCertificate(string host); + void RemoveHostCertificate(string host); Task UpdateBookmarkOrder(); Task UpdateTabOrder(); void Update(T obj); diff --git a/Resources/Localization/Text.Designer.cs b/Resources/Localization/Text.Designer.cs index 19400af..cc29d2c 100644 --- a/Resources/Localization/Text.Designer.cs +++ b/Resources/Localization/Text.Designer.cs @@ -339,16 +339,6 @@ internal static string BrowserView_FindNext_No_instances_found { } } - /// - /// Looks up a localized string similar to A fatal error occurred when requesting the page: {0}. - /// - internal static string BrowserView_HandleGeminiResponse_A_fatal_error_occurred_when_requesting_the_page___0_ { - get { - return ResourceManager.GetString("BrowserView_HandleGeminiResponse_A_fatal_error_occurred_when_requesting_the_page_" + - "__0_", resourceCulture); - } - } - /// /// Looks up a localized string similar to Error. /// diff --git a/Resources/Localization/Text.resx b/Resources/Localization/Text.resx index db05cf4..62fc776 100644 --- a/Resources/Localization/Text.resx +++ b/Resources/Localization/Text.resx @@ -400,73 +400,73 @@ Share URL - Toggle visible + Toggle visible - Toggle the visibility of the password + Toggle the visibility of the password - Upload + Upload - token + token - Upload Text + Upload Text - Upload File + Upload File - Allow IPv6 requests + Allow IPv6 requests - Preview + Preview - An example of a page rendered using the selected theme + An example of a page rendered using the selected theme - Version + Version - The application's version number + The application's version number - Copy + Copy - Copy the version number + Copy the version number - Information + Information - Display information about the page + Display information about the page - Bookmark + Bookmark - Toggle a bookmark for the current page + Toggle a bookmark for the current page - Home + Home - Hold to set a home page, tap to navigate to the home page + Hold to set a home page, tap to navigate to the home page - Next + Next - Find the next occurrence of the text being searched for + Find the next occurrence of the text being searched for - That address is invalid + That address is invalid - What's New + What's New Swipe to move between tabs @@ -704,7 +704,4 @@ Try again after you've granted the app permission to do so. Annotate non-Gemini links - - A fatal error occurred when requesting the page: {0} - \ No newline at end of file diff --git a/Views/BrowserView.xaml.cs b/Views/BrowserView.xaml.cs index 9732d54..6d0cb78 100644 --- a/Views/BrowserView.xaml.cs +++ b/Views/BrowserView.xaml.cs @@ -42,6 +42,8 @@ public partial class BrowserView : ContentView private bool _resetFindNext; private Tab _tab; private bool _hasEverLoaded; + private bool _newCertAccepted; + private bool _newCertRejected; public BrowserView() : this(MauiProgram.Services.GetRequiredService(), @@ -109,7 +111,14 @@ private async Task RemoteCertificateUnrecognizedCallback(RemoteCertificateUnreco Text.BrowserView_RemoteCertificateUnrecognizedCallback_No); if (arg.AcceptAndTrust) - _browsingDatabase.AcceptHostCertificate(arg.Host); + { + _browsingDatabase.RemoveHostCertificate(arg.Host); + _newCertAccepted = true; + } + else + { + _newCertRejected = true; + } } private async Task RemoteCertificateInvalidCallback(RemoteCertificateInvalidArgs arg) @@ -280,6 +289,8 @@ public async Task LoadPage(bool triggeredByRefresh = false, bool useCache = fals _tab.CanShowHostCertificate = false; _hasEverLoaded = true; + _newCertRejected = false; + _newCertAccepted = false; if (_tab.Location == null || _tab.Location.Scheme == Constants.InternalScheme) { @@ -316,7 +327,7 @@ public async Task LoadPage(bool triggeredByRefresh = false, bool useCache = fals try { - for (var attempts = 0; attempts < Constants.MaxRequestAttempts; attempts++) + for (var attempts = 0; attempts < Constants.MaxRequestAttempts || _newCertAccepted; attempts++) { if (useCache && !triggeredByRefresh) { @@ -354,6 +365,13 @@ public async Task LoadPage(bool triggeredByRefresh = false, bool useCache = fals _logger.LogInformation(@"Request finished after {Attempts} attempt(s)", attempts + 1); break; } + + if (_newCertAccepted) + { + // the host's certificate changed and was accepted by the user; we should try the request again + _newCertAccepted = false; + continue; + } } } catch (Exception e) @@ -449,11 +467,10 @@ private async Task HandleGeminiResponse(IGeminiResponse response // Currently this only happens in the case of invalid or rejected remote // certificates, where re-sending the request would not make sense - if (_tab.ParentPage != null) + if (_tab.ParentPage != null && !_newCertRejected) { await _tab.ParentPage.DisplayAlertOnMainThread(Text.BrowserView_LoadPage_Error, - string.Format(Text.BrowserView_HandleGeminiResponse_A_fatal_error_occurred_when_requesting_the_page___0_, error.Message), - Text.BrowserView_LoadPage_OK); + "The page could not be displayed due to a fatal error.", Text.BrowserView_LoadPage_OK); } _logger.LogError(@"A fatal exception occurred when sending the request: {Message}", error.Message); From b65cf5d19da6c9b3a65f4629d3de8b7b1e2fee15 Mon Sep 17 00:00:00 2001 From: Addison Schuhardt Date: Sun, 28 Jul 2024 14:15:43 -0700 Subject: [PATCH 3/7] Eliminating a couple of compiler warnings --- Platforms/Android/ActionMenuClickHandler.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Platforms/Android/ActionMenuClickHandler.cs b/Platforms/Android/ActionMenuClickHandler.cs index 8b62546..c6f8ef6 100644 --- a/Platforms/Android/ActionMenuClickHandler.cs +++ b/Platforms/Android/ActionMenuClickHandler.cs @@ -15,8 +15,6 @@ public ActionMenuClickHandler(T argument, Action action) _action = action; } - public IntPtr Handle { get; } - public bool OnMenuItemClick(IMenuItem item) { _action?.Invoke(_argument); @@ -33,8 +31,6 @@ public ActionMenuClickHandler(Action action) _action = action; } - public IntPtr Handle { get; } - public bool OnMenuItemClick(IMenuItem item) { _action?.Invoke(); From 00615359a893df1067386cb30cc6360ba0e27e3d Mon Sep 17 00:00:00 2001 From: Addison Schuhardt Date: Sun, 28 Jul 2024 14:15:51 -0700 Subject: [PATCH 4/7] Upgrading libraries --- RosyCrow.csproj | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/RosyCrow.csproj b/RosyCrow.csproj index 2fd2f98..1b24277 100644 --- a/RosyCrow.csproj +++ b/RosyCrow.csproj @@ -89,31 +89,31 @@ - - - - - - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - - - - + + + + + - - - - - + + + + + From 9d0c131112edb828001cd8fb0cb4b0f582c56417 Mon Sep 17 00:00:00 2001 From: Addison Schuhardt Date: Sun, 28 Jul 2024 14:16:13 -0700 Subject: [PATCH 5/7] Commenting-out styles.xml elements that don't work anymore for some reason --- Platforms/Android/Resources/values/styles.xml | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Platforms/Android/Resources/values/styles.xml b/Platforms/Android/Resources/values/styles.xml index c85b1ab..c89bf52 100644 --- a/Platforms/Android/Resources/values/styles.xml +++ b/Platforms/Android/Resources/values/styles.xml @@ -2,26 +2,26 @@ From a5817421bc8a1023920db8c34eb0017233861de4 Mon Sep 17 00:00:00 2001 From: Addison Schuhardt Date: Sun, 28 Jul 2024 15:18:51 -0700 Subject: [PATCH 6/7] Refactoring the Find in Page feature to actually work correctly BubbleID #47 --- Models/Tab.cs | 5 +++++ Views/BrowserView.xaml.cs | 34 ++++++++-------------------------- Views/MainPage.xaml.cs | 10 ++++++++-- 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/Models/Tab.cs b/Models/Tab.cs index 04e9399..108bd2b 100644 --- a/Models/Tab.cs +++ b/Models/Tab.cs @@ -296,4 +296,9 @@ public virtual void OnLocationChanged() { OnPropertyChanged(nameof(Location)); } + + public virtual void OnHasFindNextQueryChanged() + { + OnPropertyChanged(nameof(HasFindNextQuery)); + } } \ No newline at end of file diff --git a/Views/BrowserView.xaml.cs b/Views/BrowserView.xaml.cs index 6d0cb78..2f950ae 100644 --- a/Views/BrowserView.xaml.cs +++ b/Views/BrowserView.xaml.cs @@ -74,25 +74,6 @@ public BrowserView(IOpalClient geminiClient, ISettingsDatabase settingsDatabase, _geminiClient.RemoteCertificateUnrecognizedCallback = RemoteCertificateUnrecognizedCallback; } - public bool HasFindNextQuery - { - get => !string.IsNullOrEmpty(FindNextQuery); - } - - public string FindNextQuery - { - get => _findNextQuery; - private set - { - if (value == _findNextQuery) - return; - - _findNextQuery = value; - OnPropertyChanged(); - OnPropertyChanged(nameof(HasFindNextQuery)); - } - } - private async Task RemoteCertificateUnrecognizedCallback(RemoteCertificateUnrecognizedArgs arg) { if (_tab.ParentPage == null) @@ -198,17 +179,17 @@ public void GoBack() public void ClearFindResults() { - FindNextQuery = null; + _tab.FindNextQuery = null; OnClearFindNext(); } public void FindTextInPage(string query) { // if the query is different from the last time, then start the search over from the top of the page - if (query != FindNextQuery) + if (query != _tab.FindNextQuery) _resetFindNext = true; - FindNextQuery = query; + _tab.FindNextQuery = query; OnFindNext(); _resetFindNext = false; @@ -320,7 +301,7 @@ public async Task LoadPage(bool triggeredByRefresh = false, bool useCache = fals _tab.CanPrint = false; - if (HasFindNextQuery) + if (_tab.HasFindNextQuery) ClearFindResults(); _logger.LogInformation(@"Navigating to {URI}", _tab.Location); @@ -642,6 +623,7 @@ protected virtual void OnFindNext() protected virtual void OnClearFindNext() { ClearMatches?.Invoke(this, EventArgs.Empty); + _tab.OnHasFindNextQueryChanged(); } private string CreateTabLabel() @@ -699,7 +681,7 @@ private void PageWebView_OnHandlerChanged(object sender, EventArgs e) FindNext += (_, _) => { if (_resetFindNext) // new query - webViewHandler.PlatformView.FindAllAsync(FindNextQuery); + webViewHandler.PlatformView.FindAllAsync(_tab.FindNextQuery); else // existing query; continue forward webViewHandler.PlatformView.FindNext(true); }; @@ -712,7 +694,7 @@ private void PageWebView_OnHandlerChanged(object sender, EventArgs e) if (count == 0) { _tab.ParentPage.ShowToast(Text.BrowserView_FindNext_No_instances_found, ToastDuration.Short); - FindNextQuery = null; + _tab.FindNextQuery = null; } else { @@ -749,7 +731,7 @@ private void BrowserView_OnBindingContextChanged(object sender, EventArgs e) tab.FindNext = new Command(query => FindTextInPage((string)query)); tab.Print = new Command(Print, () => _tab.CanPrint); tab.GoBack = new Command(GoBack, () => _tab.RecentHistory.TryPeek(out _)); - tab.ClearFind = new Command(ClearFindResults, () => HasFindNextQuery); + tab.ClearFind = new Command(ClearFindResults, () => _tab.HasFindNextQuery); tab.Load = new Command(async () => await LoadPage(false, true).ConfigureAwait(false), () => !_isLoading && _tab.Selected); tab.Location = tab.Url.ToGeminiUri(); diff --git a/Views/MainPage.xaml.cs b/Views/MainPage.xaml.cs index 726fe1f..f6f4c26 100644 --- a/Views/MainPage.xaml.cs +++ b/Views/MainPage.xaml.cs @@ -577,6 +577,12 @@ protected override bool OnBackButtonPressed() return true; } + if ((CurrentTab?.HasFindNextQuery ?? false) && + (CurrentTab?.ClearFind?.CanExecute(null) ?? false)) + { + CurrentTab.ClearFind.Execute(null); + } + if (CurrentTab?.GoBack.CanExecute(null) ?? false) { CurrentTab.GoBack.Execute(null); @@ -702,8 +708,8 @@ private async Task TryFindInPage() IsMenuExpanded = false; - if (CurrentTab?.FindNext.CanExecute(CurrentTab.FindNextQuery) ?? false) - CurrentTab.FindNext.Execute(CurrentTab.FindNextQuery); + if (CurrentTab?.FindNext.CanExecute(query) ?? false) + CurrentTab.FindNext.Execute(query); } catch (Exception e) { From 5f26457e2e0f5cb31861f16f137f351d0b9cb439 Mon Sep 17 00:00:00 2001 From: Addison Schuhardt Date: Sun, 28 Jul 2024 15:31:18 -0700 Subject: [PATCH 7/7] updating whats-new.html --- Resources/Raw/whats-new.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Resources/Raw/whats-new.html b/Resources/Raw/whats-new.html index 77b41ac..f4a8141 100644 --- a/Resources/Raw/whats-new.html +++ b/Resources/Raw/whats-new.html @@ -9,6 +9,11 @@ margin-top: 0!important; } +

Version 1.4.8 - July 28th, 2024

+
    +
  • #47 Find in Page now works correctly.
  • +
  • #26, #48 Fixed an issue which was causing the app to repeatedly prompt the user to accept a changed host certificate.
  • +

Version 1.4.7 - January 6th, 2024

Happy new year!