1
0
mirror of https://github.com/bitwarden/mobile synced 2026-01-06 02:23:57 +00:00

[SG-460] Master Password security checks (mobile) (#2312)

* [SG-886] MasterPassword Strength Indicator (#2238)

* [SG-886] Add password strength indicator control

* [SG-570] Add weak password dialog check

* [SG-886] rename enum password strength

* [SG-886] Change control scale

* [SG-886] Move calculate user inputs to IPasswordGenerationService, refactor.

* [SG-886] Move formatted string to xaml. Move minimum chars to constant

* [SG-886] String to enum converter

* [SG-886] PR fixes. Code refactor control

* [SG-886] Update UI on OS theme change.

* [SG-886] Move colors to view

* [SG-886] Fixed password strength validation

* [SG-564][SG-565] Check Exposed Password (#2239)

* [SG-886] Add password strength indicator control

* [SG-570] Add weak password dialog check

* [SG-886] rename enum password strength

* [SG-564] [SG-565] Add check for exposed password and show dialog

* code format

* [SG-886] Change control scale

* [SG-886] Move calculate user inputs to IPasswordGenerationService, refactor.

* [SG-886] Move formatted string to xaml. Move minimum chars to constant

* [SG-886] String to enum converter

* [SG-886] Remove import

* [SG-886] Update UI on OS theme change.

* [SG-886] Move colors to view

* [SG-886] Fixed password strength validation
This commit is contained in:
André Bispo
2023-01-20 13:38:31 +00:00
committed by GitHub
parent 5aa1146657
commit d61bc4b5c1
18 changed files with 553 additions and 31 deletions

View File

@@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace Bit.App.Controls
{
public interface IPasswordStrengthable
{
string Password { get; }
List<string> UserInputs { get; }
}
}

View File

@@ -0,0 +1,17 @@
using Bit.Core.Attributes;
namespace Bit.App.Controls
{
public enum PasswordStrengthLevel
{
[LocalizableEnum("Weak")]
VeryWeak,
[LocalizableEnum("Weak")]
Weak,
[LocalizableEnum("Good")]
Good,
[LocalizableEnum("Strong")]
Strong
}
}

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" ?>
<StackLayout
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities"
x:DataType="controls:PasswordStrengthViewModel"
x:Class="Bit.App.Controls.PasswordStrengthProgressBar"
StyleClass="box">
<StackLayout.Resources>
<ResourceDictionary>
<u:LocalizableEnumConverter x:Key="localizableEnum" />
</ResourceDictionary>
</StackLayout.Resources>
<ProgressBar
x:Name="_progressBar"
u:ProgressBarExtensions.AnimatedProgress="{Binding PasswordStrength}"
ScaleY="2" />
<Label
x:Name="_progressLabel"
Text="{Binding PasswordStrengthLevel, Converter={StaticResource localizableEnum}, TargetNullValue=' ' }"
StyleClass="box-footer-label" />
</StackLayout>

View File

@@ -0,0 +1,107 @@
using System;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public partial class PasswordStrengthProgressBar : StackLayout
{
public static readonly BindableProperty PasswordStrengthLevelProperty = BindableProperty.Create(
nameof(PasswordStrengthLevel),
typeof(PasswordStrengthLevel),
typeof(PasswordStrengthProgressBar),
propertyChanged: OnControlPropertyChanged);
public static readonly BindableProperty VeryWeakColorProperty = BindableProperty.Create(
nameof(VeryWeakColor),
typeof(Color),
typeof(PasswordStrengthProgressBar),
propertyChanged: OnControlPropertyChanged);
public static readonly BindableProperty WeakColorProperty = BindableProperty.Create(
nameof(WeakColor),
typeof(Color),
typeof(PasswordStrengthProgressBar),
propertyChanged: OnControlPropertyChanged);
public static readonly BindableProperty GoodColorProperty = BindableProperty.Create(
nameof(GoodColor),
typeof(Color),
typeof(PasswordStrengthProgressBar),
propertyChanged: OnControlPropertyChanged);
public static readonly BindableProperty StrongColorProperty = BindableProperty.Create(
nameof(StrongColor),
typeof(Color),
typeof(PasswordStrengthProgressBar),
propertyChanged: OnControlPropertyChanged);
public PasswordStrengthLevel? PasswordStrengthLevel
{
get { return (PasswordStrengthLevel?)GetValue(PasswordStrengthLevelProperty); }
set { SetValue(PasswordStrengthLevelProperty, value); }
}
public Color VeryWeakColor
{
get { return (Color)GetValue(VeryWeakColorProperty); }
set { SetValue(VeryWeakColorProperty, value); }
}
public Color WeakColor
{
get { return (Color)GetValue(WeakColorProperty); }
set { SetValue(WeakColorProperty, value); }
}
public Color GoodColor
{
get { return (Color)GetValue(GoodColorProperty); }
set { SetValue(GoodColorProperty, value); }
}
public Color StrongColor
{
get { return (Color)GetValue(StrongColorProperty); }
set { SetValue(StrongColorProperty, value); }
}
public PasswordStrengthProgressBar()
{
InitializeComponent();
SetBinding(PasswordStrengthProgressBar.PasswordStrengthLevelProperty, new Binding() { Path = nameof(PasswordStrengthViewModel.PasswordStrengthLevel) });
}
private static void OnControlPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
(bindable as PasswordStrengthProgressBar)?.UpdateColors();
}
public void UpdateColors()
{
if (_progressBar == null || _progressLabel == null)
{
return;
}
_progressBar.ProgressColor = GetColorForStrength();
_progressLabel.TextColor = _progressBar.ProgressColor;
}
private Color GetColorForStrength()
{
switch (PasswordStrengthLevel)
{
case Controls.PasswordStrengthLevel.VeryWeak:
return VeryWeakColor;
case Controls.PasswordStrengthLevel.Weak:
return WeakColor;
case Controls.PasswordStrengthLevel.Good:
return GoodColor;
case Controls.PasswordStrengthLevel.Strong:
return StrongColor;
default:
return Color.Transparent;
}
}
}
}

View File

@@ -0,0 +1,67 @@
using System.Collections.Generic;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class PasswordStrengthViewModel : ExtendedViewModel
{
private readonly IPasswordGenerationService _passwordGenerationService;
private readonly IPasswordStrengthable _passwordStrengthable;
private double _passwordStrength;
private Color _passwordColor;
private PasswordStrengthLevel? _passwordStrengthLevel;
public PasswordStrengthViewModel(IPasswordStrengthable passwordStrengthable)
{
_passwordGenerationService = ServiceContainer.Resolve<IPasswordGenerationService>();
_passwordStrengthable = passwordStrengthable;
}
public double PasswordStrength
{
get => _passwordStrength;
set => SetProperty(ref _passwordStrength, value);
}
public PasswordStrengthLevel? PasswordStrengthLevel
{
get => _passwordStrengthLevel;
set => SetProperty(ref _passwordStrengthLevel, value);
}
public List<string> GetPasswordStrengthUserInput(string email) => _passwordGenerationService.GetPasswordStrengthUserInput(email);
public void CalculatePasswordStrength()
{
if (string.IsNullOrEmpty(_passwordStrengthable.Password))
{
PasswordStrength = 0;
PasswordStrengthLevel = null;
return;
}
var passwordStrength = _passwordGenerationService.PasswordStrength(_passwordStrengthable.Password, _passwordStrengthable.UserInputs);
// The passwordStrength.Score is 0..4, convertion was made to be used as a progress directly by the control 0..1
PasswordStrength = (passwordStrength.Score + 1f) / 5f;
if (PasswordStrength <= 0.4f)
{
PasswordStrengthLevel = Controls.PasswordStrengthLevel.VeryWeak;
}
else if (PasswordStrength <= 0.6f)
{
PasswordStrengthLevel = Controls.PasswordStrengthLevel.Weak;
}
else if (PasswordStrength <= 0.8f)
{
PasswordStrengthLevel = Controls.PasswordStrengthLevel.Good;
}
else
{
PasswordStrengthLevel = Controls.PasswordStrengthLevel.Strong;
}
}
}
}