From 1d6ec0f953518c51ccf41e4e4c48b5f8cf5e36d0 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Wed, 18 Oct 2017 20:55:33 -0400 Subject: [PATCH] refactoring code for login => cipher support --- src/Android/MainApplication.cs | 4 +- .../Repositories/IAttachmentRepository.cs | 2 +- .../Repositories/ICipherRepository.cs | 13 ++ .../Repositories/IFolderRepository.cs | 2 +- .../Repositories/ILoginRepository.cs | 13 -- .../Abstractions/Services/ICipherService.cs | 21 ++++ .../Abstractions/Services/ILoginService.cs | 21 ---- src/App/Abstractions/Services/ISyncService.cs | 2 +- src/App/App.csproj | 20 ++- src/App/Enums/CipherType.cs | 3 +- src/App/Enums/SecureNoteType.cs | 7 ++ src/App/Models/Api/CardDataModel.cs | 12 ++ src/App/Models/Api/IdentityDataModel.cs | 24 ++++ src/App/Models/Api/Request/CipherRequest.cs | 117 +++++++++++++++--- src/App/Models/Api/SecureNoteDataModel.cs | 9 ++ src/App/Models/Card.cs | 29 +++++ src/App/Models/Cipher.cs | 76 ++++++++++++ src/App/Models/Data/AttachmentData.cs | 9 +- src/App/Models/Data/CipherData.cs | 100 +++++++++++++++ src/App/Models/Data/LoginData.cs | 73 ----------- src/App/Models/Identity.cs | 54 ++++++++ src/App/Models/Login.cs | 42 +------ src/App/Models/Page/VaultListPageModel.cs | 22 ++-- .../Models/Page/VaultViewLoginPageModel.cs | 30 ++--- src/App/Models/SecureNote.cs | 15 +++ src/App/Pages/Vault/VaultAddLoginPage.cs | 27 ++-- src/App/Pages/Vault/VaultAttachmentsPage.cs | 12 +- .../Vault/VaultAutofillListLoginsPage.cs | 6 +- src/App/Pages/Vault/VaultCustomFieldsPage.cs | 10 +- src/App/Pages/Vault/VaultEditLoginPage.cs | 60 ++++----- src/App/Pages/Vault/VaultListLoginsPage.cs | 6 +- src/App/Pages/Vault/VaultViewLoginPage.cs | 20 +-- src/App/Repositories/AttachmentRepository.cs | 5 +- src/App/Repositories/CipherRepository.cs | 29 +++++ src/App/Repositories/FolderRepository.cs | 4 +- src/App/Repositories/LoginRepository.cs | 29 ----- .../{LoginService.cs => CipherService.cs} | 68 +++++----- src/App/Services/DatabaseService.cs | 2 +- src/App/Services/PushNotificationListener.cs | 2 +- src/App/Services/SyncService.cs | 100 +++++++-------- src/UWP/App.xaml.cs | 4 +- src/iOS.Extension/LoadingViewController.cs | 4 +- src/iOS.Extension/LoginAddViewController.cs | 19 +-- src/iOS.Extension/LoginListViewController.cs | 8 +- src/iOS.Extension/Models/LoginViewModel.cs | 2 +- src/iOS/AppDelegate.cs | 4 +- 46 files changed, 731 insertions(+), 410 deletions(-) create mode 100644 src/App/Abstractions/Repositories/ICipherRepository.cs delete mode 100644 src/App/Abstractions/Repositories/ILoginRepository.cs create mode 100644 src/App/Abstractions/Services/ICipherService.cs delete mode 100644 src/App/Abstractions/Services/ILoginService.cs create mode 100644 src/App/Enums/SecureNoteType.cs create mode 100644 src/App/Models/Api/CardDataModel.cs create mode 100644 src/App/Models/Api/IdentityDataModel.cs create mode 100644 src/App/Models/Api/SecureNoteDataModel.cs create mode 100644 src/App/Models/Card.cs create mode 100644 src/App/Models/Cipher.cs create mode 100644 src/App/Models/Data/CipherData.cs delete mode 100644 src/App/Models/Data/LoginData.cs create mode 100644 src/App/Models/Identity.cs create mode 100644 src/App/Models/SecureNote.cs create mode 100644 src/App/Repositories/CipherRepository.cs delete mode 100644 src/App/Repositories/LoginRepository.cs rename src/App/Services/{LoginService.cs => CipherService.cs} (85%) diff --git a/src/Android/MainApplication.cs b/src/Android/MainApplication.cs index 0f213ba0c..12c94aa94 100644 --- a/src/Android/MainApplication.cs +++ b/src/Android/MainApplication.cs @@ -195,7 +195,7 @@ namespace Bit.Android container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); - container.RegisterSingleton(); + container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); @@ -216,7 +216,7 @@ namespace Bit.Android // Repositories container.RegisterSingleton(); container.RegisterSingleton(); - container.RegisterSingleton(); + container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); diff --git a/src/App/Abstractions/Repositories/IAttachmentRepository.cs b/src/App/Abstractions/Repositories/IAttachmentRepository.cs index f1cde2e89..b6fc5f1ac 100644 --- a/src/App/Abstractions/Repositories/IAttachmentRepository.cs +++ b/src/App/Abstractions/Repositories/IAttachmentRepository.cs @@ -7,7 +7,7 @@ namespace Bit.App.Abstractions { public interface IAttachmentRepository : IRepository { - Task> GetAllByLoginIdAsync(string loginId); + Task> GetAllByCipherIdAsync(string cipherId); Task> GetAllByUserIdAsync(string userId); } } diff --git a/src/App/Abstractions/Repositories/ICipherRepository.cs b/src/App/Abstractions/Repositories/ICipherRepository.cs new file mode 100644 index 000000000..ad1a393e9 --- /dev/null +++ b/src/App/Abstractions/Repositories/ICipherRepository.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Bit.App.Models.Data; + +namespace Bit.App.Abstractions +{ + public interface ICipherRepository : IRepository + { + Task> GetAllByUserIdAsync(string userId); + Task> GetAllByUserIdAsync(string userId, bool favorite); + } +} diff --git a/src/App/Abstractions/Repositories/IFolderRepository.cs b/src/App/Abstractions/Repositories/IFolderRepository.cs index c496c32cb..5724fc715 100644 --- a/src/App/Abstractions/Repositories/IFolderRepository.cs +++ b/src/App/Abstractions/Repositories/IFolderRepository.cs @@ -8,6 +8,6 @@ namespace Bit.App.Abstractions public interface IFolderRepository : IRepository { Task> GetAllByUserIdAsync(string userId); - Task DeleteWithLoginUpdateAsync(string id, DateTime revisionDate); + Task DeleteWithCipherUpdateAsync(string id, DateTime revisionDate); } } diff --git a/src/App/Abstractions/Repositories/ILoginRepository.cs b/src/App/Abstractions/Repositories/ILoginRepository.cs deleted file mode 100644 index ce474ae22..000000000 --- a/src/App/Abstractions/Repositories/ILoginRepository.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Bit.App.Models.Data; - -namespace Bit.App.Abstractions -{ - public interface ILoginRepository : IRepository - { - Task> GetAllByUserIdAsync(string userId); - Task> GetAllByUserIdAsync(string userId, bool favorite); - } -} diff --git a/src/App/Abstractions/Services/ICipherService.cs b/src/App/Abstractions/Services/ICipherService.cs new file mode 100644 index 000000000..428130bff --- /dev/null +++ b/src/App/Abstractions/Services/ICipherService.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Bit.App.Models; +using Bit.App.Models.Api; +using System; + +namespace Bit.App.Abstractions +{ + public interface ICipherService + { + Task GetByIdAsync(string id); + Task> GetAllAsync(); + Task> GetAllAsync(bool favorites); + Task, IEnumerable>> GetAllAsync(string uriString); + Task> SaveAsync(Cipher login); + Task DeleteAsync(string id); + Task DownloadAndDecryptAttachmentAsync(string url, string orgId = null); + Task> EncryptAndSaveAttachmentAsync(Cipher login, byte[] data, string fileName); + Task DeleteAttachmentAsync(Cipher login, string attachmentId); + } +} diff --git a/src/App/Abstractions/Services/ILoginService.cs b/src/App/Abstractions/Services/ILoginService.cs deleted file mode 100644 index b4a3ecd4e..000000000 --- a/src/App/Abstractions/Services/ILoginService.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Bit.App.Models; -using Bit.App.Models.Api; -using System; - -namespace Bit.App.Abstractions -{ - public interface ILoginService - { - Task GetByIdAsync(string id); - Task> GetAllAsync(); - Task> GetAllAsync(bool favorites); - Task, IEnumerable>> GetAllAsync(string uriString); - Task> SaveAsync(Login login); - Task DeleteAsync(string id); - Task DownloadAndDecryptAttachmentAsync(string url, string orgId = null); - Task> EncryptAndSaveAttachmentAsync(Login login, byte[] data, string fileName); - Task DeleteAttachmentAsync(Login login, string attachmentId); - } -} diff --git a/src/App/Abstractions/Services/ISyncService.cs b/src/App/Abstractions/Services/ISyncService.cs index c0b448a2d..63e877b34 100644 --- a/src/App/Abstractions/Services/ISyncService.cs +++ b/src/App/Abstractions/Services/ISyncService.cs @@ -9,7 +9,7 @@ namespace Bit.App.Abstractions Task SyncCipherAsync(string id); Task SyncFolderAsync(string id); Task SyncDeleteFolderAsync(string id, DateTime revisionDate); - Task SyncDeleteLoginAsync(string id); + Task SyncDeleteCipherAsync(string id); Task SyncSettingsAsync(); Task SyncProfileAsync(); Task FullSyncAsync(bool forceSync = false); diff --git a/src/App/App.csproj b/src/App/App.csproj index b43109751..51e6c42b6 100644 --- a/src/App/App.csproj +++ b/src/App/App.csproj @@ -58,7 +58,7 @@ - + @@ -91,6 +91,7 @@ + @@ -104,6 +105,9 @@ + + + @@ -125,16 +129,20 @@ + + + + - + @@ -144,7 +152,7 @@ - + @@ -175,7 +183,7 @@ - + @@ -192,7 +200,7 @@ - + @@ -340,7 +348,7 @@ - + diff --git a/src/App/Enums/CipherType.cs b/src/App/Enums/CipherType.cs index 41950bc79..94f8785ec 100644 --- a/src/App/Enums/CipherType.cs +++ b/src/App/Enums/CipherType.cs @@ -6,6 +6,7 @@ //Folder = 0, Login = 1, SecureNote = 2, - Card = 3 + Card = 3, + Identity = 4 } } diff --git a/src/App/Enums/SecureNoteType.cs b/src/App/Enums/SecureNoteType.cs new file mode 100644 index 000000000..0bbea38f2 --- /dev/null +++ b/src/App/Enums/SecureNoteType.cs @@ -0,0 +1,7 @@ +namespace Bit.App.Enums +{ + public enum SecureNoteType : byte + { + Generic = 0 + } +} diff --git a/src/App/Models/Api/CardDataModel.cs b/src/App/Models/Api/CardDataModel.cs new file mode 100644 index 000000000..b19d73eb2 --- /dev/null +++ b/src/App/Models/Api/CardDataModel.cs @@ -0,0 +1,12 @@ +namespace Bit.App.Models.Api +{ + public class CardDataModel : CipherDataModel + { + public string CardholderName { get; set; } + public string Brand { get; set; } + public string Number { get; set; } + public string ExpMonth { get; set; } + public string ExpYear { get; set; } + public string Code { get; set; } + } +} diff --git a/src/App/Models/Api/IdentityDataModel.cs b/src/App/Models/Api/IdentityDataModel.cs new file mode 100644 index 000000000..c49cda2de --- /dev/null +++ b/src/App/Models/Api/IdentityDataModel.cs @@ -0,0 +1,24 @@ +namespace Bit.App.Models.Api +{ + public class IdentityDataModel : CipherDataModel + { + public string Title { get; set; } + public string FirstName { get; set; } + public string MiddleName { get; set; } + public string LastName { get; set; } + public string Address1 { get; set; } + public string Address2 { get; set; } + public string Address3 { get; set; } + public string City { get; set; } + public string State { get; set; } + public string PostalCode { get; set; } + public string Country { get; set; } + public string Company { get; set; } + public string Email { get; set; } + public string Phone { get; set; } + public string SSN { get; set; } + public string Username { get; set; } + public string PassportNumber { get; set; } + public string LicenseNumber { get; set; } + } +} diff --git a/src/App/Models/Api/Request/CipherRequest.cs b/src/App/Models/Api/Request/CipherRequest.cs index 4e59a5b99..55aed604c 100644 --- a/src/App/Models/Api/Request/CipherRequest.cs +++ b/src/App/Models/Api/Request/CipherRequest.cs @@ -6,18 +6,18 @@ namespace Bit.App.Models.Api { public class CipherRequest { - public CipherRequest(Login login) + public CipherRequest(Cipher cipher) { - Type = CipherType.Login; - OrganizationId = login.OrganizationId; - FolderId = login.FolderId; - Name = login.Name?.EncryptedString; - Notes = login.Notes?.EncryptedString; - Favorite = login.Favorite; + Type = cipher.Type; + OrganizationId = cipher.OrganizationId; + FolderId = cipher.FolderId; + Name = cipher.Name?.EncryptedString; + Notes = cipher.Notes?.EncryptedString; + Favorite = cipher.Favorite; - if(login.Fields != null) + if(cipher.Fields != null) { - Fields = login.Fields.Select(f => new FieldDataModel + Fields = cipher.Fields.Select(f => new FieldDataModel { Name = f.Name?.EncryptedString, Value = f.Value?.EncryptedString, @@ -28,7 +28,16 @@ namespace Bit.App.Models.Api switch(Type) { case CipherType.Login: - Login = new LoginType(login); + Login = new LoginType(cipher); + break; + case CipherType.Card: + Card = new CardType(cipher); + break; + case CipherType.Identity: + Identity = new IdentityType(cipher); + break; + case CipherType.SecureNote: + SecureNote = new SecureNoteType(cipher); break; default: break; @@ -42,16 +51,20 @@ namespace Bit.App.Models.Api public string Name { get; set; } public string Notes { get; set; } public IEnumerable Fields { get; set; } + public LoginType Login { get; set; } + public CardType Card { get; set; } + public IdentityType Identity { get; set; } + public SecureNoteType SecureNote { get; set; } public class LoginType { - public LoginType(Login login) + public LoginType(Cipher cipher) { - Uri = login.Uri?.EncryptedString; - Username = login.Username?.EncryptedString; - Password = login.Password?.EncryptedString; - Totp = login.Totp?.EncryptedString; + Uri = cipher.Login.Uri?.EncryptedString; + Username = cipher.Login.Username?.EncryptedString; + Password = cipher.Login.Password?.EncryptedString; + Totp = cipher.Login.Totp?.EncryptedString; } public string Uri { get; set; } @@ -59,5 +72,79 @@ namespace Bit.App.Models.Api public string Password { get; set; } public string Totp { get; set; } } + + public class CardType + { + public CardType(Cipher cipher) + { + CardholderName = cipher.Card.CardholderName?.EncryptedString; + Brand = cipher.Card.Brand?.EncryptedString; + Number = cipher.Card.Number?.EncryptedString; + ExpMonth = cipher.Card.ExpMonth?.EncryptedString; + ExpYear = cipher.Card.ExpYear?.EncryptedString; + Code = cipher.Card.Code?.EncryptedString; + } + + public string CardholderName { get; set; } + public string Brand { get; set; } + public string Number { get; set; } + public string ExpMonth { get; set; } + public string ExpYear { get; set; } + public string Code { get; set; } + } + + public class IdentityType + { + public IdentityType(Cipher cipher) + { + Title = cipher.Identity.Title?.EncryptedString; + FirstName = cipher.Identity.FirstName?.EncryptedString; + MiddleName = cipher.Identity.MiddleName?.EncryptedString; + LastName = cipher.Identity.LastName?.EncryptedString; + Address1 = cipher.Identity.Address1?.EncryptedString; + Address2 = cipher.Identity.Address2?.EncryptedString; + Address3 = cipher.Identity.Address3?.EncryptedString; + City = cipher.Identity.City?.EncryptedString; + State = cipher.Identity.State?.EncryptedString; + PostalCode = cipher.Identity.PostalCode?.EncryptedString; + Country = cipher.Identity.Country?.EncryptedString; + Company = cipher.Identity.Company?.EncryptedString; + Email = cipher.Identity.Email?.EncryptedString; + Phone = cipher.Identity.Phone?.EncryptedString; + SSN = cipher.Identity.SSN?.EncryptedString; + Username = cipher.Identity.Username?.EncryptedString; + PassportNumber = cipher.Identity.PassportNumber?.EncryptedString; + LicenseNumber = cipher.Identity.LicenseNumber?.EncryptedString; + } + + public string Title { get; set; } + public string FirstName { get; set; } + public string MiddleName { get; set; } + public string LastName { get; set; } + public string Address1 { get; set; } + public string Address2 { get; set; } + public string Address3 { get; set; } + public string City { get; set; } + public string State { get; set; } + public string PostalCode { get; set; } + public string Country { get; set; } + public string Company { get; set; } + public string Email { get; set; } + public string Phone { get; set; } + public string SSN { get; set; } + public string Username { get; set; } + public string PassportNumber { get; set; } + public string LicenseNumber { get; set; } + } + + public class SecureNoteType + { + public SecureNoteType(Cipher cipher) + { + Type = cipher.SecureNote.Type; + } + + public Enums.SecureNoteType Type { get; set; } + } } } diff --git a/src/App/Models/Api/SecureNoteDataModel.cs b/src/App/Models/Api/SecureNoteDataModel.cs new file mode 100644 index 000000000..5e2e5ee12 --- /dev/null +++ b/src/App/Models/Api/SecureNoteDataModel.cs @@ -0,0 +1,9 @@ +using Bit.App.Enums; + +namespace Bit.App.Models.Api +{ + public class SecureNoteDataModel : CipherDataModel + { + public SecureNoteType Type { get; set; } + } +} diff --git a/src/App/Models/Card.cs b/src/App/Models/Card.cs new file mode 100644 index 000000000..e71d89b1f --- /dev/null +++ b/src/App/Models/Card.cs @@ -0,0 +1,29 @@ +using Bit.App.Models.Api; +using Bit.App.Models.Data; +using Newtonsoft.Json; + +namespace Bit.App.Models +{ + public class Card + { + public Card(CipherData data) + { + var deserializedData = JsonConvert.DeserializeObject(data.Data); + + CardholderName = deserializedData.CardholderName != null ? + new CipherString(deserializedData.CardholderName) : null; + Brand = deserializedData.Brand != null ? new CipherString(deserializedData.Brand) : null; + Number = deserializedData.Number != null ? new CipherString(deserializedData.Number) : null; + ExpMonth = deserializedData.ExpMonth != null ? new CipherString(deserializedData.ExpMonth) : null; + ExpYear = deserializedData.ExpYear != null ? new CipherString(deserializedData.ExpYear) : null; + Code = deserializedData.Code != null ? new CipherString(deserializedData.Code) : null; + } + + public CipherString CardholderName { get; set; } + public CipherString Brand { get; set; } + public CipherString Number { get; set; } + public CipherString ExpMonth { get; set; } + public CipherString ExpYear { get; set; } + public CipherString Code { get; set; } + } +} diff --git a/src/App/Models/Cipher.cs b/src/App/Models/Cipher.cs new file mode 100644 index 000000000..be070303e --- /dev/null +++ b/src/App/Models/Cipher.cs @@ -0,0 +1,76 @@ +using Bit.App.Enums; +using Bit.App.Models.Api; +using Bit.App.Models.Data; +using Newtonsoft.Json; +using System.Collections.Generic; +using System.Linq; + +namespace Bit.App.Models +{ + public class Cipher + { + public Cipher() + { } + + public Cipher(CipherData data, IEnumerable attachments = null) + { + Id = data.Id; + UserId = data.UserId; + OrganizationId = data.OrganizationId; + FolderId = data.FolderId; + Type = data.Type; + Name = data.Name != null ? new CipherString(data.Name) : null; + Notes = data.Notes != null ? new CipherString(data.Notes) : null; + Favorite = data.Favorite; + Edit = data.Edit; + OrganizationUseTotp = data.OrganizationUseTotp; + Attachments = attachments?.Select(a => new Attachment(a)); + + switch(Type) + { + case CipherType.Login: + Login = new Login(data); + break; + case CipherType.SecureNote: + SecureNote = new SecureNote(data); + break; + case CipherType.Card: + Card = new Card(data); + break; + case CipherType.Identity: + Identity = new Identity(data); + break; + default: + break; + } + + if(!string.IsNullOrWhiteSpace(data.Fields)) + { + try + { + var fieldModels = JsonConvert.DeserializeObject>(data.Fields); + Fields = fieldModels?.Select(f => new Field(f)); + } + catch(JsonSerializationException) { } + } + } + + public string Id { get; set; } + public string UserId { get; set; } + public string OrganizationId { get; set; } + public string FolderId { get; set; } + public CipherType Type { get; set; } + public CipherString Name { get; set; } + public CipherString Notes { get; set; } + public IEnumerable Fields { get; set; } + public bool Favorite { get; set; } + public bool Edit { get; set; } + public bool OrganizationUseTotp { get; set; } + public IEnumerable Attachments { get; set; } + + public Login Login { get; set; } + public Identity Identity { get; set; } + public Card Card { get; set; } + public SecureNote SecureNote { get; set; } + } +} diff --git a/src/App/Models/Data/AttachmentData.cs b/src/App/Models/Data/AttachmentData.cs index d59156743..5be55d0d3 100644 --- a/src/App/Models/Data/AttachmentData.cs +++ b/src/App/Models/Data/AttachmentData.cs @@ -10,20 +10,20 @@ namespace Bit.App.Models.Data public AttachmentData() { } - public AttachmentData(Attachment attachment, string loginId) + public AttachmentData(Attachment attachment, string cipherId) { Id = attachment.Id; - LoginId = loginId; + LoginId = cipherId; Url = attachment.Url; FileName = attachment.FileName?.EncryptedString; Size = attachment.Size.ToString(); SizeName = attachment.SizeName; } - public AttachmentData(AttachmentResponse response, string loginId) + public AttachmentData(AttachmentResponse response, string cipherId) { Id = response.Id; - LoginId = loginId; + LoginId = cipherId; Url = response.Url; FileName = response.FileName; Size = response.Size; @@ -32,6 +32,7 @@ namespace Bit.App.Models.Data [PrimaryKey] public string Id { get; set; } + // Really should be called CipherId [Indexed] public string LoginId { get; set; } public string Url { get; set; } diff --git a/src/App/Models/Data/CipherData.cs b/src/App/Models/Data/CipherData.cs new file mode 100644 index 000000000..717133472 --- /dev/null +++ b/src/App/Models/Data/CipherData.cs @@ -0,0 +1,100 @@ +using System; +using SQLite; +using Bit.App.Abstractions; +using Bit.App.Models.Api; +using Newtonsoft.Json; +using System.Linq; +using Bit.App.Enums; + +namespace Bit.App.Models.Data +{ + // Old table that has just carried over for backward compat. sake. Should really be "Cipher" + [Table("Site")] + public class CipherData : IDataObject + { + public CipherData() + { } + + public CipherData(CipherResponse cipher, string userId) + { + Id = cipher.Id; + FolderId = cipher.FolderId; + UserId = userId; + OrganizationId = cipher.OrganizationId; + Favorite = cipher.Favorite; + Edit = cipher.Edit; + OrganizationUseTotp = cipher.OrganizationUseTotp; + RevisionDateTime = cipher.RevisionDate; + Type = cipher.Type; + Data = JsonConvert.SerializeObject(cipher.Data); + + CipherDataModel cipherData = null; + switch(cipher.Type) + { + case CipherType.Login: + var loginData = cipher.Data.ToObject(); + cipherData = loginData; + + Uri = loginData.Uri; + Username = loginData.Username; + Password = loginData.Password; + Totp = loginData.Totp; + break; + case CipherType.SecureNote: + var noteData = cipher.Data.ToObject(); + cipherData = noteData; + + SecureNoteType = noteData.Type; + break; + case CipherType.Card: + var cardData = cipher.Data.ToObject(); + cipherData = cardData; + break; + case CipherType.Identity: + var idData = cipher.Data.ToObject(); + cipherData = idData; + break; + default: + throw new ArgumentException(nameof(cipher.Type)); + } + + Name = cipherData.Name; + Notes = cipherData.Notes; + + if(cipherData.Fields != null && cipherData.Fields.Any()) + { + try + { + Fields = JsonConvert.SerializeObject(cipherData.Fields); + } + catch(JsonSerializationException) { } + } + } + + [PrimaryKey] + public string Id { get; set; } + public string FolderId { get; set; } + [Indexed] + public string UserId { get; set; } + public string OrganizationId { get; set; } + public string Name { get; set; } + public string Notes { get; set; } + public string Fields { get; set; } + public bool Favorite { get; set; } + public bool Edit { get; set; } + public bool OrganizationUseTotp { get; set; } + public DateTime RevisionDateTime { get; set; } = DateTime.UtcNow; + [Indexed] + public CipherType Type { get; set; } = CipherType.Login; + public string Data { get; set; } + + // Login metadata + public string Uri { get; set; } + public string Username { get; set; } + public string Password { get; set; } + public string Totp { get; set; } + + // Secure Note metadata + public SecureNoteType? SecureNoteType { get; set; } + } +} diff --git a/src/App/Models/Data/LoginData.cs b/src/App/Models/Data/LoginData.cs deleted file mode 100644 index 9bd763000..000000000 --- a/src/App/Models/Data/LoginData.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using SQLite; -using Bit.App.Abstractions; -using Bit.App.Models.Api; -using Newtonsoft.Json; -using System.Linq; - -namespace Bit.App.Models.Data -{ - [Table("Site")] - public class LoginData : IDataObject - { - public LoginData() - { } - - public LoginData(CipherResponse cipher, string userId) - { - if(cipher.Type != Enums.CipherType.Login) - { - throw new ArgumentException(nameof(cipher.Type)); - } - - var data = cipher.Data.ToObject(); - - Id = cipher.Id; - FolderId = cipher.FolderId; - UserId = userId; - OrganizationId = cipher.OrganizationId; - Name = data.Name; - Uri = data.Uri; - Username = data.Username; - Password = data.Password; - Notes = data.Notes; - Totp = data.Totp; - Favorite = cipher.Favorite; - Edit = cipher.Edit; - OrganizationUseTotp = cipher.OrganizationUseTotp; - RevisionDateTime = cipher.RevisionDate; - - if(data.Fields != null && data.Fields.Any()) - { - try - { - Fields = JsonConvert.SerializeObject(data.Fields); - } - catch(JsonSerializationException) { } - } - } - - [PrimaryKey] - public string Id { get; set; } - public string FolderId { get; set; } - [Indexed] - public string UserId { get; set; } - public string OrganizationId { get; set; } - public string Name { get; set; } - public string Uri { get; set; } - public string Username { get; set; } - public string Password { get; set; } - public string Notes { get; set; } - public string Totp { get; set; } - public string Fields { get; set; } - public bool Favorite { get; set; } - public bool Edit { get; set; } - public bool OrganizationUseTotp { get; set; } - public DateTime RevisionDateTime { get; set; } = DateTime.UtcNow; - - public Login ToLogin() - { - return new Login(this); - } - } -} diff --git a/src/App/Models/Identity.cs b/src/App/Models/Identity.cs new file mode 100644 index 000000000..a5f5319af --- /dev/null +++ b/src/App/Models/Identity.cs @@ -0,0 +1,54 @@ +using Bit.App.Models.Api; +using Bit.App.Models.Data; +using Newtonsoft.Json; + +namespace Bit.App.Models +{ + public class Identity + { + public Identity(CipherData data) + { + var deserializedData = JsonConvert.DeserializeObject(data.Data); + + Title = deserializedData.Title != null ? new CipherString(deserializedData.Title) : null; + FirstName = deserializedData.FirstName != null ? new CipherString(deserializedData.FirstName) : null; + MiddleName = deserializedData.MiddleName != null ? new CipherString(deserializedData.MiddleName) : null; + LastName = deserializedData.LastName != null ? new CipherString(deserializedData.LastName) : null; + Address1 = deserializedData.Address1 != null ? new CipherString(deserializedData.Address1) : null; + Address2 = deserializedData.Address2 != null ? new CipherString(deserializedData.Address2) : null; + Address3 = deserializedData.Address3 != null ? new CipherString(deserializedData.Address3) : null; + City = deserializedData.City != null ? new CipherString(deserializedData.City) : null; + State = deserializedData.State != null ? new CipherString(deserializedData.State) : null; + PostalCode = deserializedData.PostalCode != null ? new CipherString(deserializedData.PostalCode) : null; + Country = deserializedData.Country != null ? new CipherString(deserializedData.Country) : null; + Company = deserializedData.Company != null ? new CipherString(deserializedData.Company) : null; + Email = deserializedData.Email != null ? new CipherString(deserializedData.Email) : null; + Phone = deserializedData.Phone != null ? new CipherString(deserializedData.Phone) : null; + SSN = deserializedData.SSN != null ? new CipherString(deserializedData.SSN) : null; + Username = deserializedData.Username != null ? new CipherString(deserializedData.Username) : null; + PassportNumber = deserializedData.PassportNumber != null ? + new CipherString(deserializedData.PassportNumber) : null; + LicenseNumber = deserializedData.LicenseNumber != null ? + new CipherString(deserializedData.LicenseNumber) : null; + } + + public CipherString Title { get; set; } + public CipherString FirstName { get; set; } + public CipherString MiddleName { get; set; } + public CipherString LastName { get; set; } + public CipherString Address1 { get; set; } + public CipherString Address2 { get; set; } + public CipherString Address3 { get; set; } + public CipherString City { get; set; } + public CipherString State { get; set; } + public CipherString PostalCode { get; set; } + public CipherString Country { get; set; } + public CipherString Company { get; set; } + public CipherString Email { get; set; } + public CipherString Phone { get; set; } + public CipherString SSN { get; set; } + public CipherString Username { get; set; } + public CipherString PassportNumber { get; set; } + public CipherString LicenseNumber { get; set; } + } +} diff --git a/src/App/Models/Login.cs b/src/App/Models/Login.cs index 690e17616..c5691f175 100644 --- a/src/App/Models/Login.cs +++ b/src/App/Models/Login.cs @@ -1,58 +1,22 @@ -using Bit.App.Models.Api; -using Bit.App.Models.Data; -using Newtonsoft.Json; -using System.Collections.Generic; -using System.Linq; +using Bit.App.Models.Data; namespace Bit.App.Models { public class Login { - public Login() - { } + public Login() { } - public Login(LoginData data, IEnumerable attachments = null) + public Login(CipherData data) { - Id = data.Id; - UserId = data.UserId; - OrganizationId = data.OrganizationId; - FolderId = data.FolderId; - Name = data.Name != null ? new CipherString(data.Name) : null; Uri = data.Uri != null ? new CipherString(data.Uri) : null; Username = data.Username != null ? new CipherString(data.Username) : null; Password = data.Password != null ? new CipherString(data.Password) : null; - Notes = data.Notes != null ? new CipherString(data.Notes) : null; Totp = data.Totp != null ? new CipherString(data.Totp) : null; - Favorite = data.Favorite; - Edit = data.Edit; - OrganizationUseTotp = data.OrganizationUseTotp; - Attachments = attachments?.Select(a => new Attachment(a)); - - if(!string.IsNullOrWhiteSpace(data.Fields)) - { - try - { - var fieldModels = JsonConvert.DeserializeObject>(data.Fields); - Fields = fieldModels?.Select(f => new Field(f)); - } - catch(JsonSerializationException) { } - } } - public string Id { get; set; } - public string UserId { get; set; } - public string OrganizationId { get; set; } - public string FolderId { get; set; } - public CipherString Name { get; set; } public CipherString Uri { get; set; } public CipherString Username { get; set; } public CipherString Password { get; set; } - public CipherString Notes { get; set; } public CipherString Totp { get; set; } - public IEnumerable Fields { get; set; } - public bool Favorite { get; set; } - public bool Edit { get; set; } - public bool OrganizationUseTotp { get; set; } - public IEnumerable Attachments { get; set; } } } diff --git a/src/App/Models/Page/VaultListPageModel.cs b/src/App/Models/Page/VaultListPageModel.cs index d4c4cb1f4..70ae3c89e 100644 --- a/src/App/Models/Page/VaultListPageModel.cs +++ b/src/App/Models/Page/VaultListPageModel.cs @@ -9,17 +9,17 @@ namespace Bit.App.Models.Page { public class Login { - public Login(Models.Login login) + public Login(Models.Cipher cipher) { - Id = login.Id; - Shared = !string.IsNullOrWhiteSpace(login.OrganizationId); - HasAttachments = login.Attachments?.Any() ?? false; - FolderId = login.FolderId; - Name = login.Name?.Decrypt(login.OrganizationId); - Username = login.Username?.Decrypt(login.OrganizationId) ?? " "; - Password = new Lazy(() => login.Password?.Decrypt(login.OrganizationId)); - Uri = new Lazy(() => login.Uri?.Decrypt(login.OrganizationId)); - Totp = new Lazy(() => login.Totp?.Decrypt(login.OrganizationId)); + Id = cipher.Id; + Shared = !string.IsNullOrWhiteSpace(cipher.OrganizationId); + HasAttachments = cipher.Attachments?.Any() ?? false; + FolderId = cipher.FolderId; + Name = cipher.Name?.Decrypt(cipher.OrganizationId); + Username = cipher.Login?.Username?.Decrypt(cipher.OrganizationId) ?? " "; + Password = new Lazy(() => cipher.Login?.Password?.Decrypt(cipher.OrganizationId)); + Uri = new Lazy(() => cipher.Login?.Uri?.Decrypt(cipher.OrganizationId)); + Totp = new Lazy(() => cipher.Login?.Totp?.Decrypt(cipher.OrganizationId)); } public string Id { get; set; } @@ -35,7 +35,7 @@ namespace Bit.App.Models.Page public class AutofillLogin : Login { - public AutofillLogin(Models.Login login, bool fuzzy = false) + public AutofillLogin(Models.Cipher login, bool fuzzy = false) : base(login) { Fuzzy = fuzzy; diff --git a/src/App/Models/Page/VaultViewLoginPageModel.cs b/src/App/Models/Page/VaultViewLoginPageModel.cs index 89a974f95..5d72fa635 100644 --- a/src/App/Models/Page/VaultViewLoginPageModel.cs +++ b/src/App/Models/Page/VaultViewLoginPageModel.cs @@ -201,23 +201,23 @@ namespace Bit.App.Models.Page } public bool ShowFields => (Fields?.Count ?? 0) > 0; - public void Update(Login login) + public void Update(Cipher cipher) { - Name = login.Name?.Decrypt(login.OrganizationId); - Username = login.Username?.Decrypt(login.OrganizationId); - Password = login.Password?.Decrypt(login.OrganizationId); - Uri = login.Uri?.Decrypt(login.OrganizationId); - Notes = login.Notes?.Decrypt(login.OrganizationId); + Name = cipher.Name?.Decrypt(cipher.OrganizationId); + Username = cipher.Login?.Username?.Decrypt(cipher.OrganizationId); + Password = cipher.Login?.Password?.Decrypt(cipher.OrganizationId); + Uri = cipher.Login?.Uri?.Decrypt(cipher.OrganizationId); + Notes = cipher.Notes?.Decrypt(cipher.OrganizationId); - if(login.Attachments != null) + if(cipher.Attachments != null) { var attachments = new List(); - foreach(var attachment in login.Attachments) + foreach(var attachment in cipher.Attachments) { attachments.Add(new Attachment { Id = attachment.Id, - Name = attachment.FileName?.Decrypt(login.OrganizationId), + Name = attachment.FileName?.Decrypt(cipher.OrganizationId), SizeName = attachment.SizeName, Size = attachment.Size, Url = attachment.Url @@ -227,18 +227,18 @@ namespace Bit.App.Models.Page } else { - login.Attachments = null; + cipher.Attachments = null; } - if(login.Fields != null) + if(cipher.Fields != null) { var fields = new List(); - foreach(var field in login.Fields) + foreach(var field in cipher.Fields) { fields.Add(new Field { - Name = field.Name?.Decrypt(login.OrganizationId), - Value = field.Value?.Decrypt(login.OrganizationId), + Name = field.Name?.Decrypt(cipher.OrganizationId), + Value = field.Value?.Decrypt(cipher.OrganizationId), Type = field.Type }); } @@ -246,7 +246,7 @@ namespace Bit.App.Models.Page } else { - login.Fields = null; + cipher.Fields = null; } } diff --git a/src/App/Models/SecureNote.cs b/src/App/Models/SecureNote.cs new file mode 100644 index 000000000..d0c87882e --- /dev/null +++ b/src/App/Models/SecureNote.cs @@ -0,0 +1,15 @@ +using Bit.App.Enums; +using Bit.App.Models.Data; + +namespace Bit.App.Models +{ + public class SecureNote + { + public SecureNote(CipherData data) + { + Type = data.SecureNoteType.Value; + } + + public SecureNoteType Type { get; set; } + } +} diff --git a/src/App/Pages/Vault/VaultAddLoginPage.cs b/src/App/Pages/Vault/VaultAddLoginPage.cs index b9b01d2ef..9535ff42d 100644 --- a/src/App/Pages/Vault/VaultAddLoginPage.cs +++ b/src/App/Pages/Vault/VaultAddLoginPage.cs @@ -18,7 +18,7 @@ namespace Bit.App.Pages { private const string AddedLoginAlertKey = "addedSiteAlert"; - private readonly ILoginService _loginService; + private readonly ICipherService _cipherService; private readonly IFolderService _folderService; private readonly IUserDialogs _userDialogs; private readonly IConnectivity _connectivity; @@ -37,7 +37,7 @@ namespace Bit.App.Pages _defaultName = defaultName; _fromAutofill = fromAutofill; - _loginService = Resolver.Resolve(); + _cipherService = Resolver.Resolve(); _folderService = Resolver.Resolve(); _userDialogs = Resolver.Resolve(); _connectivity = Resolver.Resolve(); @@ -177,24 +177,31 @@ namespace Bit.App.Pages return; } - var login = new Login + var cipher = new Cipher { Name = NameCell.Entry.Text.Encrypt(), - 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(), Notes = string.IsNullOrWhiteSpace(NotesCell.Editor.Text) ? null : NotesCell.Editor.Text.Encrypt(), - Totp = string.IsNullOrWhiteSpace(TotpCell.Entry.Text) ? null : TotpCell.Entry.Text.Encrypt(), - Favorite = favoriteCell.On + 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(), + } }; if(FolderCell.Picker.SelectedIndex > 0) { - login.FolderId = folders.ElementAt(FolderCell.Picker.SelectedIndex - 1).Id; + cipher.FolderId = folders.ElementAt(FolderCell.Picker.SelectedIndex - 1).Id; } _userDialogs.ShowLoading(AppResources.Saving, MaskType.Black); - var saveTask = await _loginService.SaveAsync(login); + var saveTask = await _cipherService.SaveAsync(cipher); _userDialogs.HideLoading(); if(saveTask.Succeeded) diff --git a/src/App/Pages/Vault/VaultAttachmentsPage.cs b/src/App/Pages/Vault/VaultAttachmentsPage.cs index e352715b1..30ab36adc 100644 --- a/src/App/Pages/Vault/VaultAttachmentsPage.cs +++ b/src/App/Pages/Vault/VaultAttachmentsPage.cs @@ -17,7 +17,7 @@ namespace Bit.App.Pages { public class VaultAttachmentsPage : ExtendedContentPage { - private readonly ILoginService _loginService; + private readonly ICipherService _cipherService; private readonly IUserDialogs _userDialogs; private readonly IConnectivity _connectivity; private readonly IDeviceActionService _deviceActiveService; @@ -25,7 +25,7 @@ namespace Bit.App.Pages private readonly ITokenService _tokenService; private readonly ICryptoService _cryptoService; private readonly string _loginId; - private Login _login; + private Cipher _login; private byte[] _fileBytes; private DateTime? _lastAction; private bool _canUseAttachments = true; @@ -34,7 +34,7 @@ namespace Bit.App.Pages : base(true) { _loginId = loginId; - _loginService = Resolver.Resolve(); + _cipherService = Resolver.Resolve(); _connectivity = Resolver.Resolve(); _userDialogs = Resolver.Resolve(); _deviceActiveService = Resolver.Resolve(); @@ -162,7 +162,7 @@ namespace Bit.App.Pages } _userDialogs.ShowLoading(AppResources.Saving, MaskType.Black); - var saveTask = await _loginService.EncryptAndSaveAttachmentAsync(_login, _fileBytes, FileLabel.Text); + var saveTask = await _cipherService.EncryptAndSaveAttachmentAsync(_login, _fileBytes, FileLabel.Text); _userDialogs.HideLoading(); @@ -223,7 +223,7 @@ namespace Bit.App.Pages private async Task LoadAttachmentsAsync() { - _login = await _loginService.GetByIdAsync(_loginId); + _login = await _cipherService.GetByIdAsync(_loginId); if(_login == null) { await Navigation.PopForDeviceAsync(); @@ -268,7 +268,7 @@ namespace Bit.App.Pages } _userDialogs.ShowLoading(AppResources.Deleting, MaskType.Black); - var saveTask = await _loginService.DeleteAttachmentAsync(_login, attachment.Id); + var saveTask = await _cipherService.DeleteAttachmentAsync(_login, attachment.Id); _userDialogs.HideLoading(); if(saveTask.Succeeded) diff --git a/src/App/Pages/Vault/VaultAutofillListLoginsPage.cs b/src/App/Pages/Vault/VaultAutofillListLoginsPage.cs index 4f9a84ce9..946554f1b 100644 --- a/src/App/Pages/Vault/VaultAutofillListLoginsPage.cs +++ b/src/App/Pages/Vault/VaultAutofillListLoginsPage.cs @@ -17,7 +17,7 @@ namespace Bit.App.Pages { public class VaultAutofillListLoginsPage : ExtendedContentPage { - private readonly ILoginService _loginService; + private readonly ICipherService _cipherService; private readonly IDeviceInfoService _deviceInfoService; private readonly IDeviceActionService _clipboardService; private readonly ISettingsService _settingsService; @@ -40,7 +40,7 @@ namespace Bit.App.Pages _name = "--"; } - _loginService = Resolver.Resolve(); + _cipherService = Resolver.Resolve(); _deviceInfoService = Resolver.Resolve(); _clipboardService = Resolver.Resolve(); _settingsService = Resolver.Resolve(); @@ -162,7 +162,7 @@ namespace Bit.App.Pages Task.Run(async () => { var autofillGroupings = new List(); - var logins = await _loginService.GetAllAsync(Uri); + var logins = await _cipherService.GetAllAsync(Uri); var normalLogins = logins?.Item1.Select(l => new VaultListPageModel.AutofillLogin(l, false)) .OrderBy(s => s.Name) diff --git a/src/App/Pages/Vault/VaultCustomFieldsPage.cs b/src/App/Pages/Vault/VaultCustomFieldsPage.cs index 0b3b43ed3..ce9ec7073 100644 --- a/src/App/Pages/Vault/VaultCustomFieldsPage.cs +++ b/src/App/Pages/Vault/VaultCustomFieldsPage.cs @@ -16,19 +16,19 @@ namespace Bit.App.Pages { public class VaultCustomFieldsPage : ExtendedContentPage { - private readonly ILoginService _loginService; + private readonly ICipherService _cipherService; private readonly IUserDialogs _userDialogs; private readonly IConnectivity _connectivity; private readonly IGoogleAnalyticsService _googleAnalyticsService; private readonly string _loginId; - private Login _login; + private Cipher _login; private DateTime? _lastAction; public VaultCustomFieldsPage(string loginId) : base(true) { _loginId = loginId; - _loginService = Resolver.Resolve(); + _cipherService = Resolver.Resolve(); _connectivity = Resolver.Resolve(); _userDialogs = Resolver.Resolve(); _googleAnalyticsService = Resolver.Resolve(); @@ -114,7 +114,7 @@ namespace Bit.App.Pages } _userDialogs.ShowLoading(AppResources.Saving, MaskType.Black); - var saveTask = await _loginService.SaveAsync(_login); + var saveTask = await _cipherService.SaveAsync(_login); _userDialogs.HideLoading(); @@ -148,7 +148,7 @@ namespace Bit.App.Pages { base.OnAppearing(); - _login = await _loginService.GetByIdAsync(_loginId); + _login = await _cipherService.GetByIdAsync(_loginId); if(_login == null) { await Navigation.PopForDeviceAsync(); diff --git a/src/App/Pages/Vault/VaultEditLoginPage.cs b/src/App/Pages/Vault/VaultEditLoginPage.cs index 23104526b..b077e4be1 100644 --- a/src/App/Pages/Vault/VaultEditLoginPage.cs +++ b/src/App/Pages/Vault/VaultEditLoginPage.cs @@ -15,7 +15,7 @@ namespace Bit.App.Pages public class VaultEditLoginPage : ExtendedContentPage { private readonly string _loginId; - private readonly ILoginService _loginService; + private readonly ICipherService _cipherService; private readonly IFolderService _folderService; private readonly IUserDialogs _userDialogs; private readonly IConnectivity _connectivity; @@ -26,7 +26,7 @@ namespace Bit.App.Pages public VaultEditLoginPage(string loginId) { _loginId = loginId; - _loginService = Resolver.Resolve(); + _cipherService = Resolver.Resolve(); _folderService = Resolver.Resolve(); _userDialogs = Resolver.Resolve(); _connectivity = Resolver.Resolve(); @@ -50,8 +50,8 @@ namespace Bit.App.Pages private void Init() { - var login = _loginService.GetByIdAsync(_loginId).GetAwaiter().GetResult(); - if(login == null) + var cipher = _cipherService.GetByIdAsync(_loginId).GetAwaiter().GetResult(); + if(cipher == null) { // TODO: handle error. navigate back? should never happen... return; @@ -59,7 +59,7 @@ namespace Bit.App.Pages NotesCell = new FormEditorCell(height: 300); NotesCell.Editor.Keyboard = Keyboard.Text; - NotesCell.Editor.Text = login.Notes?.Decrypt(login.OrganizationId); + NotesCell.Editor.Text = cipher.Notes?.Decrypt(cipher.OrganizationId); TotpCell = new FormEntryCell(AppResources.AuthenticatorKey, nextElement: NotesCell.Editor, useButton: _deviceInfo.HasCamera); @@ -67,28 +67,28 @@ namespace Bit.App.Pages { TotpCell.Button.Image = "camera"; } - TotpCell.Entry.Text = login.Totp?.Decrypt(login.OrganizationId); + TotpCell.Entry.Text = cipher.Login?.Totp?.Decrypt(cipher.OrganizationId); 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.Entry.Text = login.Password?.Decrypt(login.OrganizationId); + PasswordCell.Entry.Text = cipher.Login?.Password?.Decrypt(cipher.OrganizationId); 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.Text = login.Username?.Decrypt(login.OrganizationId); + UsernameCell.Entry.Text = cipher.Login?.Username?.Decrypt(cipher.OrganizationId); UsernameCell.Entry.DisableAutocapitalize = true; UsernameCell.Entry.Autocorrect = false; UriCell = new FormEntryCell(AppResources.URI, Keyboard.Url, nextElement: UsernameCell.Entry); - UriCell.Entry.Text = login.Uri?.Decrypt(login.OrganizationId); + UriCell.Entry.Text = cipher.Login?.Uri?.Decrypt(cipher.OrganizationId); NameCell = new FormEntryCell(AppResources.Name, nextElement: UriCell.Entry); - NameCell.Entry.Text = login.Name?.Decrypt(login.OrganizationId); + NameCell.Entry.Text = cipher.Name?.Decrypt(cipher.OrganizationId); GenerateCell = new ExtendedTextCell { @@ -104,7 +104,7 @@ namespace Bit.App.Pages foreach(var folder in folders) { i++; - if(folder.Id == login.FolderId) + if(folder.Id == cipher.FolderId) { selectedIndex = i; } @@ -117,7 +117,7 @@ namespace Bit.App.Pages var favoriteCell = new ExtendedSwitchCell { Text = AppResources.Favorite, - On = login.Favorite + On = cipher.Favorite }; AttachmentsCell = new ExtendedTextCell @@ -204,30 +204,34 @@ namespace Bit.App.Pages return; } - login.Name = NameCell.Entry.Text.Encrypt(login.OrganizationId); - login.Uri = string.IsNullOrWhiteSpace(UriCell.Entry.Text) ? null : - UriCell.Entry.Text.Encrypt(login.OrganizationId); - login.Username = string.IsNullOrWhiteSpace(UsernameCell.Entry.Text) ? null : - UsernameCell.Entry.Text.Encrypt(login.OrganizationId); - login.Password = string.IsNullOrWhiteSpace(PasswordCell.Entry.Text) ? null : - PasswordCell.Entry.Text.Encrypt(login.OrganizationId); - login.Notes = string.IsNullOrWhiteSpace(NotesCell.Editor.Text) ? null : - NotesCell.Editor.Text.Encrypt(login.OrganizationId); - login.Totp = string.IsNullOrWhiteSpace(TotpCell.Entry.Text) ? null : - TotpCell.Entry.Text.Encrypt(login.OrganizationId); - login.Favorite = favoriteCell.On; + cipher.Name = NameCell.Entry.Text.Encrypt(cipher.OrganizationId); + cipher.Notes = string.IsNullOrWhiteSpace(NotesCell.Editor.Text) ? null : + NotesCell.Editor.Text.Encrypt(cipher.OrganizationId); + cipher.Favorite = favoriteCell.On; + + cipher.Login = new Models.Login + { + Uri = string.IsNullOrWhiteSpace(UriCell.Entry.Text) ? null : + UriCell.Entry.Text.Encrypt(cipher.OrganizationId), + Username = string.IsNullOrWhiteSpace(UsernameCell.Entry.Text) ? null : + UsernameCell.Entry.Text.Encrypt(cipher.OrganizationId), + Password = string.IsNullOrWhiteSpace(PasswordCell.Entry.Text) ? null : + PasswordCell.Entry.Text.Encrypt(cipher.OrganizationId), + Totp = string.IsNullOrWhiteSpace(TotpCell.Entry.Text) ? null : + TotpCell.Entry.Text.Encrypt(cipher.OrganizationId) + }; if(FolderCell.Picker.SelectedIndex > 0) { - login.FolderId = folders.ElementAt(FolderCell.Picker.SelectedIndex - 1).Id; + cipher.FolderId = folders.ElementAt(FolderCell.Picker.SelectedIndex - 1).Id; } else { - login.FolderId = null; + cipher.FolderId = null; } _userDialogs.ShowLoading(AppResources.Saving, MaskType.Black); - var saveTask = await _loginService.SaveAsync(login); + var saveTask = await _cipherService.SaveAsync(cipher); _userDialogs.HideLoading(); @@ -405,7 +409,7 @@ namespace Bit.App.Pages } _userDialogs.ShowLoading(AppResources.Deleting, MaskType.Black); - var deleteTask = await _loginService.DeleteAsync(_loginId); + var deleteTask = await _cipherService.DeleteAsync(_loginId); _userDialogs.HideLoading(); if(deleteTask.Succeeded) diff --git a/src/App/Pages/Vault/VaultListLoginsPage.cs b/src/App/Pages/Vault/VaultListLoginsPage.cs index 16e8a2b7e..7b3006928 100644 --- a/src/App/Pages/Vault/VaultListLoginsPage.cs +++ b/src/App/Pages/Vault/VaultListLoginsPage.cs @@ -20,7 +20,7 @@ namespace Bit.App.Pages public class VaultListLoginsPage : ExtendedContentPage { private readonly IFolderService _folderService; - private readonly ILoginService _loginService; + private readonly ICipherService _cipherService; private readonly IUserDialogs _userDialogs; private readonly IConnectivity _connectivity; private readonly IDeviceActionService _clipboardService; @@ -37,7 +37,7 @@ namespace Bit.App.Pages { _favorites = favorites; _folderService = Resolver.Resolve(); - _loginService = Resolver.Resolve(); + _cipherService = Resolver.Resolve(); _connectivity = Resolver.Resolve(); _userDialogs = Resolver.Resolve(); _clipboardService = Resolver.Resolve(); @@ -310,7 +310,7 @@ namespace Bit.App.Pages Task.Run(async () => { var foldersTask = _folderService.GetAllAsync(); - var loginsTask = _favorites ? _loginService.GetAllAsync(true) : _loginService.GetAllAsync(); + var loginsTask = _favorites ? _cipherService.GetAllAsync(true) : _cipherService.GetAllAsync(); await Task.WhenAll(foldersTask, loginsTask); var folders = await foldersTask; diff --git a/src/App/Pages/Vault/VaultViewLoginPage.cs b/src/App/Pages/Vault/VaultViewLoginPage.cs index 34e4eb675..d60ce7955 100644 --- a/src/App/Pages/Vault/VaultViewLoginPage.cs +++ b/src/App/Pages/Vault/VaultViewLoginPage.cs @@ -18,7 +18,7 @@ namespace Bit.App.Pages public class VaultViewLoginPage : ExtendedContentPage { private readonly string _loginId; - private readonly ILoginService _loginService; + private readonly ICipherService _cipherService; private readonly IUserDialogs _userDialogs; private readonly IDeviceActionService _deviceActionService; private readonly ITokenService _tokenService; @@ -27,7 +27,7 @@ namespace Bit.App.Pages public VaultViewLoginPage(string loginId) { _loginId = loginId; - _loginService = Resolver.Resolve(); + _cipherService = Resolver.Resolve(); _userDialogs = Resolver.Resolve(); _deviceActionService = Resolver.Resolve(); _tokenService = Resolver.Resolve(); @@ -161,14 +161,14 @@ namespace Bit.App.Pages NotesCell.Tapped += NotesCell_Tapped; EditItem.InitEvents(); - var login = await _loginService.GetByIdAsync(_loginId); - if(login == null) + var cipher = await _cipherService.GetByIdAsync(_loginId); + if(cipher == null) { await Navigation.PopForDeviceAsync(); return; } - Model.Update(login); + Model.Update(cipher); if(LoginInformationSection.Contains(UriCell)) { @@ -211,9 +211,9 @@ namespace Bit.App.Pages { LoginInformationSection.Remove(TotpCodeCell); } - if(login.Totp != null && (_tokenService.TokenPremium || login.OrganizationUseTotp)) + if(cipher.Login?.Totp != null && (_tokenService.TokenPremium || cipher.OrganizationUseTotp)) { - var totpKey = login.Totp.Decrypt(login.OrganizationId); + var totpKey = cipher.Login?.Totp.Decrypt(cipher.OrganizationId); if(!string.IsNullOrWhiteSpace(totpKey)) { Model.TotpCode = Crypto.Totp(totpKey); @@ -249,7 +249,7 @@ namespace Bit.App.Pages { var attachmentCell = new AttachmentViewCell(attachment, async () => { - await OpenAttachmentAsync(login, attachment); + await OpenAttachmentAsync(cipher, attachment); }); AttachmentCells.Add(attachmentCell); AttachmentsSection.Add(attachmentCell); @@ -309,7 +309,7 @@ namespace Bit.App.Pages } } - private async Task OpenAttachmentAsync(Login login, VaultViewLoginPageModel.Attachment attachment) + private async Task OpenAttachmentAsync(Cipher login, VaultViewLoginPageModel.Attachment attachment) { if(!_tokenService.TokenPremium && !login.OrganizationUseTotp) { @@ -332,7 +332,7 @@ namespace Bit.App.Pages } _userDialogs.ShowLoading(AppResources.Downloading, MaskType.Black); - var data = await _loginService.DownloadAndDecryptAttachmentAsync(attachment.Url, login.OrganizationId); + var data = await _cipherService.DownloadAndDecryptAttachmentAsync(attachment.Url, login.OrganizationId); _userDialogs.HideLoading(); if(data == null) { diff --git a/src/App/Repositories/AttachmentRepository.cs b/src/App/Repositories/AttachmentRepository.cs index 41166640d..36b4f732a 100644 --- a/src/App/Repositories/AttachmentRepository.cs +++ b/src/App/Repositories/AttachmentRepository.cs @@ -13,9 +13,10 @@ namespace Bit.App.Repositories : base(sqlService) { } - public Task> GetAllByLoginIdAsync(string loginId) + public Task> GetAllByCipherIdAsync(string cipherId) { - var attachments = Connection.Table().Where(a => a.LoginId == loginId).Cast(); + var attachments = Connection.Table().Where(a => a.LoginId == cipherId) + .Cast(); return Task.FromResult(attachments); } diff --git a/src/App/Repositories/CipherRepository.cs b/src/App/Repositories/CipherRepository.cs new file mode 100644 index 000000000..bb2f7d417 --- /dev/null +++ b/src/App/Repositories/CipherRepository.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Bit.App.Abstractions; +using Bit.App.Models.Data; + +namespace Bit.App.Repositories +{ + public class CipherRepository : Repository, ICipherRepository + { + public CipherRepository(ISqlService sqlService) + : base(sqlService) + { } + + public Task> GetAllByUserIdAsync(string userId) + { + var logins = Connection.Table().Where(l => l.UserId == userId).Cast(); + return Task.FromResult(logins); + } + + public Task> GetAllByUserIdAsync(string userId, bool favorite) + { + var logins = Connection.Table().Where(l => l.UserId == userId && l.Favorite == favorite) + .Cast(); + return Task.FromResult(logins); + } + } +} diff --git a/src/App/Repositories/FolderRepository.cs b/src/App/Repositories/FolderRepository.cs index 4ae3b87b7..6af7d9cf3 100644 --- a/src/App/Repositories/FolderRepository.cs +++ b/src/App/Repositories/FolderRepository.cs @@ -22,11 +22,11 @@ namespace Bit.App.Repositories public override Task DeleteAsync(string id) { var now = DateTime.UtcNow; - DeleteWithLoginUpdateAsync(id, now); + DeleteWithCipherUpdateAsync(id, now); return Task.FromResult(0); } - public Task DeleteWithLoginUpdateAsync(string id, DateTime revisionDate) + public Task DeleteWithCipherUpdateAsync(string id, DateTime revisionDate) { Connection.RunInTransaction(() => { diff --git a/src/App/Repositories/LoginRepository.cs b/src/App/Repositories/LoginRepository.cs deleted file mode 100644 index 1e462803f..000000000 --- a/src/App/Repositories/LoginRepository.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Bit.App.Abstractions; -using Bit.App.Models.Data; - -namespace Bit.App.Repositories -{ - public class LoginRepository : Repository, ILoginRepository - { - public LoginRepository(ISqlService sqlService) - : base(sqlService) - { } - - public Task> GetAllByUserIdAsync(string userId) - { - var logins = Connection.Table().Where(l => l.UserId == userId).Cast(); - return Task.FromResult(logins); - } - - public Task> GetAllByUserIdAsync(string userId, bool favorite) - { - var logins = Connection.Table().Where(l => l.UserId == userId && l.Favorite == favorite) - .Cast(); - return Task.FromResult(logins); - } - } -} diff --git a/src/App/Services/LoginService.cs b/src/App/Services/CipherService.cs similarity index 85% rename from src/App/Services/LoginService.cs rename to src/App/Services/CipherService.cs index 4896ca50f..c4f1b7417 100644 --- a/src/App/Services/LoginService.cs +++ b/src/App/Services/CipherService.cs @@ -11,26 +11,26 @@ using System.Net.Http; namespace Bit.App.Services { - public class LoginService : ILoginService + public class CipherService : ICipherService { private readonly string[] _ignoredSearchTerms = new string[] { "com", "net", "org", "android", "io", "co", "uk", "au", "nz", "fr", "de", "tv", "info", "app", "apps", "eu", "me", "dev", "jp", "mobile" }; - private readonly ILoginRepository _loginRepository; + private readonly ICipherRepository _cipherRepository; private readonly IAttachmentRepository _attachmentRepository; private readonly IAuthService _authService; private readonly ICipherApiRepository _cipherApiRepository; private readonly ISettingsService _settingsService; private readonly ICryptoService _cryptoService; - public LoginService( - ILoginRepository loginRepository, + public CipherService( + ICipherRepository cipherRepository, IAttachmentRepository attachmentRepository, IAuthService authService, ICipherApiRepository cipherApiRepository, ISettingsService settingsService, ICryptoService cryptoService) { - _loginRepository = loginRepository; + _cipherRepository = cipherRepository; _attachmentRepository = attachmentRepository; _authService = authService; _cipherApiRepository = cipherApiRepository; @@ -38,38 +38,38 @@ namespace Bit.App.Services _cryptoService = cryptoService; } - public async Task GetByIdAsync(string id) + public async Task GetByIdAsync(string id) { - var data = await _loginRepository.GetByIdAsync(id); + var data = await _cipherRepository.GetByIdAsync(id); if(data == null || data.UserId != _authService.UserId) { return null; } - var attachments = await _attachmentRepository.GetAllByLoginIdAsync(id); - var login = new Login(data, attachments); - return login; + var attachments = await _attachmentRepository.GetAllByCipherIdAsync(id); + var cipher = new Cipher(data, attachments); + return cipher; } - public async Task> GetAllAsync() + public async Task> GetAllAsync() { var attachmentData = await _attachmentRepository.GetAllByUserIdAsync(_authService.UserId); var attachmentDict = attachmentData.GroupBy(a => a.LoginId).ToDictionary(g => g.Key, g => g.ToList()); - var data = await _loginRepository.GetAllByUserIdAsync(_authService.UserId); - var logins = data.Select(f => new Login(f, attachmentDict.ContainsKey(f.Id) ? attachmentDict[f.Id] : null)); + var data = await _cipherRepository.GetAllByUserIdAsync(_authService.UserId); + var logins = data.Select(f => new Cipher(f, attachmentDict.ContainsKey(f.Id) ? attachmentDict[f.Id] : null)); return logins; } - public async Task> GetAllAsync(bool favorites) + public async Task> GetAllAsync(bool favorites) { var attachmentData = await _attachmentRepository.GetAllByUserIdAsync(_authService.UserId); var attachmentDict = attachmentData.GroupBy(a => a.LoginId).ToDictionary(g => g.Key, g => g.ToList()); - var data = await _loginRepository.GetAllByUserIdAsync(_authService.UserId, favorites); - var logins = data.Select(f => new Login(f, attachmentDict.ContainsKey(f.Id) ? attachmentDict[f.Id] : null)); + var data = await _cipherRepository.GetAllByUserIdAsync(_authService.UserId, favorites); + var logins = data.Select(f => new Cipher(f, attachmentDict.ContainsKey(f.Id) ? attachmentDict[f.Id] : null)); return logins; } - public async Task, IEnumerable>> GetAllAsync(string uriString) + public async Task, IEnumerable>> GetAllAsync(string uriString) { if(string.IsNullOrWhiteSpace(uriString)) { @@ -125,9 +125,9 @@ namespace Bit.App.Services var matchingDomainsArray = matchingDomains.ToArray(); var matchingFuzzyDomainsArray = matchingFuzzyDomains.ToArray(); - var matchingLogins = new List(); - var matchingFuzzyLogins = new List(); - var logins = await _loginRepository.GetAllByUserIdAsync(_authService.UserId); + var matchingLogins = new List(); + var matchingFuzzyLogins = new List(); + var logins = await _cipherRepository.GetAllByUserIdAsync(_authService.UserId); foreach(var login in logins) { if(string.IsNullOrWhiteSpace(login.Uri)) @@ -143,12 +143,12 @@ namespace Bit.App.Services if(Array.IndexOf(matchingDomainsArray, loginUriString) >= 0) { - matchingLogins.Add(new Login(login)); + matchingLogins.Add(new Cipher(login)); continue; } else if(mobileApp && Array.IndexOf(matchingFuzzyDomainsArray, loginUriString) >= 0) { - matchingFuzzyLogins.Add(new Login(login)); + matchingFuzzyLogins.Add(new Cipher(login)); continue; } else if(!mobileApp) @@ -156,7 +156,7 @@ namespace Bit.App.Services var info = InfoFromMobileAppUri(loginUriString); if(info?.Item1 != null && Array.IndexOf(matchingDomainsArray, info.Item1) >= 0) { - matchingFuzzyLogins.Add(new Login(login)); + matchingFuzzyLogins.Add(new Cipher(login)); continue; } } @@ -170,12 +170,12 @@ namespace Bit.App.Services if(Array.IndexOf(matchingDomainsArray, loginDomainName) >= 0) { - matchingLogins.Add(new Login(login)); + matchingLogins.Add(new Cipher(login)); continue; } else if(mobileApp && Array.IndexOf(matchingFuzzyDomainsArray, loginDomainName) >= 0) { - matchingFuzzyLogins.Add(new Login(login)); + matchingFuzzyLogins.Add(new Cipher(login)); continue; } } @@ -197,7 +197,7 @@ namespace Bit.App.Services if(addedFromSearchTerm) { - matchingFuzzyLogins.Add(new Login(login)); + matchingFuzzyLogins.Add(new Cipher(login)); break; } } @@ -209,10 +209,10 @@ namespace Bit.App.Services } } - return new Tuple, IEnumerable>(matchingLogins, matchingFuzzyLogins); + return new Tuple, IEnumerable>(matchingLogins, matchingFuzzyLogins); } - public async Task> SaveAsync(Login login) + public async Task> SaveAsync(Cipher login) { ApiResult response = null; var request = new CipherRequest(login); @@ -228,15 +228,15 @@ namespace Bit.App.Services if(response.Succeeded) { - var data = new LoginData(response.Result, _authService.UserId); + var data = new CipherData(response.Result, _authService.UserId); if(login.Id == null) { - await _loginRepository.InsertAsync(data); + await _cipherRepository.InsertAsync(data); login.Id = data.Id; } else { - await _loginRepository.UpdateAsync(data); + await _cipherRepository.UpdateAsync(data); } } else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden @@ -253,7 +253,7 @@ namespace Bit.App.Services var response = await _cipherApiRepository.DeleteAsync(id); if(response.Succeeded) { - await _loginRepository.DeleteAsync(id); + await _cipherRepository.DeleteAsync(id); } else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden || response.StatusCode == System.Net.HttpStatusCode.Unauthorized) @@ -298,7 +298,7 @@ namespace Bit.App.Services } } - public async Task> EncryptAndSaveAttachmentAsync(Login login, byte[] data, string fileName) + public async Task> EncryptAndSaveAttachmentAsync(Cipher login, byte[] data, string fileName) { var encFileName = fileName.Encrypt(login.OrganizationId); var encBytes = _cryptoService.EncryptToBytes(data, @@ -323,7 +323,7 @@ namespace Bit.App.Services return response; } - public async Task DeleteAttachmentAsync(Login login, string attachmentId) + public async Task DeleteAttachmentAsync(Cipher login, string attachmentId) { var response = await _cipherApiRepository.DeleteAttachmentAsync(login.Id, attachmentId); if(response.Succeeded) diff --git a/src/App/Services/DatabaseService.cs b/src/App/Services/DatabaseService.cs index bc03aef43..578a610f4 100644 --- a/src/App/Services/DatabaseService.cs +++ b/src/App/Services/DatabaseService.cs @@ -17,7 +17,7 @@ namespace Bit.App.Services public void CreateTables() { _connection.CreateTable(); - _connection.CreateTable(); + _connection.CreateTable(); _connection.CreateTable(); _connection.CreateTable(); } diff --git a/src/App/Services/PushNotificationListener.cs b/src/App/Services/PushNotificationListener.cs index 07eda012e..0aaf8e99c 100644 --- a/src/App/Services/PushNotificationListener.cs +++ b/src/App/Services/PushNotificationListener.cs @@ -110,7 +110,7 @@ namespace Bit.App.Services { break; } - _syncService.SyncDeleteLoginAsync(loginDeleteMessage.Id); + _syncService.SyncDeleteCipherAsync(loginDeleteMessage.Id); break; case Enums.PushType.SyncCiphers: case Enums.PushType.SyncVault: diff --git a/src/App/Services/SyncService.cs b/src/App/Services/SyncService.cs index d4f085de2..ae3f6ffdc 100644 --- a/src/App/Services/SyncService.cs +++ b/src/App/Services/SyncService.cs @@ -20,7 +20,7 @@ namespace Bit.App.Services private readonly ISettingsApiRepository _settingsApiRepository; private readonly ISyncApiRepository _syncApiRepository; private readonly IFolderRepository _folderRepository; - private readonly ILoginRepository _loginRepository; + private readonly ICipherRepository _cipherRepository; private readonly IAttachmentRepository _attachmentRepository; private readonly ISettingsRepository _settingsRepository; private readonly IAuthService _authService; @@ -35,7 +35,7 @@ namespace Bit.App.Services ISettingsApiRepository settingsApiRepository, ISyncApiRepository syncApiRepository, IFolderRepository folderRepository, - ILoginRepository loginRepository, + ICipherRepository cipherRepository, IAttachmentRepository attachmentRepository, ISettingsRepository settingsRepository, IAuthService authService, @@ -49,7 +49,7 @@ namespace Bit.App.Services _settingsApiRepository = settingsApiRepository; _syncApiRepository = syncApiRepository; _folderRepository = folderRepository; - _loginRepository = loginRepository; + _cipherRepository = cipherRepository; _attachmentRepository = attachmentRepository; _settingsRepository = settingsRepository; _authService = authService; @@ -77,40 +77,32 @@ namespace Bit.App.Services try { - switch(cipher.Result.Type) + var cipherData = new CipherData(cipher.Result, _authService.UserId); + await _cipherRepository.UpsertAsync(cipherData).ConfigureAwait(false); + + var localAttachments = (await _attachmentRepository.GetAllByCipherIdAsync(cipherData.Id) + .ConfigureAwait(false)); + + if(cipher.Result.Attachments != null) { - case Enums.CipherType.Login: - var loginData = new LoginData(cipher.Result, _authService.UserId); - await _loginRepository.UpsertAsync(loginData).ConfigureAwait(false); + foreach(var attachment in cipher.Result.Attachments) + { + var attachmentData = new AttachmentData(attachment, cipherData.Id); + await _attachmentRepository.UpsertAsync(attachmentData).ConfigureAwait(false); + } + } - var localAttachments = (await _attachmentRepository.GetAllByLoginIdAsync(loginData.Id) - .ConfigureAwait(false)); - - if(cipher.Result.Attachments != null) + if(localAttachments != null) + { + foreach(var attachment in localAttachments + .Where(a => !cipher.Result.Attachments.Any(sa => sa.Id == a.Id))) + { + try { - foreach(var attachment in cipher.Result.Attachments) - { - var attachmentData = new AttachmentData(attachment, loginData.Id); - await _attachmentRepository.UpsertAsync(attachmentData).ConfigureAwait(false); - } + await _attachmentRepository.DeleteAsync(attachment.Id).ConfigureAwait(false); } - - if(localAttachments != null) - { - foreach(var attachment in localAttachments - .Where(a => !cipher.Result.Attachments.Any(sa => sa.Id == a.Id))) - { - try - { - await _attachmentRepository.DeleteAsync(attachment.Id).ConfigureAwait(false); - } - catch(SQLite.SQLiteException) { } - } - } - break; - default: - SyncCompleted(false); - return false; + catch(SQLite.SQLiteException) { } + } } } catch(SQLite.SQLiteException) @@ -164,7 +156,7 @@ namespace Bit.App.Services try { - await _folderRepository.DeleteWithLoginUpdateAsync(id, revisionDate).ConfigureAwait(false); + await _folderRepository.DeleteWithCipherUpdateAsync(id, revisionDate).ConfigureAwait(false); SyncCompleted(true); return true; } @@ -175,7 +167,7 @@ namespace Bit.App.Services } } - public async Task SyncDeleteLoginAsync(string id) + public async Task SyncDeleteCipherAsync(string id) { if(!_authService.IsAuthenticated) { @@ -186,7 +178,7 @@ namespace Bit.App.Services try { - await _loginRepository.DeleteAsync(id).ConfigureAwait(false); + await _cipherRepository.DeleteAsync(id).ConfigureAwait(false); SyncCompleted(true); return true; } @@ -277,17 +269,16 @@ namespace Bit.App.Services return false; } - var loginsDict = syncResponse.Result.Ciphers.Where(c => c.Type == Enums.CipherType.Login) - .ToDictionary(s => s.Id); + var ciphersDict = syncResponse.Result.Ciphers.ToDictionary(s => s.Id); var foldersDict = syncResponse.Result.Folders.ToDictionary(f => f.Id); - var loginTask = SyncLoginsAsync(loginsDict); + var cipherTask = SyncCiphersAsync(ciphersDict); var folderTask = SyncFoldersAsync(foldersDict); var domainsTask = SyncDomainsAsync(syncResponse.Result.Domains); var profileTask = SyncProfileKeysAsync(syncResponse.Result.Profile); - await Task.WhenAll(loginTask, folderTask, domainsTask, profileTask).ConfigureAwait(false); + await Task.WhenAll(cipherTask, folderTask, domainsTask, profileTask).ConfigureAwait(false); - if(folderTask.Exception != null || loginTask.Exception != null || domainsTask.Exception != null || + if(folderTask.Exception != null || cipherTask.Exception != null || domainsTask.Exception != null || profileTask.Exception != null) { SyncCompleted(false); @@ -361,14 +352,14 @@ namespace Bit.App.Services } } - private async Task SyncLoginsAsync(IDictionary serverLogins) + private async Task SyncCiphersAsync(IDictionary serviceCiphers) { if(!_authService.IsAuthenticated) { return; } - var localLogins = (await _loginRepository.GetAllByUserIdAsync(_authService.UserId) + var localCiphers = (await _cipherRepository.GetAllByUserIdAsync(_authService.UserId) .ConfigureAwait(false)) .GroupBy(s => s.Id) .Select(s => s.First()) @@ -379,7 +370,7 @@ namespace Bit.App.Services .GroupBy(a => a.LoginId) .ToDictionary(g => g.Key); - foreach(var serverLogin in serverLogins) + foreach(var serverCipher in serviceCiphers) { if(!_authService.IsAuthenticated) { @@ -388,24 +379,25 @@ namespace Bit.App.Services try { - var localLogin = localLogins.ContainsKey(serverLogin.Value.Id) ? localLogins[serverLogin.Value.Id] : null; + var localCipher = localCiphers.ContainsKey(serverCipher.Value.Id) ? + localCiphers[serverCipher.Value.Id] : null; - var data = new LoginData(serverLogin.Value, _authService.UserId); - await _loginRepository.UpsertAsync(data).ConfigureAwait(false); + var data = new CipherData(serverCipher.Value, _authService.UserId); + await _cipherRepository.UpsertAsync(data).ConfigureAwait(false); - if(serverLogin.Value.Attachments != null) + if(serverCipher.Value.Attachments != null) { - foreach(var attachment in serverLogin.Value.Attachments) + foreach(var attachment in serverCipher.Value.Attachments) { var attachmentData = new AttachmentData(attachment, data.Id); await _attachmentRepository.UpsertAsync(attachmentData).ConfigureAwait(false); } } - if(localLogin != null && localAttachments != null && localAttachments.ContainsKey(localLogin.Id)) + if(localCipher != null && localAttachments != null && localAttachments.ContainsKey(localCipher.Id)) { - foreach(var attachment in localAttachments[localLogin.Id] - .Where(a => !serverLogin.Value.Attachments.Any(sa => sa.Id == a.Id))) + foreach(var attachment in localAttachments[localCipher.Id] + .Where(a => !serverCipher.Value.Attachments.Any(sa => sa.Id == a.Id))) { try { @@ -418,11 +410,11 @@ namespace Bit.App.Services catch(SQLite.SQLiteException) { } } - foreach(var login in localLogins.Where(localLogin => !serverLogins.ContainsKey(localLogin.Key))) + foreach(var cipher in localCiphers.Where(local => !serviceCiphers.ContainsKey(local.Key))) { try { - await _loginRepository.DeleteAsync(login.Value.Id).ConfigureAwait(false); + await _cipherRepository.DeleteAsync(cipher.Value.Id).ConfigureAwait(false); } catch(SQLite.SQLiteException) { } } diff --git a/src/UWP/App.xaml.cs b/src/UWP/App.xaml.cs index cab38e814..658a5551b 100644 --- a/src/UWP/App.xaml.cs +++ b/src/UWP/App.xaml.cs @@ -88,7 +88,7 @@ namespace Bit.UWP container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); - container.RegisterSingleton(); + container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); @@ -108,7 +108,7 @@ namespace Bit.UWP // Repositories container.RegisterSingleton(); container.RegisterSingleton(); - container.RegisterSingleton(); + container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); diff --git a/src/iOS.Extension/LoadingViewController.cs b/src/iOS.Extension/LoadingViewController.cs index 3433461bc..fe5058246 100644 --- a/src/iOS.Extension/LoadingViewController.cs +++ b/src/iOS.Extension/LoadingViewController.cs @@ -277,7 +277,7 @@ namespace Bit.iOS.Extension container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); - container.RegisterSingleton(); + container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); @@ -294,7 +294,7 @@ namespace Bit.iOS.Extension // Repositories container.RegisterSingleton(); container.RegisterSingleton(); - container.RegisterSingleton(); + container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); diff --git a/src/iOS.Extension/LoginAddViewController.cs b/src/iOS.Extension/LoginAddViewController.cs index a5cc108a5..42f1ca61b 100644 --- a/src/iOS.Extension/LoginAddViewController.cs +++ b/src/iOS.Extension/LoginAddViewController.cs @@ -19,7 +19,7 @@ namespace Bit.iOS.Extension { public partial class LoginAddViewController : ExtendedUITableViewController { - private ILoginService _loginService; + private ICipherService _cipherService; private IFolderService _folderService; private IConnectivity _connectivity; private IEnumerable _folders; @@ -49,7 +49,7 @@ namespace Bit.iOS.Extension public override void ViewDidLoad() { - _loginService = Resolver.Resolve(); + _cipherService = Resolver.Resolve(); _connectivity = Resolver.Resolve(); _folderService = Resolver.Resolve(); _googleAnalyticsService = Resolver.Resolve(); @@ -151,18 +151,21 @@ namespace Bit.iOS.Extension return; } - var login = new Login + var cipher = new Cipher { - Uri = string.IsNullOrWhiteSpace(UriCell.TextField.Text) ? null : UriCell.TextField.Text.Encrypt(), Name = string.IsNullOrWhiteSpace(NameCell.TextField.Text) ? null : NameCell.TextField.Text.Encrypt(), - Username = string.IsNullOrWhiteSpace(UsernameCell.TextField.Text) ? null : UsernameCell.TextField.Text.Encrypt(), - Password = string.IsNullOrWhiteSpace(PasswordCell.TextField.Text) ? null : PasswordCell.TextField.Text.Encrypt(), Notes = string.IsNullOrWhiteSpace(NotesCell.TextView.Text) ? null : NotesCell.TextView.Text.Encrypt(), Favorite = FavoriteCell.Switch.On, - FolderId = FolderCell.SelectedIndex == 0 ? null : _folders.ElementAtOrDefault(FolderCell.SelectedIndex - 1)?.Id + FolderId = FolderCell.SelectedIndex == 0 ? null : _folders.ElementAtOrDefault(FolderCell.SelectedIndex - 1)?.Id, + Login = new Login + { + Uri = string.IsNullOrWhiteSpace(UriCell.TextField.Text) ? null : UriCell.TextField.Text.Encrypt(), + Username = string.IsNullOrWhiteSpace(UsernameCell.TextField.Text) ? null : UsernameCell.TextField.Text.Encrypt(), + Password = string.IsNullOrWhiteSpace(PasswordCell.TextField.Text) ? null : PasswordCell.TextField.Text.Encrypt() + } }; - var saveTask = _loginService.SaveAsync(login); + var saveTask = _cipherService.SaveAsync(cipher); var loadingAlert = Dialogs.CreateLoadingAlert(AppResources.Saving); PresentViewController(loadingAlert, true, null); await saveTask; diff --git a/src/iOS.Extension/LoginListViewController.cs b/src/iOS.Extension/LoginListViewController.cs index 62fd39081..a091bd4fd 100644 --- a/src/iOS.Extension/LoginListViewController.cs +++ b/src/iOS.Extension/LoginListViewController.cs @@ -105,7 +105,7 @@ namespace Bit.iOS.Extension private IEnumerable _tableItems = new List(); private Context _context; private LoginListViewController _controller; - private ILoginService _loginService; + private ICipherService _cipherService; private ISettings _settings; private bool _isPremium; @@ -114,15 +114,15 @@ namespace Bit.iOS.Extension _context = controller.Context; _controller = controller; _isPremium = Resolver.Resolve()?.TokenPremium ?? false; - _loginService = Resolver.Resolve(); + _cipherService = Resolver.Resolve(); _settings = Resolver.Resolve(); } public async Task LoadItemsAsync() { - var combinedLogins = new List(); + var combinedLogins = new List(); - var logins = await _loginService.GetAllAsync(_context.UrlString); + var logins = await _cipherService.GetAllAsync(_context.UrlString); if(logins?.Item1 != null) { combinedLogins.AddRange(logins.Item1); diff --git a/src/iOS.Extension/Models/LoginViewModel.cs b/src/iOS.Extension/Models/LoginViewModel.cs index 319002dc4..72a40254a 100644 --- a/src/iOS.Extension/Models/LoginViewModel.cs +++ b/src/iOS.Extension/Models/LoginViewModel.cs @@ -7,7 +7,7 @@ namespace Bit.iOS.Extension.Models { public class LoginViewModel { - public LoginViewModel(Login login) + public LoginViewModel(Cipher login) { Id = login.Id; Name = login.Name?.Decrypt(login.OrganizationId); diff --git a/src/iOS/AppDelegate.cs b/src/iOS/AppDelegate.cs index c3d6353d7..1a72e4b6a 100644 --- a/src/iOS/AppDelegate.cs +++ b/src/iOS/AppDelegate.cs @@ -256,7 +256,7 @@ namespace Bit.iOS container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); - container.RegisterSingleton(); + container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); @@ -276,7 +276,7 @@ namespace Bit.iOS // Repositories container.RegisterSingleton(); container.RegisterSingleton(); - container.RegisterSingleton(); + container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterSingleton();