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

View file

@ -7,7 +7,7 @@ namespace Bit.App.Abstractions
{
public interface IAttachmentRepository : IRepository<AttachmentData, string>
{
Task<IEnumerable<AttachmentData>> GetAllByLoginIdAsync(string loginId);
Task<IEnumerable<AttachmentData>> GetAllByCipherIdAsync(string cipherId);
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>
{
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> SyncFolderAsync(string id);
Task<bool> SyncDeleteFolderAsync(string id, DateTime revisionDate);
Task<bool> SyncDeleteLoginAsync(string id);
Task<bool> SyncDeleteCipherAsync(string id);
Task<bool> SyncSettingsAsync();
Task<bool> SyncProfileAsync();
Task<bool> FullSyncAsync(bool forceSync = false);

View file

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

View file

@ -6,6 +6,7 @@
//Folder = 0,
Login = 1,
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 CipherRequest(Login login)
public CipherRequest(Cipher cipher)
{
Type = CipherType.Login;
OrganizationId = login.OrganizationId;
FolderId = login.FolderId;
Name = login.Name?.EncryptedString;
Notes = login.Notes?.EncryptedString;
Favorite = login.Favorite;
Type = cipher.Type;
OrganizationId = cipher.OrganizationId;
FolderId = cipher.FolderId;
Name = cipher.Name?.EncryptedString;
Notes = cipher.Notes?.EncryptedString;
Favorite = cipher.Favorite;
if(login.Fields != null)
if(cipher.Fields != null)
{
Fields = login.Fields.Select(f => new FieldDataModel
Fields = cipher.Fields.Select(f => new FieldDataModel
{
Name = f.Name?.EncryptedString,
Value = f.Value?.EncryptedString,
@ -28,7 +28,16 @@ namespace Bit.App.Models.Api
switch(Type)
{
case CipherType.Login:
Login = new LoginType(login);
Login = new LoginType(cipher);
break;
case CipherType.Card:
Card = new CardType(cipher);
break;
case CipherType.Identity:
Identity = new IdentityType(cipher);
break;
case CipherType.SecureNote:
SecureNote = new SecureNoteType(cipher);
break;
default:
break;
@ -42,16 +51,20 @@ namespace Bit.App.Models.Api
public string Name { get; set; }
public string Notes { get; set; }
public IEnumerable<FieldDataModel> Fields { get; set; }
public LoginType Login { get; set; }
public CardType Card { get; set; }
public IdentityType Identity { get; set; }
public SecureNoteType SecureNote { get; set; }
public class LoginType
{
public LoginType(Login login)
public LoginType(Cipher cipher)
{
Uri = login.Uri?.EncryptedString;
Username = login.Username?.EncryptedString;
Password = login.Password?.EncryptedString;
Totp = login.Totp?.EncryptedString;
Uri = cipher.Login.Uri?.EncryptedString;
Username = cipher.Login.Username?.EncryptedString;
Password = cipher.Login.Password?.EncryptedString;
Totp = cipher.Login.Totp?.EncryptedString;
}
public string Uri { get; set; }
@ -59,5 +72,79 @@ namespace Bit.App.Models.Api
public string Password { get; set; }
public string Totp { get; set; }
}
public class CardType
{
public CardType(Cipher cipher)
{
CardholderName = cipher.Card.CardholderName?.EncryptedString;
Brand = cipher.Card.Brand?.EncryptedString;
Number = cipher.Card.Number?.EncryptedString;
ExpMonth = cipher.Card.ExpMonth?.EncryptedString;
ExpYear = cipher.Card.ExpYear?.EncryptedString;
Code = cipher.Card.Code?.EncryptedString;
}
public string CardholderName { get; set; }
public string Brand { get; set; }
public string Number { get; set; }
public string ExpMonth { get; set; }
public string ExpYear { get; set; }
public string Code { get; set; }
}
public class IdentityType
{
public IdentityType(Cipher cipher)
{
Title = cipher.Identity.Title?.EncryptedString;
FirstName = cipher.Identity.FirstName?.EncryptedString;
MiddleName = cipher.Identity.MiddleName?.EncryptedString;
LastName = cipher.Identity.LastName?.EncryptedString;
Address1 = cipher.Identity.Address1?.EncryptedString;
Address2 = cipher.Identity.Address2?.EncryptedString;
Address3 = cipher.Identity.Address3?.EncryptedString;
City = cipher.Identity.City?.EncryptedString;
State = cipher.Identity.State?.EncryptedString;
PostalCode = cipher.Identity.PostalCode?.EncryptedString;
Country = cipher.Identity.Country?.EncryptedString;
Company = cipher.Identity.Company?.EncryptedString;
Email = cipher.Identity.Email?.EncryptedString;
Phone = cipher.Identity.Phone?.EncryptedString;
SSN = cipher.Identity.SSN?.EncryptedString;
Username = cipher.Identity.Username?.EncryptedString;
PassportNumber = cipher.Identity.PassportNumber?.EncryptedString;
LicenseNumber = cipher.Identity.LicenseNumber?.EncryptedString;
}
public string Title { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Address3 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public string Company { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string SSN { get; set; }
public string Username { get; set; }
public string PassportNumber { get; set; }
public string LicenseNumber { get; set; }
}
public class SecureNoteType
{
public SecureNoteType(Cipher cipher)
{
Type = cipher.SecureNote.Type;
}
public Enums.SecureNoteType Type { get; set; }
}
}
}

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

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 Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
using Bit.App.Models.Data;
namespace Bit.App.Models
{
public class Login
{
public Login()
{ }
public Login() { }
public Login(LoginData data, IEnumerable<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;
Username = data.Username != null ? new CipherString(data.Username) : null;
Password = data.Password != null ? new CipherString(data.Password) : null;
Notes = data.Notes != null ? new CipherString(data.Notes) : null;
Totp = data.Totp != null ? new CipherString(data.Totp) : null;
Favorite = data.Favorite;
Edit = data.Edit;
OrganizationUseTotp = data.OrganizationUseTotp;
Attachments = attachments?.Select(a => new Attachment(a));
if(!string.IsNullOrWhiteSpace(data.Fields))
{
try
{
var fieldModels = JsonConvert.DeserializeObject<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 Username { get; set; }
public CipherString Password { get; set; }
public CipherString Notes { 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 Login(Models.Login login)
public Login(Models.Cipher cipher)
{
Id = login.Id;
Shared = !string.IsNullOrWhiteSpace(login.OrganizationId);
HasAttachments = login.Attachments?.Any() ?? false;
FolderId = login.FolderId;
Name = login.Name?.Decrypt(login.OrganizationId);
Username = login.Username?.Decrypt(login.OrganizationId) ?? " ";
Password = new Lazy<string>(() => login.Password?.Decrypt(login.OrganizationId));
Uri = new Lazy<string>(() => login.Uri?.Decrypt(login.OrganizationId));
Totp = new Lazy<string>(() => login.Totp?.Decrypt(login.OrganizationId));
Id = cipher.Id;
Shared = !string.IsNullOrWhiteSpace(cipher.OrganizationId);
HasAttachments = cipher.Attachments?.Any() ?? false;
FolderId = cipher.FolderId;
Name = cipher.Name?.Decrypt(cipher.OrganizationId);
Username = cipher.Login?.Username?.Decrypt(cipher.OrganizationId) ?? " ";
Password = new Lazy<string>(() => cipher.Login?.Password?.Decrypt(cipher.OrganizationId));
Uri = new Lazy<string>(() => cipher.Login?.Uri?.Decrypt(cipher.OrganizationId));
Totp = new Lazy<string>(() => cipher.Login?.Totp?.Decrypt(cipher.OrganizationId));
}
public string Id { get; set; }
@ -35,7 +35,7 @@ namespace Bit.App.Models.Page
public class AutofillLogin : Login
{
public AutofillLogin(Models.Login login, bool fuzzy = false)
public AutofillLogin(Models.Cipher login, bool fuzzy = false)
: base(login)
{
Fuzzy = fuzzy;

View file

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

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 readonly ILoginService _loginService;
private readonly ICipherService _cipherService;
private readonly IFolderService _folderService;
private readonly IUserDialogs _userDialogs;
private readonly IConnectivity _connectivity;
@ -37,7 +37,7 @@ namespace Bit.App.Pages
_defaultName = defaultName;
_fromAutofill = fromAutofill;
_loginService = Resolver.Resolve<ILoginService>();
_cipherService = Resolver.Resolve<ICipherService>();
_folderService = Resolver.Resolve<IFolderService>();
_userDialogs = Resolver.Resolve<IUserDialogs>();
_connectivity = Resolver.Resolve<IConnectivity>();
@ -177,24 +177,31 @@ namespace Bit.App.Pages
return;
}
var login = new Login
var cipher = new Cipher
{
Name = NameCell.Entry.Text.Encrypt(),
Uri = string.IsNullOrWhiteSpace(UriCell.Entry.Text) ? null : UriCell.Entry.Text.Encrypt(),
Username = string.IsNullOrWhiteSpace(UsernameCell.Entry.Text) ? null : UsernameCell.Entry.Text.Encrypt(),
Password = string.IsNullOrWhiteSpace(PasswordCell.Entry.Text) ? null : PasswordCell.Entry.Text.Encrypt(),
Notes = string.IsNullOrWhiteSpace(NotesCell.Editor.Text) ? null : NotesCell.Editor.Text.Encrypt(),
Totp = string.IsNullOrWhiteSpace(TotpCell.Entry.Text) ? null : TotpCell.Entry.Text.Encrypt(),
Favorite = favoriteCell.On
Favorite = favoriteCell.On,
Login = new Login
{
Uri = string.IsNullOrWhiteSpace(UriCell.Entry.Text) ? null :
UriCell.Entry.Text.Encrypt(),
Username = string.IsNullOrWhiteSpace(UsernameCell.Entry.Text) ? null :
UsernameCell.Entry.Text.Encrypt(),
Password = string.IsNullOrWhiteSpace(PasswordCell.Entry.Text) ? null :
PasswordCell.Entry.Text.Encrypt(),
Totp = string.IsNullOrWhiteSpace(TotpCell.Entry.Text) ? null :
TotpCell.Entry.Text.Encrypt(),
}
};
if(FolderCell.Picker.SelectedIndex > 0)
{
login.FolderId = folders.ElementAt(FolderCell.Picker.SelectedIndex - 1).Id;
cipher.FolderId = folders.ElementAt(FolderCell.Picker.SelectedIndex - 1).Id;
}
_userDialogs.ShowLoading(AppResources.Saving, MaskType.Black);
var saveTask = await _loginService.SaveAsync(login);
var saveTask = await _cipherService.SaveAsync(cipher);
_userDialogs.HideLoading();
if(saveTask.Succeeded)

View file

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

View file

@ -17,7 +17,7 @@ namespace Bit.App.Pages
{
public class VaultAutofillListLoginsPage : ExtendedContentPage
{
private readonly ILoginService _loginService;
private readonly ICipherService _cipherService;
private readonly IDeviceInfoService _deviceInfoService;
private readonly IDeviceActionService _clipboardService;
private readonly ISettingsService _settingsService;
@ -40,7 +40,7 @@ namespace Bit.App.Pages
_name = "--";
}
_loginService = Resolver.Resolve<ILoginService>();
_cipherService = Resolver.Resolve<ICipherService>();
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
_clipboardService = Resolver.Resolve<IDeviceActionService>();
_settingsService = Resolver.Resolve<ISettingsService>();
@ -162,7 +162,7 @@ namespace Bit.App.Pages
Task.Run(async () =>
{
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))
.OrderBy(s => s.Name)

View file

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

View file

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

View file

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

View file

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

View file

@ -13,9 +13,10 @@ namespace Bit.App.Repositories
: 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);
}

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)
{
var now = DateTime.UtcNow;
DeleteWithLoginUpdateAsync(id, now);
DeleteWithCipherUpdateAsync(id, now);
return Task.FromResult(0);
}
public Task DeleteWithLoginUpdateAsync(string id, DateTime revisionDate)
public Task DeleteWithCipherUpdateAsync(string id, DateTime revisionDate)
{
Connection.RunInTransaction(() =>
{

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -19,7 +19,7 @@ namespace Bit.iOS.Extension
{
public partial class LoginAddViewController : ExtendedUITableViewController
{
private ILoginService _loginService;
private ICipherService _cipherService;
private IFolderService _folderService;
private IConnectivity _connectivity;
private IEnumerable<Folder> _folders;
@ -49,7 +49,7 @@ namespace Bit.iOS.Extension
public override void ViewDidLoad()
{
_loginService = Resolver.Resolve<ILoginService>();
_cipherService = Resolver.Resolve<ICipherService>();
_connectivity = Resolver.Resolve<IConnectivity>();
_folderService = Resolver.Resolve<IFolderService>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
@ -151,18 +151,21 @@ namespace Bit.iOS.Extension
return;
}
var login = new Login
var cipher = new Cipher
{
Uri = string.IsNullOrWhiteSpace(UriCell.TextField.Text) ? null : UriCell.TextField.Text.Encrypt(),
Name = string.IsNullOrWhiteSpace(NameCell.TextField.Text) ? null : NameCell.TextField.Text.Encrypt(),
Username = string.IsNullOrWhiteSpace(UsernameCell.TextField.Text) ? null : UsernameCell.TextField.Text.Encrypt(),
Password = string.IsNullOrWhiteSpace(PasswordCell.TextField.Text) ? null : PasswordCell.TextField.Text.Encrypt(),
Notes = string.IsNullOrWhiteSpace(NotesCell.TextView.Text) ? null : NotesCell.TextView.Text.Encrypt(),
Favorite = FavoriteCell.Switch.On,
FolderId = FolderCell.SelectedIndex == 0 ? null : _folders.ElementAtOrDefault(FolderCell.SelectedIndex - 1)?.Id
FolderId = FolderCell.SelectedIndex == 0 ? null : _folders.ElementAtOrDefault(FolderCell.SelectedIndex - 1)?.Id,
Login = new Login
{
Uri = string.IsNullOrWhiteSpace(UriCell.TextField.Text) ? null : UriCell.TextField.Text.Encrypt(),
Username = string.IsNullOrWhiteSpace(UsernameCell.TextField.Text) ? null : UsernameCell.TextField.Text.Encrypt(),
Password = string.IsNullOrWhiteSpace(PasswordCell.TextField.Text) ? null : PasswordCell.TextField.Text.Encrypt()
}
};
var saveTask = _loginService.SaveAsync(login);
var saveTask = _cipherService.SaveAsync(cipher);
var loadingAlert = Dialogs.CreateLoadingAlert(AppResources.Saving);
PresentViewController(loadingAlert, true, null);
await saveTask;

View file

@ -105,7 +105,7 @@ namespace Bit.iOS.Extension
private IEnumerable<LoginViewModel> _tableItems = new List<LoginViewModel>();
private Context _context;
private LoginListViewController _controller;
private ILoginService _loginService;
private ICipherService _cipherService;
private ISettings _settings;
private bool _isPremium;
@ -114,15 +114,15 @@ namespace Bit.iOS.Extension
_context = controller.Context;
_controller = controller;
_isPremium = Resolver.Resolve<ITokenService>()?.TokenPremium ?? false;
_loginService = Resolver.Resolve<ILoginService>();
_cipherService = Resolver.Resolve<ICipherService>();
_settings = Resolver.Resolve<ISettings>();
}
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)
{
combinedLogins.AddRange(logins.Item1);

View file

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

View file

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