diff --git a/src/App/Abstractions/Repositories/IAttachmentRepository.cs b/src/App/Abstractions/Repositories/IAttachmentRepository.cs index 6c615b3b6..f1cde2e89 100644 --- a/src/App/Abstractions/Repositories/IAttachmentRepository.cs +++ b/src/App/Abstractions/Repositories/IAttachmentRepository.cs @@ -8,5 +8,6 @@ namespace Bit.App.Abstractions public interface IAttachmentRepository : IRepository { Task> GetAllByLoginIdAsync(string loginId); + Task> GetAllByUserIdAsync(string userId); } } diff --git a/src/App/Repositories/AttachmentRepository.cs b/src/App/Repositories/AttachmentRepository.cs index 86f909bf5..41166640d 100644 --- a/src/App/Repositories/AttachmentRepository.cs +++ b/src/App/Repositories/AttachmentRepository.cs @@ -18,5 +18,19 @@ namespace Bit.App.Repositories var attachments = Connection.Table().Where(a => a.LoginId == loginId).Cast(); return Task.FromResult(attachments); } + + public Task> GetAllByUserIdAsync(string userId) + { + var attachments = Connection.Query(@" + SELECT + A.* + FROM + Attachment AS A + INNER JOIN + Site AS S ON S.Id = A.LoginId + WHERE + S.UserId = ?", userId); + return Task.FromResult>(attachments); + } } } diff --git a/src/App/Services/SyncService.cs b/src/App/Services/SyncService.cs index 26cd4d219..016c77d28 100644 --- a/src/App/Services/SyncService.cs +++ b/src/App/Services/SyncService.cs @@ -82,6 +82,10 @@ namespace Bit.App.Services case Enums.CipherType.Login: var loginData = new LoginData(cipher.Result, _authService.UserId); await _loginRepository.UpsertAsync(loginData).ConfigureAwait(false); + + var localAttachments = (await _attachmentRepository.GetAllByLoginIdAsync(loginData.Id) + .ConfigureAwait(false)); + if(cipher.Result.Attachments != null) { foreach(var attachment in cipher.Result.Attachments) @@ -90,6 +94,19 @@ namespace Bit.App.Services await _attachmentRepository.UpsertAsync(attachmentData).ConfigureAwait(false); } } + + if(localAttachments != null) + { + foreach(var attachment in localAttachments + .Where(a => !cipher.Result.Attachments.Any(sa => sa.Id == a.Id))) + { + try + { + await _attachmentRepository.DeleteAsync(attachment.Id).ConfigureAwait(false); + } + catch(SQLite.SQLiteException) { } + } + } break; default: SyncCompleted(false); @@ -363,6 +380,11 @@ namespace Bit.App.Services .Select(s => s.First()) .ToDictionary(s => s.Id); + var localAttachments = (await _attachmentRepository.GetAllByUserIdAsync(_authService.UserId) + .ConfigureAwait(false)) + .GroupBy(a => a.LoginId) + .ToDictionary(g => g.Key); + foreach(var serverLogin in serverLogins) { if(!_authService.IsAuthenticated) @@ -372,6 +394,8 @@ namespace Bit.App.Services try { + var localLogin = localLogins.ContainsKey(serverLogin.Value.Id) ? localLogins[serverLogin.Value.Id] : null; + var data = new LoginData(serverLogin.Value, _authService.UserId); await _loginRepository.UpsertAsync(data).ConfigureAwait(false); @@ -383,6 +407,19 @@ namespace Bit.App.Services await _attachmentRepository.UpsertAsync(attachmentData).ConfigureAwait(false); } } + + if(localLogin != null && localAttachments != null && localAttachments.ContainsKey(localLogin.Id)) + { + foreach(var attachment in localAttachments[localLogin.Id] + .Where(a => !serverLogin.Value.Attachments.Any(sa => sa.Id == a.Id))) + { + try + { + await _attachmentRepository.DeleteAsync(attachment.Id).ConfigureAwait(false); + } + catch(SQLite.SQLiteException) { } + } + } } catch(SQLite.SQLiteException) { } }