diff --git a/src/App/Controls/FormEntryCell.cs b/src/App/Controls/FormEntryCell.cs index 879124e3a..7dbe76498 100644 --- a/src/App/Controls/FormEntryCell.cs +++ b/src/App/Controls/FormEntryCell.cs @@ -138,6 +138,14 @@ namespace Bit.App.Controls public Label Label { get; private set; } public ExtendedEntry Entry { get; private set; } public ExtendedButton Button { get; private set; } + public VisualElement NextElement + { + get => _nextElement; + set + { + _nextElement = value; + } + } public void InitEvents() { @@ -150,7 +158,7 @@ namespace Bit.App.Controls { _tgr.Tapped += Tgr_Tapped; } - + Tapped += FormEntryCell_Tapped; } diff --git a/src/App/Models/Card.cs b/src/App/Models/Card.cs index e71d89b1f..b6767d485 100644 --- a/src/App/Models/Card.cs +++ b/src/App/Models/Card.cs @@ -6,6 +6,8 @@ namespace Bit.App.Models { public class Card { + public Card() { } + public Card(CipherData data) { var deserializedData = JsonConvert.DeserializeObject(data.Data); diff --git a/src/App/Models/Identity.cs b/src/App/Models/Identity.cs index a5f5319af..7be189538 100644 --- a/src/App/Models/Identity.cs +++ b/src/App/Models/Identity.cs @@ -6,6 +6,8 @@ namespace Bit.App.Models { public class Identity { + public Identity() { } + public Identity(CipherData data) { var deserializedData = JsonConvert.DeserializeObject(data.Data); diff --git a/src/App/Models/SecureNote.cs b/src/App/Models/SecureNote.cs index d0c87882e..5c207f593 100644 --- a/src/App/Models/SecureNote.cs +++ b/src/App/Models/SecureNote.cs @@ -5,6 +5,8 @@ namespace Bit.App.Models { public class SecureNote { + public SecureNote() { } + public SecureNote(CipherData data) { Type = data.SecureNoteType.Value; diff --git a/src/App/Pages/Vault/VaultAddLoginPage.cs b/src/App/Pages/Vault/VaultAddLoginPage.cs index d048b72aa..808c849b2 100644 --- a/src/App/Pages/Vault/VaultAddLoginPage.cs +++ b/src/App/Pages/Vault/VaultAddLoginPage.cs @@ -11,6 +11,7 @@ using Xamarin.Forms; using XLabs.Ioc; using Plugin.Settings.Abstractions; using Bit.App.Utilities; +using Bit.App.Enums; namespace Bit.App.Pages { @@ -18,6 +19,7 @@ namespace Bit.App.Pages { private const string AddedLoginAlertKey = "addedSiteAlert"; + private readonly CipherType _type; private readonly ICipherService _cipherService; private readonly IFolderService _folderService; private readonly IUserDialogs _userDialogs; @@ -31,8 +33,10 @@ namespace Bit.App.Pages private readonly bool _fromAutofill; private DateTime? _lastAction; - public VaultAddLoginPage(string defaultUri = null, string defaultName = null, bool fromAutofill = false) + public VaultAddLoginPage(CipherType type, string defaultUri = null, + string defaultName = null, bool fromAutofill = false) { + _type = type; _defaultUri = defaultUri; _defaultName = defaultName; _fromAutofill = fromAutofill; @@ -49,113 +53,450 @@ namespace Bit.App.Pages Init(); } - public FormEntryCell PasswordCell { get; private set; } - public FormEntryCell UsernameCell { get; private set; } - public FormEntryCell UriCell { get; private set; } + public List Folders { get; set; } + public TableRoot TableRoot { get; set; } + public TableSection TopSection { get; set; } + public TableSection MiddleSection { get; set; } + public ExtendedTableView Table { get; set; } + public FormEntryCell NameCell { get; private set; } - public FormEntryCell TotpCell { get; private set; } public FormEditorCell NotesCell { get; private set; } public FormPickerCell FolderCell { get; private set; } public ExtendedTextCell GenerateCell { get; private set; } + public ExtendedSwitchCell FavoriteCell { get; set; } + + // Login + public FormEntryCell LoginPasswordCell { get; private set; } + public FormEntryCell LoginUsernameCell { get; private set; } + public FormEntryCell LoginUriCell { get; private set; } + public FormEntryCell LoginTotpCell { get; private set; } + + // Card + public FormEntryCell CardNameCell { get; private set; } + public FormEntryCell CardNumberCell { get; private set; } + public FormPickerCell CardBrandCell { get; private set; } + public FormPickerCell CardExpMonthCell { get; private set; } + public FormEntryCell CardExpYearCell { get; private set; } + public FormEntryCell CardCodeCell { get; private set; } + + // Identity + public FormPickerCell IdTitleCell { get; private set; } + public FormEntryCell IdFirstNameCell { get; private set; } + public FormEntryCell IdMiddleNameCell { get; private set; } + public FormEntryCell IdLastNameCell { get; private set; } + public FormEntryCell IdUsernameCell { get; private set; } + public FormEntryCell IdCompanyCell { get; private set; } + public FormEntryCell IdSsnCell { get; private set; } + public FormEntryCell IdPassportNumberCell { get; private set; } + public FormEntryCell IdLicenseNumberCell { get; private set; } + public FormEntryCell IdEmailCell { get; private set; } + public FormEntryCell IdPhoneCell { get; private set; } + public FormEntryCell IdAddress1Cell { get; private set; } + public FormEntryCell IdAddress2Cell { get; private set; } + public FormEntryCell IdAddress3Cell { get; private set; } + public FormEntryCell IdCityCell { get; private set; } + public FormEntryCell IdStateCell { get; private set; } + public FormEntryCell IdPostalCodeCell { get; private set; } + public FormEntryCell IdCountryCell { get; private set; } private void Init() { - NotesCell = new FormEditorCell(height: 180); - NotesCell.Editor.Keyboard = Keyboard.Text; - - TotpCell = new FormEntryCell(AppResources.AuthenticatorKey, nextElement: NotesCell.Editor, - useButton: _deviceInfo.HasCamera); - if(_deviceInfo.HasCamera) - { - TotpCell.Button.Image = "camera"; - } - TotpCell.Entry.DisableAutocapitalize = true; - TotpCell.Entry.Autocorrect = false; - TotpCell.Entry.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier"); - - PasswordCell = new FormEntryCell(AppResources.Password, isPassword: true, nextElement: TotpCell.Entry, - useButton: true); - PasswordCell.Button.Image = "eye"; - PasswordCell.Entry.DisableAutocapitalize = true; - PasswordCell.Entry.Autocorrect = false; - PasswordCell.Entry.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier"); - - UsernameCell = new FormEntryCell(AppResources.Username, nextElement: PasswordCell.Entry); - UsernameCell.Entry.DisableAutocapitalize = true; - UsernameCell.Entry.Autocorrect = false; - - UriCell = new FormEntryCell(AppResources.URI, Keyboard.Url, nextElement: UsernameCell.Entry); - if(!string.IsNullOrWhiteSpace(_defaultUri)) - { - UriCell.Entry.Text = _defaultUri; - } - - NameCell = new FormEntryCell(AppResources.Name, nextElement: UriCell.Entry); + // Name + NameCell = new FormEntryCell(AppResources.Name); if(!string.IsNullOrWhiteSpace(_defaultName)) { NameCell.Entry.Text = _defaultName; } + // Notes + NotesCell = new FormEditorCell(height: 180); + NotesCell.Editor.Keyboard = Keyboard.Text; + + // Folders var folderOptions = new List { AppResources.FolderNone }; - var folders = _folderService.GetAllAsync().GetAwaiter().GetResult() + Folders = _folderService.GetAllAsync().GetAwaiter().GetResult() .OrderBy(f => f.Name?.Decrypt()).ToList(); - foreach(var folder in folders) + foreach(var folder in Folders) { folderOptions.Add(folder.Name.Decrypt()); } FolderCell = new FormPickerCell(AppResources.Folder, folderOptions.ToArray()); - GenerateCell = new ExtendedTextCell + // Favorite + FavoriteCell = new ExtendedSwitchCell { Text = AppResources.Favorite }; + + InitTable(); + InitSave(); + + Title = AppResources.AddItem; + Content = Table; + if(Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.Windows) { - Text = AppResources.GeneratePassword, - ShowDisclousure = true + ToolbarItems.Add(new DismissModalToolBarItem(this, AppResources.Cancel)); + } + } + + protected override void OnAppearing() + { + base.OnAppearing(); + if(!_connectivity.IsConnected) + { + AlertNoConnection(); + } + + NameCell.InitEvents(); + NotesCell.InitEvents(); + FolderCell.InitEvents(); + + switch(_type) + { + case CipherType.Login: + LoginPasswordCell.InitEvents(); + LoginUsernameCell.InitEvents(); + LoginUriCell.InitEvents(); + LoginTotpCell.InitEvents(); + LoginPasswordCell.Button.Clicked += PasswordButton_Clicked; + GenerateCell.Tapped += GenerateCell_Tapped; + if(LoginTotpCell?.Button != null) + { + LoginTotpCell.Button.Clicked += TotpButton_Clicked; + } + break; + case CipherType.Card: + CardBrandCell.InitEvents(); + CardCodeCell.InitEvents(); + CardExpMonthCell.InitEvents(); + CardExpYearCell.InitEvents(); + CardNameCell.InitEvents(); + CardNumberCell.InitEvents(); + break; + case CipherType.Identity: + IdTitleCell.InitEvents(); + IdFirstNameCell.InitEvents(); + IdMiddleNameCell.InitEvents(); + IdLastNameCell.InitEvents(); + IdUsernameCell.InitEvents(); + IdCompanyCell.InitEvents(); + IdSsnCell.InitEvents(); + IdPassportNumberCell.InitEvents(); + IdLicenseNumberCell.InitEvents(); + IdEmailCell.InitEvents(); + IdPhoneCell.InitEvents(); + IdAddress1Cell.InitEvents(); + IdAddress2Cell.InitEvents(); + IdAddress3Cell.InitEvents(); + IdCityCell.InitEvents(); + IdStateCell.InitEvents(); + IdPostalCodeCell.InitEvents(); + IdCountryCell.InitEvents(); + break; + default: + break; + } + + if(_type == CipherType.Login && !_fromAutofill && !_settings.GetValueOrDefault(AddedLoginAlertKey, false)) + { + _settings.AddOrUpdateValue(AddedLoginAlertKey, true); + if(Device.RuntimePlatform == Device.iOS) + { + DisplayAlert(AppResources.BitwardenAppExtension, AppResources.BitwardenAppExtensionAlert, + AppResources.Ok); + } + else if(Device.RuntimePlatform == Device.Android && !_appInfoService.AutofillServiceEnabled) + { + DisplayAlert(AppResources.BitwardenAutofillService, AppResources.BitwardenAutofillServiceAlert, + AppResources.Ok); + } + } + + NameCell?.Entry.FocusWithDelay(); + } + + protected override void OnDisappearing() + { + base.OnDisappearing(); + + NameCell.Dispose(); + NotesCell.Dispose(); + FolderCell.Dispose(); + + switch(_type) + { + case CipherType.Login: + LoginTotpCell.Dispose(); + LoginPasswordCell.Dispose(); + LoginUsernameCell.Dispose(); + LoginUriCell.Dispose(); + LoginPasswordCell.Button.Clicked -= PasswordButton_Clicked; + GenerateCell.Tapped -= GenerateCell_Tapped; + if(LoginTotpCell?.Button != null) + { + LoginTotpCell.Button.Clicked -= TotpButton_Clicked; + } + break; + case CipherType.Card: + CardBrandCell.Dispose(); + CardCodeCell.Dispose(); + CardExpMonthCell.Dispose(); + CardExpYearCell.Dispose(); + CardNameCell.Dispose(); + CardNumberCell.Dispose(); + break; + case CipherType.Identity: + IdTitleCell.Dispose(); + IdFirstNameCell.Dispose(); + IdMiddleNameCell.Dispose(); + IdLastNameCell.Dispose(); + IdUsernameCell.Dispose(); + IdCompanyCell.Dispose(); + IdSsnCell.Dispose(); + IdPassportNumberCell.Dispose(); + IdLicenseNumberCell.Dispose(); + IdEmailCell.Dispose(); + IdPhoneCell.Dispose(); + IdAddress1Cell.Dispose(); + IdAddress2Cell.Dispose(); + IdAddress3Cell.Dispose(); + IdCityCell.Dispose(); + IdStateCell.Dispose(); + IdPostalCodeCell.Dispose(); + IdCountryCell.Dispose(); + break; + default: + break; + } + } + + private void PasswordButton_Clicked(object sender, EventArgs e) + { + LoginPasswordCell.Entry.InvokeToggleIsPassword(); + LoginPasswordCell.Button.Image = "eye" + (!LoginPasswordCell.Entry.IsPasswordFromToggled ? "_slash" : string.Empty); + } + + private async void TotpButton_Clicked(object sender, EventArgs e) + { + var scanPage = new ScanPage((key) => + { + Device.BeginInvokeOnMainThread(async () => + { + await Navigation.PopModalAsync(); + if(!string.IsNullOrWhiteSpace(key)) + { + LoginTotpCell.Entry.Text = key; + _userDialogs.Toast(AppResources.AuthenticatorKeyAdded); + } + else + { + _userDialogs.Alert(AppResources.AuthenticatorKeyReadError); + } + }); + }); + + await Navigation.PushModalAsync(new ExtendedNavigationPage(scanPage)); + } + + private async void GenerateCell_Tapped(object sender, EventArgs e) + { + var page = new ToolsPasswordGeneratorPage((password) => + { + LoginPasswordCell.Entry.Text = password; + _userDialogs.Toast(AppResources.PasswordGenerated); + }, _fromAutofill); + await Navigation.PushForDeviceAsync(page); + } + + private void AlertNoConnection() + { + DisplayAlert(AppResources.InternetConnectionRequiredTitle, AppResources.InternetConnectionRequiredMessage, + AppResources.Ok); + } + + private void InitTable() + { + // Sections + TopSection = new TableSection(AppResources.ItemInformation) + { + NameCell }; - var favoriteCell = new ExtendedSwitchCell { Text = AppResources.Favorite }; + MiddleSection = new TableSection(" ") + { + FolderCell, + FavoriteCell + }; - var table = new ExtendedTableView + if(_type == CipherType.Login) + { + LoginTotpCell = new FormEntryCell(AppResources.AuthenticatorKey, nextElement: NotesCell.Editor, + useButton: _deviceInfo.HasCamera); + if(_deviceInfo.HasCamera) + { + LoginTotpCell.Button.Image = "camera"; + } + LoginTotpCell.Entry.DisableAutocapitalize = true; + LoginTotpCell.Entry.Autocorrect = false; + LoginTotpCell.Entry.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier"); + + LoginPasswordCell = new FormEntryCell(AppResources.Password, isPassword: true, nextElement: LoginTotpCell.Entry, + useButton: true); + LoginPasswordCell.Button.Image = "eye"; + LoginPasswordCell.Entry.DisableAutocapitalize = true; + LoginPasswordCell.Entry.Autocorrect = false; + LoginPasswordCell.Entry.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier"); + + GenerateCell = new ExtendedTextCell + { + Text = AppResources.GeneratePassword, + ShowDisclousure = true + }; + + LoginUsernameCell = new FormEntryCell(AppResources.Username, nextElement: LoginPasswordCell.Entry); + LoginUsernameCell.Entry.DisableAutocapitalize = true; + LoginUsernameCell.Entry.Autocorrect = false; + + LoginUriCell = new FormEntryCell(AppResources.URI, Keyboard.Url, nextElement: LoginUsernameCell.Entry); + if(!string.IsNullOrWhiteSpace(_defaultUri)) + { + LoginUriCell.Entry.Text = _defaultUri; + } + + NameCell.NextElement = LoginUriCell.Entry; + + // Build sections + TopSection.Add(LoginUriCell); + TopSection.Add(LoginUsernameCell); + TopSection.Add(LoginPasswordCell); + TopSection.Add(GenerateCell); + MiddleSection.Insert(0, LoginTotpCell); + } + else if(_type == CipherType.Card) + { + CardCodeCell = new FormEntryCell(AppResources.SecurityCode, Keyboard.Numeric, + nextElement: NotesCell.Editor); + CardExpYearCell = new FormEntryCell(AppResources.ExpirationYear, Keyboard.Numeric, + nextElement: CardCodeCell.Entry); + CardExpMonthCell = new FormPickerCell(AppResources.ExpirationMonth, new string[] { + "--", AppResources.January, AppResources.February, AppResources.March, AppResources.April, + AppResources.May, AppResources.June, AppResources.July, AppResources.August, AppResources.September, + AppResources.October, AppResources.November, AppResources.December + }); + CardBrandCell = new FormPickerCell(AppResources.Brand, new string[] { + "--", "Visa", "Mastercard", "American Express", "Discover", "Diners Club", + "JCB", "Maestro", "UnionPay", AppResources.Other + }); + CardNumberCell = new FormEntryCell(AppResources.Number, Keyboard.Numeric); + CardNameCell = new FormEntryCell(AppResources.CardholderName, nextElement: CardNumberCell.Entry); + NameCell.NextElement = CardNameCell.Entry; + + // Build sections + TopSection.Add(CardNameCell); + TopSection.Add(CardNumberCell); + TopSection.Add(CardBrandCell); + TopSection.Add(CardExpMonthCell); + TopSection.Add(CardExpYearCell); + TopSection.Add(CardCodeCell); + } + else if(_type == CipherType.Identity) + { + IdCountryCell = new FormEntryCell(AppResources.Country, nextElement: NotesCell.Editor); + IdPostalCodeCell = new FormEntryCell(AppResources.ZipPostalCode, nextElement: IdCountryCell.Entry); + IdPostalCodeCell.Entry.DisableAutocapitalize = true; + IdPostalCodeCell.Entry.Autocorrect = false; + IdStateCell = new FormEntryCell(AppResources.StateProvince, nextElement: IdPostalCodeCell.Entry); + IdCityCell = new FormEntryCell(AppResources.CityTown, nextElement: IdStateCell.Entry); + IdAddress3Cell = new FormEntryCell(AppResources.Address3, nextElement: IdCityCell.Entry); + IdAddress2Cell = new FormEntryCell(AppResources.Address2, nextElement: IdAddress3Cell.Entry); + IdAddress1Cell = new FormEntryCell(AppResources.Address1, nextElement: IdAddress2Cell.Entry); + IdPhoneCell = new FormEntryCell(AppResources.Phone, nextElement: IdAddress1Cell.Entry); + IdPhoneCell.Entry.DisableAutocapitalize = true; + IdPhoneCell.Entry.Autocorrect = false; + IdEmailCell = new FormEntryCell(AppResources.Email, Keyboard.Email, nextElement: IdPhoneCell.Entry); + IdEmailCell.Entry.DisableAutocapitalize = true; + IdEmailCell.Entry.Autocorrect = false; + IdLicenseNumberCell = new FormEntryCell(AppResources.LicenseNumber, nextElement: IdEmailCell.Entry); + IdLicenseNumberCell.Entry.DisableAutocapitalize = true; + IdLicenseNumberCell.Entry.Autocorrect = false; + IdPassportNumberCell = new FormEntryCell(AppResources.PassportNumber, nextElement: IdLicenseNumberCell.Entry); + IdPassportNumberCell.Entry.DisableAutocapitalize = true; + IdPassportNumberCell.Entry.Autocorrect = false; + IdSsnCell = new FormEntryCell(AppResources.SSN, nextElement: IdPassportNumberCell.Entry); + IdSsnCell.Entry.DisableAutocapitalize = true; + IdSsnCell.Entry.Autocorrect = false; + IdCompanyCell = new FormEntryCell(AppResources.Company, nextElement: IdSsnCell.Entry); + IdUsernameCell = new FormEntryCell(AppResources.Username, nextElement: IdCompanyCell.Entry); + IdUsernameCell.Entry.DisableAutocapitalize = true; + IdUsernameCell.Entry.Autocorrect = false; + IdLastNameCell = new FormEntryCell(AppResources.LastName, nextElement: IdUsernameCell.Entry); + IdMiddleNameCell = new FormEntryCell(AppResources.MiddleName, nextElement: IdLastNameCell.Entry); + IdFirstNameCell = new FormEntryCell(AppResources.FirstName, nextElement: IdMiddleNameCell.Entry); + IdTitleCell = new FormPickerCell(AppResources.Title, new string[] { + "--", AppResources.Mr, AppResources.Mrs, AppResources.Ms, AppResources.Dr + }); + + // Name + NameCell.NextElement = IdFirstNameCell.Entry; + + // Build sections + TopSection.Add(IdTitleCell); + TopSection.Add(IdFirstNameCell); + TopSection.Add(IdMiddleNameCell); + TopSection.Add(IdLastNameCell); + TopSection.Add(IdUsernameCell); + TopSection.Add(IdCompanyCell); + TopSection.Add(IdSsnCell); + TopSection.Add(IdPassportNumberCell); + TopSection.Add(IdLicenseNumberCell); + TopSection.Add(IdEmailCell); + TopSection.Add(IdPhoneCell); + TopSection.Add(IdAddress1Cell); + TopSection.Add(IdAddress2Cell); + TopSection.Add(IdAddress3Cell); + TopSection.Add(IdCityCell); + TopSection.Add(IdStateCell); + TopSection.Add(IdPostalCodeCell); + TopSection.Add(IdCountryCell); + } + + // Make table + TableRoot = new TableRoot + { + TopSection, + MiddleSection, + new TableSection(AppResources.Notes) + { + NotesCell + } + }; + + Table = new ExtendedTableView { Intent = TableIntent.Settings, EnableScrolling = true, HasUnevenRows = true, - Root = new TableRoot - { - new TableSection(AppResources.ItemInformation) - { - NameCell, - UriCell, - UsernameCell, - PasswordCell, - GenerateCell - }, - new TableSection(" ") - { - TotpCell, - FolderCell, - favoriteCell - }, - new TableSection(AppResources.Notes) - { - NotesCell - } - } + Root = TableRoot }; if(Device.RuntimePlatform == Device.iOS) { - table.RowHeight = -1; - table.EstimatedRowHeight = 70; + Table.RowHeight = -1; + Table.EstimatedRowHeight = 70; } else if(Device.RuntimePlatform == Device.Android) { - PasswordCell.Button.WidthRequest = 40; - - if(TotpCell.Button != null) + if(LoginPasswordCell?.Button != null) { - TotpCell.Button.WidthRequest = 40; + LoginPasswordCell.Button.WidthRequest = 40; + } + + if(LoginTotpCell?.Button != null) + { + LoginTotpCell.Button.WidthRequest = 40; } } + } + private void InitSave() + { var saveToolBarItem = new ToolbarItem(AppResources.Save, null, async () => { if(_lastAction.LastActionWasRecent()) @@ -181,23 +522,151 @@ namespace Bit.App.Pages { Name = NameCell.Entry.Text.Encrypt(), Notes = string.IsNullOrWhiteSpace(NotesCell.Editor.Text) ? null : NotesCell.Editor.Text.Encrypt(), - Favorite = favoriteCell.On, - Login = new Login - { - Uri = string.IsNullOrWhiteSpace(UriCell.Entry.Text) ? null : - UriCell.Entry.Text.Encrypt(), - Username = string.IsNullOrWhiteSpace(UsernameCell.Entry.Text) ? null : - UsernameCell.Entry.Text.Encrypt(), - Password = string.IsNullOrWhiteSpace(PasswordCell.Entry.Text) ? null : - PasswordCell.Entry.Text.Encrypt(), - Totp = string.IsNullOrWhiteSpace(TotpCell.Entry.Text) ? null : - TotpCell.Entry.Text.Encrypt(), - } + Favorite = FavoriteCell.On, + Type = _type }; + switch(_type) + { + case CipherType.Login: + cipher.Login = new Login + { + Uri = string.IsNullOrWhiteSpace(LoginUriCell.Entry.Text) ? null : + LoginUriCell.Entry.Text.Encrypt(), + Username = string.IsNullOrWhiteSpace(LoginUsernameCell.Entry.Text) ? null : + LoginUsernameCell.Entry.Text.Encrypt(), + Password = string.IsNullOrWhiteSpace(LoginPasswordCell.Entry.Text) ? null : + LoginPasswordCell.Entry.Text.Encrypt(), + Totp = string.IsNullOrWhiteSpace(LoginTotpCell.Entry.Text) ? null : + LoginTotpCell.Entry.Text.Encrypt(), + }; + break; + case CipherType.SecureNote: + cipher.SecureNote = new SecureNote + { + Type = SecureNoteType.Generic + }; + break; + case CipherType.Card: + string brand; + switch(CardBrandCell.Picker.SelectedIndex) + { + case 1: + brand = "Visa"; + break; + case 2: + brand = "Mastercard"; + break; + case 3: + brand = "Amex"; + break; + case 4: + brand = "Discover"; + break; + case 5: + brand = "Diners Club"; + break; + case 6: + brand = "JCB"; + break; + case 7: + brand = "Maestro"; + break; + case 8: + brand = "UnionPay"; + break; + case 9: + brand = "Other"; + break; + default: + brand = null; + break; + } + + var expMonth = CardExpMonthCell.Picker.SelectedIndex > 0 ? + CardExpMonthCell.Picker.SelectedIndex.ToString() : null; + + cipher.Card = new Card + { + CardholderName = string.IsNullOrWhiteSpace(CardNameCell.Entry.Text) ? null : + CardNameCell.Entry.Text.Encrypt(), + Number = string.IsNullOrWhiteSpace(CardNumberCell.Entry.Text) ? null : + CardNumberCell.Entry.Text.Encrypt(), + ExpYear = string.IsNullOrWhiteSpace(CardExpYearCell.Entry.Text) ? null : + CardExpYearCell.Entry.Text.Encrypt(), + Code = string.IsNullOrWhiteSpace(CardCodeCell.Entry.Text) ? null : + CardCodeCell.Entry.Text.Encrypt(), + Brand = string.IsNullOrWhiteSpace(brand) ? null : brand.Encrypt(), + ExpMonth = string.IsNullOrWhiteSpace(expMonth) ? null : expMonth.Encrypt(), + }; + break; + case CipherType.Identity: + string title; + switch(IdTitleCell.Picker.SelectedIndex) + { + case 1: + title = AppResources.Mr; + break; + case 2: + title = AppResources.Mrs; + break; + case 3: + title = AppResources.Ms; + break; + case 4: + title = AppResources.Dr; + break; + default: + title = null; + break; + } + + cipher.Identity = new Identity + { + Title = string.IsNullOrWhiteSpace(title) ? null : title.Encrypt(), + FirstName = string.IsNullOrWhiteSpace(IdFirstNameCell.Entry.Text) ? null : + IdFirstNameCell.Entry.Text.Encrypt(), + MiddleName = string.IsNullOrWhiteSpace(IdMiddleNameCell.Entry.Text) ? null : + IdMiddleNameCell.Entry.Text.Encrypt(), + LastName = string.IsNullOrWhiteSpace(IdLastNameCell.Entry.Text) ? null : + IdLastNameCell.Entry.Text.Encrypt(), + Username = string.IsNullOrWhiteSpace(IdUsernameCell.Entry.Text) ? null : + IdUsernameCell.Entry.Text.Encrypt(), + Company = string.IsNullOrWhiteSpace(IdCompanyCell.Entry.Text) ? null : + IdCompanyCell.Entry.Text.Encrypt(), + SSN = string.IsNullOrWhiteSpace(IdSsnCell.Entry.Text) ? null : + IdSsnCell.Entry.Text.Encrypt(), + PassportNumber = string.IsNullOrWhiteSpace(IdPassportNumberCell.Entry.Text) ? null : + IdPassportNumberCell.Entry.Text.Encrypt(), + LicenseNumber = string.IsNullOrWhiteSpace(IdLicenseNumberCell.Entry.Text) ? null : + IdLicenseNumberCell.Entry.Text.Encrypt(), + Email = string.IsNullOrWhiteSpace(IdEmailCell.Entry.Text) ? null : + IdEmailCell.Entry.Text.Encrypt(), + Phone = string.IsNullOrWhiteSpace(IdPhoneCell.Entry.Text) ? null : + IdPhoneCell.Entry.Text.Encrypt(), + Address1 = string.IsNullOrWhiteSpace(IdAddress1Cell.Entry.Text) ? null : + IdAddress1Cell.Entry.Text.Encrypt(), + Address2 = string.IsNullOrWhiteSpace(IdAddress2Cell.Entry.Text) ? null : + IdAddress2Cell.Entry.Text.Encrypt(), + Address3 = string.IsNullOrWhiteSpace(IdAddress3Cell.Entry.Text) ? null : + IdAddress3Cell.Entry.Text.Encrypt(), + City = string.IsNullOrWhiteSpace(IdCityCell.Entry.Text) ? null : + IdCityCell.Entry.Text.Encrypt(), + State = string.IsNullOrWhiteSpace(IdStateCell.Entry.Text) ? null : + IdStateCell.Entry.Text.Encrypt(), + PostalCode = string.IsNullOrWhiteSpace(IdPostalCodeCell.Entry.Text) ? null : + IdPostalCodeCell.Entry.Text.Encrypt(), + Country = string.IsNullOrWhiteSpace(IdCountryCell.Entry.Text) ? null : + IdCountryCell.Entry.Text.Encrypt() + }; + break; + default: + break; + } + if(FolderCell.Picker.SelectedIndex > 0) { - cipher.FolderId = folders.ElementAt(FolderCell.Picker.SelectedIndex - 1).Id; + cipher.FolderId = Folders.ElementAt(FolderCell.Picker.SelectedIndex - 1).Id; } _userDialogs.ShowLoading(AppResources.Saving, MaskType.Black); @@ -227,115 +696,7 @@ namespace Bit.App.Pages } }, ToolbarItemOrder.Default, 0); - Title = AppResources.AddItem; - Content = table; ToolbarItems.Add(saveToolBarItem); - if(Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.Windows) - { - ToolbarItems.Add(new DismissModalToolBarItem(this, AppResources.Cancel)); - } - } - - protected override void OnAppearing() - { - base.OnAppearing(); - if(!_connectivity.IsConnected) - { - AlertNoConnection(); - } - - PasswordCell.InitEvents(); - UsernameCell.InitEvents(); - UriCell.InitEvents(); - NameCell.InitEvents(); - NotesCell.InitEvents(); - TotpCell.InitEvents(); - FolderCell.InitEvents(); - PasswordCell.Button.Clicked += PasswordButton_Clicked; - if(TotpCell?.Button != null) - { - TotpCell.Button.Clicked += TotpButton_Clicked; - } - GenerateCell.Tapped += GenerateCell_Tapped; - - if(!_fromAutofill && !_settings.GetValueOrDefault(AddedLoginAlertKey, false)) - { - _settings.AddOrUpdateValue(AddedLoginAlertKey, true); - if(Device.RuntimePlatform == Device.iOS) - { - DisplayAlert(AppResources.BitwardenAppExtension, AppResources.BitwardenAppExtensionAlert, - AppResources.Ok); - } - else if(Device.RuntimePlatform == Device.Android && !_appInfoService.AutofillServiceEnabled) - { - DisplayAlert(AppResources.BitwardenAutofillService, AppResources.BitwardenAutofillServiceAlert, - AppResources.Ok); - } - } - - NameCell.Entry.FocusWithDelay(); - } - - protected override void OnDisappearing() - { - base.OnDisappearing(); - PasswordCell.Dispose(); - UsernameCell.Dispose(); - UriCell.Dispose(); - NameCell.Dispose(); - NotesCell.Dispose(); - TotpCell.Dispose(); - FolderCell.Dispose(); - PasswordCell.Button.Clicked -= PasswordButton_Clicked; - if(TotpCell?.Button != null) - { - TotpCell.Button.Clicked -= TotpButton_Clicked; - } - GenerateCell.Tapped -= GenerateCell_Tapped; - } - - private void PasswordButton_Clicked(object sender, EventArgs e) - { - PasswordCell.Entry.InvokeToggleIsPassword(); - PasswordCell.Button.Image = "eye" + (!PasswordCell.Entry.IsPasswordFromToggled ? "_slash" : string.Empty); - } - - private async void TotpButton_Clicked(object sender, EventArgs e) - { - var scanPage = new ScanPage((key) => - { - Device.BeginInvokeOnMainThread(async () => - { - await Navigation.PopModalAsync(); - if(!string.IsNullOrWhiteSpace(key)) - { - TotpCell.Entry.Text = key; - _userDialogs.Toast(AppResources.AuthenticatorKeyAdded); - } - else - { - _userDialogs.Alert(AppResources.AuthenticatorKeyReadError); - } - }); - }); - - await Navigation.PushModalAsync(new ExtendedNavigationPage(scanPage)); - } - - private async void GenerateCell_Tapped(object sender, EventArgs e) - { - var page = new ToolsPasswordGeneratorPage((password) => - { - PasswordCell.Entry.Text = password; - _userDialogs.Toast(AppResources.PasswordGenerated); - }, _fromAutofill); - await Navigation.PushForDeviceAsync(page); - } - - private void AlertNoConnection() - { - DisplayAlert(AppResources.InternetConnectionRequiredTitle, AppResources.InternetConnectionRequiredMessage, - AppResources.Ok); } } } diff --git a/src/App/Pages/Vault/VaultAutofillListCiphersPage.cs b/src/App/Pages/Vault/VaultAutofillListCiphersPage.cs index 546d2b4a2..6d9bf8a74 100644 --- a/src/App/Pages/Vault/VaultAutofillListCiphersPage.cs +++ b/src/App/Pages/Vault/VaultAutofillListCiphersPage.cs @@ -12,6 +12,7 @@ using Bit.App.Utilities; using System.Threading; using Bit.App.Models; using System.Collections.Generic; +using Bit.App.Enums; namespace Bit.App.Pages { @@ -231,7 +232,7 @@ namespace Bit.App.Pages private async void AddCipherAsync() { - var page = new VaultAddLoginPage(Uri, _name, true); + var page = new VaultAddLoginPage(CipherType.Login, Uri, _name, true); await Navigation.PushForDeviceAsync(page); } diff --git a/src/App/Pages/Vault/VaultListCiphersPage.cs b/src/App/Pages/Vault/VaultListCiphersPage.cs index 585aef1ec..fcae89c0b 100644 --- a/src/App/Pages/Vault/VaultListCiphersPage.cs +++ b/src/App/Pages/Vault/VaultListCiphersPage.cs @@ -14,6 +14,7 @@ using Plugin.Connectivity.Abstractions; using System.Collections.Generic; using System.Threading; using FFImageLoading.Forms; +using Bit.App.Enums; namespace Bit.App.Pages { @@ -490,7 +491,28 @@ namespace Bit.App.Pages private async void AddCipher() { - var page = new VaultAddLoginPage(Uri); + var type = await _userDialogs.ActionSheetAsync(AppResources.SelectTypeAdd, AppResources.Cancel, null, null, + AppResources.TypeLogin, AppResources.TypeCard, AppResources.TypeIdentity, AppResources.TypeSecureNote); + + var selectedType = CipherType.SecureNote; + if(type == AppResources.Cancel) + { + return; + } + else if(type == AppResources.TypeLogin) + { + selectedType = CipherType.Login; + } + else if(type == AppResources.TypeCard) + { + selectedType = CipherType.Card; + } + else if(type == AppResources.TypeIdentity) + { + selectedType = CipherType.Identity; + } + + var page = new VaultAddLoginPage(selectedType, Uri); await Navigation.PushForDeviceAsync(page); } diff --git a/src/App/Resources/AppResources.Designer.cs b/src/App/Resources/AppResources.Designer.cs index 1b8f3363b..a1a143bac 100644 --- a/src/App/Resources/AppResources.Designer.cs +++ b/src/App/Resources/AppResources.Designer.cs @@ -133,6 +133,33 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Address 1. + /// + public static string Address1 { + get { + return ResourceManager.GetString("Address1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Address 2. + /// + public static string Address2 { + get { + return ResourceManager.GetString("Address2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Address 3. + /// + public static string Address3 { + get { + return ResourceManager.GetString("Address3", resourceCulture); + } + } + /// /// Looks up a localized string similar to An error has occurred.. /// @@ -160,6 +187,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to April. + /// + public static string April { + get { + return ResourceManager.GetString("April", resourceCulture); + } + } + /// /// Looks up a localized string similar to Attachment added. /// @@ -196,6 +232,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to August. + /// + public static string August { + get { + return ResourceManager.GetString("August", resourceCulture); + } + } + /// /// Looks up a localized string similar to Authenticator App. /// @@ -484,6 +529,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Brand. + /// + public static string Brand { + get { + return ResourceManager.GetString("Brand", resourceCulture); + } + } + /// /// Looks up a localized string similar to Camera. /// @@ -529,6 +583,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Cardholder Name. + /// + public static string CardholderName { + get { + return ResourceManager.GetString("CardholderName", resourceCulture); + } + } + /// /// Looks up a localized string similar to Change Email. /// @@ -574,6 +637,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to City / Town. + /// + public static string CityTown { + get { + return ResourceManager.GetString("CityTown", resourceCulture); + } + } + /// /// Looks up a localized string similar to Close. /// @@ -592,6 +664,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Company. + /// + public static string Company { + get { + return ResourceManager.GetString("Company", resourceCulture); + } + } + /// /// Looks up a localized string similar to Continue. /// @@ -691,6 +772,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Country. + /// + public static string Country { + get { + return ResourceManager.GetString("Country", resourceCulture); + } + } + /// /// Looks up a localized string similar to Create Account. /// @@ -754,6 +844,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to December. + /// + public static string December { + get { + return ResourceManager.GetString("December", resourceCulture); + } + } + /// /// Looks up a localized string similar to Delete. /// @@ -835,6 +934,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Dr. + /// + public static string Dr { + get { + return ResourceManager.GetString("Dr", resourceCulture); + } + } + /// /// Looks up a localized string similar to Edit. /// @@ -970,6 +1078,24 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Expiration Month. + /// + public static string ExpirationMonth { + get { + return ResourceManager.GetString("ExpirationMonth", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expiration Year. + /// + public static string ExpirationYear { + get { + return ResourceManager.GetString("ExpirationYear", resourceCulture); + } + } + /// /// Looks up a localized string similar to Extension Activated!. /// @@ -1105,6 +1231,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to February. + /// + public static string February { + get { + return ResourceManager.GetString("February", resourceCulture); + } + } + /// /// Looks up a localized string similar to File. /// @@ -1159,6 +1294,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to First Name. + /// + public static string FirstName { + get { + return ResourceManager.GetString("FirstName", resourceCulture); + } + } + /// /// Looks up a localized string similar to Folder. /// @@ -1393,6 +1537,42 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to January. + /// + public static string January { + get { + return ResourceManager.GetString("January", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to July. + /// + public static string July { + get { + return ResourceManager.GetString("July", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to June. + /// + public static string June { + get { + return ResourceManager.GetString("June", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Last Name. + /// + public static string LastName { + get { + return ResourceManager.GetString("LastName", resourceCulture); + } + } + /// /// Looks up a localized string similar to Last Sync:. /// @@ -1429,6 +1609,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to License Number. + /// + public static string LicenseNumber { + get { + return ResourceManager.GetString("LicenseNumber", resourceCulture); + } + } + /// /// Looks up a localized string similar to Lock. /// @@ -1573,6 +1762,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to March. + /// + public static string March { + get { + return ResourceManager.GetString("March", resourceCulture); + } + } + /// /// Looks up a localized string similar to Master Password. /// @@ -1645,6 +1843,24 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to May. + /// + public static string May { + get { + return ResourceManager.GetString("May", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Middle Name. + /// + public static string MiddleName { + get { + return ResourceManager.GetString("MiddleName", resourceCulture); + } + } + /// /// Looks up a localized string similar to Minimum Numbers. /// @@ -1681,6 +1897,33 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Mr. + /// + public static string Mr { + get { + return ResourceManager.GetString("Mr", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Mrs. + /// + public static string Mrs { + get { + return ResourceManager.GetString("Mrs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ms. + /// + public static string Ms { + get { + return ResourceManager.GetString("Ms", resourceCulture); + } + } + /// /// Looks up a localized string similar to You must log into the main bitwarden app before you can use the extension.. /// @@ -1825,6 +2068,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to November. + /// + public static string November { + get { + return ResourceManager.GetString("November", resourceCulture); + } + } + /// /// Looks up a localized string similar to Number. /// @@ -1834,6 +2086,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to October. + /// + public static string October { + get { + return ResourceManager.GetString("October", resourceCulture); + } + } + /// /// Looks up a localized string similar to Ok. /// @@ -1879,6 +2140,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Passport Number. + /// + public static string PassportNumber { + get { + return ResourceManager.GetString("PassportNumber", resourceCulture); + } + } + /// /// Looks up a localized string similar to Password. /// @@ -1942,6 +2212,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Phone. + /// + public static string Phone { + get { + return ResourceManager.GetString("Phone", resourceCulture); + } + } + /// /// Looks up a localized string similar to Photos. /// @@ -2122,6 +2401,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to What type of item do you want to add?. + /// + public static string SelectTypeAdd { + get { + return ResourceManager.GetString("SelectTypeAdd", resourceCulture); + } + } + /// /// Looks up a localized string similar to Self-hosted Environment. /// @@ -2149,6 +2437,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to September. + /// + public static string September { + get { + return ResourceManager.GetString("September", resourceCulture); + } + } + /// /// Looks up a localized string similar to Server URL. /// @@ -2212,6 +2509,24 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Social Security Number. + /// + public static string SSN { + get { + return ResourceManager.GetString("SSN", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to State / Province. + /// + public static string StateProvince { + get { + return ResourceManager.GetString("StateProvince", resourceCulture); + } + } + /// /// Looks up a localized string similar to Status. /// @@ -2293,6 +2608,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Title. + /// + public static string Title { + get { + return ResourceManager.GetString("Title", resourceCulture); + } + } + /// /// Looks up a localized string similar to Tools. /// @@ -2347,6 +2671,42 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Card. + /// + public static string TypeCard { + get { + return ResourceManager.GetString("TypeCard", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Identity. + /// + public static string TypeIdentity { + get { + return ResourceManager.GetString("TypeIdentity", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Login. + /// + public static string TypeLogin { + get { + return ResourceManager.GetString("TypeLogin", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Secure Note. + /// + public static string TypeSecureNote { + get { + return ResourceManager.GetString("TypeSecureNote", resourceCulture); + } + } + /// /// Looks up a localized string similar to Unable to download file.. /// @@ -2625,5 +2985,14 @@ namespace Bit.App.Resources { return ResourceManager.GetString("YubiKeyTitle", resourceCulture); } } + + /// + /// Looks up a localized string similar to Zip / Postal Code. + /// + public static string ZipPostalCode { + get { + return ResourceManager.GetString("ZipPostalCode", resourceCulture); + } + } } } diff --git a/src/App/Resources/AppResources.resx b/src/App/Resources/AppResources.resx index 61f54e324..3d6b01a9c 100644 --- a/src/App/Resources/AppResources.resx +++ b/src/App/Resources/AppResources.resx @@ -1047,4 +1047,127 @@ Security Code + + What type of item do you want to add? + + + Card + + + Identity + + + Login + + + Secure Note + + + Address 1 + + + Address 2 + + + Address 3 + + + April + + + August + + + Brand + + + Cardholder Name + + + City / Town + + + Company + + + Country + + + December + + + Dr + + + Expiration Month + + + Expiration Year + + + February + + + First Name + + + January + + + July + + + June + + + Last Name + + + License Number + + + March + + + May + + + Middle Name + + + Mr + + + Mrs + + + Ms + + + November + + + October + + + Passport Number + + + Phone + + + September + + + Social Security Number + + + State / Province + + + Title + + + Zip / Postal Code + \ No newline at end of file