diff --git a/src/App/Pages/Vault/ViewPage.xaml b/src/App/Pages/Vault/ViewPage.xaml index 29b230cd4..652ea8aff 100644 --- a/src/App/Pages/Vault/ViewPage.xaml +++ b/src/App/Pages/Vault/ViewPage.xaml @@ -96,7 +96,7 @@ Grid.Column="0" IsVisible="{Binding ShowPassword, Converter={StaticResource inverseBool}}" /> _cipher?.Type == Core.Enums.CipherType.Card; public bool IsSecureNote => _cipher?.Type == Core.Enums.CipherType.SecureNote; public bool ShowUsername => IsLogin && !string.IsNullOrWhiteSpace(_cipher.Login.Username); + public FormattedString ColoredPassword => PasswordFormatter.FormatPassword(_cipher.Login.Password); public bool ShowPasswordBox => IsLogin && !string.IsNullOrWhiteSpace(_cipher.Login.Password); public bool ShowUris => IsLogin && _cipher.Login.HasUris; public bool ShowNotes => !string.IsNullOrWhiteSpace(_cipher.Notes); diff --git a/src/App/Styles/Dark.xaml b/src/App/Styles/Dark.xaml index 777119f0a..60f34ce6c 100644 --- a/src/App/Styles/Dark.xaml +++ b/src/App/Styles/Dark.xaml @@ -9,6 +9,8 @@ #555555 #bf7e16 #777777 + #007fde + #c40800 #dddddd diff --git a/src/App/Styles/Light.xaml b/src/App/Styles/Light.xaml index 2e402e016..6a1f14cd1 100644 --- a/src/App/Styles/Light.xaml +++ b/src/App/Styles/Light.xaml @@ -9,6 +9,8 @@ #555555 #bf7e16 #777777 + #007fde + #c40800 #dddddd diff --git a/src/App/Utilities/PasswordFormatter.cs b/src/App/Utilities/PasswordFormatter.cs new file mode 100644 index 000000000..0e20eb2e9 --- /dev/null +++ b/src/App/Utilities/PasswordFormatter.cs @@ -0,0 +1,75 @@ +using System; +using Xamarin.Forms; + +namespace Bit.App.Utilities +{ + /** + * Helper class to format a password with numeric encoding to separate + * normal text from numbers and special characters. + */ + class PasswordFormatter + { + /** + * This enum is used for the state machine when building the colorized + * password string. + */ + private enum CharType + { + None, + Normal, + Number, + Special + } + + public static FormattedString FormatPassword(String password) + { + var result = new FormattedString(); + // Start off with an empty span to prevent possible NPEs. Due to the way the state machine + // works, this will actually always be replaced by a new span anyway. + var currentSpan = new Span(); + // Start with an otherwise uncovered case so we will definitely enter the "something changed" + // state. + var currentType = CharType.None; + + foreach(var c in password) + { + // First, identify what the current char is. + CharType charType; + if(char.IsLetter(c)) + { + charType = CharType.Normal; + } + else if(char.IsDigit(c)) + { + charType = CharType.Number; + } + else + { + charType = CharType.Special; + } + + // If the char type changed, build a new span to append the text to. + if(charType != currentType) + { + currentSpan = new Span(); + result.Spans.Add(currentSpan); + currentType = charType; + + // Switch the color if it is not a normal text. Otherwise leave the + // default value. + switch(currentType) + { + case CharType.Number: + currentSpan.TextColor = (Color)Application.Current.Resources["PasswordNumberColor"]; + break; + case CharType.Special: + currentSpan.TextColor = (Color)Application.Current.Resources["PasswordSpecialColor"]; + break; + } + } + currentSpan.Text += c; + } + return result; + } + } +}