Change password generator to use ColoredPassword (#686)

* Change password generator to use ColoredPassword

* Change ColoredPassword from FormattedString to HTML string for improved performance

* PasswordFormatter fixes

* Correct || to && condition

* Apply password colouring to history pages
This commit is contained in:
ShirokaiLon 2020-01-03 19:56:55 +00:00 committed by Kyle Spearrin
parent 051e15215d
commit a9dacd561c
7 changed files with 64 additions and 16 deletions

View file

@ -19,6 +19,7 @@
<ResourceDictionary> <ResourceDictionary>
<u:InverseBoolConverter x:Key="inverseBool" /> <u:InverseBoolConverter x:Key="inverseBool" />
<u:DateTimeConverter x:Key="dateTime" /> <u:DateTimeConverter x:Key="dateTime" />
<u:ColoredPasswordConverter x:Key="coloredPassword" />
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" <ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1"
x:Name="_closeItem" x:Key="closeItem" /> x:Name="_closeItem" x:Key="closeItem" />
<ToolbarItem Text="{u:I18n Clear}" <ToolbarItem Text="{u:I18n Clear}"
@ -71,7 +72,8 @@
Grid.Column="0" Grid.Column="0"
Grid.Row="0" Grid.Row="0"
StyleClass="list-title, list-title-platform" StyleClass="list-title, list-title-platform"
Text="{Binding Password, Mode=OneWay}" /> TextType="Html"
Text="{Binding Password, Mode=OneWay, Converter={StaticResource coloredPassword}}" />
<Label LineBreakMode="TailTruncation" <Label LineBreakMode="TailTruncation"
Grid.Column="0" Grid.Column="0"
Grid.Row="1" Grid.Row="1"

View file

@ -40,7 +40,8 @@
<StackLayout Spacing="0" Padding="0"> <StackLayout Spacing="0" Padding="0">
<StackLayout StyleClass="box"> <StackLayout StyleClass="box">
<controls:MonoLabel <controls:MonoLabel
Text="{Binding Password}" Text="{Binding ColoredPassword, Mode=OneWay}"
TextType="Html"
Margin="0, 20" Margin="0, 20"
StyleClass="text-lg" StyleClass="text-lg"
HorizontalTextAlignment="Center" HorizontalTextAlignment="Center"

View file

@ -53,7 +53,7 @@ namespace Bit.App.Pages
}); });
} }
public FormattedString ColoredPassword => PasswordFormatter.FormatPassword(Password); public string ColoredPassword => PasswordFormatter.FormatPassword(Password);
public bool IsPassword public bool IsPassword
{ {

View file

@ -23,6 +23,7 @@
<ResourceDictionary> <ResourceDictionary>
<u:InverseBoolConverter x:Key="inverseBool" /> <u:InverseBoolConverter x:Key="inverseBool" />
<u:DateTimeConverter x:Key="dateTime" /> <u:DateTimeConverter x:Key="dateTime" />
<u:ColoredPasswordConverter x:Key="coloredPassword" />
</ResourceDictionary> </ResourceDictionary>
</ContentPage.Resources> </ContentPage.Resources>
@ -62,7 +63,8 @@
Grid.Column="0" Grid.Column="0"
Grid.Row="0" Grid.Row="0"
StyleClass="list-title, list-title-platform" StyleClass="list-title, list-title-platform"
Text="{Binding Password, Mode=OneWay}" /> TextType="Html"
Text="{Binding Password, Mode=OneWay, Converter={StaticResource coloredPassword}}" />
<Label LineBreakMode="TailTruncation" <Label LineBreakMode="TailTruncation"
Grid.Column="0" Grid.Column="0"
Grid.Row="1" Grid.Row="1"

View file

@ -118,7 +118,8 @@
Grid.Column="0" Grid.Column="0"
IsVisible="{Binding ShowPassword, Converter={StaticResource inverseBool}}" /> IsVisible="{Binding ShowPassword, Converter={StaticResource inverseBool}}" />
<controls:MonoLabel <controls:MonoLabel
FormattedText="{Binding ColoredPassword, Mode=OneWay}" Text="{Binding ColoredPassword, Mode=OneWay}"
TextType="Html"
StyleClass="box-value" StyleClass="box-value"
Grid.Row="1" Grid.Row="1"
Grid.Column="0" Grid.Column="0"

View file

@ -0,0 +1,28 @@
using System;
using Xamarin.Forms;
namespace Bit.App.Utilities
{
public class ColoredPasswordConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if(targetType != typeof(string))
{
throw new InvalidOperationException("The target must be a string.");
}
if(value == null)
{
return string.Empty;
}
return PasswordFormatter.FormatPassword((string)value);
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
}

View file

@ -21,17 +21,19 @@ namespace Bit.App.Utilities
Special Special
} }
public static FormattedString FormatPassword(string password) public static string FormatPassword(string password)
{ {
if(password == null) if(password == null)
{ {
return new FormattedString(); return string.Empty;
} }
var result = new FormattedString(); // First two digits of returned hex code contains the alpha,
// Start off with an empty span to prevent possible NPEs. Due to the way the state machine // which is not supported in HTML color, so we need to cut those out.
// works, this will actually always be replaced by a new span anyway. var numberColor = $"<span style=\"color:#{((Color)Application.Current.Resources["PasswordNumberColor"]).ToHex().Substring(2)}\">";
var currentSpan = new Span(); var specialColor = $"<span style=\"color:#{((Color)Application.Current.Resources["PasswordSpecialColor"]).ToHex().Substring(2)}\">";
var result = string.Empty;
// Start with an otherwise uncovered case so we will definitely enter the "something changed" // Start with an otherwise uncovered case so we will definitely enter the "something changed"
// state. // state.
var currentType = CharType.None; var currentType = CharType.None;
@ -56,24 +58,36 @@ namespace Bit.App.Utilities
// If the char type changed, build a new span to append the text to. // If the char type changed, build a new span to append the text to.
if(charType != currentType) if(charType != currentType)
{ {
currentSpan = new Span(); // Close off previous span.
result.Spans.Add(currentSpan); if (currentType != CharType.None && currentType != CharType.Normal)
{
result += "</span>";
}
currentType = charType; currentType = charType;
// Switch the color if it is not a normal text. Otherwise leave the // Switch the color if it is not a normal text. Otherwise leave the
// default value. // default value.
switch(currentType) switch(currentType)
{ {
// Apply color style to span.
case CharType.Number: case CharType.Number:
currentSpan.TextColor = (Color)Application.Current.Resources["PasswordNumberColor"]; result += numberColor;
break; break;
case CharType.Special: case CharType.Special:
currentSpan.TextColor = (Color)Application.Current.Resources["PasswordSpecialColor"]; result += specialColor;
break; break;
} }
} }
currentSpan.Text += c; result += c;
} }
// Close off last span.
if (currentType != CharType.None && currentType != CharType.Normal)
{
result += "</span>";
}
return result; return result;
} }
} }