diff --git a/src/App/Pages/Generator/GeneratorPage.xaml b/src/App/Pages/Generator/GeneratorPage.xaml
index 3bf1489cd..2989518d0 100644
--- a/src/App/Pages/Generator/GeneratorPage.xaml
+++ b/src/App/Pages/Generator/GeneratorPage.xaml
@@ -1,9 +1,10 @@
-
@@ -11,27 +12,45 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/src/App/Pages/Generator/GeneratorPage.xaml.cs b/src/App/Pages/Generator/GeneratorPage.xaml.cs
index aa7b6b49e..90d0219d4 100644
--- a/src/App/Pages/Generator/GeneratorPage.xaml.cs
+++ b/src/App/Pages/Generator/GeneratorPage.xaml.cs
@@ -1,18 +1,42 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Xamarin.Forms;
-using Xamarin.Forms.Xaml;
namespace Bit.App.Pages
{
- public partial class GeneratorPage : ContentPage
+ public partial class GeneratorPage : BaseContentPage
{
+ private GeneratorPageViewModel _vm;
+
public GeneratorPage()
{
InitializeComponent();
+ _vm = BindingContext as GeneratorPageViewModel;
+ _vm.Page = this;
+ }
+
+ protected async override void OnAppearing()
+ {
+ base.OnAppearing();
+ await _vm.InitAsync();
+ }
+
+ private async void Regenerate_Clicked(object sender, EventArgs e)
+ {
+ await _vm.RegenerateAsync();
+ }
+
+ private async void Copy_Clicked(object sender, EventArgs e)
+ {
+ await _vm.CopyAsync();
+ }
+
+ private void Select_Clicked(object sender, EventArgs e)
+ {
+
+ }
+
+ private void History_Clicked(object sender, EventArgs e)
+ {
+
}
}
}
diff --git a/src/App/Pages/Generator/GeneratorPageViewModel.cs b/src/App/Pages/Generator/GeneratorPageViewModel.cs
index 1d0a9b749..2504a8b89 100644
--- a/src/App/Pages/Generator/GeneratorPageViewModel.cs
+++ b/src/App/Pages/Generator/GeneratorPageViewModel.cs
@@ -1,14 +1,100 @@
-using System;
+using Bit.App.Resources;
+using Bit.Core.Abstractions;
+using Bit.Core.Models.Domain;
+using Bit.Core.Utilities;
+using System;
using System.Collections.Generic;
using System.Text;
+using System.Threading.Tasks;
namespace Bit.App.Pages
{
public class GeneratorPageViewModel : BaseViewModel
{
+ private readonly IPasswordGenerationService _passwordGenerationService;
+ private readonly IPlatformUtilsService _platformUtilsService;
+
+ private PasswordGenerationOptions _options;
+ private string _password;
+ private bool _isPassword;
+ private int _typeSelectedIndex;
+
public GeneratorPageViewModel()
{
- PageTitle = "Password Generator";
+ _passwordGenerationService = ServiceContainer.Resolve(
+ "passwordGenerationService");
+ _platformUtilsService = ServiceContainer.Resolve("platformUtilsService");
+ PageTitle = AppResources.PasswordGenerator;
+ TypeOptions = new List { AppResources.Password, AppResources.Passphrase };
+ }
+
+ public List TypeOptions { get; set; }
+
+ public string Password
+ {
+ get => _password;
+ set => SetProperty(ref _password, value);
+ }
+
+ public bool IsPassword
+ {
+ get => _isPassword;
+ set => SetProperty(ref _isPassword, value);
+ }
+
+ public PasswordGenerationOptions Options
+ {
+ get => _options;
+ set => SetProperty(ref _options, value);
+ }
+
+ public int TypeSelectedIndex
+ {
+ get => _typeSelectedIndex;
+ set
+ {
+ if(SetProperty(ref _typeSelectedIndex, value))
+ {
+ TypeChanged();
+ }
+ }
+ }
+
+ public async Task InitAsync()
+ {
+ Options = await _passwordGenerationService.GetOptionsAsync();
+ TypeSelectedIndex = Options.Type == "passphrase" ? 1 : 0;
+ Password = await _passwordGenerationService.GeneratePasswordAsync(Options);
+ await _passwordGenerationService.AddHistoryAsync(Password);
+ }
+
+ public async Task RegenerateAsync()
+ {
+ Password = await _passwordGenerationService.GeneratePasswordAsync(Options);
+ await _passwordGenerationService.AddHistoryAsync(Password);
+ }
+
+ public async Task SaveOptionsAsync(bool regenerate = true)
+ {
+ _passwordGenerationService.NormalizeOptions(Options);
+ await _passwordGenerationService.SaveOptionsAsync(Options);
+ if(regenerate)
+ {
+ await RegenerateAsync();
+ }
+ }
+
+ public async Task CopyAsync()
+ {
+ await _platformUtilsService.CopyToClipboardAsync(Password);
+ _platformUtilsService.ShowToast("success", null, AppResources.CopiedPassword);
+ }
+
+ public async void TypeChanged()
+ {
+ IsPassword = TypeSelectedIndex == 0;
+ Options.Type = IsPassword ? "password" : "passphrase";
+ await SaveOptionsAsync();
}
}
}
diff --git a/src/App/Resources/AppResources.Designer.cs b/src/App/Resources/AppResources.Designer.cs
index 557aa2d1f..42400d59c 100644
--- a/src/App/Resources/AppResources.Designer.cs
+++ b/src/App/Resources/AppResources.Designer.cs
@@ -2589,6 +2589,15 @@ namespace Bit.App.Resources {
}
}
+ ///
+ /// Looks up a localized string similar to Number of Words.
+ ///
+ public static string NumberOfWords {
+ get {
+ return ResourceManager.GetString("NumberOfWords", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to October.
///
@@ -2661,6 +2670,15 @@ namespace Bit.App.Resources {
}
}
+ ///
+ /// Looks up a localized string similar to Passphrase.
+ ///
+ public static string Passphrase {
+ get {
+ return ResourceManager.GetString("Passphrase", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Passport Number.
///
@@ -3741,6 +3759,15 @@ namespace Bit.App.Resources {
}
}
+ ///
+ /// Looks up a localized string similar to Word Separator.
+ ///
+ public static string WordSeparator {
+ get {
+ return ResourceManager.GetString("WordSeparator", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Yes.
///
diff --git a/src/App/Resources/AppResources.resx b/src/App/Resources/AppResources.resx
index 5fbbaba47..500d50953 100644
--- a/src/App/Resources/AppResources.resx
+++ b/src/App/Resources/AppResources.resx
@@ -1447,4 +1447,13 @@
Choose an organization that you wish to share this item with. Sharing transfers ownership of the item to the organization. You will no longer be the direct owner of this item once it has been shared.
+
+ Number of Words
+
+
+ Passphrase
+
+
+ Word Separator
+
\ No newline at end of file
diff --git a/src/App/Styles/Base.xaml b/src/App/Styles/Base.xaml
index 8313e8ef3..970c84a1a 100644
--- a/src/App/Styles/Base.xaml
+++ b/src/App/Styles/Base.xaml
@@ -40,7 +40,8 @@
Value="Small" />
diff --git a/src/Core/Abstractions/ICryptoFunctionService.cs b/src/Core/Abstractions/ICryptoFunctionService.cs
index f0d7cf0ab..cb1e5a2a7 100644
--- a/src/Core/Abstractions/ICryptoFunctionService.cs
+++ b/src/Core/Abstractions/ICryptoFunctionService.cs
@@ -21,6 +21,8 @@ namespace Bit.Core.Abstractions
Task RsaExtractPublicKeyAsync(byte[] privateKey);
Task> RsaGenerateKeyPairAsync(int length);
Task RandomBytesAsync(int length);
+ byte[] RandomBytes(int length);
Task RandomNumberAsync();
+ uint RandomNumber();
}
}
diff --git a/src/Core/Abstractions/IPasswordGenerationService.cs b/src/Core/Abstractions/IPasswordGenerationService.cs
index 35cfa99c1..d4e37d603 100644
--- a/src/Core/Abstractions/IPasswordGenerationService.cs
+++ b/src/Core/Abstractions/IPasswordGenerationService.cs
@@ -14,5 +14,6 @@ namespace Bit.Core.Abstractions
Task GetOptionsAsync();
Task