mirror of
https://github.com/bitwarden/mobile
synced 2026-01-03 00:53:27 +00:00
[PM-2671] Update mobile client to use regions (#2798)
* [PM-2671] Update mobile client to use regions * [PM-2671] Refactor * [PM-2671] Move migration of region to migration service. * [PM-2671] Move comment * [PM-2671] Change method name * [PM-2671] Change method name on usages --------- Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
This commit is contained in:
@@ -9,7 +9,7 @@ using System.Threading.Tasks;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Domain;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Request;
|
||||
using Bit.Core.Models.Response;
|
||||
using Bit.Core.Utilities;
|
||||
@@ -54,7 +54,7 @@ namespace Bit.Core.Services
|
||||
public string IdentityBaseUrl { get; set; }
|
||||
public string EventsBaseUrl { get; set; }
|
||||
|
||||
public void SetUrls(EnvironmentUrls urls)
|
||||
public void SetUrls(EnvironmentUrlData urls)
|
||||
{
|
||||
UrlsSet = true;
|
||||
if (!string.IsNullOrWhiteSpace(urls.Base))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Domain;
|
||||
using Bit.Core.Utilities;
|
||||
@@ -33,6 +34,7 @@ namespace Bit.Core.Services
|
||||
public string IconsUrl { get; set; }
|
||||
public string NotificationsUrl { get; set; }
|
||||
public string EventsUrl { get; set; }
|
||||
public Region SelectedRegion { get; set; }
|
||||
|
||||
public string GetWebVaultUrl(bool returnNullIfDefault = false)
|
||||
{
|
||||
@@ -54,38 +56,33 @@ namespace Bit.Core.Services
|
||||
return GetWebVaultUrl(true) is string webVaultUrl ? $"{webVaultUrl}/#/send/" : DEFAULT_WEB_SEND_URL;
|
||||
}
|
||||
|
||||
public string GetCurrentDomain()
|
||||
{
|
||||
return new EnvironmentUrlData
|
||||
{
|
||||
WebVault = WebVaultUrl,
|
||||
Base = BaseUrl,
|
||||
Api = ApiUrl,
|
||||
Identity = IdentityUrl
|
||||
}.GetDomainOrHostname();
|
||||
}
|
||||
|
||||
public async Task SetUrlsFromStorageAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var region = await _stateService.GetActiveUserRegionAsync();
|
||||
var urls = await _stateService.GetEnvironmentUrlsAsync();
|
||||
if (urls == null)
|
||||
{
|
||||
urls = await _stateService.GetPreAuthEnvironmentUrlsAsync();
|
||||
}
|
||||
if (urls == null)
|
||||
{
|
||||
urls = new EnvironmentUrlData();
|
||||
}
|
||||
var envUrls = new EnvironmentUrls();
|
||||
if (!string.IsNullOrWhiteSpace(urls.Base))
|
||||
{
|
||||
BaseUrl = envUrls.Base = urls.Base;
|
||||
_apiService.SetUrls(envUrls);
|
||||
urls ??= await _stateService.GetPreAuthEnvironmentUrlsAsync();
|
||||
|
||||
if (urls == null || urls.IsEmpty)
|
||||
{
|
||||
await SetRegionAsync(Region.US);
|
||||
_conditionedAwaiterManager.SetAsCompleted(AwaiterPrecondition.EnvironmentUrlsInited);
|
||||
return;
|
||||
}
|
||||
|
||||
BaseUrl = urls.Base;
|
||||
WebVaultUrl = urls.WebVault;
|
||||
ApiUrl = envUrls.Api = urls.Api;
|
||||
IdentityUrl = envUrls.Identity = urls.Identity;
|
||||
IconsUrl = urls.Icons;
|
||||
NotificationsUrl = urls.Notifications;
|
||||
EventsUrl = envUrls.Events = urls.Events;
|
||||
_apiService.SetUrls(envUrls);
|
||||
|
||||
await SetRegionAsync(region.Value, urls);
|
||||
_conditionedAwaiterManager.SetAsCompleted(AwaiterPrecondition.EnvironmentUrlsInited);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
@@ -96,15 +93,26 @@ namespace Bit.Core.Services
|
||||
|
||||
}
|
||||
|
||||
public async Task<EnvironmentUrlData> SetUrlsAsync(EnvironmentUrlData urls)
|
||||
public async Task<EnvironmentUrlData> SetRegionAsync(Region region, EnvironmentUrlData selfHostedUrls = null)
|
||||
{
|
||||
urls.Base = FormatUrl(urls.Base);
|
||||
urls.WebVault = FormatUrl(urls.WebVault);
|
||||
urls.Api = FormatUrl(urls.Api);
|
||||
urls.Identity = FormatUrl(urls.Identity);
|
||||
urls.Icons = FormatUrl(urls.Icons);
|
||||
urls.Notifications = FormatUrl(urls.Notifications);
|
||||
urls.Events = FormatUrl(urls.Events);
|
||||
EnvironmentUrlData urls;
|
||||
|
||||
if (region == Region.SelfHosted)
|
||||
{
|
||||
// If user saves a self-hosted region with empty fields, default to US
|
||||
if (selfHostedUrls.IsEmpty)
|
||||
{
|
||||
return await SetRegionAsync(Region.US);
|
||||
}
|
||||
urls = selfHostedUrls.FormatUrls();
|
||||
}
|
||||
else
|
||||
{
|
||||
urls = region.GetUrls();
|
||||
}
|
||||
|
||||
SelectedRegion = region;
|
||||
await _stateService.SetPreAuthRegionAsync(region);
|
||||
await _stateService.SetPreAuthEnvironmentUrlsAsync(urls);
|
||||
BaseUrl = urls.Base;
|
||||
WebVaultUrl = urls.WebVault;
|
||||
@@ -113,35 +121,8 @@ namespace Bit.Core.Services
|
||||
IconsUrl = urls.Icons;
|
||||
NotificationsUrl = urls.Notifications;
|
||||
EventsUrl = urls.Events;
|
||||
|
||||
var envUrls = new EnvironmentUrls();
|
||||
if (!string.IsNullOrWhiteSpace(BaseUrl))
|
||||
{
|
||||
envUrls.Base = BaseUrl;
|
||||
}
|
||||
else
|
||||
{
|
||||
envUrls.Api = ApiUrl;
|
||||
envUrls.Identity = IdentityUrl;
|
||||
envUrls.Events = EventsUrl;
|
||||
}
|
||||
|
||||
_apiService.SetUrls(envUrls);
|
||||
_apiService.SetUrls(urls);
|
||||
return urls;
|
||||
}
|
||||
|
||||
private string FormatUrl(string url)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
url = Regex.Replace(url, "\\/+$", string.Empty);
|
||||
if (!url.StartsWith("http://") && !url.StartsWith("https://"))
|
||||
{
|
||||
url = string.Concat("https://", url);
|
||||
}
|
||||
return url.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,13 @@ using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Domain;
|
||||
using Bit.Core.Utilities;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
public class StateMigrationService : IStateMigrationService
|
||||
{
|
||||
private const int StateVersion = 6;
|
||||
private const int StateVersion = 7;
|
||||
|
||||
private readonly DeviceType _deviceType;
|
||||
private readonly IStorageService _preferencesStorageService;
|
||||
@@ -86,6 +87,9 @@ namespace Bit.Core.Services
|
||||
goto case 5;
|
||||
case 5:
|
||||
await MigrateFrom5To6Async();
|
||||
goto case 6;
|
||||
case 6:
|
||||
await MigrateFrom6To7Async();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -837,6 +841,42 @@ namespace Bit.Core.Services
|
||||
|
||||
#endregion
|
||||
|
||||
#region v6 to v7 Migration
|
||||
|
||||
private class V7Keys
|
||||
{
|
||||
// global keys
|
||||
internal const string StateKey = "state";
|
||||
internal const string RegionEnvironmentKey = "regionEnvironment";
|
||||
internal const string PreAuthEnvironmentUrlsKey = "preAuthEnvironmentUrls";
|
||||
}
|
||||
|
||||
private async Task MigrateFrom6To7Async()
|
||||
{
|
||||
// account data
|
||||
var state = await GetValueAsync<State>(Storage.Prefs, V7Keys.StateKey);
|
||||
|
||||
// Migrate environment data to use Regions
|
||||
foreach (var account in state.Accounts.Where(a => a.Value?.Profile?.UserId != null && a.Value?.Settings != null))
|
||||
{
|
||||
var urls = account.Value.Settings.EnvironmentUrls ?? Region.US.GetUrls();
|
||||
account.Value.Settings.Region = urls.Region;
|
||||
account.Value.Settings.EnvironmentUrls = urls.Region.GetUrls() ?? urls;
|
||||
}
|
||||
|
||||
await SetValueAsync(Storage.Prefs, Constants.StateKey, state);
|
||||
|
||||
// Update pre auth urls and region
|
||||
var preAuthUrls = await GetValueAsync<EnvironmentUrlData>(Storage.Prefs, V7Keys.PreAuthEnvironmentUrlsKey) ?? Region.US.GetUrls();
|
||||
await SetValueAsync(Storage.Prefs, V7Keys.RegionEnvironmentKey, preAuthUrls.Region);
|
||||
await SetValueAsync(Storage.Prefs, V7Keys.PreAuthEnvironmentUrlsKey, preAuthUrls.Region.GetUrls() ?? preAuthUrls);
|
||||
|
||||
|
||||
// Update stored version
|
||||
await SetLastStateVersionAsync(7);
|
||||
}
|
||||
#endregion
|
||||
|
||||
// Helpers
|
||||
|
||||
private async Task<int> GetLastStateVersionAsync()
|
||||
|
||||
@@ -1363,6 +1363,21 @@ namespace Bit.Core.Services
|
||||
_storageMediatorService.Save(Constants.ConfigsKey, value);
|
||||
}
|
||||
|
||||
public async Task<Region?> GetActiveUserRegionAsync()
|
||||
{
|
||||
return await GetActiveUserCustomDataAsync(a => a?.Settings?.Region);
|
||||
}
|
||||
|
||||
public async Task<Region?> GetPreAuthRegionAsync()
|
||||
{
|
||||
return await _storageMediatorService.GetAsync<Region?>(Constants.RegionEnvironment);
|
||||
}
|
||||
|
||||
public async Task SetPreAuthRegionAsync(Region value)
|
||||
{
|
||||
await _storageMediatorService.SaveAsync(Constants.RegionEnvironment, value);
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
[Obsolete("Use IStorageMediatorService instead")]
|
||||
@@ -1552,6 +1567,7 @@ namespace Bit.Core.Services
|
||||
await CheckStateAsync();
|
||||
|
||||
account.Settings.EnvironmentUrls = await GetPreAuthEnvironmentUrlsAsync();
|
||||
account.Settings.Region = await GetPreAuthRegionAsync();
|
||||
|
||||
// Storage
|
||||
var state = await GetStateFromStorageAsync() ?? new State();
|
||||
|
||||
Reference in New Issue
Block a user