mirror of
https://github.com/bitwarden/mobile.git
synced 2024-11-23 11:45:38 +01:00
sync and display attachments on view login
This commit is contained in:
parent
18a86d3f12
commit
0a7ad44d23
@ -227,6 +227,7 @@ namespace Bit.Android
|
||||
container.RegisterSingleton<IFolderRepository, FolderRepository>();
|
||||
container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>();
|
||||
container.RegisterSingleton<ILoginRepository, LoginRepository>();
|
||||
container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>();
|
||||
container.RegisterSingleton<ILoginApiRepository, LoginApiRepository>();
|
||||
container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>();
|
||||
container.RegisterSingleton<IDeviceApiRepository, DeviceApiRepository>();
|
||||
|
12
src/App/Abstractions/Repositories/IAttachmentRepository.cs
Normal file
12
src/App/Abstractions/Repositories/IAttachmentRepository.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Models.Data;
|
||||
|
||||
namespace Bit.App.Abstractions
|
||||
{
|
||||
public interface IAttachmentRepository : IRepository<AttachmentData, string>
|
||||
{
|
||||
Task<IEnumerable<AttachmentData>> GetAllByLoginIdAsync(string loginId);
|
||||
}
|
||||
}
|
@ -35,6 +35,7 @@
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Abstractions\Repositories\IAttachmentRepository.cs" />
|
||||
<Compile Include="Abstractions\Repositories\ITwoFactorApiRepository.cs" />
|
||||
<Compile Include="Abstractions\Repositories\ISettingsApiRepository.cs" />
|
||||
<Compile Include="Abstractions\Repositories\IAccountsApiRepository.cs" />
|
||||
@ -161,6 +162,7 @@
|
||||
<Compile Include="Pages\Vault\VaultAutofillListLoginsPage.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Abstractions\Repositories\ILoginRepository.cs" />
|
||||
<Compile Include="Repositories\AttachmentRepository.cs" />
|
||||
<Compile Include="Repositories\TwoFactorApiRepository.cs" />
|
||||
<Compile Include="Repositories\SettingsApiRepository.cs" />
|
||||
<Compile Include="Repositories\ApiRepository.cs" />
|
||||
|
@ -12,7 +12,7 @@ namespace Bit.App.Models
|
||||
{
|
||||
Id = data.Id;
|
||||
Url = data.Url;
|
||||
FileName = data.FileName;
|
||||
FileName = data.FileName != null ? new CipherString(data.FileName) : null;
|
||||
Size = data.Size;
|
||||
SizeName = data.SizeName;
|
||||
}
|
||||
@ -21,14 +21,14 @@ namespace Bit.App.Models
|
||||
{
|
||||
Id = response.Id;
|
||||
Url = response.Url;
|
||||
FileName = response.FileName;
|
||||
FileName = response.FileName != null ? new CipherString(response.FileName) : null;
|
||||
Size = response.Size;
|
||||
SizeName = response.SizeName;
|
||||
}
|
||||
|
||||
public string Id { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string FileName { get; set; }
|
||||
public CipherString FileName { get; set; }
|
||||
public string Size { get; set; }
|
||||
public string SizeName { get; set; }
|
||||
|
||||
|
@ -15,7 +15,7 @@ namespace Bit.App.Models.Data
|
||||
Id = attachment.Id;
|
||||
LoginId = loginId;
|
||||
Url = attachment.Url;
|
||||
FileName = attachment.FileName;
|
||||
FileName = attachment.FileName?.EncryptedString;
|
||||
Size = attachment.Size;
|
||||
SizeName = attachment.SizeName;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System.ComponentModel;
|
||||
using Bit.App.Resources;
|
||||
using Xamarin.Forms;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Bit.App.Models.Page
|
||||
{
|
||||
@ -13,6 +14,7 @@ namespace Bit.App.Models.Page
|
||||
private string _uri;
|
||||
private string _notes;
|
||||
private bool _revealPassword;
|
||||
private List<Attachment> _attachments;
|
||||
|
||||
public VaultViewLoginPageModel() { }
|
||||
|
||||
@ -192,6 +194,18 @@ namespace Bit.App.Models.Page
|
||||
public string ShowHideText => RevealPassword ? AppResources.Hide : AppResources.Show;
|
||||
public ImageSource ShowHideImage => RevealPassword ? ImageSource.FromFile("eye_slash") : ImageSource.FromFile("eye");
|
||||
|
||||
public List<Attachment> Attachments
|
||||
{
|
||||
get { return _attachments; }
|
||||
set
|
||||
{
|
||||
_attachments = value;
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Attachments)));
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowAttachments)));
|
||||
}
|
||||
}
|
||||
public bool ShowAttachments => (Attachments?.Count ?? 0) > 0;
|
||||
|
||||
public void Update(Login login)
|
||||
{
|
||||
Name = login.Name?.Decrypt(login.OrganizationId);
|
||||
@ -199,6 +213,32 @@ namespace Bit.App.Models.Page
|
||||
Password = login.Password?.Decrypt(login.OrganizationId);
|
||||
Uri = login.Uri?.Decrypt(login.OrganizationId);
|
||||
Notes = login.Notes?.Decrypt(login.OrganizationId);
|
||||
|
||||
if(login.Attachments != null)
|
||||
{
|
||||
var attachments = new List<Attachment>();
|
||||
foreach(var attachment in login.Attachments)
|
||||
{
|
||||
attachments.Add(new Attachment
|
||||
{
|
||||
Id = attachment.Id,
|
||||
Name = attachment.FileName?.Decrypt(login.OrganizationId),
|
||||
Size = attachment.SizeName
|
||||
});
|
||||
}
|
||||
Attachments = attachments;
|
||||
}
|
||||
else
|
||||
{
|
||||
login.Attachments = null;
|
||||
}
|
||||
}
|
||||
|
||||
public class Attachment
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Size { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ namespace Bit.App.Pages
|
||||
private ExtendedTableView Table { get; set; }
|
||||
private TableSection LoginInformationSection { get; set; }
|
||||
private TableSection NotesSection { get; set; }
|
||||
private TableSection AttachmentsSection { get; set; }
|
||||
public LabeledValueCell UsernameCell { get; set; }
|
||||
public LabeledValueCell PasswordCell { get; set; }
|
||||
public LabeledValueCell UriCell { get; set; }
|
||||
@ -184,6 +185,23 @@ namespace Bit.App.Pages
|
||||
Table.Root.Add(NotesSection);
|
||||
}
|
||||
|
||||
if(!Model.ShowAttachments && Table.Root.Contains(AttachmentsSection))
|
||||
{
|
||||
Table.Root.Remove(AttachmentsSection);
|
||||
}
|
||||
else if(Model.ShowAttachments && !Table.Root.Contains(AttachmentsSection))
|
||||
{
|
||||
AttachmentsSection = new TableSection(AppResources.Attachments);
|
||||
foreach(var attachment in Model.Attachments)
|
||||
{
|
||||
AttachmentsSection.Add(new AttachmentViewCell(attachment, () =>
|
||||
{
|
||||
|
||||
}));
|
||||
}
|
||||
Table.Root.Add(AttachmentsSection);
|
||||
}
|
||||
|
||||
base.OnAppearing();
|
||||
}
|
||||
|
||||
@ -223,5 +241,23 @@ namespace Bit.App.Pages
|
||||
await _page.Navigation.PushForDeviceAsync(page);
|
||||
}
|
||||
}
|
||||
|
||||
public class AttachmentViewCell : ExtendedTextCell
|
||||
{
|
||||
Action _clicked;
|
||||
|
||||
public AttachmentViewCell(VaultViewLoginPageModel.Attachment attachment, Action clickedAction)
|
||||
{
|
||||
_clicked = clickedAction;
|
||||
Text = attachment.Name;
|
||||
Tapped += AttachmentViewCell_Tapped;
|
||||
BackgroundColor = Color.White;
|
||||
}
|
||||
|
||||
private void AttachmentViewCell_Tapped(object sender, EventArgs e)
|
||||
{
|
||||
_clicked?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
22
src/App/Repositories/AttachmentRepository.cs
Normal file
22
src/App/Repositories/AttachmentRepository.cs
Normal file
@ -0,0 +1,22 @@
|
||||
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 AttachmentRepository : Repository<AttachmentData, string>, IAttachmentRepository
|
||||
{
|
||||
public AttachmentRepository(ISqlService sqlService)
|
||||
: base(sqlService)
|
||||
{ }
|
||||
|
||||
public Task<IEnumerable<AttachmentData>> GetAllByLoginIdAsync(string loginId)
|
||||
{
|
||||
var attachments = Connection.Table<AttachmentData>().Where(a => a.LoginId == loginId).Cast<AttachmentData>();
|
||||
return Task.FromResult(attachments);
|
||||
}
|
||||
}
|
||||
}
|
18
src/App/Resources/AppResources.Designer.cs
generated
18
src/App/Resources/AppResources.Designer.cs
generated
@ -124,6 +124,15 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Add New Attachment.
|
||||
/// </summary>
|
||||
public static string AddNewAttachment {
|
||||
get {
|
||||
return ResourceManager.GetString("AddNewAttachment", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to An error has occurred..
|
||||
/// </summary>
|
||||
@ -142,6 +151,15 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Attachments.
|
||||
/// </summary>
|
||||
public static string Attachments {
|
||||
get {
|
||||
return ResourceManager.GetString("Attachments", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Authenticator App.
|
||||
/// </summary>
|
||||
|
@ -902,4 +902,10 @@
|
||||
<value>YubiKey NEO Security Key</value>
|
||||
<comment>"YubiKey NEO" is the product name and should not be translated.</comment>
|
||||
</data>
|
||||
<data name="AddNewAttachment" xml:space="preserve">
|
||||
<value>Add New Attachment</value>
|
||||
</data>
|
||||
<data name="Attachments" xml:space="preserve">
|
||||
<value>Attachments</value>
|
||||
</data>
|
||||
</root>
|
@ -18,6 +18,7 @@ namespace Bit.App.Services
|
||||
{
|
||||
_connection.CreateTable<FolderData>();
|
||||
_connection.CreateTable<LoginData>();
|
||||
_connection.CreateTable<AttachmentData>();
|
||||
_connection.CreateTable<SettingsData>();
|
||||
}
|
||||
}
|
||||
|
@ -13,17 +13,20 @@ namespace Bit.App.Services
|
||||
public class LoginService : ILoginService
|
||||
{
|
||||
private readonly ILoginRepository _loginRepository;
|
||||
private readonly IAttachmentRepository _attachmentRepository;
|
||||
private readonly IAuthService _authService;
|
||||
private readonly ILoginApiRepository _loginApiRepository;
|
||||
private readonly ISettingsService _settingsService;
|
||||
|
||||
public LoginService(
|
||||
ILoginRepository loginRepository,
|
||||
IAttachmentRepository attachmentRepository,
|
||||
IAuthService authService,
|
||||
ILoginApiRepository loginApiRepository,
|
||||
ISettingsService settingsService)
|
||||
{
|
||||
_loginRepository = loginRepository;
|
||||
_attachmentRepository = attachmentRepository;
|
||||
_authService = authService;
|
||||
_loginApiRepository = loginApiRepository;
|
||||
_settingsService = settingsService;
|
||||
@ -37,7 +40,8 @@ namespace Bit.App.Services
|
||||
return null;
|
||||
}
|
||||
|
||||
var login = new Login(data);
|
||||
var attachments = await _attachmentRepository.GetAllByLoginIdAsync(id);
|
||||
var login = new Login(data, attachments);
|
||||
return login;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ namespace Bit.App.Services
|
||||
private readonly ISettingsApiRepository _settingsApiRepository;
|
||||
private readonly IFolderRepository _folderRepository;
|
||||
private readonly ILoginRepository _loginRepository;
|
||||
private readonly IAttachmentRepository _attachmentRepository;
|
||||
private readonly ISettingsRepository _settingsRepository;
|
||||
private readonly IAuthService _authService;
|
||||
private readonly ICryptoService _cryptoService;
|
||||
@ -35,6 +36,7 @@ namespace Bit.App.Services
|
||||
ISettingsApiRepository settingsApiRepository,
|
||||
IFolderRepository folderRepository,
|
||||
ILoginRepository loginRepository,
|
||||
IAttachmentRepository attachmentRepository,
|
||||
ISettingsRepository settingsRepository,
|
||||
IAuthService authService,
|
||||
ICryptoService cryptoService,
|
||||
@ -48,6 +50,7 @@ namespace Bit.App.Services
|
||||
_settingsApiRepository = settingsApiRepository;
|
||||
_folderRepository = folderRepository;
|
||||
_loginRepository = loginRepository;
|
||||
_attachmentRepository = attachmentRepository;
|
||||
_settingsRepository = settingsRepository;
|
||||
_authService = authService;
|
||||
_cryptoService = cryptoService;
|
||||
@ -79,6 +82,14 @@ namespace Bit.App.Services
|
||||
case Enums.CipherType.Login:
|
||||
var loginData = new LoginData(cipher.Result, _authService.UserId);
|
||||
await _loginRepository.UpsertAsync(loginData).ConfigureAwait(false);
|
||||
if(cipher.Result.Attachments != null)
|
||||
{
|
||||
foreach(var attachment in cipher.Result.Attachments)
|
||||
{
|
||||
var attachmentData = new AttachmentData(attachment, loginData.Id);
|
||||
await _attachmentRepository.UpsertAsync(attachmentData).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SyncCompleted(false);
|
||||
@ -363,6 +374,15 @@ namespace Bit.App.Services
|
||||
{
|
||||
var data = new LoginData(serverLogin.Value, _authService.UserId);
|
||||
await _loginRepository.UpsertAsync(data).ConfigureAwait(false);
|
||||
|
||||
if(serverLogin.Value.Attachments != null)
|
||||
{
|
||||
foreach(var attachment in serverLogin.Value.Attachments)
|
||||
{
|
||||
var attachmentData = new AttachmentData(attachment, data.Id);
|
||||
await _attachmentRepository.UpsertAsync(attachmentData).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(SQLite.SQLiteException) { }
|
||||
}
|
||||
|
@ -288,6 +288,7 @@ namespace Bit.iOS.Extension
|
||||
container.RegisterSingleton<IFolderRepository, FolderRepository>();
|
||||
container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>();
|
||||
container.RegisterSingleton<ILoginRepository, LoginRepository>();
|
||||
container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>();
|
||||
container.RegisterSingleton<ILoginApiRepository, LoginApiRepository>();
|
||||
container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>();
|
||||
container.RegisterSingleton<ISettingsRepository, SettingsRepository>();
|
||||
|
@ -273,6 +273,7 @@ namespace Bit.iOS
|
||||
container.RegisterSingleton<IFolderRepository, FolderRepository>();
|
||||
container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>();
|
||||
container.RegisterSingleton<ILoginRepository, LoginRepository>();
|
||||
container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>();
|
||||
container.RegisterSingleton<ILoginApiRepository, LoginApiRepository>();
|
||||
container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>();
|
||||
container.RegisterSingleton<IDeviceApiRepository, DeviceApiRepository>();
|
||||
|
Loading…
Reference in New Issue
Block a user