[PM-2901] Synchronize sends on send creation/update/deletion notification (#2606)

* Add sync on send create/update/delete notification

* Update send notifications to only sync sends

* Fix incorrect notification type in PushNotificationListenerService

Co-authored-by: aj-rosado <109146700+aj-rosado@users.noreply.github.com>

* Invert if to improve readability

* Simplify shouldUpdate logic in SyncUpsertSendAsync

* Further simplify SyncService code

* Fix if condition in SyncService

Co-authored-by: aj-rosado <109146700+aj-rosado@users.noreply.github.com>

* Fixed whitespace formatting

---------

Co-authored-by: aj-rosado <109146700+aj-rosado@users.noreply.github.com>
Co-authored-by: Andre Rosado <arosado@bitwarden.com>
This commit is contained in:
Bernd Schoolmann 2023-08-08 15:59:42 +02:00 committed by GitHub
parent ec93a61275
commit eea7c6b7d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 87 additions and 0 deletions

View file

@ -131,6 +131,24 @@ namespace Bit.App.Services
_messagingService.Value.Send("logout"); _messagingService.Value.Send("logout");
} }
break; break;
case NotificationType.SyncSendCreate:
case NotificationType.SyncSendUpdate:
var sendCreateUpdateMessage = JsonConvert.DeserializeObject<SyncSendNotification>(
notification.Payload);
if (isAuthenticated && sendCreateUpdateMessage.UserId == myUserId)
{
await _syncService.Value.SyncUpsertSendAsync(sendCreateUpdateMessage,
notification.Type == NotificationType.SyncSendUpdate);
}
break;
case NotificationType.SyncSendDelete:
var sendDeleteMessage = JsonConvert.DeserializeObject<SyncSendNotification>(
notification.Payload);
if (isAuthenticated && sendDeleteMessage.UserId == myUserId)
{
await _syncService.Value.SyncDeleteSendAsync(sendDeleteMessage);
}
break;
case NotificationType.AuthRequest: case NotificationType.AuthRequest:
var passwordlessLoginMessage = JsonConvert.DeserializeObject<PasswordlessRequestNotification>(notification.Payload); var passwordlessLoginMessage = JsonConvert.DeserializeObject<PasswordlessRequestNotification>(notification.Payload);

View file

@ -12,8 +12,10 @@ namespace Bit.Core.Abstractions
Task SetLastSyncAsync(DateTime date); Task SetLastSyncAsync(DateTime date);
Task<bool> SyncDeleteCipherAsync(SyncCipherNotification notification); Task<bool> SyncDeleteCipherAsync(SyncCipherNotification notification);
Task<bool> SyncDeleteFolderAsync(SyncFolderNotification notification); Task<bool> SyncDeleteFolderAsync(SyncFolderNotification notification);
Task<bool> SyncDeleteSendAsync(SyncSendNotification notification);
Task<bool> SyncUpsertCipherAsync(SyncCipherNotification notification, bool isEdit); Task<bool> SyncUpsertCipherAsync(SyncCipherNotification notification, bool isEdit);
Task<bool> SyncUpsertFolderAsync(SyncFolderNotification notification, bool isEdit); Task<bool> SyncUpsertFolderAsync(SyncFolderNotification notification, bool isEdit);
Task<bool> SyncUpsertSendAsync(SyncSendNotification notification, bool isEdit);
// Passwordless code will be moved to an independent service in future techdept // Passwordless code will be moved to an independent service in future techdept
Task SyncPasswordlessLoginRequestsAsync(); Task SyncPasswordlessLoginRequestsAsync();
} }

View file

@ -34,6 +34,13 @@ namespace Bit.Core.Models.Response
public DateTime Date { get; set; } public DateTime Date { get; set; }
} }
public class SyncSendNotification
{
public string Id { get; set; }
public string UserId { get; set; }
public DateTime RevisionDate { get; set; }
}
public class PasswordlessRequestNotification public class PasswordlessRequestNotification
{ {
public string UserId { get; set; } public string UserId { get; set; }

View file

@ -274,6 +274,66 @@ namespace Bit.Core.Services
return SyncCompleted(false); return SyncCompleted(false);
} }
public async Task<bool> SyncUpsertSendAsync(SyncSendNotification notification, bool isEdit)
{
SyncStarted();
if (!await _stateService.IsAuthenticatedAsync())
{
return SyncCompleted(false);
}
try
{
var localSend = await _sendService.GetAsync(notification.Id);
if ((localSend != null && localSend.RevisionDate >= notification.RevisionDate)
|| (isEdit && localSend == null) || (!isEdit && localSend != null))
{
return SyncCompleted(false);
}
var remoteSend = await _apiService.GetSendAsync(notification.Id);
if (remoteSend != null)
{
var userId = await _stateService.GetActiveUserIdAsync();
await _sendService.UpsertAsync(new SendData(remoteSend, userId));
_messagingService.Send("syncedUpsertedSend", new Dictionary<string, string>
{
["sendId"] = notification.Id
});
return SyncCompleted(true);
}
}
catch (ApiException e)
{
if (e.Error != null && e.Error.StatusCode == System.Net.HttpStatusCode.NotFound && isEdit)
{
await _sendService.DeleteAsync(notification.Id);
_messagingService.Send("syncedDeletedSend", new Dictionary<string, string>
{
["sendId"] = notification.Id
});
return SyncCompleted(true);
}
}
return SyncCompleted(false);
}
public async Task<bool> SyncDeleteSendAsync(SyncSendNotification notification)
{
SyncStarted();
if (await _stateService.IsAuthenticatedAsync())
{
await _sendService.DeleteAsync(notification.Id);
_messagingService.Send("syncedDeletedSend", new Dictionary<string, string>
{
["sendId"] = notification.Id
});
return SyncCompleted(true);
}
return SyncCompleted(false);
}
// Helpers // Helpers
private void SyncStarted() private void SyncStarted()