[PS 920] Fix selfhosted url validations (#1967)

* PS-920 - Added feedback to user when saving bad formed URLs
* Added feedback to user when trying to perform login with bad formed URL

* PS-920 - Refactor to use AsyncCommand
*(missing file from previous commit)

* PS-920 - Fixed whitespace formatting

* PS-920 - Removed unused method

* PS-920 - Fixed validation
* Added comment for hard coded string

* PS-920 - Removed unused properties
* Fixed url validations
* Refactored method to local function

* PS-920 - Added exception handling and logging
* Added generic error message string to AppResources
This commit is contained in:
Carlos Gonçalves 2022-07-11 18:02:11 +01:00 committed by GitHub
parent 75e8276784
commit d621a5d2f3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 64 additions and 14 deletions

View file

@ -14,7 +14,7 @@
<ContentPage.ToolbarItems> <ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Cancel}" Clicked="Close_Clicked" Order="Primary" Priority="-1" /> <ToolbarItem Text="{u:I18n Cancel}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
<ToolbarItem Text="{u:I18n Save}" Clicked="Submit_Clicked" /> <ToolbarItem Text="{u:I18n Save}" Command="{Binding SubmitCommand}" />
</ContentPage.ToolbarItems> </ContentPage.ToolbarItems>
<ScrollView> <ScrollView>

View file

@ -36,14 +36,6 @@ namespace Bit.App.Pages
}; };
} }
private async void Submit_Clicked(object sender, EventArgs e)
{
if (DoOnce())
{
await _vm.SubmitAsync();
}
}
private async Task SubmitSuccessAsync() private async Task SubmitSuccessAsync()
{ {
_platformUtilsService.ShowToast("success", null, AppResources.EnvironmentSaved); _platformUtilsService.ShowToast("success", null, AppResources.EnvironmentSaved);

View file

@ -1,15 +1,17 @@
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input;
using Bit.App.Resources; using Bit.App.Resources;
using Bit.Core.Abstractions; using Bit.Core.Abstractions;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Xamarin.Forms; using Xamarin.CommunityToolkit.ObjectModel;
namespace Bit.App.Pages namespace Bit.App.Pages
{ {
public class EnvironmentPageViewModel : BaseViewModel public class EnvironmentPageViewModel : BaseViewModel
{ {
private readonly IEnvironmentService _environmentService; private readonly IEnvironmentService _environmentService;
readonly LazyResolve<ILogger> _logger = new LazyResolve<ILogger>("logger");
public EnvironmentPageViewModel() public EnvironmentPageViewModel()
{ {
@ -22,10 +24,10 @@ namespace Bit.App.Pages
IdentityUrl = _environmentService.IdentityUrl; IdentityUrl = _environmentService.IdentityUrl;
IconsUrl = _environmentService.IconsUrl; IconsUrl = _environmentService.IconsUrl;
NotificationsUrls = _environmentService.NotificationsUrl; NotificationsUrls = _environmentService.NotificationsUrl;
SubmitCommand = new Command(async () => await SubmitAsync()); SubmitCommand = new AsyncCommand(SubmitAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
} }
public Command SubmitCommand { get; } public ICommand SubmitCommand { get; }
public string BaseUrl { get; set; } public string BaseUrl { get; set; }
public string ApiUrl { get; set; } public string ApiUrl { get; set; }
public string IdentityUrl { get; set; } public string IdentityUrl { get; set; }
@ -37,6 +39,12 @@ namespace Bit.App.Pages
public async Task SubmitAsync() public async Task SubmitAsync()
{ {
if (!ValidateUrls())
{
await Page.DisplayAlert(AppResources.AnErrorHasOccurred, AppResources.EnvironmentPageUrlsError, AppResources.Ok);
return;
}
var resUrls = await _environmentService.SetUrlsAsync(new Core.Models.Data.EnvironmentUrlData var resUrls = await _environmentService.SetUrlsAsync(new Core.Models.Data.EnvironmentUrlData
{ {
Base = BaseUrl, Base = BaseUrl,
@ -57,5 +65,25 @@ namespace Bit.App.Pages
SubmitSuccessAction?.Invoke(); SubmitSuccessAction?.Invoke();
} }
public bool ValidateUrls()
{
bool IsUrlValid(string url)
{
return string.IsNullOrEmpty(url) || Uri.IsWellFormedUriString(url, UriKind.Absolute);
}
return IsUrlValid(BaseUrl)
&& IsUrlValid(ApiUrl)
&& IsUrlValid(IdentityUrl)
&& IsUrlValid(WebVaultUrl)
&& IsUrlValid(IconsUrl);
}
private void OnSubmitException(Exception ex)
{
_logger.Value.Exception(ex);
Page.DisplayAlert(AppResources.AnErrorHasOccurred, AppResources.GenericErrorMessage, AppResources.Ok);
}
} }
} }

View file

@ -1,4 +1,4 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // This code was generated by a tool.
// Runtime Version:4.0.30319.42000 // Runtime Version:4.0.30319.42000
@ -4044,5 +4044,17 @@ namespace Bit.App.Resources {
return ResourceManager.GetString("NeverLockWarning", resourceCulture); return ResourceManager.GetString("NeverLockWarning", resourceCulture);
} }
} }
public static string EnvironmentPageUrlsError {
get {
return ResourceManager.GetString("EnvironmentPageUrlsError", resourceCulture);
}
}
public static string GenericErrorMessage {
get {
return ResourceManager.GetString("GenericErrorMessage", resourceCulture);
}
}
} }
} }

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
@ -2257,4 +2257,10 @@
<data name="NeverLockWarning" xml:space="preserve"> <data name="NeverLockWarning" xml:space="preserve">
<value>Setting your lock options to “Never” keeps your vault available to anyone with access to your device. If you use this option, you should ensure that you keep your device properly protected.</value> <value>Setting your lock options to “Never” keeps your vault available to anyone with access to your device. If you use this option, you should ensure that you keep your device properly protected.</value>
</data> </data>
<data name="EnvironmentPageUrlsError" xml:space="preserve">
<value>One or more of the URLs entered are invalid. Please revise it and try to save again.</value>
</data>
<data name="GenericErrorMessage" xml:space="preserve">
<value>We were unable to process your request. Please try again or contact us.</value>
</data>
</root> </root>

View file

@ -589,7 +589,19 @@ namespace Bit.Core.Services
{ {
requestMessage.Version = new Version(1, 0); requestMessage.Version = new Version(1, 0);
requestMessage.Method = method; requestMessage.Method = method;
if (!Uri.IsWellFormedUriString(ApiBaseUrl, UriKind.Absolute))
{
throw new ApiException(new ErrorResponse
{
StatusCode = HttpStatusCode.BadGateway,
//Note: This message is hardcoded until AppResources.resx gets moved into Core.csproj
Message = "One or more URLs saved in the Settings are incorrect. Please revise it and try to log in again."
});
}
requestMessage.RequestUri = new Uri(string.Concat(ApiBaseUrl, path)); requestMessage.RequestUri = new Uri(string.Concat(ApiBaseUrl, path));
if (body != null) if (body != null)
{ {
var bodyType = body.GetType(); var bodyType = body.GetType();