Respect options on gneerate password. Allow override parameters to be passed into password generation service. Respect context password options. Copy password.

This commit is contained in:
Kyle Spearrin 2016-07-15 01:01:00 -04:00
parent 83359b2d43
commit b90c153353
8 changed files with 241 additions and 62 deletions

View File

@ -2,6 +2,16 @@
{ {
public interface IPasswordGenerationService public interface IPasswordGenerationService
{ {
string GeneratePassword(); string GeneratePassword(
int? length = null,
bool? uppercase = null,
bool? lowercase = null,
bool? numbers = null,
bool? special = null,
bool? ambiguous = null,
int? minUppercase = null,
int? minLowercase = null,
int? minNumbers = null,
int? minSpecial = null);
} }
} }

View File

@ -17,78 +17,88 @@ namespace Bit.App.Services
_settings = settings; _settings = settings;
} }
public string GeneratePassword() public string GeneratePassword(
int? length = null,
bool? uppercase = null,
bool? lowercase = null,
bool? numbers = null,
bool? special = null,
bool? ambiguous = null,
int? minUppercase = null,
int? minLowercase = null,
int? minNumbers = null,
int? minSpecial = null)
{ {
int minUppercase = 1, int minUppercaseValue = minUppercase.GetValueOrDefault(1),
minLowercase = 1, minLowercaseValue = minLowercase.GetValueOrDefault(1),
minNumbers = _settings.GetValueOrDefault(Constants.PasswordGeneratorMinNumbers, 1), minNumbersValue = minNumbers.GetValueOrDefault(_settings.GetValueOrDefault(Constants.PasswordGeneratorMinNumbers, 1)),
minSpecial = _settings.GetValueOrDefault(Constants.PasswordGeneratorMinSpecial, 1), minSpecialValue = minSpecial.GetValueOrDefault(_settings.GetValueOrDefault(Constants.PasswordGeneratorMinSpecial, 1)),
length = _settings.GetValueOrDefault(Constants.PasswordGeneratorLength, 10); lengthValue = length.GetValueOrDefault(_settings.GetValueOrDefault(Constants.PasswordGeneratorLength, 10));
bool uppercase = _settings.GetValueOrDefault(Constants.PasswordGeneratorUppercase, true), bool uppercaseValue = uppercase.GetValueOrDefault(_settings.GetValueOrDefault(Constants.PasswordGeneratorUppercase, true)),
lowercase = _settings.GetValueOrDefault(Constants.PasswordGeneratorLowercase, true), lowercaseValue = lowercase.GetValueOrDefault(_settings.GetValueOrDefault(Constants.PasswordGeneratorLowercase, true)),
numbers = _settings.GetValueOrDefault(Constants.PasswordGeneratorNumbers, true), numbersValue = numbers.GetValueOrDefault(_settings.GetValueOrDefault(Constants.PasswordGeneratorNumbers, true)),
special = _settings.GetValueOrDefault(Constants.PasswordGeneratorSpecial, true), specialValue = special.GetValueOrDefault(_settings.GetValueOrDefault(Constants.PasswordGeneratorSpecial, true)),
ambiguous = _settings.GetValueOrDefault(Constants.PasswordGeneratorAmbiguous, false); ambiguousValue = ambiguous.GetValueOrDefault(_settings.GetValueOrDefault(Constants.PasswordGeneratorAmbiguous, false));
// Sanitize // Sanitize
if(uppercase && minUppercase < 0) if(uppercaseValue && minUppercaseValue < 0)
{ {
minUppercase = 1; minUppercaseValue = 1;
} }
if(lowercase && minLowercase < 0) if(lowercaseValue && minLowercaseValue < 0)
{ {
minLowercase = 1; minLowercaseValue = 1;
} }
if(numbers && minNumbers < 0) if(numbersValue && minNumbersValue < 0)
{ {
minNumbers = 1; minNumbersValue = 1;
} }
if(special && minSpecial < 0) if(specialValue && minSpecialValue < 0)
{ {
minSpecial = 1; minSpecialValue = 1;
} }
if(length < 1) if(lengthValue < 1)
{ {
length = 10; lengthValue = 10;
} }
var minLength = minUppercase + minLowercase + minNumbers + minSpecial; var minLength = minUppercaseValue + minLowercaseValue + minNumbersValue + minSpecialValue;
if(length < minLength) if(lengthValue < minLength)
{ {
length = minLength; lengthValue = minLength;
} }
var positionsBuilder = new StringBuilder(); var positionsBuilder = new StringBuilder();
if(lowercase && minLowercase > 0) if(lowercaseValue && minLowercaseValue > 0)
{ {
for(int i = 0; i < minLowercase; i++) for(int i = 0; i < minLowercaseValue; i++)
{ {
positionsBuilder.Append("l"); positionsBuilder.Append("l");
} }
} }
if(uppercase && minUppercase > 0) if(uppercaseValue && minUppercaseValue > 0)
{ {
for(int i = 0; i < minUppercase; i++) for(int i = 0; i < minUppercaseValue; i++)
{ {
positionsBuilder.Append("u"); positionsBuilder.Append("u");
} }
} }
if(numbers && minNumbers > 0) if(numbersValue && minNumbersValue > 0)
{ {
for(int i = 0; i < minNumbers; i++) for(int i = 0; i < minNumbersValue; i++)
{ {
positionsBuilder.Append("n"); positionsBuilder.Append("n");
} }
} }
if(special && minSpecial > 0) if(specialValue && minSpecialValue > 0)
{ {
for(int i = 0; i < minSpecial; i++) for(int i = 0; i < minSpecialValue; i++)
{ {
positionsBuilder.Append("s"); positionsBuilder.Append("s");
} }
} }
while(positionsBuilder.Length < length) while(positionsBuilder.Length < lengthValue)
{ {
positionsBuilder.Append("a"); positionsBuilder.Append("a");
} }
@ -100,43 +110,43 @@ namespace Bit.App.Services
var allCharSet = string.Empty; var allCharSet = string.Empty;
var lowercaseCharSet = "abcdefghijkmnopqrstuvwxyz"; var lowercaseCharSet = "abcdefghijkmnopqrstuvwxyz";
if(ambiguous) if(ambiguousValue)
{ {
lowercaseCharSet = string.Concat(lowercaseCharSet, "l"); lowercaseCharSet = string.Concat(lowercaseCharSet, "l");
} }
if(lowercase) if(lowercaseValue)
{ {
allCharSet = string.Concat(allCharSet, lowercaseCharSet); allCharSet = string.Concat(allCharSet, lowercaseCharSet);
} }
var uppercaseCharSet = "ABCDEFGHIJKLMNPQRSTUVWXYZ"; var uppercaseCharSet = "ABCDEFGHIJKLMNPQRSTUVWXYZ";
if(ambiguous) if(ambiguousValue)
{ {
uppercaseCharSet = string.Concat(uppercaseCharSet, "O"); uppercaseCharSet = string.Concat(uppercaseCharSet, "O");
} }
if(uppercase) if(uppercaseValue)
{ {
allCharSet = string.Concat(allCharSet, uppercaseCharSet); allCharSet = string.Concat(allCharSet, uppercaseCharSet);
} }
var numberCharSet = "23456789"; var numberCharSet = "23456789";
if(ambiguous) if(ambiguousValue)
{ {
numberCharSet = string.Concat(numberCharSet, "01"); numberCharSet = string.Concat(numberCharSet, "01");
} }
if(numbers) if(numbersValue)
{ {
allCharSet = string.Concat(allCharSet, numberCharSet); allCharSet = string.Concat(allCharSet, numberCharSet);
} }
var specialCharSet = "!@#$%^&*"; var specialCharSet = "!@#$%^&*";
if(special) if(specialValue)
{ {
allCharSet = string.Concat(allCharSet, specialCharSet); allCharSet = string.Concat(allCharSet, specialCharSet);
} }
var password = new StringBuilder(); var password = new StringBuilder();
for(var i = 0; i < length; i++) for(var i = 0; i < lengthValue; i++)
{ {
string positionChars = string.Empty; string positionChars = string.Empty;
switch(positions[i]) switch(positions[i])

View File

@ -20,6 +20,13 @@ namespace Bit.iOS.Core.Utilities
return alert; return alert;
} }
public static UIAlertController CreateMessageAlert(string message)
{
var alert = UIAlertController.Create(null, message, UIAlertControllerStyle.Alert);
alert.View.TintColor = UIColor.Black;
return alert;
}
public static UIAlertController CreateAlert(string title, string message, string accept) public static UIAlertController CreateAlert(string title, string message, string accept)
{ {
var alert = UIAlertController.Create(title, message, UIAlertControllerStyle.Alert); var alert = UIAlertController.Create(title, message, UIAlertControllerStyle.Alert);

View File

@ -6,33 +6,51 @@ namespace Bit.iOS.Core.Views
public class SliderTableViewCell : UITableViewCell public class SliderTableViewCell : UITableViewCell
{ {
private string _detailRightSpace = "\t"; private string _detailRightSpace = "\t";
private int _value;
public SliderTableViewCell(string labelName, float value, float min, float max) public SliderTableViewCell(string labelName, int value, int min, int max)
: base(UITableViewCellStyle.Value1, nameof(SwitchTableViewCell)) : base(UITableViewCellStyle.Value1, nameof(SwitchTableViewCell))
{ {
TextLabel.Text = labelName; TextLabel.Text = labelName;
DetailTextLabel.Text = string.Concat(value.ToString(), _detailRightSpace);
DetailTextLabel.TextColor = new UIColor(red: 0.47f, green: 0.47f, blue: 0.47f, alpha: 1.0f); DetailTextLabel.TextColor = new UIColor(red: 0.47f, green: 0.47f, blue: 0.47f, alpha: 1.0f);
Slider = new UISlider Slider = new UISlider
{ {
MinValue = min, MinValue = min,
MaxValue = max, MaxValue = max,
Value = value,
TintColor = new UIColor(red: 0.24f, green: 0.55f, blue: 0.74f, alpha: 1.0f), TintColor = new UIColor(red: 0.24f, green: 0.55f, blue: 0.74f, alpha: 1.0f),
Frame = new CoreGraphics.CGRect(0, 0, 180, 20) Frame = new CoreGraphics.CGRect(0, 0, 180, 20)
}; };
Slider.ValueChanged += Slider_ValueChanged; Slider.ValueChanged += Slider_ValueChanged;
Value = value;
AccessoryView = Slider; AccessoryView = Slider;
} }
private void Slider_ValueChanged(object sender, EventArgs e) private void Slider_ValueChanged(object sender, EventArgs e)
{ {
Slider.Value = Convert.ToInt32(Math.Round(Slider.Value, 0)); var newValue = Convert.ToInt32(Math.Round(Slider.Value, 0));
DetailTextLabel.Text = string.Concat(Slider.Value.ToString(), _detailRightSpace); bool valueChanged = newValue != Value;
Value = newValue;
if(valueChanged)
{
ValueChanged(this, null);
}
} }
public UISlider Slider { get; set; } public UISlider Slider { get; set; }
public int Value
{
get { return _value; }
set
{
_value = value;
Slider.Value = value;
DetailTextLabel.Text = string.Concat(value.ToString(), _detailRightSpace);
}
}
public event EventHandler ValueChanged;
} }
} }

View File

@ -9,31 +9,43 @@ namespace Bit.iOS.Core.Views
// This is a bit of a hack, but I did not see a way to specify a margin on the // This is a bit of a hack, but I did not see a way to specify a margin on the
// detaul DetailTextLabel or AccessoryView // detaul DetailTextLabel or AccessoryView
private string _detailRightSpace = "\t"; private string _detailRightSpace = "\t";
private int _value;
public StepperTableViewCell(string labelName, double value, double min, double max, double increment) public StepperTableViewCell(string labelName, int value, int min, int max, int increment)
: base(UITableViewCellStyle.Value1, nameof(SwitchTableViewCell)) : base(UITableViewCellStyle.Value1, nameof(SwitchTableViewCell))
{ {
TextLabel.Text = labelName; TextLabel.Text = labelName;
DetailTextLabel.Text = string.Concat(value.ToString(), _detailRightSpace);
DetailTextLabel.TextColor = new UIColor(red: 0.47f, green: 0.47f, blue: 0.47f, alpha: 1.0f); DetailTextLabel.TextColor = new UIColor(red: 0.47f, green: 0.47f, blue: 0.47f, alpha: 1.0f);
Stepper = new UIStepper Stepper = new UIStepper
{ {
TintColor = new UIColor(red: 0.47f, green: 0.47f, blue: 0.47f, alpha: 1.0f), TintColor = new UIColor(red: 0.47f, green: 0.47f, blue: 0.47f, alpha: 1.0f),
Value = value,
MinimumValue = min, MinimumValue = min,
MaximumValue = max MaximumValue = max
}; };
Stepper.ValueChanged += Stepper_ValueChanged; Stepper.ValueChanged += Stepper_ValueChanged;
Value = value;
AccessoryView = Stepper; AccessoryView = Stepper;
} }
private void Stepper_ValueChanged(object sender, EventArgs e) private void Stepper_ValueChanged(object sender, EventArgs e)
{ {
DetailTextLabel.Text = string.Concat(Stepper.Value.ToString(), _detailRightSpace); Value = Convert.ToInt32(Stepper.Value);
ValueChanged(this, null);
} }
public UIStepper Stepper { get; private set; } public UIStepper Stepper { get; private set; }
public int Value
{
get { return _value; }
set
{
_value = value;
Stepper.Value = value;
DetailTextLabel.Text = string.Concat(value.ToString(), _detailRightSpace);
}
}
public event EventHandler ValueChanged;
} }
} }

View File

@ -10,8 +10,16 @@ namespace Bit.iOS.Core.Views
{ {
TextLabel.Text = labelName; TextLabel.Text = labelName;
AccessoryView = Switch; AccessoryView = Switch;
Switch.ValueChanged += Switch_ValueChanged;
}
private void Switch_ValueChanged(object sender, EventArgs e)
{
ValueChanged(this, null);
} }
public UISwitch Switch { get; set; } = new UISwitch(); public UISwitch Switch { get; set; } = new UISwitch();
public event EventHandler ValueChanged;
} }
} }

View File

@ -98,7 +98,6 @@ namespace Bit.iOS.Extension
.RegisterType<ISyncService, SyncService>(new ContainerControlledLifetimeManager()) .RegisterType<ISyncService, SyncService>(new ContainerControlledLifetimeManager())
.RegisterType<IPasswordGenerationService, PasswordGenerationService>(new ContainerControlledLifetimeManager()) .RegisterType<IPasswordGenerationService, PasswordGenerationService>(new ContainerControlledLifetimeManager())
.RegisterType<IAppIdService, AppIdService>(new ContainerControlledLifetimeManager()) .RegisterType<IAppIdService, AppIdService>(new ContainerControlledLifetimeManager())
//.RegisterType<IClipboardService, ClipboardService>(new ContainerControlledLifetimeManager())
// Repositories // Repositories
.RegisterType<IFolderRepository, FolderRepository>(new ContainerControlledLifetimeManager()) .RegisterType<IFolderRepository, FolderRepository>(new ContainerControlledLifetimeManager())
.RegisterType<IFolderApiRepository, FolderApiRepository>(new ContainerControlledLifetimeManager()) .RegisterType<IFolderApiRepository, FolderApiRepository>(new ContainerControlledLifetimeManager())

View File

@ -1,20 +1,15 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using Bit.App.Abstractions; using Bit.App.Abstractions;
using Bit.App.Models;
using Bit.App.Resources;
using Bit.iOS.Core.Views; using Bit.iOS.Core.Views;
using Bit.iOS.Extension.Models; using Bit.iOS.Extension.Models;
using Foundation; using Foundation;
using UIKit; using UIKit;
using XLabs.Ioc; using XLabs.Ioc;
using Bit.App;
using Plugin.Connectivity.Abstractions;
using Bit.iOS.Core.Utilities;
using Plugin.Settings.Abstractions; using Plugin.Settings.Abstractions;
using CoreGraphics; using CoreGraphics;
using Bit.App;
using Bit.iOS.Core.Utilities;
namespace Bit.iOS.Extension namespace Bit.iOS.Extension
{ {
@ -51,7 +46,6 @@ namespace Bit.iOS.Extension
View.BackgroundColor = new UIColor(red: 0.94f, green: 0.94f, blue: 0.96f, alpha: 1.0f); View.BackgroundColor = new UIColor(red: 0.94f, green: 0.94f, blue: 0.96f, alpha: 1.0f);
PasswordLabel.Text = _passwordGenerationService.GeneratePassword();
var descriptor = UIFontDescriptor.PreferredBody; var descriptor = UIFontDescriptor.PreferredBody;
PasswordLabel.Font = UIFont.FromName("Courier", descriptor.PointSize * 1.3f); PasswordLabel.Font = UIFont.FromName("Courier", descriptor.PointSize * 1.3f);
PasswordLabel.LineBreakMode = UILineBreakMode.TailTruncation; PasswordLabel.LineBreakMode = UILineBreakMode.TailTruncation;
@ -73,9 +67,94 @@ namespace Bit.iOS.Extension
OptionsTableViewController.View.BackgroundColor = new UIColor(red: 0.94f, green: 0.94f, blue: 0.96f, alpha: 1.0f); OptionsTableViewController.View.BackgroundColor = new UIColor(red: 0.94f, green: 0.94f, blue: 0.96f, alpha: 1.0f);
} }
UppercaseCell.Switch.On = _settings.GetValueOrDefault(Constants.PasswordGeneratorUppercase, true);
LowercaseCell.Switch.On = _settings.GetValueOrDefault(Constants.PasswordGeneratorLowercase, true);
SpecialCell.Switch.On = _settings.GetValueOrDefault(Constants.PasswordGeneratorSpecial, true);
NumbersCell.Switch.On = _settings.GetValueOrDefault(Constants.PasswordGeneratorNumbers, true);
MinNumbersCell.Value = _settings.GetValueOrDefault(Constants.PasswordGeneratorMinNumbers, 1);
MinSpecialCell.Value = _settings.GetValueOrDefault(Constants.PasswordGeneratorMinSpecial, 1);
LengthCell.Value = _settings.GetValueOrDefault(Constants.PasswordGeneratorLength, 10);
UppercaseCell.ValueChanged += Options_ValueChanged;
LowercaseCell.ValueChanged += Options_ValueChanged;
NumbersCell.ValueChanged += Options_ValueChanged;
SpecialCell.ValueChanged += Options_ValueChanged;
MinNumbersCell.ValueChanged += Options_ValueChanged;
MinSpecialCell.ValueChanged += Options_ValueChanged;
LengthCell.ValueChanged += Options_ValueChanged;
// Adjust based on context password options
if(Context.PasswordOptions != null)
{
if(Context.PasswordOptions.RequireDigits)
{
NumbersCell.Switch.On = true;
NumbersCell.Switch.Enabled = false;
if(MinNumbersCell.Value < 1)
{
MinNumbersCell.Value = 1;
}
MinNumbersCell.Stepper.MinimumValue = 1;
}
if(Context.PasswordOptions.RequireSymbols)
{
SpecialCell.Switch.On = true;
SpecialCell.Switch.Enabled = false;
if(MinSpecialCell.Value < 1)
{
MinSpecialCell.Value = 1;
}
MinSpecialCell.Stepper.MinimumValue = 1;
}
if(Context.PasswordOptions.MinLength < Context.PasswordOptions.MaxLength)
{
if(Context.PasswordOptions.MinLength > 0 && Context.PasswordOptions.MinLength > LengthCell.Slider.MinValue)
{
if(LengthCell.Value < Context.PasswordOptions.MinLength)
{
LengthCell.Slider.Value = Context.PasswordOptions.MinLength;
}
LengthCell.Slider.MinValue = Context.PasswordOptions.MinLength;
}
if(Context.PasswordOptions.MaxLength > 5 && Context.PasswordOptions.MaxLength < LengthCell.Slider.MaxValue)
{
if(LengthCell.Value > Context.PasswordOptions.MaxLength)
{
LengthCell.Slider.Value = Context.PasswordOptions.MaxLength;
}
LengthCell.Slider.MaxValue = Context.PasswordOptions.MaxLength;
}
}
}
GeneratePassword();
base.ViewDidLoad(); base.ViewDidLoad();
} }
private void Options_ValueChanged(object sender, EventArgs e)
{
if(InvalidState())
{
LowercaseCell.Switch.On = true;
}
GeneratePassword();
}
private bool InvalidState()
{
return !LowercaseCell.Switch.On && !UppercaseCell.Switch.On && !NumbersCell.Switch.On && !SpecialCell.Switch.On;
}
partial void SelectBarButton_Activated(UIBarButtonItem sender) partial void SelectBarButton_Activated(UIBarButtonItem sender)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
@ -86,6 +165,18 @@ namespace Bit.iOS.Extension
throw new NotImplementedException(); throw new NotImplementedException();
} }
private void GeneratePassword()
{
PasswordLabel.Text = _passwordGenerationService.GeneratePassword(
length: LengthCell.Value,
uppercase: UppercaseCell.Switch.On,
lowercase: LowercaseCell.Switch.On,
numbers: NumbersCell.Switch.On,
special: SpecialCell.Switch.On,
minSpecial: MinSpecialCell.Value,
minNumbers: MinNumbersCell.Value);
}
public class TableSource : UITableViewSource public class TableSource : UITableViewSource
{ {
private PasswordGeneratorViewController _controller; private PasswordGeneratorViewController _controller;
@ -197,23 +288,47 @@ namespace Bit.iOS.Extension
return null; return null;
} }
public override string TitleForFooter(UITableView tableView, nint section)
{
if(section == 1)
{
return "Option defaults are set from the main bitwarden app's password generator tool.";
}
return null;
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath) public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{ {
if(indexPath.Section == 0) if(indexPath.Section == 0)
{ {
if(indexPath.Row == 0) if(indexPath.Row == 0)
{ {
_controller.PasswordLabel.Text = _controller._passwordGenerationService.GeneratePassword(); _controller.GeneratePassword();
} }
else if(indexPath.Row == 1) else if(indexPath.Row == 1)
{ {
// TODO: copy to clipboard UIPasteboard clipboard = UIPasteboard.General;
clipboard.String = _controller.PasswordLabel.Text;
var alert = Dialogs.CreateMessageAlert("Copied!");
_controller.PresentViewController(alert, true, () =>
{
_controller.DismissViewController(true, null);
});
} }
} }
tableView.DeselectRow(indexPath, true); tableView.DeselectRow(indexPath, true);
tableView.EndEditing(true); tableView.EndEditing(true);
} }
public NSDate DateTimeToNSDate(DateTime date)
{
DateTime reference = TimeZone.CurrentTimeZone.ToLocalTime(
new DateTime(2001, 1, 1, 0, 0, 0));
return NSDate.FromTimeIntervalSinceReferenceDate(
(date - reference).TotalSeconds);
}
} }
} }
} }