mirror of
https://github.com/bitwarden/android.git
synced 2024-12-25 02:18:27 +03:00
Vault Timeout Policy (#1530)
This commit is contained in:
parent
d3c1b58c2a
commit
6023374fbe
16 changed files with 5504 additions and 3526 deletions
|
@ -309,12 +309,7 @@ namespace Bit.App
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Will only ever be null - look to remove this in the future
|
var vaultTimeout = await _storageService.GetAsync<int?>(Constants.VaultTimeoutKey);
|
||||||
var vaultTimeout = _platformUtilsService.LockTimeout();
|
|
||||||
if (vaultTimeout == null)
|
|
||||||
{
|
|
||||||
vaultTimeout = await _storageService.GetAsync<int?>(Constants.VaultTimeoutKey);
|
|
||||||
}
|
|
||||||
vaultTimeout = vaultTimeout.GetValueOrDefault(-1);
|
vaultTimeout = vaultTimeout.GetValueOrDefault(-1);
|
||||||
if (vaultTimeout == 0)
|
if (vaultTimeout == 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,18 +21,38 @@
|
||||||
x:DataType="pages:SettingsPageListItem">
|
x:DataType="pages:SettingsPageListItem">
|
||||||
<controls:ExtendedStackLayout Orientation="Horizontal"
|
<controls:ExtendedStackLayout Orientation="Horizontal"
|
||||||
StyleClass="list-row, list-row-platform">
|
StyleClass="list-row, list-row-platform">
|
||||||
<Label Text="{Binding Name, Mode=OneWay}"
|
<Frame
|
||||||
LineBreakMode="TailTruncation"
|
IsVisible="{Binding UseFrame}"
|
||||||
|
Padding="10"
|
||||||
|
HasShadow="False"
|
||||||
|
BackgroundColor="Transparent"
|
||||||
|
BorderColor="Accent">
|
||||||
|
<Label
|
||||||
|
Text="{Binding Name, Mode=OneWay}"
|
||||||
|
StyleClass="text-muted, text-sm, text-bold"
|
||||||
|
HorizontalTextAlignment="Center" />
|
||||||
|
</Frame>
|
||||||
|
<Label IsVisible="{Binding UseFrame, Converter={StaticResource inverseBool}}"
|
||||||
|
Text="{Binding Name, Mode=OneWay}"
|
||||||
|
LineBreakMode="{Binding LineBreakMode}"
|
||||||
HorizontalOptions="StartAndExpand"
|
HorizontalOptions="StartAndExpand"
|
||||||
VerticalOptions="CenterAndExpand"
|
VerticalOptions="CenterAndExpand"
|
||||||
StyleClass="list-title"/>
|
StyleClass="list-title"/>
|
||||||
<Label Text="{Binding SubLabel, Mode=OneWay}"
|
<Label Text="{Binding SubLabel, Mode=OneWay}"
|
||||||
IsVisible="{Binding SubLabel, Converter={StaticResource stringHasValue}}"
|
IsVisible="{Binding ShowSubLabel}"
|
||||||
HorizontalOptions="End"
|
HorizontalOptions="End"
|
||||||
HorizontalTextAlignment="End"
|
HorizontalTextAlignment="End"
|
||||||
VerticalOptions="CenterAndExpand"
|
VerticalOptions="CenterAndExpand"
|
||||||
TextColor="{Binding SubLabelColor}"
|
TextColor="{Binding SubLabelColor}"
|
||||||
StyleClass="list-sub" />
|
StyleClass="list-sub" />
|
||||||
|
<TimePicker IsVisible="{Binding ShowTimeInput}"
|
||||||
|
Time="{Binding Time}" Format="HH:mm"
|
||||||
|
PropertyChanged="OnTimePickerPropertyChanged"
|
||||||
|
HorizontalOptions="End"
|
||||||
|
VerticalOptions="Center"
|
||||||
|
FontSize="Small"
|
||||||
|
TextColor="{Binding SubLabelColor}"
|
||||||
|
StyleClass="list-sub" Margin="-5" />
|
||||||
</controls:ExtendedStackLayout>
|
</controls:ExtendedStackLayout>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Bit.App.Abstractions;
|
using System.ComponentModel;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -43,6 +44,16 @@ namespace Bit.App.Pages
|
||||||
return base.OnBackButtonPressed();
|
return base.OnBackButtonPressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async void OnTimePickerPropertyChanged(object sender, PropertyChangedEventArgs args)
|
||||||
|
{
|
||||||
|
var s = (TimePicker) sender;
|
||||||
|
var time = s.Time.TotalMinutes;
|
||||||
|
if (s.IsFocused && args.PropertyName == "Time")
|
||||||
|
{
|
||||||
|
await _vm.VaultTimeoutAsync(false, (int)time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async void RowSelected(object sender, SelectionChangedEventArgs e)
|
private async void RowSelected(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
((ExtendedCollectionView)sender).SelectedItem = null;
|
((ExtendedCollectionView)sender).SelectedItem = null;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Bit.App.Resources;
|
using System;
|
||||||
|
using Bit.App.Resources;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
@ -10,7 +11,12 @@ namespace Bit.App.Pages
|
||||||
public string Icon { get; set; }
|
public string Icon { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string SubLabel { get; set; }
|
public string SubLabel { get; set; }
|
||||||
|
public TimeSpan? Time { get; set; }
|
||||||
|
public bool UseFrame { get; set; }
|
||||||
public bool SubLabelTextEnabled => SubLabel == AppResources.Enabled;
|
public bool SubLabelTextEnabled => SubLabel == AppResources.Enabled;
|
||||||
|
public string LineBreakMode => SubLabel == null ? "TailTruncation" : "";
|
||||||
|
public bool ShowSubLabel => SubLabel.Length != 0;
|
||||||
|
public bool ShowTimeInput => Time != null;
|
||||||
public Color SubLabelColor => SubLabelTextEnabled ?
|
public Color SubLabelColor => SubLabelTextEnabled ?
|
||||||
ThemeManager.GetResourceColor("SuccessColor") :
|
ThemeManager.GetResourceColor("SuccessColor") :
|
||||||
ThemeManager.GetResourceColor("MutedColor");
|
ThemeManager.GetResourceColor("MutedColor");
|
||||||
|
|
|
@ -7,6 +7,8 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Models.Domain;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
|
@ -23,6 +25,9 @@ namespace Bit.App.Pages
|
||||||
private readonly IStorageService _storageService;
|
private readonly IStorageService _storageService;
|
||||||
private readonly ISyncService _syncService;
|
private readonly ISyncService _syncService;
|
||||||
private readonly IBiometricService _biometricService;
|
private readonly IBiometricService _biometricService;
|
||||||
|
private readonly IPolicyService _policyService;
|
||||||
|
|
||||||
|
private const int CustomVaultTimeoutValue = -100;
|
||||||
|
|
||||||
private bool _supportsBiometric;
|
private bool _supportsBiometric;
|
||||||
private bool _pin;
|
private bool _pin;
|
||||||
|
@ -42,6 +47,7 @@ namespace Bit.App.Pages
|
||||||
new KeyValuePair<string, int?>(AppResources.FourHours, 240),
|
new KeyValuePair<string, int?>(AppResources.FourHours, 240),
|
||||||
new KeyValuePair<string, int?>(AppResources.OnRestart, -1),
|
new KeyValuePair<string, int?>(AppResources.OnRestart, -1),
|
||||||
new KeyValuePair<string, int?>(AppResources.Never, null),
|
new KeyValuePair<string, int?>(AppResources.Never, null),
|
||||||
|
new KeyValuePair<string, int?>(AppResources.Custom, CustomVaultTimeoutValue),
|
||||||
};
|
};
|
||||||
private List<KeyValuePair<string, string>> _vaultTimeoutActions =
|
private List<KeyValuePair<string, string>> _vaultTimeoutActions =
|
||||||
new List<KeyValuePair<string, string>>
|
new List<KeyValuePair<string, string>>
|
||||||
|
@ -50,6 +56,9 @@ namespace Bit.App.Pages
|
||||||
new KeyValuePair<string, string>(AppResources.LogOut, "logOut"),
|
new KeyValuePair<string, string>(AppResources.LogOut, "logOut"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private Policy _vaultTimeoutPolicy;
|
||||||
|
private int _vaultTimeout;
|
||||||
|
|
||||||
public SettingsPageViewModel()
|
public SettingsPageViewModel()
|
||||||
{
|
{
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||||
|
@ -62,6 +71,7 @@ namespace Bit.App.Pages
|
||||||
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
||||||
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
|
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
|
||||||
_biometricService = ServiceContainer.Resolve<IBiometricService>("biometricService");
|
_biometricService = ServiceContainer.Resolve<IBiometricService>("biometricService");
|
||||||
|
_policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
|
||||||
|
|
||||||
GroupedItems = new ExtendedObservableCollection<SettingsPageListGroup>();
|
GroupedItems = new ExtendedObservableCollection<SettingsPageListGroup>();
|
||||||
PageTitle = AppResources.Settings;
|
PageTitle = AppResources.Settings;
|
||||||
|
@ -79,13 +89,30 @@ namespace Bit.App.Pages
|
||||||
_lastSyncDate = string.Format("{0} {1}", lastSync.Value.ToShortDateString(),
|
_lastSyncDate = string.Format("{0} {1}", lastSync.Value.ToShortDateString(),
|
||||||
lastSync.Value.ToShortTimeString());
|
lastSync.Value.ToShortTimeString());
|
||||||
}
|
}
|
||||||
var timeout = await _storageService.GetAsync<int?>(Constants.VaultTimeoutKey);
|
|
||||||
_vaultTimeoutDisplayValue = _vaultTimeouts.FirstOrDefault(o => o.Value == timeout).Key;
|
if (await _policyService.PolicyAppliesToUser(PolicyType.MaximumVaultTimeout))
|
||||||
|
{
|
||||||
|
_vaultTimeoutPolicy = (await _policyService.GetAll(PolicyType.MaximumVaultTimeout)).First();
|
||||||
|
var minutes = _policyService.GetPolicyInt(_vaultTimeoutPolicy, "minutes").GetValueOrDefault();
|
||||||
|
_vaultTimeouts = _vaultTimeouts.Where(t =>
|
||||||
|
t.Value <= minutes &&
|
||||||
|
(t.Value > 0 || t.Value == CustomVaultTimeoutValue) &&
|
||||||
|
t.Value != null).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
_vaultTimeout = await _vaultTimeoutService.GetVaultTimeout();
|
||||||
|
_vaultTimeoutDisplayValue = _vaultTimeouts.FirstOrDefault(o => o.Value == _vaultTimeout).Key;
|
||||||
var action = await _storageService.GetAsync<string>(Constants.VaultTimeoutActionKey) ?? "lock";
|
var action = await _storageService.GetAsync<string>(Constants.VaultTimeoutActionKey) ?? "lock";
|
||||||
_vaultTimeoutActionDisplayValue = _vaultTimeoutActions.FirstOrDefault(o => o.Value == action).Key;
|
_vaultTimeoutActionDisplayValue = _vaultTimeoutActions.FirstOrDefault(o => o.Value == action).Key;
|
||||||
var pinSet = await _vaultTimeoutService.IsPinLockSetAsync();
|
var pinSet = await _vaultTimeoutService.IsPinLockSetAsync();
|
||||||
_pin = pinSet.Item1 || pinSet.Item2;
|
_pin = pinSet.Item1 || pinSet.Item2;
|
||||||
_biometric = await _vaultTimeoutService.IsBiometricLockSetAsync();
|
_biometric = await _vaultTimeoutService.IsBiometricLockSetAsync();
|
||||||
|
|
||||||
|
if (_vaultTimeoutDisplayValue == null)
|
||||||
|
{
|
||||||
|
_vaultTimeoutDisplayValue = AppResources.Custom;
|
||||||
|
}
|
||||||
|
|
||||||
BuildList();
|
BuildList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,22 +220,51 @@ namespace Bit.App.Pages
|
||||||
await _vaultTimeoutService.LockAsync(true, true);
|
await _vaultTimeoutService.LockAsync(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task VaultTimeoutAsync()
|
public async Task VaultTimeoutAsync(bool promptOptions = true, int newTimeout = 0)
|
||||||
{
|
{
|
||||||
|
var oldTimeout = _vaultTimeout;
|
||||||
|
|
||||||
var options = _vaultTimeouts.Select(
|
var options = _vaultTimeouts.Select(
|
||||||
o => o.Key == _vaultTimeoutDisplayValue ? $"✓ {o.Key}" : o.Key).ToArray();
|
o => o.Key == _vaultTimeoutDisplayValue ? $"✓ {o.Key}" : o.Key).ToArray();
|
||||||
var selection = await Page.DisplayActionSheet(AppResources.VaultTimeout,
|
if (promptOptions)
|
||||||
AppResources.Cancel, null, options);
|
|
||||||
if (selection == null || selection == AppResources.Cancel)
|
|
||||||
{
|
{
|
||||||
return;
|
var selection = await Page.DisplayActionSheet(AppResources.VaultTimeout,
|
||||||
|
AppResources.Cancel, null, options);
|
||||||
|
if (selection == null || selection == AppResources.Cancel)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var cleanSelection = selection.Replace("✓ ", string.Empty);
|
||||||
|
var selectionOption = _vaultTimeouts.FirstOrDefault(o => o.Key == cleanSelection);
|
||||||
|
_vaultTimeoutDisplayValue = selectionOption.Key;
|
||||||
|
newTimeout = selectionOption.Value.GetValueOrDefault();
|
||||||
}
|
}
|
||||||
var cleanSelection = selection.Replace("✓ ", string.Empty);
|
|
||||||
var selectionOption = _vaultTimeouts.FirstOrDefault(o => o.Key == cleanSelection);
|
if (_vaultTimeoutPolicy != null)
|
||||||
_vaultTimeoutDisplayValue = selectionOption.Key;
|
{
|
||||||
await _vaultTimeoutService.SetVaultTimeoutOptionsAsync(selectionOption.Value,
|
var maximumTimeout = _policyService.GetPolicyInt(_vaultTimeoutPolicy, "minutes");
|
||||||
|
|
||||||
|
if (newTimeout > maximumTimeout)
|
||||||
|
{
|
||||||
|
await _platformUtilsService.ShowDialogAsync(AppResources.VaultTimeoutToLarge, AppResources.Warning);
|
||||||
|
var timeout = await _vaultTimeoutService.GetVaultTimeout();
|
||||||
|
_vaultTimeoutDisplayValue = _vaultTimeouts.FirstOrDefault(o => o.Value == timeout).Key ??
|
||||||
|
AppResources.Custom;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _vaultTimeoutService.SetVaultTimeoutOptionsAsync(newTimeout,
|
||||||
GetVaultTimeoutActionFromKey(_vaultTimeoutActionDisplayValue));
|
GetVaultTimeoutActionFromKey(_vaultTimeoutActionDisplayValue));
|
||||||
BuildList();
|
|
||||||
|
if (newTimeout != CustomVaultTimeoutValue)
|
||||||
|
{
|
||||||
|
_vaultTimeout = newTimeout;
|
||||||
|
}
|
||||||
|
if (oldTimeout != newTimeout)
|
||||||
|
{
|
||||||
|
await Device.InvokeOnMainThreadAsync(BuildList);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task VaultTimeoutActionAsync()
|
public async Task VaultTimeoutActionAsync()
|
||||||
|
@ -235,7 +291,7 @@ namespace Bit.App.Pages
|
||||||
var selectionOption = _vaultTimeoutActions.FirstOrDefault(o => o.Key == cleanSelection);
|
var selectionOption = _vaultTimeoutActions.FirstOrDefault(o => o.Key == cleanSelection);
|
||||||
var changed = _vaultTimeoutActionDisplayValue != selectionOption.Key;
|
var changed = _vaultTimeoutActionDisplayValue != selectionOption.Key;
|
||||||
_vaultTimeoutActionDisplayValue = selectionOption.Key;
|
_vaultTimeoutActionDisplayValue = selectionOption.Key;
|
||||||
await _vaultTimeoutService.SetVaultTimeoutOptionsAsync(GetVaultTimeoutFromKey(_vaultTimeoutDisplayValue),
|
await _vaultTimeoutService.SetVaultTimeoutOptionsAsync(_vaultTimeout,
|
||||||
selectionOption.Value);
|
selectionOption.Value);
|
||||||
if (changed)
|
if (changed)
|
||||||
{
|
{
|
||||||
|
@ -362,6 +418,25 @@ namespace Bit.App.Pages
|
||||||
new SettingsPageListItem { Name = AppResources.LockNow },
|
new SettingsPageListItem { Name = AppResources.LockNow },
|
||||||
new SettingsPageListItem { Name = AppResources.TwoStepLogin }
|
new SettingsPageListItem { Name = AppResources.TwoStepLogin }
|
||||||
};
|
};
|
||||||
|
if (_vaultTimeoutDisplayValue == AppResources.Custom)
|
||||||
|
{
|
||||||
|
securityItems.Insert(1, new SettingsPageListItem
|
||||||
|
{
|
||||||
|
Name = AppResources.Custom,
|
||||||
|
Time = TimeSpan.FromMinutes(Math.Abs((double) _vaultTimeout)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (_vaultTimeoutPolicy != null)
|
||||||
|
{
|
||||||
|
var maximumTimeout = _policyService.GetPolicyInt(_vaultTimeoutPolicy, "minutes").GetValueOrDefault();
|
||||||
|
securityItems.Insert(0, new SettingsPageListItem
|
||||||
|
{
|
||||||
|
Name = string.Format(AppResources.VaultTimeoutPolicyInEffect,
|
||||||
|
Math.Floor((float) maximumTimeout / 60),
|
||||||
|
maximumTimeout % 60),
|
||||||
|
UseFrame = true,
|
||||||
|
});
|
||||||
|
}
|
||||||
if (_supportsBiometric || _biometric)
|
if (_supportsBiometric || _biometric)
|
||||||
{
|
{
|
||||||
var biometricName = AppResources.Biometrics;
|
var biometricName = AppResources.Biometrics;
|
||||||
|
|
8780
src/App/Resources/AppResources.Designer.cs
generated
8780
src/App/Resources/AppResources.Designer.cs
generated
File diff suppressed because it is too large
Load diff
|
@ -2034,4 +2034,10 @@
|
||||||
<data name="ResetPasswordAutoEnrollInviteWarning" xml:space="preserve">
|
<data name="ResetPasswordAutoEnrollInviteWarning" xml:space="preserve">
|
||||||
<value>This organization has an enterprise policy that will automatically enroll you in password reset. Enrollment will allow organization administrators to change your master password.</value>
|
<value>This organization has an enterprise policy that will automatically enroll you in password reset. Enrollment will allow organization administrators to change your master password.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="VaultTimeoutPolicyInEffect" xml:space="preserve">
|
||||||
|
<value>Your organization policies are affecting your vault timeout. Maximum allowed Vault Timeout is {0} hour(s) and {1} minute(s)</value>
|
||||||
|
</data>
|
||||||
|
<data name="VaultTimeoutToLarge" xml:space="preserve">
|
||||||
|
<value>Your vault timeout exceeds the restrictions set by your organization.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
|
@ -84,11 +84,6 @@ namespace Bit.App.Services
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int? LockTimeout()
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LaunchUri(string uri, Dictionary<string, object> options = null)
|
public void LaunchUri(string uri, Dictionary<string, object> options = null)
|
||||||
{
|
{
|
||||||
if ((uri.StartsWith("http://") || uri.StartsWith("https://")) &&
|
if ((uri.StartsWith("http://") || uri.StartsWith("https://")) &&
|
||||||
|
|
|
@ -17,7 +17,6 @@ namespace Bit.Core.Abstractions
|
||||||
bool IsSelfHost();
|
bool IsSelfHost();
|
||||||
bool IsViewOpen();
|
bool IsViewOpen();
|
||||||
void LaunchUri(string uri, Dictionary<string, object> options = null);
|
void LaunchUri(string uri, Dictionary<string, object> options = null);
|
||||||
int? LockTimeout();
|
|
||||||
Task<string> ReadFromClipboardAsync(Dictionary<string, object> options = null);
|
Task<string> ReadFromClipboardAsync(Dictionary<string, object> options = null);
|
||||||
void SaveFile();
|
void SaveFile();
|
||||||
Task<bool> ShowDialogAsync(string text, string title = null, string confirmText = null,
|
Task<bool> ShowDialogAsync(string text, string title = null, string confirmText = null,
|
||||||
|
|
|
@ -18,5 +18,7 @@ namespace Bit.Core.Abstractions
|
||||||
MasterPasswordPolicyOptions enforcedPolicyOptions);
|
MasterPasswordPolicyOptions enforcedPolicyOptions);
|
||||||
Tuple<ResetPasswordPolicyOptions, bool> GetResetPasswordPolicyOptions(IEnumerable<Policy> policies,
|
Tuple<ResetPasswordPolicyOptions, bool> GetResetPasswordPolicyOptions(IEnumerable<Policy> policies,
|
||||||
string orgId);
|
string orgId);
|
||||||
|
Task<bool> PolicyAppliesToUser(PolicyType policyType, Func<Policy, bool> policyFilter = null);
|
||||||
|
int? GetPolicyInt(Policy policy, string key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,5 +17,6 @@ namespace Bit.Core.Abstractions
|
||||||
Task LockAsync(bool allowSoftLock = false, bool userInitiated = false);
|
Task LockAsync(bool allowSoftLock = false, bool userInitiated = false);
|
||||||
Task LogOutAsync();
|
Task LogOutAsync();
|
||||||
Task SetVaultTimeoutOptionsAsync(int? timeout, string action);
|
Task SetVaultTimeoutOptionsAsync(int? timeout, string action);
|
||||||
|
Task<int> GetVaultTimeout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,5 +11,6 @@
|
||||||
DisableSend = 6, // Disables the ability to create and edit Sends
|
DisableSend = 6, // Disables the ability to create and edit Sends
|
||||||
SendOptions = 7, // Sets restrictions or defaults for Bitwarden Sends
|
SendOptions = 7, // Sets restrictions or defaults for Bitwarden Sends
|
||||||
ResetPassword = 8, // Allows orgs to use reset password : also can enable auto-enrollment during invite flow
|
ResetPassword = 8, // Allows orgs to use reset password : also can enable auto-enrollment during invite flow
|
||||||
|
MaximumVaultTimeout = 9, // Sets the maximum allowed vault timeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,5 +91,6 @@ namespace Bit.Core.Models.Domain
|
||||||
public bool canManageGroups => IsAdmin || Permissions.ManageGroups;
|
public bool canManageGroups => IsAdmin || Permissions.ManageGroups;
|
||||||
public bool canManagePolicies => IsAdmin || Permissions.ManagePolicies;
|
public bool canManagePolicies => IsAdmin || Permissions.ManagePolicies;
|
||||||
public bool canManageUser => IsAdmin || Permissions.ManageUsers;
|
public bool canManageUser => IsAdmin || Permissions.ManageUsers;
|
||||||
|
public bool IsExemptFromPolicies => canManagePolicies;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,7 +198,32 @@ namespace Bit.Core.Services
|
||||||
return new Tuple<ResetPasswordPolicyOptions, bool>(resetPasswordPolicyOptions, policy != null);
|
return new Tuple<ResetPasswordPolicyOptions, bool>(resetPasswordPolicyOptions, policy != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int? GetPolicyInt(Policy policy, string key)
|
public async Task<bool> PolicyAppliesToUser(PolicyType policyType, Func<Policy, bool> policyFilter = null)
|
||||||
|
{
|
||||||
|
if (policyFilter == null) {
|
||||||
|
policyFilter = _ => true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var policies = await GetAll(policyType);
|
||||||
|
var organizations = await _userService.GetAllOrganizationAsync();
|
||||||
|
|
||||||
|
var filteredPolicies = policies.Where(p =>
|
||||||
|
p.Enabled &&
|
||||||
|
p.Type == policyType &&
|
||||||
|
policyFilter(p))
|
||||||
|
.Select(p => p.OrganizationId);
|
||||||
|
|
||||||
|
var policySet = filteredPolicies.Distinct();
|
||||||
|
|
||||||
|
return organizations.Any(o =>
|
||||||
|
o.Enabled &&
|
||||||
|
o.Status >= OrganizationUserStatusType.Accepted &&
|
||||||
|
o.UsePolicies &&
|
||||||
|
!o.IsExemptFromPolicies &&
|
||||||
|
policySet.Distinct().Contains(o.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int? GetPolicyInt(Policy policy, string key)
|
||||||
{
|
{
|
||||||
if (policy.Data.ContainsKey(key))
|
if (policy.Data.ContainsKey(key))
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Models.Domain;
|
using Bit.Core.Models.Domain;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
|
||||||
namespace Bit.Core.Services
|
namespace Bit.Core.Services
|
||||||
{
|
{
|
||||||
|
@ -17,6 +19,7 @@ namespace Bit.Core.Services
|
||||||
private readonly ISearchService _searchService;
|
private readonly ISearchService _searchService;
|
||||||
private readonly IMessagingService _messagingService;
|
private readonly IMessagingService _messagingService;
|
||||||
private readonly ITokenService _tokenService;
|
private readonly ITokenService _tokenService;
|
||||||
|
private readonly IPolicyService _policyService;
|
||||||
private readonly Action<bool> _lockedCallback;
|
private readonly Action<bool> _lockedCallback;
|
||||||
private readonly Func<bool, Task> _loggedOutCallback;
|
private readonly Func<bool, Task> _loggedOutCallback;
|
||||||
|
|
||||||
|
@ -31,6 +34,7 @@ namespace Bit.Core.Services
|
||||||
ISearchService searchService,
|
ISearchService searchService,
|
||||||
IMessagingService messagingService,
|
IMessagingService messagingService,
|
||||||
ITokenService tokenService,
|
ITokenService tokenService,
|
||||||
|
IPolicyService policyService,
|
||||||
Action<bool> lockedCallback,
|
Action<bool> lockedCallback,
|
||||||
Func<bool, Task> loggedOutCallback)
|
Func<bool, Task> loggedOutCallback)
|
||||||
{
|
{
|
||||||
|
@ -44,6 +48,7 @@ namespace Bit.Core.Services
|
||||||
_searchService = searchService;
|
_searchService = searchService;
|
||||||
_messagingService = messagingService;
|
_messagingService = messagingService;
|
||||||
_tokenService = tokenService;
|
_tokenService = tokenService;
|
||||||
|
_policyService = policyService;
|
||||||
_lockedCallback = lockedCallback;
|
_lockedCallback = lockedCallback;
|
||||||
_loggedOutCallback = loggedOutCallback;
|
_loggedOutCallback = loggedOutCallback;
|
||||||
}
|
}
|
||||||
|
@ -80,13 +85,8 @@ namespace Bit.Core.Services
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// This only returns null
|
var vaultTimeoutMinutes = await GetVaultTimeout();
|
||||||
var vaultTimeoutMinutes = _platformUtilsService.LockTimeout();
|
if (vaultTimeoutMinutes < 0)
|
||||||
if (vaultTimeoutMinutes == null)
|
|
||||||
{
|
|
||||||
vaultTimeoutMinutes = await _storageService.GetAsync<int?>(Constants.VaultTimeoutKey);
|
|
||||||
}
|
|
||||||
if (vaultTimeoutMinutes.GetValueOrDefault(-1) < 0)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -177,5 +177,34 @@ namespace Bit.Core.Services
|
||||||
PinProtectedKey = null;
|
PinProtectedKey = null;
|
||||||
await _storageService.RemoveAsync(Constants.ProtectedPin);
|
await _storageService.RemoveAsync(Constants.ProtectedPin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<int> GetVaultTimeout() {
|
||||||
|
var vaultTimeout = (await _storageService.GetAsync<int?>(Constants.VaultTimeoutKey)).GetValueOrDefault(-1);
|
||||||
|
|
||||||
|
if (await _policyService.PolicyAppliesToUser(PolicyType.MaximumVaultTimeout)) {
|
||||||
|
var policy = (await _policyService.GetAll(PolicyType.MaximumVaultTimeout)).First();
|
||||||
|
// Remove negative values, and ensure it's smaller than maximum allowed value according to policy
|
||||||
|
var policyTimeout = _policyService.GetPolicyInt(policy, "minutes");
|
||||||
|
if (!policyTimeout.HasValue)
|
||||||
|
{
|
||||||
|
return vaultTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeout = Math.Min(vaultTimeout, policyTimeout.Value);
|
||||||
|
|
||||||
|
if (timeout < 0) {
|
||||||
|
timeout = policyTimeout.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We really shouldn't need to set the value here, but multiple services relies on this value being correct.
|
||||||
|
if (vaultTimeout != timeout) {
|
||||||
|
await _storageService.SaveAsync(Constants.VaultTimeoutKey, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vaultTimeout;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,14 +48,14 @@ namespace Bit.Core.Utilities
|
||||||
var sendService = new SendService(cryptoService, userService, apiService, fileUploadService, storageService,
|
var sendService = new SendService(cryptoService, userService, apiService, fileUploadService, storageService,
|
||||||
i18nService, cryptoFunctionService);
|
i18nService, cryptoFunctionService);
|
||||||
searchService = new SearchService(cipherService, sendService);
|
searchService = new SearchService(cipherService, sendService);
|
||||||
|
var policyService = new PolicyService(storageService, userService);
|
||||||
var vaultTimeoutService = new VaultTimeoutService(cryptoService, userService, platformUtilsService,
|
var vaultTimeoutService = new VaultTimeoutService(cryptoService, userService, platformUtilsService,
|
||||||
storageService, folderService, cipherService, collectionService, searchService, messagingService, tokenService,
|
storageService, folderService, cipherService, collectionService, searchService, messagingService, tokenService,
|
||||||
null, (expired) =>
|
policyService, null, (expired) =>
|
||||||
{
|
{
|
||||||
messagingService.Send("logout", expired);
|
messagingService.Send("logout", expired);
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
});
|
});
|
||||||
var policyService = new PolicyService(storageService, userService);
|
|
||||||
var syncService = new SyncService(userService, apiService, settingsService, folderService,
|
var syncService = new SyncService(userService, apiService, settingsService, folderService,
|
||||||
cipherService, cryptoService, collectionService, storageService, messagingService, policyService, sendService,
|
cipherService, cryptoService, collectionService, storageService, messagingService, policyService, sendService,
|
||||||
(bool expired) =>
|
(bool expired) =>
|
||||||
|
|
Loading…
Reference in a new issue