refactoring code for login => cipher support

This commit is contained in:
Kyle Spearrin 2017-10-18 20:55:33 -04:00
parent 37f05f0a12
commit 1d6ec0f953
46 changed files with 731 additions and 410 deletions

View file

@ -195,7 +195,7 @@ namespace Bit.Android
container.RegisterSingleton<IKeyDerivationService, BouncyCastleKeyDerivationService>(); container.RegisterSingleton<IKeyDerivationService, BouncyCastleKeyDerivationService>();
container.RegisterSingleton<IAuthService, AuthService>(); container.RegisterSingleton<IAuthService, AuthService>();
container.RegisterSingleton<IFolderService, FolderService>(); container.RegisterSingleton<IFolderService, FolderService>();
container.RegisterSingleton<ILoginService, LoginService>(); container.RegisterSingleton<ICipherService, CipherService>();
container.RegisterSingleton<ISyncService, SyncService>(); container.RegisterSingleton<ISyncService, SyncService>();
container.RegisterSingleton<IDeviceActionService, DeviceActionService>(); container.RegisterSingleton<IDeviceActionService, DeviceActionService>();
container.RegisterSingleton<IAppIdService, AppIdService>(); container.RegisterSingleton<IAppIdService, AppIdService>();
@ -216,7 +216,7 @@ namespace Bit.Android
// Repositories // Repositories
container.RegisterSingleton<IFolderRepository, FolderRepository>(); container.RegisterSingleton<IFolderRepository, FolderRepository>();
container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>(); container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>();
container.RegisterSingleton<ILoginRepository, LoginRepository>(); container.RegisterSingleton<ICipherRepository, CipherRepository>();
container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>(); container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>();
container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>(); container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>();
container.RegisterSingleton<IDeviceApiRepository, DeviceApiRepository>(); container.RegisterSingleton<IDeviceApiRepository, DeviceApiRepository>();

View file

@ -7,7 +7,7 @@ namespace Bit.App.Abstractions
{ {
public interface IAttachmentRepository : IRepository<AttachmentData, string> public interface IAttachmentRepository : IRepository<AttachmentData, string>
{ {
Task<IEnumerable<AttachmentData>> GetAllByLoginIdAsync(string loginId); Task<IEnumerable<AttachmentData>> GetAllByCipherIdAsync(string cipherId);
Task<IEnumerable<AttachmentData>> GetAllByUserIdAsync(string userId); Task<IEnumerable<AttachmentData>> GetAllByUserIdAsync(string userId);
} }
} }

View file

@ -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<CipherData, string>
{
Task<IEnumerable<CipherData>> GetAllByUserIdAsync(string userId);
Task<IEnumerable<CipherData>> GetAllByUserIdAsync(string userId, bool favorite);
}
}

View file

@ -8,6 +8,6 @@ namespace Bit.App.Abstractions
public interface IFolderRepository : IRepository<FolderData, string> public interface IFolderRepository : IRepository<FolderData, string>
{ {
Task<IEnumerable<FolderData>> GetAllByUserIdAsync(string userId); Task<IEnumerable<FolderData>> GetAllByUserIdAsync(string userId);
Task DeleteWithLoginUpdateAsync(string id, DateTime revisionDate); Task DeleteWithCipherUpdateAsync(string id, DateTime revisionDate);
} }
} }

View file

@ -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<LoginData, string>
{
Task<IEnumerable<LoginData>> GetAllByUserIdAsync(string userId);
Task<IEnumerable<LoginData>> GetAllByUserIdAsync(string userId, bool favorite);
}
}

View file

@ -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<Cipher> GetByIdAsync(string id);
Task<IEnumerable<Cipher>> GetAllAsync();
Task<IEnumerable<Cipher>> GetAllAsync(bool favorites);
Task<Tuple<IEnumerable<Cipher>, IEnumerable<Cipher>>> GetAllAsync(string uriString);
Task<ApiResult<CipherResponse>> SaveAsync(Cipher login);
Task<ApiResult> DeleteAsync(string id);
Task<byte[]> DownloadAndDecryptAttachmentAsync(string url, string orgId = null);
Task<ApiResult<CipherResponse>> EncryptAndSaveAttachmentAsync(Cipher login, byte[] data, string fileName);
Task<ApiResult> DeleteAttachmentAsync(Cipher login, string attachmentId);
}
}

View file

@ -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<Login> GetByIdAsync(string id);
Task<IEnumerable<Login>> GetAllAsync();
Task<IEnumerable<Login>> GetAllAsync(bool favorites);
Task<Tuple<IEnumerable<Login>, IEnumerable<Login>>> GetAllAsync(string uriString);
Task<ApiResult<CipherResponse>> SaveAsync(Login login);
Task<ApiResult> DeleteAsync(string id);
Task<byte[]> DownloadAndDecryptAttachmentAsync(string url, string orgId = null);
Task<ApiResult<CipherResponse>> EncryptAndSaveAttachmentAsync(Login login, byte[] data, string fileName);
Task<ApiResult> DeleteAttachmentAsync(Login login, string attachmentId);
}
}

View file

@ -9,7 +9,7 @@ namespace Bit.App.Abstractions
Task<bool> SyncCipherAsync(string id); Task<bool> SyncCipherAsync(string id);
Task<bool> SyncFolderAsync(string id); Task<bool> SyncFolderAsync(string id);
Task<bool> SyncDeleteFolderAsync(string id, DateTime revisionDate); Task<bool> SyncDeleteFolderAsync(string id, DateTime revisionDate);
Task<bool> SyncDeleteLoginAsync(string id); Task<bool> SyncDeleteCipherAsync(string id);
Task<bool> SyncSettingsAsync(); Task<bool> SyncSettingsAsync();
Task<bool> SyncProfileAsync(); Task<bool> SyncProfileAsync();
Task<bool> FullSyncAsync(bool forceSync = false); Task<bool> FullSyncAsync(bool forceSync = false);

View file

@ -58,7 +58,7 @@
<Compile Include="Abstractions\Services\IKeyDerivationService.cs" /> <Compile Include="Abstractions\Services\IKeyDerivationService.cs" />
<Compile Include="Abstractions\Services\ILogService.cs" /> <Compile Include="Abstractions\Services\ILogService.cs" />
<Compile Include="Abstractions\Services\IReflectionService.cs" /> <Compile Include="Abstractions\Services\IReflectionService.cs" />
<Compile Include="Abstractions\Services\ILoginService.cs" /> <Compile Include="Abstractions\Services\ICipherService.cs" />
<Compile Include="Abstractions\Services\IFolderService.cs" /> <Compile Include="Abstractions\Services\IFolderService.cs" />
<Compile Include="App.cs" /> <Compile Include="App.cs" />
<Compile Include="Abstractions\Services\ISecureStorageService.cs" /> <Compile Include="Abstractions\Services\ISecureStorageService.cs" />
@ -91,6 +91,7 @@
<Compile Include="Controls\VaultListViewCell.cs" /> <Compile Include="Controls\VaultListViewCell.cs" />
<Compile Include="Enums\DeviceType.cs" /> <Compile Include="Enums\DeviceType.cs" />
<Compile Include="Enums\FieldType.cs" /> <Compile Include="Enums\FieldType.cs" />
<Compile Include="Enums\SecureNoteType.cs" />
<Compile Include="Enums\TwoFactorProviderType.cs" /> <Compile Include="Enums\TwoFactorProviderType.cs" />
<Compile Include="Enums\EncryptionType.cs" /> <Compile Include="Enums\EncryptionType.cs" />
<Compile Include="Enums\OrganizationUserType.cs" /> <Compile Include="Enums\OrganizationUserType.cs" />
@ -104,6 +105,9 @@
<Compile Include="Models\Api\ApiResult.cs" /> <Compile Include="Models\Api\ApiResult.cs" />
<Compile Include="Models\Api\CipherDataModel.cs" /> <Compile Include="Models\Api\CipherDataModel.cs" />
<Compile Include="Models\Api\FieldDataModel.cs" /> <Compile Include="Models\Api\FieldDataModel.cs" />
<Compile Include="Models\Api\CardDataModel.cs" />
<Compile Include="Models\Api\IdentityDataModel.cs" />
<Compile Include="Models\Api\SecureNoteDataModel.cs" />
<Compile Include="Models\Api\Request\DeviceTokenRequest.cs" /> <Compile Include="Models\Api\Request\DeviceTokenRequest.cs" />
<Compile Include="Models\Api\Request\FolderRequest.cs" /> <Compile Include="Models\Api\Request\FolderRequest.cs" />
<Compile Include="Models\Api\Request\DeviceRequest.cs" /> <Compile Include="Models\Api\Request\DeviceRequest.cs" />
@ -125,16 +129,20 @@
<Compile Include="Models\Api\Response\TokenResponse.cs" /> <Compile Include="Models\Api\Response\TokenResponse.cs" />
<Compile Include="Models\Api\Response\ProfileResponse.cs" /> <Compile Include="Models\Api\Response\ProfileResponse.cs" />
<Compile Include="Models\Api\LoginDataModel.cs" /> <Compile Include="Models\Api\LoginDataModel.cs" />
<Compile Include="Models\Card.cs" />
<Compile Include="Models\CipherString.cs" /> <Compile Include="Models\CipherString.cs" />
<Compile Include="Models\Data\AttachmentData.cs" /> <Compile Include="Models\Data\AttachmentData.cs" />
<Compile Include="Models\Attachment.cs" /> <Compile Include="Models\Attachment.cs" />
<Compile Include="Models\Field.cs" /> <Compile Include="Models\Field.cs" />
<Compile Include="Models\Identity.cs" />
<Compile Include="Models\Login.cs" />
<Compile Include="Models\Page\VaultAttachmentsPageModel.cs" /> <Compile Include="Models\Page\VaultAttachmentsPageModel.cs" />
<Compile Include="Models\SecureNote.cs" />
<Compile Include="Models\SymmetricCryptoKey.cs" /> <Compile Include="Models\SymmetricCryptoKey.cs" />
<Compile Include="Models\Data\SettingsData.cs" /> <Compile Include="Models\Data\SettingsData.cs" />
<Compile Include="Models\Data\FolderData.cs" /> <Compile Include="Models\Data\FolderData.cs" />
<Compile Include="Abstractions\IDataObject.cs" /> <Compile Include="Abstractions\IDataObject.cs" />
<Compile Include="Models\Data\LoginData.cs" /> <Compile Include="Models\Data\CipherData.cs" />
<Compile Include="Models\DomainName.cs" /> <Compile Include="Models\DomainName.cs" />
<Compile Include="Models\Folder.cs" /> <Compile Include="Models\Folder.cs" />
<Compile Include="Models\LoginResult.cs" /> <Compile Include="Models\LoginResult.cs" />
@ -144,7 +152,7 @@
<Compile Include="Models\Page\PasswordGeneratorPageModel.cs" /> <Compile Include="Models\Page\PasswordGeneratorPageModel.cs" />
<Compile Include="Models\PlatformCulture.cs" /> <Compile Include="Models\PlatformCulture.cs" />
<Compile Include="Models\PushNotification.cs" /> <Compile Include="Models\PushNotification.cs" />
<Compile Include="Models\Login.cs" /> <Compile Include="Models\Cipher.cs" />
<Compile Include="Models\Page\VaultViewLoginPageModel.cs" /> <Compile Include="Models\Page\VaultViewLoginPageModel.cs" />
<Compile Include="Pages\HomePage.cs" /> <Compile Include="Pages\HomePage.cs" />
<Compile Include="Pages\Lock\BaseLockPage.cs" /> <Compile Include="Pages\Lock\BaseLockPage.cs" />
@ -175,7 +183,7 @@
<Compile Include="Pages\Vault\VaultAutofillListLoginsPage.cs" /> <Compile Include="Pages\Vault\VaultAutofillListLoginsPage.cs" />
<Compile Include="Pages\Vault\VaultAttachmentsPage.cs" /> <Compile Include="Pages\Vault\VaultAttachmentsPage.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Abstractions\Repositories\ILoginRepository.cs" /> <Compile Include="Abstractions\Repositories\ICipherRepository.cs" />
<Compile Include="Repositories\AttachmentRepository.cs" /> <Compile Include="Repositories\AttachmentRepository.cs" />
<Compile Include="Repositories\SyncApiRepository.cs" /> <Compile Include="Repositories\SyncApiRepository.cs" />
<Compile Include="Repositories\TwoFactorApiRepository.cs" /> <Compile Include="Repositories\TwoFactorApiRepository.cs" />
@ -192,7 +200,7 @@
<Compile Include="Abstractions\Repositories\ICipherApiRepository.cs" /> <Compile Include="Abstractions\Repositories\ICipherApiRepository.cs" />
<Compile Include="Repositories\SettingsRepository.cs" /> <Compile Include="Repositories\SettingsRepository.cs" />
<Compile Include="Repositories\FolderApiRepository.cs" /> <Compile Include="Repositories\FolderApiRepository.cs" />
<Compile Include="Repositories\LoginRepository.cs" /> <Compile Include="Repositories\CipherRepository.cs" />
<Compile Include="Repositories\FolderRepository.cs" /> <Compile Include="Repositories\FolderRepository.cs" />
<Compile Include="Abstractions\Repositories\IFolderRepository.cs" /> <Compile Include="Abstractions\Repositories\IFolderRepository.cs" />
<Compile Include="Abstractions\Repositories\IRepository.cs" /> <Compile Include="Abstractions\Repositories\IRepository.cs" />
@ -340,7 +348,7 @@
<Compile Include="Abstractions\Services\ISyncService.cs" /> <Compile Include="Abstractions\Services\ISyncService.cs" />
<Compile Include="Abstractions\Services\IPasswordGenerationService.cs" /> <Compile Include="Abstractions\Services\IPasswordGenerationService.cs" />
<Compile Include="Services\SyncService.cs" /> <Compile Include="Services\SyncService.cs" />
<Compile Include="Services\LoginService.cs" /> <Compile Include="Services\CipherService.cs" />
<Compile Include="Services\AuthService.cs" /> <Compile Include="Services\AuthService.cs" />
<Compile Include="Services\CryptoService.cs" /> <Compile Include="Services\CryptoService.cs" />
<Compile Include="Models\Page\VaultListPageModel.cs" /> <Compile Include="Models\Page\VaultListPageModel.cs" />

View file

@ -6,6 +6,7 @@
//Folder = 0, //Folder = 0,
Login = 1, Login = 1,
SecureNote = 2, SecureNote = 2,
Card = 3 Card = 3,
Identity = 4
} }
} }

View file

@ -0,0 +1,7 @@
namespace Bit.App.Enums
{
public enum SecureNoteType : byte
{
Generic = 0
}
}

View file

@ -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; }
}
}

View file

@ -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; }
}
}

View file

@ -6,18 +6,18 @@ namespace Bit.App.Models.Api
{ {
public class CipherRequest public class CipherRequest
{ {
public CipherRequest(Login login) public CipherRequest(Cipher cipher)
{ {
Type = CipherType.Login; Type = cipher.Type;
OrganizationId = login.OrganizationId; OrganizationId = cipher.OrganizationId;
FolderId = login.FolderId; FolderId = cipher.FolderId;
Name = login.Name?.EncryptedString; Name = cipher.Name?.EncryptedString;
Notes = login.Notes?.EncryptedString; Notes = cipher.Notes?.EncryptedString;
Favorite = login.Favorite; 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, Name = f.Name?.EncryptedString,
Value = f.Value?.EncryptedString, Value = f.Value?.EncryptedString,
@ -28,7 +28,16 @@ namespace Bit.App.Models.Api
switch(Type) switch(Type)
{ {
case CipherType.Login: 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; break;
default: default:
break; break;
@ -42,16 +51,20 @@ namespace Bit.App.Models.Api
public string Name { get; set; } public string Name { get; set; }
public string Notes { get; set; } public string Notes { get; set; }
public IEnumerable<FieldDataModel> Fields { get; set; } public IEnumerable<FieldDataModel> Fields { get; set; }
public LoginType Login { 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 class LoginType
{ {
public LoginType(Login login) public LoginType(Cipher cipher)
{ {
Uri = login.Uri?.EncryptedString; Uri = cipher.Login.Uri?.EncryptedString;
Username = login.Username?.EncryptedString; Username = cipher.Login.Username?.EncryptedString;
Password = login.Password?.EncryptedString; Password = cipher.Login.Password?.EncryptedString;
Totp = login.Totp?.EncryptedString; Totp = cipher.Login.Totp?.EncryptedString;
} }
public string Uri { get; set; } public string Uri { get; set; }
@ -59,5 +72,79 @@ namespace Bit.App.Models.Api
public string Password { get; set; } public string Password { get; set; }
public string Totp { 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; }
}
} }
} }

View file

@ -0,0 +1,9 @@
using Bit.App.Enums;
namespace Bit.App.Models.Api
{
public class SecureNoteDataModel : CipherDataModel
{
public SecureNoteType Type { get; set; }
}
}

29
src/App/Models/Card.cs Normal file
View file

@ -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<CardDataModel>(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; }
}
}

76
src/App/Models/Cipher.cs Normal file
View file

@ -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<AttachmentData> 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<IEnumerable<FieldDataModel>>(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<Field> Fields { get; set; }
public bool Favorite { get; set; }
public bool Edit { get; set; }
public bool OrganizationUseTotp { get; set; }
public IEnumerable<Attachment> Attachments { get; set; }
public Login Login { get; set; }
public Identity Identity { get; set; }
public Card Card { get; set; }
public SecureNote SecureNote { get; set; }
}
}

View file

@ -10,20 +10,20 @@ namespace Bit.App.Models.Data
public AttachmentData() public AttachmentData()
{ } { }
public AttachmentData(Attachment attachment, string loginId) public AttachmentData(Attachment attachment, string cipherId)
{ {
Id = attachment.Id; Id = attachment.Id;
LoginId = loginId; LoginId = cipherId;
Url = attachment.Url; Url = attachment.Url;
FileName = attachment.FileName?.EncryptedString; FileName = attachment.FileName?.EncryptedString;
Size = attachment.Size.ToString(); Size = attachment.Size.ToString();
SizeName = attachment.SizeName; SizeName = attachment.SizeName;
} }
public AttachmentData(AttachmentResponse response, string loginId) public AttachmentData(AttachmentResponse response, string cipherId)
{ {
Id = response.Id; Id = response.Id;
LoginId = loginId; LoginId = cipherId;
Url = response.Url; Url = response.Url;
FileName = response.FileName; FileName = response.FileName;
Size = response.Size; Size = response.Size;
@ -32,6 +32,7 @@ namespace Bit.App.Models.Data
[PrimaryKey] [PrimaryKey]
public string Id { get; set; } public string Id { get; set; }
// Really should be called CipherId
[Indexed] [Indexed]
public string LoginId { get; set; } public string LoginId { get; set; }
public string Url { get; set; } public string Url { get; set; }

View file

@ -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<string>
{
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<LoginDataModel>();
cipherData = loginData;
Uri = loginData.Uri;
Username = loginData.Username;
Password = loginData.Password;
Totp = loginData.Totp;
break;
case CipherType.SecureNote:
var noteData = cipher.Data.ToObject<SecureNoteDataModel>();
cipherData = noteData;
SecureNoteType = noteData.Type;
break;
case CipherType.Card:
var cardData = cipher.Data.ToObject<CardDataModel>();
cipherData = cardData;
break;
case CipherType.Identity:
var idData = cipher.Data.ToObject<IdentityDataModel>();
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; }
}
}

View file

@ -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<string>
{
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<LoginDataModel>();
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);
}
}
}

View file

@ -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<IdentityDataModel>(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; }
}
}

View file

@ -1,58 +1,22 @@
using Bit.App.Models.Api; using Bit.App.Models.Data;
using Bit.App.Models.Data;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
namespace Bit.App.Models namespace Bit.App.Models
{ {
public class Login public class Login
{ {
public Login() public Login() { }
{ }
public Login(LoginData data, IEnumerable<AttachmentData> 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; Uri = data.Uri != null ? new CipherString(data.Uri) : null;
Username = data.Username != null ? new CipherString(data.Username) : null; Username = data.Username != null ? new CipherString(data.Username) : null;
Password = data.Password != null ? new CipherString(data.Password) : 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; 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<IEnumerable<FieldDataModel>>(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 Uri { get; set; }
public CipherString Username { get; set; } public CipherString Username { get; set; }
public CipherString Password { get; set; } public CipherString Password { get; set; }
public CipherString Notes { get; set; }
public CipherString Totp { get; set; } public CipherString Totp { get; set; }
public IEnumerable<Field> Fields { get; set; }
public bool Favorite { get; set; }
public bool Edit { get; set; }
public bool OrganizationUseTotp { get; set; }
public IEnumerable<Attachment> Attachments { get; set; }
} }
} }

View file

@ -9,17 +9,17 @@ namespace Bit.App.Models.Page
{ {
public class Login public class Login
{ {
public Login(Models.Login login) public Login(Models.Cipher cipher)
{ {
Id = login.Id; Id = cipher.Id;
Shared = !string.IsNullOrWhiteSpace(login.OrganizationId); Shared = !string.IsNullOrWhiteSpace(cipher.OrganizationId);
HasAttachments = login.Attachments?.Any() ?? false; HasAttachments = cipher.Attachments?.Any() ?? false;
FolderId = login.FolderId; FolderId = cipher.FolderId;
Name = login.Name?.Decrypt(login.OrganizationId); Name = cipher.Name?.Decrypt(cipher.OrganizationId);
Username = login.Username?.Decrypt(login.OrganizationId) ?? " "; Username = cipher.Login?.Username?.Decrypt(cipher.OrganizationId) ?? " ";
Password = new Lazy<string>(() => login.Password?.Decrypt(login.OrganizationId)); Password = new Lazy<string>(() => cipher.Login?.Password?.Decrypt(cipher.OrganizationId));
Uri = new Lazy<string>(() => login.Uri?.Decrypt(login.OrganizationId)); Uri = new Lazy<string>(() => cipher.Login?.Uri?.Decrypt(cipher.OrganizationId));
Totp = new Lazy<string>(() => login.Totp?.Decrypt(login.OrganizationId)); Totp = new Lazy<string>(() => cipher.Login?.Totp?.Decrypt(cipher.OrganizationId));
} }
public string Id { get; set; } public string Id { get; set; }
@ -35,7 +35,7 @@ namespace Bit.App.Models.Page
public class AutofillLogin : Login public class AutofillLogin : Login
{ {
public AutofillLogin(Models.Login login, bool fuzzy = false) public AutofillLogin(Models.Cipher login, bool fuzzy = false)
: base(login) : base(login)
{ {
Fuzzy = fuzzy; Fuzzy = fuzzy;

View file

@ -201,23 +201,23 @@ namespace Bit.App.Models.Page
} }
public bool ShowFields => (Fields?.Count ?? 0) > 0; public bool ShowFields => (Fields?.Count ?? 0) > 0;
public void Update(Login login) public void Update(Cipher cipher)
{ {
Name = login.Name?.Decrypt(login.OrganizationId); Name = cipher.Name?.Decrypt(cipher.OrganizationId);
Username = login.Username?.Decrypt(login.OrganizationId); Username = cipher.Login?.Username?.Decrypt(cipher.OrganizationId);
Password = login.Password?.Decrypt(login.OrganizationId); Password = cipher.Login?.Password?.Decrypt(cipher.OrganizationId);
Uri = login.Uri?.Decrypt(login.OrganizationId); Uri = cipher.Login?.Uri?.Decrypt(cipher.OrganizationId);
Notes = login.Notes?.Decrypt(login.OrganizationId); Notes = cipher.Notes?.Decrypt(cipher.OrganizationId);
if(login.Attachments != null) if(cipher.Attachments != null)
{ {
var attachments = new List<Attachment>(); var attachments = new List<Attachment>();
foreach(var attachment in login.Attachments) foreach(var attachment in cipher.Attachments)
{ {
attachments.Add(new Attachment attachments.Add(new Attachment
{ {
Id = attachment.Id, Id = attachment.Id,
Name = attachment.FileName?.Decrypt(login.OrganizationId), Name = attachment.FileName?.Decrypt(cipher.OrganizationId),
SizeName = attachment.SizeName, SizeName = attachment.SizeName,
Size = attachment.Size, Size = attachment.Size,
Url = attachment.Url Url = attachment.Url
@ -227,18 +227,18 @@ namespace Bit.App.Models.Page
} }
else else
{ {
login.Attachments = null; cipher.Attachments = null;
} }
if(login.Fields != null) if(cipher.Fields != null)
{ {
var fields = new List<Field>(); var fields = new List<Field>();
foreach(var field in login.Fields) foreach(var field in cipher.Fields)
{ {
fields.Add(new Field fields.Add(new Field
{ {
Name = field.Name?.Decrypt(login.OrganizationId), Name = field.Name?.Decrypt(cipher.OrganizationId),
Value = field.Value?.Decrypt(login.OrganizationId), Value = field.Value?.Decrypt(cipher.OrganizationId),
Type = field.Type Type = field.Type
}); });
} }
@ -246,7 +246,7 @@ namespace Bit.App.Models.Page
} }
else else
{ {
login.Fields = null; cipher.Fields = null;
} }
} }

View file

@ -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; }
}
}

View file

@ -18,7 +18,7 @@ namespace Bit.App.Pages
{ {
private const string AddedLoginAlertKey = "addedSiteAlert"; private const string AddedLoginAlertKey = "addedSiteAlert";
private readonly ILoginService _loginService; private readonly ICipherService _cipherService;
private readonly IFolderService _folderService; private readonly IFolderService _folderService;
private readonly IUserDialogs _userDialogs; private readonly IUserDialogs _userDialogs;
private readonly IConnectivity _connectivity; private readonly IConnectivity _connectivity;
@ -37,7 +37,7 @@ namespace Bit.App.Pages
_defaultName = defaultName; _defaultName = defaultName;
_fromAutofill = fromAutofill; _fromAutofill = fromAutofill;
_loginService = Resolver.Resolve<ILoginService>(); _cipherService = Resolver.Resolve<ICipherService>();
_folderService = Resolver.Resolve<IFolderService>(); _folderService = Resolver.Resolve<IFolderService>();
_userDialogs = Resolver.Resolve<IUserDialogs>(); _userDialogs = Resolver.Resolve<IUserDialogs>();
_connectivity = Resolver.Resolve<IConnectivity>(); _connectivity = Resolver.Resolve<IConnectivity>();
@ -177,24 +177,31 @@ namespace Bit.App.Pages
return; return;
} }
var login = new Login var cipher = new Cipher
{ {
Name = NameCell.Entry.Text.Encrypt(), 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(), 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) 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); _userDialogs.ShowLoading(AppResources.Saving, MaskType.Black);
var saveTask = await _loginService.SaveAsync(login); var saveTask = await _cipherService.SaveAsync(cipher);
_userDialogs.HideLoading(); _userDialogs.HideLoading();
if(saveTask.Succeeded) if(saveTask.Succeeded)

View file

@ -17,7 +17,7 @@ namespace Bit.App.Pages
{ {
public class VaultAttachmentsPage : ExtendedContentPage public class VaultAttachmentsPage : ExtendedContentPage
{ {
private readonly ILoginService _loginService; private readonly ICipherService _cipherService;
private readonly IUserDialogs _userDialogs; private readonly IUserDialogs _userDialogs;
private readonly IConnectivity _connectivity; private readonly IConnectivity _connectivity;
private readonly IDeviceActionService _deviceActiveService; private readonly IDeviceActionService _deviceActiveService;
@ -25,7 +25,7 @@ namespace Bit.App.Pages
private readonly ITokenService _tokenService; private readonly ITokenService _tokenService;
private readonly ICryptoService _cryptoService; private readonly ICryptoService _cryptoService;
private readonly string _loginId; private readonly string _loginId;
private Login _login; private Cipher _login;
private byte[] _fileBytes; private byte[] _fileBytes;
private DateTime? _lastAction; private DateTime? _lastAction;
private bool _canUseAttachments = true; private bool _canUseAttachments = true;
@ -34,7 +34,7 @@ namespace Bit.App.Pages
: base(true) : base(true)
{ {
_loginId = loginId; _loginId = loginId;
_loginService = Resolver.Resolve<ILoginService>(); _cipherService = Resolver.Resolve<ICipherService>();
_connectivity = Resolver.Resolve<IConnectivity>(); _connectivity = Resolver.Resolve<IConnectivity>();
_userDialogs = Resolver.Resolve<IUserDialogs>(); _userDialogs = Resolver.Resolve<IUserDialogs>();
_deviceActiveService = Resolver.Resolve<IDeviceActionService>(); _deviceActiveService = Resolver.Resolve<IDeviceActionService>();
@ -162,7 +162,7 @@ namespace Bit.App.Pages
} }
_userDialogs.ShowLoading(AppResources.Saving, MaskType.Black); _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(); _userDialogs.HideLoading();
@ -223,7 +223,7 @@ namespace Bit.App.Pages
private async Task LoadAttachmentsAsync() private async Task LoadAttachmentsAsync()
{ {
_login = await _loginService.GetByIdAsync(_loginId); _login = await _cipherService.GetByIdAsync(_loginId);
if(_login == null) if(_login == null)
{ {
await Navigation.PopForDeviceAsync(); await Navigation.PopForDeviceAsync();
@ -268,7 +268,7 @@ namespace Bit.App.Pages
} }
_userDialogs.ShowLoading(AppResources.Deleting, MaskType.Black); _userDialogs.ShowLoading(AppResources.Deleting, MaskType.Black);
var saveTask = await _loginService.DeleteAttachmentAsync(_login, attachment.Id); var saveTask = await _cipherService.DeleteAttachmentAsync(_login, attachment.Id);
_userDialogs.HideLoading(); _userDialogs.HideLoading();
if(saveTask.Succeeded) if(saveTask.Succeeded)

View file

@ -17,7 +17,7 @@ namespace Bit.App.Pages
{ {
public class VaultAutofillListLoginsPage : ExtendedContentPage public class VaultAutofillListLoginsPage : ExtendedContentPage
{ {
private readonly ILoginService _loginService; private readonly ICipherService _cipherService;
private readonly IDeviceInfoService _deviceInfoService; private readonly IDeviceInfoService _deviceInfoService;
private readonly IDeviceActionService _clipboardService; private readonly IDeviceActionService _clipboardService;
private readonly ISettingsService _settingsService; private readonly ISettingsService _settingsService;
@ -40,7 +40,7 @@ namespace Bit.App.Pages
_name = "--"; _name = "--";
} }
_loginService = Resolver.Resolve<ILoginService>(); _cipherService = Resolver.Resolve<ICipherService>();
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>(); _deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
_clipboardService = Resolver.Resolve<IDeviceActionService>(); _clipboardService = Resolver.Resolve<IDeviceActionService>();
_settingsService = Resolver.Resolve<ISettingsService>(); _settingsService = Resolver.Resolve<ISettingsService>();
@ -162,7 +162,7 @@ namespace Bit.App.Pages
Task.Run(async () => Task.Run(async () =>
{ {
var autofillGroupings = new List<VaultListPageModel.AutofillGrouping>(); var autofillGroupings = new List<VaultListPageModel.AutofillGrouping>();
var logins = await _loginService.GetAllAsync(Uri); var logins = await _cipherService.GetAllAsync(Uri);
var normalLogins = logins?.Item1.Select(l => new VaultListPageModel.AutofillLogin(l, false)) var normalLogins = logins?.Item1.Select(l => new VaultListPageModel.AutofillLogin(l, false))
.OrderBy(s => s.Name) .OrderBy(s => s.Name)

View file

@ -16,19 +16,19 @@ namespace Bit.App.Pages
{ {
public class VaultCustomFieldsPage : ExtendedContentPage public class VaultCustomFieldsPage : ExtendedContentPage
{ {
private readonly ILoginService _loginService; private readonly ICipherService _cipherService;
private readonly IUserDialogs _userDialogs; private readonly IUserDialogs _userDialogs;
private readonly IConnectivity _connectivity; private readonly IConnectivity _connectivity;
private readonly IGoogleAnalyticsService _googleAnalyticsService; private readonly IGoogleAnalyticsService _googleAnalyticsService;
private readonly string _loginId; private readonly string _loginId;
private Login _login; private Cipher _login;
private DateTime? _lastAction; private DateTime? _lastAction;
public VaultCustomFieldsPage(string loginId) public VaultCustomFieldsPage(string loginId)
: base(true) : base(true)
{ {
_loginId = loginId; _loginId = loginId;
_loginService = Resolver.Resolve<ILoginService>(); _cipherService = Resolver.Resolve<ICipherService>();
_connectivity = Resolver.Resolve<IConnectivity>(); _connectivity = Resolver.Resolve<IConnectivity>();
_userDialogs = Resolver.Resolve<IUserDialogs>(); _userDialogs = Resolver.Resolve<IUserDialogs>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>(); _googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
@ -114,7 +114,7 @@ namespace Bit.App.Pages
} }
_userDialogs.ShowLoading(AppResources.Saving, MaskType.Black); _userDialogs.ShowLoading(AppResources.Saving, MaskType.Black);
var saveTask = await _loginService.SaveAsync(_login); var saveTask = await _cipherService.SaveAsync(_login);
_userDialogs.HideLoading(); _userDialogs.HideLoading();
@ -148,7 +148,7 @@ namespace Bit.App.Pages
{ {
base.OnAppearing(); base.OnAppearing();
_login = await _loginService.GetByIdAsync(_loginId); _login = await _cipherService.GetByIdAsync(_loginId);
if(_login == null) if(_login == null)
{ {
await Navigation.PopForDeviceAsync(); await Navigation.PopForDeviceAsync();

View file

@ -15,7 +15,7 @@ namespace Bit.App.Pages
public class VaultEditLoginPage : ExtendedContentPage public class VaultEditLoginPage : ExtendedContentPage
{ {
private readonly string _loginId; private readonly string _loginId;
private readonly ILoginService _loginService; private readonly ICipherService _cipherService;
private readonly IFolderService _folderService; private readonly IFolderService _folderService;
private readonly IUserDialogs _userDialogs; private readonly IUserDialogs _userDialogs;
private readonly IConnectivity _connectivity; private readonly IConnectivity _connectivity;
@ -26,7 +26,7 @@ namespace Bit.App.Pages
public VaultEditLoginPage(string loginId) public VaultEditLoginPage(string loginId)
{ {
_loginId = loginId; _loginId = loginId;
_loginService = Resolver.Resolve<ILoginService>(); _cipherService = Resolver.Resolve<ICipherService>();
_folderService = Resolver.Resolve<IFolderService>(); _folderService = Resolver.Resolve<IFolderService>();
_userDialogs = Resolver.Resolve<IUserDialogs>(); _userDialogs = Resolver.Resolve<IUserDialogs>();
_connectivity = Resolver.Resolve<IConnectivity>(); _connectivity = Resolver.Resolve<IConnectivity>();
@ -50,8 +50,8 @@ namespace Bit.App.Pages
private void Init() private void Init()
{ {
var login = _loginService.GetByIdAsync(_loginId).GetAwaiter().GetResult(); var cipher = _cipherService.GetByIdAsync(_loginId).GetAwaiter().GetResult();
if(login == null) if(cipher == null)
{ {
// TODO: handle error. navigate back? should never happen... // TODO: handle error. navigate back? should never happen...
return; return;
@ -59,7 +59,7 @@ namespace Bit.App.Pages
NotesCell = new FormEditorCell(height: 300); NotesCell = new FormEditorCell(height: 300);
NotesCell.Editor.Keyboard = Keyboard.Text; 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, TotpCell = new FormEntryCell(AppResources.AuthenticatorKey, nextElement: NotesCell.Editor,
useButton: _deviceInfo.HasCamera); useButton: _deviceInfo.HasCamera);
@ -67,28 +67,28 @@ namespace Bit.App.Pages
{ {
TotpCell.Button.Image = "camera"; 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.DisableAutocapitalize = true;
TotpCell.Entry.Autocorrect = false; TotpCell.Entry.Autocorrect = false;
TotpCell.Entry.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier"); TotpCell.Entry.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier");
PasswordCell = new FormEntryCell(AppResources.Password, isPassword: true, nextElement: TotpCell.Entry, PasswordCell = new FormEntryCell(AppResources.Password, isPassword: true, nextElement: TotpCell.Entry,
useButton: true); useButton: true);
PasswordCell.Entry.Text = login.Password?.Decrypt(login.OrganizationId); PasswordCell.Entry.Text = cipher.Login?.Password?.Decrypt(cipher.OrganizationId);
PasswordCell.Button.Image = "eye"; PasswordCell.Button.Image = "eye";
PasswordCell.Entry.DisableAutocapitalize = true; PasswordCell.Entry.DisableAutocapitalize = true;
PasswordCell.Entry.Autocorrect = false; PasswordCell.Entry.Autocorrect = false;
PasswordCell.Entry.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier"); PasswordCell.Entry.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier");
UsernameCell = new FormEntryCell(AppResources.Username, nextElement: PasswordCell.Entry); 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.DisableAutocapitalize = true;
UsernameCell.Entry.Autocorrect = false; UsernameCell.Entry.Autocorrect = false;
UriCell = new FormEntryCell(AppResources.URI, Keyboard.Url, nextElement: UsernameCell.Entry); 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 = 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 GenerateCell = new ExtendedTextCell
{ {
@ -104,7 +104,7 @@ namespace Bit.App.Pages
foreach(var folder in folders) foreach(var folder in folders)
{ {
i++; i++;
if(folder.Id == login.FolderId) if(folder.Id == cipher.FolderId)
{ {
selectedIndex = i; selectedIndex = i;
} }
@ -117,7 +117,7 @@ namespace Bit.App.Pages
var favoriteCell = new ExtendedSwitchCell var favoriteCell = new ExtendedSwitchCell
{ {
Text = AppResources.Favorite, Text = AppResources.Favorite,
On = login.Favorite On = cipher.Favorite
}; };
AttachmentsCell = new ExtendedTextCell AttachmentsCell = new ExtendedTextCell
@ -204,30 +204,34 @@ namespace Bit.App.Pages
return; return;
} }
login.Name = NameCell.Entry.Text.Encrypt(login.OrganizationId); cipher.Name = NameCell.Entry.Text.Encrypt(cipher.OrganizationId);
login.Uri = string.IsNullOrWhiteSpace(UriCell.Entry.Text) ? null : cipher.Notes = string.IsNullOrWhiteSpace(NotesCell.Editor.Text) ? null :
UriCell.Entry.Text.Encrypt(login.OrganizationId); NotesCell.Editor.Text.Encrypt(cipher.OrganizationId);
login.Username = string.IsNullOrWhiteSpace(UsernameCell.Entry.Text) ? null : cipher.Favorite = favoriteCell.On;
UsernameCell.Entry.Text.Encrypt(login.OrganizationId);
login.Password = string.IsNullOrWhiteSpace(PasswordCell.Entry.Text) ? null : cipher.Login = new Models.Login
PasswordCell.Entry.Text.Encrypt(login.OrganizationId); {
login.Notes = string.IsNullOrWhiteSpace(NotesCell.Editor.Text) ? null : Uri = string.IsNullOrWhiteSpace(UriCell.Entry.Text) ? null :
NotesCell.Editor.Text.Encrypt(login.OrganizationId); UriCell.Entry.Text.Encrypt(cipher.OrganizationId),
login.Totp = string.IsNullOrWhiteSpace(TotpCell.Entry.Text) ? null : Username = string.IsNullOrWhiteSpace(UsernameCell.Entry.Text) ? null :
TotpCell.Entry.Text.Encrypt(login.OrganizationId); UsernameCell.Entry.Text.Encrypt(cipher.OrganizationId),
login.Favorite = favoriteCell.On; 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) if(FolderCell.Picker.SelectedIndex > 0)
{ {
login.FolderId = folders.ElementAt(FolderCell.Picker.SelectedIndex - 1).Id; cipher.FolderId = folders.ElementAt(FolderCell.Picker.SelectedIndex - 1).Id;
} }
else else
{ {
login.FolderId = null; cipher.FolderId = null;
} }
_userDialogs.ShowLoading(AppResources.Saving, MaskType.Black); _userDialogs.ShowLoading(AppResources.Saving, MaskType.Black);
var saveTask = await _loginService.SaveAsync(login); var saveTask = await _cipherService.SaveAsync(cipher);
_userDialogs.HideLoading(); _userDialogs.HideLoading();
@ -405,7 +409,7 @@ namespace Bit.App.Pages
} }
_userDialogs.ShowLoading(AppResources.Deleting, MaskType.Black); _userDialogs.ShowLoading(AppResources.Deleting, MaskType.Black);
var deleteTask = await _loginService.DeleteAsync(_loginId); var deleteTask = await _cipherService.DeleteAsync(_loginId);
_userDialogs.HideLoading(); _userDialogs.HideLoading();
if(deleteTask.Succeeded) if(deleteTask.Succeeded)

View file

@ -20,7 +20,7 @@ namespace Bit.App.Pages
public class VaultListLoginsPage : ExtendedContentPage public class VaultListLoginsPage : ExtendedContentPage
{ {
private readonly IFolderService _folderService; private readonly IFolderService _folderService;
private readonly ILoginService _loginService; private readonly ICipherService _cipherService;
private readonly IUserDialogs _userDialogs; private readonly IUserDialogs _userDialogs;
private readonly IConnectivity _connectivity; private readonly IConnectivity _connectivity;
private readonly IDeviceActionService _clipboardService; private readonly IDeviceActionService _clipboardService;
@ -37,7 +37,7 @@ namespace Bit.App.Pages
{ {
_favorites = favorites; _favorites = favorites;
_folderService = Resolver.Resolve<IFolderService>(); _folderService = Resolver.Resolve<IFolderService>();
_loginService = Resolver.Resolve<ILoginService>(); _cipherService = Resolver.Resolve<ICipherService>();
_connectivity = Resolver.Resolve<IConnectivity>(); _connectivity = Resolver.Resolve<IConnectivity>();
_userDialogs = Resolver.Resolve<IUserDialogs>(); _userDialogs = Resolver.Resolve<IUserDialogs>();
_clipboardService = Resolver.Resolve<IDeviceActionService>(); _clipboardService = Resolver.Resolve<IDeviceActionService>();
@ -310,7 +310,7 @@ namespace Bit.App.Pages
Task.Run(async () => Task.Run(async () =>
{ {
var foldersTask = _folderService.GetAllAsync(); 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); await Task.WhenAll(foldersTask, loginsTask);
var folders = await foldersTask; var folders = await foldersTask;

View file

@ -18,7 +18,7 @@ namespace Bit.App.Pages
public class VaultViewLoginPage : ExtendedContentPage public class VaultViewLoginPage : ExtendedContentPage
{ {
private readonly string _loginId; private readonly string _loginId;
private readonly ILoginService _loginService; private readonly ICipherService _cipherService;
private readonly IUserDialogs _userDialogs; private readonly IUserDialogs _userDialogs;
private readonly IDeviceActionService _deviceActionService; private readonly IDeviceActionService _deviceActionService;
private readonly ITokenService _tokenService; private readonly ITokenService _tokenService;
@ -27,7 +27,7 @@ namespace Bit.App.Pages
public VaultViewLoginPage(string loginId) public VaultViewLoginPage(string loginId)
{ {
_loginId = loginId; _loginId = loginId;
_loginService = Resolver.Resolve<ILoginService>(); _cipherService = Resolver.Resolve<ICipherService>();
_userDialogs = Resolver.Resolve<IUserDialogs>(); _userDialogs = Resolver.Resolve<IUserDialogs>();
_deviceActionService = Resolver.Resolve<IDeviceActionService>(); _deviceActionService = Resolver.Resolve<IDeviceActionService>();
_tokenService = Resolver.Resolve<ITokenService>(); _tokenService = Resolver.Resolve<ITokenService>();
@ -161,14 +161,14 @@ namespace Bit.App.Pages
NotesCell.Tapped += NotesCell_Tapped; NotesCell.Tapped += NotesCell_Tapped;
EditItem.InitEvents(); EditItem.InitEvents();
var login = await _loginService.GetByIdAsync(_loginId); var cipher = await _cipherService.GetByIdAsync(_loginId);
if(login == null) if(cipher == null)
{ {
await Navigation.PopForDeviceAsync(); await Navigation.PopForDeviceAsync();
return; return;
} }
Model.Update(login); Model.Update(cipher);
if(LoginInformationSection.Contains(UriCell)) if(LoginInformationSection.Contains(UriCell))
{ {
@ -211,9 +211,9 @@ namespace Bit.App.Pages
{ {
LoginInformationSection.Remove(TotpCodeCell); 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)) if(!string.IsNullOrWhiteSpace(totpKey))
{ {
Model.TotpCode = Crypto.Totp(totpKey); Model.TotpCode = Crypto.Totp(totpKey);
@ -249,7 +249,7 @@ namespace Bit.App.Pages
{ {
var attachmentCell = new AttachmentViewCell(attachment, async () => var attachmentCell = new AttachmentViewCell(attachment, async () =>
{ {
await OpenAttachmentAsync(login, attachment); await OpenAttachmentAsync(cipher, attachment);
}); });
AttachmentCells.Add(attachmentCell); AttachmentCells.Add(attachmentCell);
AttachmentsSection.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) if(!_tokenService.TokenPremium && !login.OrganizationUseTotp)
{ {
@ -332,7 +332,7 @@ namespace Bit.App.Pages
} }
_userDialogs.ShowLoading(AppResources.Downloading, MaskType.Black); _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(); _userDialogs.HideLoading();
if(data == null) if(data == null)
{ {

View file

@ -13,9 +13,10 @@ namespace Bit.App.Repositories
: base(sqlService) : base(sqlService)
{ } { }
public Task<IEnumerable<AttachmentData>> GetAllByLoginIdAsync(string loginId) public Task<IEnumerable<AttachmentData>> GetAllByCipherIdAsync(string cipherId)
{ {
var attachments = Connection.Table<AttachmentData>().Where(a => a.LoginId == loginId).Cast<AttachmentData>(); var attachments = Connection.Table<AttachmentData>().Where(a => a.LoginId == cipherId)
.Cast<AttachmentData>();
return Task.FromResult(attachments); return Task.FromResult(attachments);
} }

View file

@ -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<CipherData, string>, ICipherRepository
{
public CipherRepository(ISqlService sqlService)
: base(sqlService)
{ }
public Task<IEnumerable<CipherData>> GetAllByUserIdAsync(string userId)
{
var logins = Connection.Table<CipherData>().Where(l => l.UserId == userId).Cast<CipherData>();
return Task.FromResult(logins);
}
public Task<IEnumerable<CipherData>> GetAllByUserIdAsync(string userId, bool favorite)
{
var logins = Connection.Table<CipherData>().Where(l => l.UserId == userId && l.Favorite == favorite)
.Cast<CipherData>();
return Task.FromResult(logins);
}
}
}

View file

@ -22,11 +22,11 @@ namespace Bit.App.Repositories
public override Task DeleteAsync(string id) public override Task DeleteAsync(string id)
{ {
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
DeleteWithLoginUpdateAsync(id, now); DeleteWithCipherUpdateAsync(id, now);
return Task.FromResult(0); return Task.FromResult(0);
} }
public Task DeleteWithLoginUpdateAsync(string id, DateTime revisionDate) public Task DeleteWithCipherUpdateAsync(string id, DateTime revisionDate)
{ {
Connection.RunInTransaction(() => Connection.RunInTransaction(() =>
{ {

View file

@ -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<LoginData, string>, ILoginRepository
{
public LoginRepository(ISqlService sqlService)
: base(sqlService)
{ }
public Task<IEnumerable<LoginData>> GetAllByUserIdAsync(string userId)
{
var logins = Connection.Table<LoginData>().Where(l => l.UserId == userId).Cast<LoginData>();
return Task.FromResult(logins);
}
public Task<IEnumerable<LoginData>> GetAllByUserIdAsync(string userId, bool favorite)
{
var logins = Connection.Table<LoginData>().Where(l => l.UserId == userId && l.Favorite == favorite)
.Cast<LoginData>();
return Task.FromResult(logins);
}
}
}

View file

@ -11,26 +11,26 @@ using System.Net.Http;
namespace Bit.App.Services namespace Bit.App.Services
{ {
public class LoginService : ILoginService public class CipherService : ICipherService
{ {
private readonly string[] _ignoredSearchTerms = new string[] { "com", "net", "org", "android", 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" }; "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 IAttachmentRepository _attachmentRepository;
private readonly IAuthService _authService; private readonly IAuthService _authService;
private readonly ICipherApiRepository _cipherApiRepository; private readonly ICipherApiRepository _cipherApiRepository;
private readonly ISettingsService _settingsService; private readonly ISettingsService _settingsService;
private readonly ICryptoService _cryptoService; private readonly ICryptoService _cryptoService;
public LoginService( public CipherService(
ILoginRepository loginRepository, ICipherRepository cipherRepository,
IAttachmentRepository attachmentRepository, IAttachmentRepository attachmentRepository,
IAuthService authService, IAuthService authService,
ICipherApiRepository cipherApiRepository, ICipherApiRepository cipherApiRepository,
ISettingsService settingsService, ISettingsService settingsService,
ICryptoService cryptoService) ICryptoService cryptoService)
{ {
_loginRepository = loginRepository; _cipherRepository = cipherRepository;
_attachmentRepository = attachmentRepository; _attachmentRepository = attachmentRepository;
_authService = authService; _authService = authService;
_cipherApiRepository = cipherApiRepository; _cipherApiRepository = cipherApiRepository;
@ -38,38 +38,38 @@ namespace Bit.App.Services
_cryptoService = cryptoService; _cryptoService = cryptoService;
} }
public async Task<Login> GetByIdAsync(string id) public async Task<Cipher> GetByIdAsync(string id)
{ {
var data = await _loginRepository.GetByIdAsync(id); var data = await _cipherRepository.GetByIdAsync(id);
if(data == null || data.UserId != _authService.UserId) if(data == null || data.UserId != _authService.UserId)
{ {
return null; return null;
} }
var attachments = await _attachmentRepository.GetAllByLoginIdAsync(id); var attachments = await _attachmentRepository.GetAllByCipherIdAsync(id);
var login = new Login(data, attachments); var cipher = new Cipher(data, attachments);
return login; return cipher;
} }
public async Task<IEnumerable<Login>> GetAllAsync() public async Task<IEnumerable<Cipher>> GetAllAsync()
{ {
var attachmentData = await _attachmentRepository.GetAllByUserIdAsync(_authService.UserId); var attachmentData = await _attachmentRepository.GetAllByUserIdAsync(_authService.UserId);
var attachmentDict = attachmentData.GroupBy(a => a.LoginId).ToDictionary(g => g.Key, g => g.ToList()); var attachmentDict = attachmentData.GroupBy(a => a.LoginId).ToDictionary(g => g.Key, g => g.ToList());
var data = await _loginRepository.GetAllByUserIdAsync(_authService.UserId); var data = await _cipherRepository.GetAllByUserIdAsync(_authService.UserId);
var logins = data.Select(f => new Login(f, attachmentDict.ContainsKey(f.Id) ? attachmentDict[f.Id] : null)); var logins = data.Select(f => new Cipher(f, attachmentDict.ContainsKey(f.Id) ? attachmentDict[f.Id] : null));
return logins; return logins;
} }
public async Task<IEnumerable<Login>> GetAllAsync(bool favorites) public async Task<IEnumerable<Cipher>> GetAllAsync(bool favorites)
{ {
var attachmentData = await _attachmentRepository.GetAllByUserIdAsync(_authService.UserId); var attachmentData = await _attachmentRepository.GetAllByUserIdAsync(_authService.UserId);
var attachmentDict = attachmentData.GroupBy(a => a.LoginId).ToDictionary(g => g.Key, g => g.ToList()); var attachmentDict = attachmentData.GroupBy(a => a.LoginId).ToDictionary(g => g.Key, g => g.ToList());
var data = await _loginRepository.GetAllByUserIdAsync(_authService.UserId, favorites); var data = await _cipherRepository.GetAllByUserIdAsync(_authService.UserId, favorites);
var logins = data.Select(f => new Login(f, attachmentDict.ContainsKey(f.Id) ? attachmentDict[f.Id] : null)); var logins = data.Select(f => new Cipher(f, attachmentDict.ContainsKey(f.Id) ? attachmentDict[f.Id] : null));
return logins; return logins;
} }
public async Task<Tuple<IEnumerable<Login>, IEnumerable<Login>>> GetAllAsync(string uriString) public async Task<Tuple<IEnumerable<Cipher>, IEnumerable<Cipher>>> GetAllAsync(string uriString)
{ {
if(string.IsNullOrWhiteSpace(uriString)) if(string.IsNullOrWhiteSpace(uriString))
{ {
@ -125,9 +125,9 @@ namespace Bit.App.Services
var matchingDomainsArray = matchingDomains.ToArray(); var matchingDomainsArray = matchingDomains.ToArray();
var matchingFuzzyDomainsArray = matchingFuzzyDomains.ToArray(); var matchingFuzzyDomainsArray = matchingFuzzyDomains.ToArray();
var matchingLogins = new List<Login>(); var matchingLogins = new List<Cipher>();
var matchingFuzzyLogins = new List<Login>(); var matchingFuzzyLogins = new List<Cipher>();
var logins = await _loginRepository.GetAllByUserIdAsync(_authService.UserId); var logins = await _cipherRepository.GetAllByUserIdAsync(_authService.UserId);
foreach(var login in logins) foreach(var login in logins)
{ {
if(string.IsNullOrWhiteSpace(login.Uri)) if(string.IsNullOrWhiteSpace(login.Uri))
@ -143,12 +143,12 @@ namespace Bit.App.Services
if(Array.IndexOf(matchingDomainsArray, loginUriString) >= 0) if(Array.IndexOf(matchingDomainsArray, loginUriString) >= 0)
{ {
matchingLogins.Add(new Login(login)); matchingLogins.Add(new Cipher(login));
continue; continue;
} }
else if(mobileApp && Array.IndexOf(matchingFuzzyDomainsArray, loginUriString) >= 0) else if(mobileApp && Array.IndexOf(matchingFuzzyDomainsArray, loginUriString) >= 0)
{ {
matchingFuzzyLogins.Add(new Login(login)); matchingFuzzyLogins.Add(new Cipher(login));
continue; continue;
} }
else if(!mobileApp) else if(!mobileApp)
@ -156,7 +156,7 @@ namespace Bit.App.Services
var info = InfoFromMobileAppUri(loginUriString); var info = InfoFromMobileAppUri(loginUriString);
if(info?.Item1 != null && Array.IndexOf(matchingDomainsArray, info.Item1) >= 0) if(info?.Item1 != null && Array.IndexOf(matchingDomainsArray, info.Item1) >= 0)
{ {
matchingFuzzyLogins.Add(new Login(login)); matchingFuzzyLogins.Add(new Cipher(login));
continue; continue;
} }
} }
@ -170,12 +170,12 @@ namespace Bit.App.Services
if(Array.IndexOf(matchingDomainsArray, loginDomainName) >= 0) if(Array.IndexOf(matchingDomainsArray, loginDomainName) >= 0)
{ {
matchingLogins.Add(new Login(login)); matchingLogins.Add(new Cipher(login));
continue; continue;
} }
else if(mobileApp && Array.IndexOf(matchingFuzzyDomainsArray, loginDomainName) >= 0) else if(mobileApp && Array.IndexOf(matchingFuzzyDomainsArray, loginDomainName) >= 0)
{ {
matchingFuzzyLogins.Add(new Login(login)); matchingFuzzyLogins.Add(new Cipher(login));
continue; continue;
} }
} }
@ -197,7 +197,7 @@ namespace Bit.App.Services
if(addedFromSearchTerm) if(addedFromSearchTerm)
{ {
matchingFuzzyLogins.Add(new Login(login)); matchingFuzzyLogins.Add(new Cipher(login));
break; break;
} }
} }
@ -209,10 +209,10 @@ namespace Bit.App.Services
} }
} }
return new Tuple<IEnumerable<Login>, IEnumerable<Login>>(matchingLogins, matchingFuzzyLogins); return new Tuple<IEnumerable<Cipher>, IEnumerable<Cipher>>(matchingLogins, matchingFuzzyLogins);
} }
public async Task<ApiResult<CipherResponse>> SaveAsync(Login login) public async Task<ApiResult<CipherResponse>> SaveAsync(Cipher login)
{ {
ApiResult<CipherResponse> response = null; ApiResult<CipherResponse> response = null;
var request = new CipherRequest(login); var request = new CipherRequest(login);
@ -228,15 +228,15 @@ namespace Bit.App.Services
if(response.Succeeded) if(response.Succeeded)
{ {
var data = new LoginData(response.Result, _authService.UserId); var data = new CipherData(response.Result, _authService.UserId);
if(login.Id == null) if(login.Id == null)
{ {
await _loginRepository.InsertAsync(data); await _cipherRepository.InsertAsync(data);
login.Id = data.Id; login.Id = data.Id;
} }
else else
{ {
await _loginRepository.UpdateAsync(data); await _cipherRepository.UpdateAsync(data);
} }
} }
else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden
@ -253,7 +253,7 @@ namespace Bit.App.Services
var response = await _cipherApiRepository.DeleteAsync(id); var response = await _cipherApiRepository.DeleteAsync(id);
if(response.Succeeded) if(response.Succeeded)
{ {
await _loginRepository.DeleteAsync(id); await _cipherRepository.DeleteAsync(id);
} }
else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden else if(response.StatusCode == System.Net.HttpStatusCode.Forbidden
|| response.StatusCode == System.Net.HttpStatusCode.Unauthorized) || response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
@ -298,7 +298,7 @@ namespace Bit.App.Services
} }
} }
public async Task<ApiResult<CipherResponse>> EncryptAndSaveAttachmentAsync(Login login, byte[] data, string fileName) public async Task<ApiResult<CipherResponse>> EncryptAndSaveAttachmentAsync(Cipher login, byte[] data, string fileName)
{ {
var encFileName = fileName.Encrypt(login.OrganizationId); var encFileName = fileName.Encrypt(login.OrganizationId);
var encBytes = _cryptoService.EncryptToBytes(data, var encBytes = _cryptoService.EncryptToBytes(data,
@ -323,7 +323,7 @@ namespace Bit.App.Services
return response; return response;
} }
public async Task<ApiResult> DeleteAttachmentAsync(Login login, string attachmentId) public async Task<ApiResult> DeleteAttachmentAsync(Cipher login, string attachmentId)
{ {
var response = await _cipherApiRepository.DeleteAttachmentAsync(login.Id, attachmentId); var response = await _cipherApiRepository.DeleteAttachmentAsync(login.Id, attachmentId);
if(response.Succeeded) if(response.Succeeded)

View file

@ -17,7 +17,7 @@ namespace Bit.App.Services
public void CreateTables() public void CreateTables()
{ {
_connection.CreateTable<FolderData>(); _connection.CreateTable<FolderData>();
_connection.CreateTable<LoginData>(); _connection.CreateTable<CipherData>();
_connection.CreateTable<AttachmentData>(); _connection.CreateTable<AttachmentData>();
_connection.CreateTable<SettingsData>(); _connection.CreateTable<SettingsData>();
} }

View file

@ -110,7 +110,7 @@ namespace Bit.App.Services
{ {
break; break;
} }
_syncService.SyncDeleteLoginAsync(loginDeleteMessage.Id); _syncService.SyncDeleteCipherAsync(loginDeleteMessage.Id);
break; break;
case Enums.PushType.SyncCiphers: case Enums.PushType.SyncCiphers:
case Enums.PushType.SyncVault: case Enums.PushType.SyncVault:

View file

@ -20,7 +20,7 @@ namespace Bit.App.Services
private readonly ISettingsApiRepository _settingsApiRepository; private readonly ISettingsApiRepository _settingsApiRepository;
private readonly ISyncApiRepository _syncApiRepository; private readonly ISyncApiRepository _syncApiRepository;
private readonly IFolderRepository _folderRepository; private readonly IFolderRepository _folderRepository;
private readonly ILoginRepository _loginRepository; private readonly ICipherRepository _cipherRepository;
private readonly IAttachmentRepository _attachmentRepository; private readonly IAttachmentRepository _attachmentRepository;
private readonly ISettingsRepository _settingsRepository; private readonly ISettingsRepository _settingsRepository;
private readonly IAuthService _authService; private readonly IAuthService _authService;
@ -35,7 +35,7 @@ namespace Bit.App.Services
ISettingsApiRepository settingsApiRepository, ISettingsApiRepository settingsApiRepository,
ISyncApiRepository syncApiRepository, ISyncApiRepository syncApiRepository,
IFolderRepository folderRepository, IFolderRepository folderRepository,
ILoginRepository loginRepository, ICipherRepository cipherRepository,
IAttachmentRepository attachmentRepository, IAttachmentRepository attachmentRepository,
ISettingsRepository settingsRepository, ISettingsRepository settingsRepository,
IAuthService authService, IAuthService authService,
@ -49,7 +49,7 @@ namespace Bit.App.Services
_settingsApiRepository = settingsApiRepository; _settingsApiRepository = settingsApiRepository;
_syncApiRepository = syncApiRepository; _syncApiRepository = syncApiRepository;
_folderRepository = folderRepository; _folderRepository = folderRepository;
_loginRepository = loginRepository; _cipherRepository = cipherRepository;
_attachmentRepository = attachmentRepository; _attachmentRepository = attachmentRepository;
_settingsRepository = settingsRepository; _settingsRepository = settingsRepository;
_authService = authService; _authService = authService;
@ -77,40 +77,32 @@ namespace Bit.App.Services
try 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: foreach(var attachment in cipher.Result.Attachments)
var loginData = new LoginData(cipher.Result, _authService.UserId); {
await _loginRepository.UpsertAsync(loginData).ConfigureAwait(false); var attachmentData = new AttachmentData(attachment, cipherData.Id);
await _attachmentRepository.UpsertAsync(attachmentData).ConfigureAwait(false);
}
}
var localAttachments = (await _attachmentRepository.GetAllByLoginIdAsync(loginData.Id) if(localAttachments != null)
.ConfigureAwait(false)); {
foreach(var attachment in localAttachments
if(cipher.Result.Attachments != null) .Where(a => !cipher.Result.Attachments.Any(sa => sa.Id == a.Id)))
{
try
{ {
foreach(var attachment in cipher.Result.Attachments) await _attachmentRepository.DeleteAsync(attachment.Id).ConfigureAwait(false);
{
var attachmentData = new AttachmentData(attachment, loginData.Id);
await _attachmentRepository.UpsertAsync(attachmentData).ConfigureAwait(false);
}
} }
catch(SQLite.SQLiteException) { }
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 try
{ {
await _folderRepository.DeleteWithLoginUpdateAsync(id, revisionDate).ConfigureAwait(false); await _folderRepository.DeleteWithCipherUpdateAsync(id, revisionDate).ConfigureAwait(false);
SyncCompleted(true); SyncCompleted(true);
return true; return true;
} }
@ -175,7 +167,7 @@ namespace Bit.App.Services
} }
} }
public async Task<bool> SyncDeleteLoginAsync(string id) public async Task<bool> SyncDeleteCipherAsync(string id)
{ {
if(!_authService.IsAuthenticated) if(!_authService.IsAuthenticated)
{ {
@ -186,7 +178,7 @@ namespace Bit.App.Services
try try
{ {
await _loginRepository.DeleteAsync(id).ConfigureAwait(false); await _cipherRepository.DeleteAsync(id).ConfigureAwait(false);
SyncCompleted(true); SyncCompleted(true);
return true; return true;
} }
@ -277,17 +269,16 @@ namespace Bit.App.Services
return false; return false;
} }
var loginsDict = syncResponse.Result.Ciphers.Where(c => c.Type == Enums.CipherType.Login) var ciphersDict = syncResponse.Result.Ciphers.ToDictionary(s => s.Id);
.ToDictionary(s => s.Id);
var foldersDict = syncResponse.Result.Folders.ToDictionary(f => f.Id); var foldersDict = syncResponse.Result.Folders.ToDictionary(f => f.Id);
var loginTask = SyncLoginsAsync(loginsDict); var cipherTask = SyncCiphersAsync(ciphersDict);
var folderTask = SyncFoldersAsync(foldersDict); var folderTask = SyncFoldersAsync(foldersDict);
var domainsTask = SyncDomainsAsync(syncResponse.Result.Domains); var domainsTask = SyncDomainsAsync(syncResponse.Result.Domains);
var profileTask = SyncProfileKeysAsync(syncResponse.Result.Profile); 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) profileTask.Exception != null)
{ {
SyncCompleted(false); SyncCompleted(false);
@ -361,14 +352,14 @@ namespace Bit.App.Services
} }
} }
private async Task SyncLoginsAsync(IDictionary<string, CipherResponse> serverLogins) private async Task SyncCiphersAsync(IDictionary<string, CipherResponse> serviceCiphers)
{ {
if(!_authService.IsAuthenticated) if(!_authService.IsAuthenticated)
{ {
return; return;
} }
var localLogins = (await _loginRepository.GetAllByUserIdAsync(_authService.UserId) var localCiphers = (await _cipherRepository.GetAllByUserIdAsync(_authService.UserId)
.ConfigureAwait(false)) .ConfigureAwait(false))
.GroupBy(s => s.Id) .GroupBy(s => s.Id)
.Select(s => s.First()) .Select(s => s.First())
@ -379,7 +370,7 @@ namespace Bit.App.Services
.GroupBy(a => a.LoginId) .GroupBy(a => a.LoginId)
.ToDictionary(g => g.Key); .ToDictionary(g => g.Key);
foreach(var serverLogin in serverLogins) foreach(var serverCipher in serviceCiphers)
{ {
if(!_authService.IsAuthenticated) if(!_authService.IsAuthenticated)
{ {
@ -388,24 +379,25 @@ namespace Bit.App.Services
try 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); var data = new CipherData(serverCipher.Value, _authService.UserId);
await _loginRepository.UpsertAsync(data).ConfigureAwait(false); 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); var attachmentData = new AttachmentData(attachment, data.Id);
await _attachmentRepository.UpsertAsync(attachmentData).ConfigureAwait(false); 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] foreach(var attachment in localAttachments[localCipher.Id]
.Where(a => !serverLogin.Value.Attachments.Any(sa => sa.Id == a.Id))) .Where(a => !serverCipher.Value.Attachments.Any(sa => sa.Id == a.Id)))
{ {
try try
{ {
@ -418,11 +410,11 @@ namespace Bit.App.Services
catch(SQLite.SQLiteException) { } 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 try
{ {
await _loginRepository.DeleteAsync(login.Value.Id).ConfigureAwait(false); await _cipherRepository.DeleteAsync(cipher.Value.Id).ConfigureAwait(false);
} }
catch(SQLite.SQLiteException) { } catch(SQLite.SQLiteException) { }
} }

View file

@ -88,7 +88,7 @@ namespace Bit.UWP
container.RegisterSingleton<IKeyDerivationService, KeyDerivationService>(); container.RegisterSingleton<IKeyDerivationService, KeyDerivationService>();
container.RegisterSingleton<IAuthService, AuthService>(); container.RegisterSingleton<IAuthService, AuthService>();
container.RegisterSingleton<IFolderService, FolderService>(); container.RegisterSingleton<IFolderService, FolderService>();
container.RegisterSingleton<ILoginService, LoginService>(); container.RegisterSingleton<ICipherService, CipherService>();
container.RegisterSingleton<ISyncService, SyncService>(); container.RegisterSingleton<ISyncService, SyncService>();
container.RegisterSingleton<IDeviceActionService, DeviceActionService>(); container.RegisterSingleton<IDeviceActionService, DeviceActionService>();
container.RegisterSingleton<IAppIdService, AppIdService>(); container.RegisterSingleton<IAppIdService, AppIdService>();
@ -108,7 +108,7 @@ namespace Bit.UWP
// Repositories // Repositories
container.RegisterSingleton<IFolderRepository, FolderRepository>(); container.RegisterSingleton<IFolderRepository, FolderRepository>();
container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>(); container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>();
container.RegisterSingleton<ILoginRepository, LoginRepository>(); container.RegisterSingleton<ICipherRepository, CipherRepository>();
container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>(); container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>();
container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>(); container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>();
container.RegisterSingleton<IDeviceApiRepository, DeviceApiRepository>(); container.RegisterSingleton<IDeviceApiRepository, DeviceApiRepository>();

View file

@ -277,7 +277,7 @@ namespace Bit.iOS.Extension
container.RegisterSingleton<IKeyDerivationService, CommonCryptoKeyDerivationService>(); container.RegisterSingleton<IKeyDerivationService, CommonCryptoKeyDerivationService>();
container.RegisterSingleton<IAuthService, AuthService>(); container.RegisterSingleton<IAuthService, AuthService>();
container.RegisterSingleton<IFolderService, FolderService>(); container.RegisterSingleton<IFolderService, FolderService>();
container.RegisterSingleton<ILoginService, LoginService>(); container.RegisterSingleton<ICipherService, CipherService>();
container.RegisterSingleton<ISyncService, SyncService>(); container.RegisterSingleton<ISyncService, SyncService>();
container.RegisterSingleton<IPasswordGenerationService, PasswordGenerationService>(); container.RegisterSingleton<IPasswordGenerationService, PasswordGenerationService>();
container.RegisterSingleton<IAppIdService, AppIdService>(); container.RegisterSingleton<IAppIdService, AppIdService>();
@ -294,7 +294,7 @@ namespace Bit.iOS.Extension
// Repositories // Repositories
container.RegisterSingleton<IFolderRepository, FolderRepository>(); container.RegisterSingleton<IFolderRepository, FolderRepository>();
container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>(); container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>();
container.RegisterSingleton<ILoginRepository, LoginRepository>(); container.RegisterSingleton<ICipherRepository, CipherRepository>();
container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>(); container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>();
container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>(); container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>();
container.RegisterSingleton<ISettingsRepository, SettingsRepository>(); container.RegisterSingleton<ISettingsRepository, SettingsRepository>();

View file

@ -19,7 +19,7 @@ namespace Bit.iOS.Extension
{ {
public partial class LoginAddViewController : ExtendedUITableViewController public partial class LoginAddViewController : ExtendedUITableViewController
{ {
private ILoginService _loginService; private ICipherService _cipherService;
private IFolderService _folderService; private IFolderService _folderService;
private IConnectivity _connectivity; private IConnectivity _connectivity;
private IEnumerable<Folder> _folders; private IEnumerable<Folder> _folders;
@ -49,7 +49,7 @@ namespace Bit.iOS.Extension
public override void ViewDidLoad() public override void ViewDidLoad()
{ {
_loginService = Resolver.Resolve<ILoginService>(); _cipherService = Resolver.Resolve<ICipherService>();
_connectivity = Resolver.Resolve<IConnectivity>(); _connectivity = Resolver.Resolve<IConnectivity>();
_folderService = Resolver.Resolve<IFolderService>(); _folderService = Resolver.Resolve<IFolderService>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>(); _googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
@ -151,18 +151,21 @@ namespace Bit.iOS.Extension
return; 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(), 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(), Notes = string.IsNullOrWhiteSpace(NotesCell.TextView.Text) ? null : NotesCell.TextView.Text.Encrypt(),
Favorite = FavoriteCell.Switch.On, 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); var loadingAlert = Dialogs.CreateLoadingAlert(AppResources.Saving);
PresentViewController(loadingAlert, true, null); PresentViewController(loadingAlert, true, null);
await saveTask; await saveTask;

View file

@ -105,7 +105,7 @@ namespace Bit.iOS.Extension
private IEnumerable<LoginViewModel> _tableItems = new List<LoginViewModel>(); private IEnumerable<LoginViewModel> _tableItems = new List<LoginViewModel>();
private Context _context; private Context _context;
private LoginListViewController _controller; private LoginListViewController _controller;
private ILoginService _loginService; private ICipherService _cipherService;
private ISettings _settings; private ISettings _settings;
private bool _isPremium; private bool _isPremium;
@ -114,15 +114,15 @@ namespace Bit.iOS.Extension
_context = controller.Context; _context = controller.Context;
_controller = controller; _controller = controller;
_isPremium = Resolver.Resolve<ITokenService>()?.TokenPremium ?? false; _isPremium = Resolver.Resolve<ITokenService>()?.TokenPremium ?? false;
_loginService = Resolver.Resolve<ILoginService>(); _cipherService = Resolver.Resolve<ICipherService>();
_settings = Resolver.Resolve<ISettings>(); _settings = Resolver.Resolve<ISettings>();
} }
public async Task LoadItemsAsync() public async Task LoadItemsAsync()
{ {
var combinedLogins = new List<Login>(); var combinedLogins = new List<Cipher>();
var logins = await _loginService.GetAllAsync(_context.UrlString); var logins = await _cipherService.GetAllAsync(_context.UrlString);
if(logins?.Item1 != null) if(logins?.Item1 != null)
{ {
combinedLogins.AddRange(logins.Item1); combinedLogins.AddRange(logins.Item1);

View file

@ -7,7 +7,7 @@ namespace Bit.iOS.Extension.Models
{ {
public class LoginViewModel public class LoginViewModel
{ {
public LoginViewModel(Login login) public LoginViewModel(Cipher login)
{ {
Id = login.Id; Id = login.Id;
Name = login.Name?.Decrypt(login.OrganizationId); Name = login.Name?.Decrypt(login.OrganizationId);

View file

@ -256,7 +256,7 @@ namespace Bit.iOS
container.RegisterSingleton<IKeyDerivationService, CommonCryptoKeyDerivationService>(); container.RegisterSingleton<IKeyDerivationService, CommonCryptoKeyDerivationService>();
container.RegisterSingleton<IAuthService, AuthService>(); container.RegisterSingleton<IAuthService, AuthService>();
container.RegisterSingleton<IFolderService, FolderService>(); container.RegisterSingleton<IFolderService, FolderService>();
container.RegisterSingleton<ILoginService, LoginService>(); container.RegisterSingleton<ICipherService, CipherService>();
container.RegisterSingleton<ISyncService, SyncService>(); container.RegisterSingleton<ISyncService, SyncService>();
container.RegisterSingleton<IDeviceActionService, DeviceActionService>(); container.RegisterSingleton<IDeviceActionService, DeviceActionService>();
container.RegisterSingleton<IAppIdService, AppIdService>(); container.RegisterSingleton<IAppIdService, AppIdService>();
@ -276,7 +276,7 @@ namespace Bit.iOS
// Repositories // Repositories
container.RegisterSingleton<IFolderRepository, FolderRepository>(); container.RegisterSingleton<IFolderRepository, FolderRepository>();
container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>(); container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>();
container.RegisterSingleton<ILoginRepository, LoginRepository>(); container.RegisterSingleton<ICipherRepository, CipherRepository>();
container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>(); container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>();
container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>(); container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>();
container.RegisterSingleton<IDeviceApiRepository, DeviceApiRepository>(); container.RegisterSingleton<IDeviceApiRepository, DeviceApiRepository>();