mirror of
https://github.com/bitwarden/server
synced 2026-01-02 00:23:40 +00:00
[PM-15084] Push global notification creation to affected clients (#5079)
* PM-10600: Notification push notification * PM-10600: Sending to specific client types for relay push notifications * PM-10600: Sending to specific client types for other clients * PM-10600: Send push notification on notification creation * PM-10600: Explicit group names * PM-10600: Id typos * PM-10600: Revert global push notifications * PM-10600: Added DeviceType claim * PM-10600: Sent to organization typo * PM-10600: UT coverage * PM-10600: Small refactor, UTs coverage * PM-10600: UTs coverage * PM-10600: Startup fix * PM-10600: Test fix * PM-10600: Required attribute, organization group for push notification fix * PM-10600: UT coverage * PM-10600: Fix Mobile devices not registering to organization push notifications We only register devices for organization push notifications when the organization is being created. This does not work, since we have a use case (Notification Center) of delivering notifications to all users of organization. This fixes it, by adding the organization id tag when device registers for push notifications. * PM-10600: Unit Test coverage for NotificationHubPushRegistrationService Fixed IFeatureService substitute mocking for Android tests. Added user part of organization test with organizationId tags expectation. * PM-10600: Unit Tests fix to NotificationHubPushRegistrationService after merge conflict * PM-10600: Organization push notifications not sending to mobile device from self-hosted. Self-hosted instance uses relay to register the mobile device against Bitwarden Cloud Api. Only the self-hosted server knows client's organization membership, which means it needs to pass in the organization id's information to the relay. Similarly, for Bitwarden Cloud, the organizaton id will come directly from the server. * PM-10600: Fix self-hosted organization notification not being received by mobile device. When mobile device registers on self-hosted through the relay, every single id, like user id, device id and now organization id needs to be prefixed with the installation id. This have been missing in the PushController that handles this for organization id. * PM-10600: Broken NotificationsController integration test Device type is now part of JWT access token, so the notification center results in the integration test are now scoped to client type web and all. * PM-10600: Merge conflicts fix * merge conflict fix * PM-10600: Push notification with full notification center content. Notification Center push notification now includes all the fields. * PM-10564: Push notification updates to other clients Cherry-picked and squashed commits:d9711b60316e69c8a0ce01c814595e3885885d5f1285a7e994fcf346985f28ff53c29357804ae27c1c9339b686* PM-15084: Push global notification creation to affected clients Cherry-picked and squashed commits:ed5051e0eb181f3e4ae649fe7c93fda8efb45a637b4122c837d21d4a67b3186a09bb921531f564b5* PM-15084: Log warning when invalid notification push notification sent * explicit Guid default value * push notification tests in wrong namespace * Installation push notification not received for on global notification center message * wrong merge conflict * wrong merge conflict * installation id type Guid in push registration request
This commit is contained in:
@@ -5,6 +5,8 @@ using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models;
|
||||
using Bit.Core.NotificationCenter.Entities;
|
||||
using Bit.Core.Platform.Push.Internal;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Test.AutoFixture;
|
||||
using Bit.Core.Test.AutoFixture.CurrentContextFixtures;
|
||||
using Bit.Core.Test.NotificationCenter.AutoFixture;
|
||||
@@ -14,7 +16,7 @@ using Microsoft.AspNetCore.Http;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Platform.Push.Internal.Test;
|
||||
namespace Bit.Core.Test.Platform.Push.Services;
|
||||
|
||||
[QueueClientCustomize]
|
||||
[SutProviderCustomize]
|
||||
@@ -24,20 +26,43 @@ public class AzureQueuePushNotificationServiceTests
|
||||
[BitAutoData]
|
||||
[NotificationCustomize]
|
||||
[CurrentContextCustomize]
|
||||
public async Task PushNotificationAsync_Notification_Sent(
|
||||
public async Task PushNotificationAsync_NotificationGlobal_Sent(
|
||||
SutProvider<AzureQueuePushNotificationService> sutProvider, Notification notification, Guid deviceIdentifier,
|
||||
ICurrentContext currentContext)
|
||||
ICurrentContext currentContext, Guid installationId)
|
||||
{
|
||||
currentContext.DeviceIdentifier.Returns(deviceIdentifier.ToString());
|
||||
sutProvider.GetDependency<IHttpContextAccessor>().HttpContext!.RequestServices
|
||||
.GetService(Arg.Any<Type>()).Returns(currentContext);
|
||||
sutProvider.GetDependency<IGlobalSettings>().Installation.Id = installationId;
|
||||
|
||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||
|
||||
await sutProvider.GetDependency<QueueClient>().Received(1)
|
||||
.SendMessageAsync(Arg.Is<string>(message =>
|
||||
MatchMessage(PushType.SyncNotification, message,
|
||||
new NotificationPushNotificationEquals(notification, null),
|
||||
MatchMessage(PushType.Notification, message,
|
||||
new NotificationPushNotificationEquals(notification, null, installationId),
|
||||
deviceIdentifier.ToString())));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
[NotificationCustomize(false)]
|
||||
[CurrentContextCustomize]
|
||||
public async Task PushNotificationAsync_NotificationNotGlobal_Sent(
|
||||
SutProvider<AzureQueuePushNotificationService> sutProvider, Notification notification, Guid deviceIdentifier,
|
||||
ICurrentContext currentContext, Guid installationId)
|
||||
{
|
||||
currentContext.DeviceIdentifier.Returns(deviceIdentifier.ToString());
|
||||
sutProvider.GetDependency<IHttpContextAccessor>().HttpContext!.RequestServices
|
||||
.GetService(Arg.Any<Type>()).Returns(currentContext);
|
||||
sutProvider.GetDependency<IGlobalSettings>().Installation.Id = installationId;
|
||||
|
||||
await sutProvider.Sut.PushNotificationAsync(notification);
|
||||
|
||||
await sutProvider.GetDependency<QueueClient>().Received(1)
|
||||
.SendMessageAsync(Arg.Is<string>(message =>
|
||||
MatchMessage(PushType.Notification, message,
|
||||
new NotificationPushNotificationEquals(notification, null, null),
|
||||
deviceIdentifier.ToString())));
|
||||
}
|
||||
|
||||
@@ -46,20 +71,44 @@ public class AzureQueuePushNotificationServiceTests
|
||||
[NotificationCustomize]
|
||||
[NotificationStatusCustomize]
|
||||
[CurrentContextCustomize]
|
||||
public async Task PushNotificationStatusAsync_Notification_Sent(
|
||||
public async Task PushNotificationStatusAsync_NotificationGlobal_Sent(
|
||||
SutProvider<AzureQueuePushNotificationService> sutProvider, Notification notification, Guid deviceIdentifier,
|
||||
ICurrentContext currentContext, NotificationStatus notificationStatus)
|
||||
ICurrentContext currentContext, NotificationStatus notificationStatus, Guid installationId)
|
||||
{
|
||||
currentContext.DeviceIdentifier.Returns(deviceIdentifier.ToString());
|
||||
sutProvider.GetDependency<IHttpContextAccessor>().HttpContext!.RequestServices
|
||||
.GetService(Arg.Any<Type>()).Returns(currentContext);
|
||||
sutProvider.GetDependency<IGlobalSettings>().Installation.Id = installationId;
|
||||
|
||||
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||
|
||||
await sutProvider.GetDependency<QueueClient>().Received(1)
|
||||
.SendMessageAsync(Arg.Is<string>(message =>
|
||||
MatchMessage(PushType.SyncNotificationStatus, message,
|
||||
new NotificationPushNotificationEquals(notification, notificationStatus),
|
||||
MatchMessage(PushType.NotificationStatus, message,
|
||||
new NotificationPushNotificationEquals(notification, notificationStatus, installationId),
|
||||
deviceIdentifier.ToString())));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
[NotificationCustomize(false)]
|
||||
[NotificationStatusCustomize]
|
||||
[CurrentContextCustomize]
|
||||
public async Task PushNotificationStatusAsync_NotificationNotGlobal_Sent(
|
||||
SutProvider<AzureQueuePushNotificationService> sutProvider, Notification notification, Guid deviceIdentifier,
|
||||
ICurrentContext currentContext, NotificationStatus notificationStatus, Guid installationId)
|
||||
{
|
||||
currentContext.DeviceIdentifier.Returns(deviceIdentifier.ToString());
|
||||
sutProvider.GetDependency<IHttpContextAccessor>().HttpContext!.RequestServices
|
||||
.GetService(Arg.Any<Type>()).Returns(currentContext);
|
||||
sutProvider.GetDependency<IGlobalSettings>().Installation.Id = installationId;
|
||||
|
||||
await sutProvider.Sut.PushNotificationStatusAsync(notification, notificationStatus);
|
||||
|
||||
await sutProvider.GetDependency<QueueClient>().Received(1)
|
||||
.SendMessageAsync(Arg.Is<string>(message =>
|
||||
MatchMessage(PushType.NotificationStatus, message,
|
||||
new NotificationPushNotificationEquals(notification, notificationStatus, null),
|
||||
deviceIdentifier.ToString())));
|
||||
}
|
||||
|
||||
@@ -73,7 +122,10 @@ public class AzureQueuePushNotificationServiceTests
|
||||
pushNotificationData.ContextId == contextId;
|
||||
}
|
||||
|
||||
private class NotificationPushNotificationEquals(Notification notification, NotificationStatus? notificationStatus)
|
||||
private class NotificationPushNotificationEquals(
|
||||
Notification notification,
|
||||
NotificationStatus? notificationStatus,
|
||||
Guid? installationId)
|
||||
: IEquatable<NotificationPushNotification>
|
||||
{
|
||||
public bool Equals(NotificationPushNotification? other)
|
||||
@@ -87,6 +139,8 @@ public class AzureQueuePushNotificationServiceTests
|
||||
other.UserId == notification.UserId &&
|
||||
other.OrganizationId.HasValue == notification.OrganizationId.HasValue &&
|
||||
other.OrganizationId == notification.OrganizationId &&
|
||||
other.ClientType == notification.ClientType &&
|
||||
other.InstallationId == installationId &&
|
||||
other.Title == notification.Title &&
|
||||
other.Body == notification.Body &&
|
||||
other.CreationDate == notification.CreationDate &&
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
#nullable enable
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.NotificationCenter.Entities;
|
||||
using Bit.Core.Platform.Push;
|
||||
using Bit.Core.Platform.Push.Internal;
|
||||
using Bit.Core.Test.NotificationCenter.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Platform.Push.Internal.Test;
|
||||
namespace Bit.Core.Test.Platform.Push.Services;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class MultiServicePushNotificationServiceTests
|
||||
@@ -75,4 +77,22 @@ public class MultiServicePushNotificationServiceTests
|
||||
.Received(1)
|
||||
.SendPayloadToOrganizationAsync(organizationId, type, payload, identifier, deviceId, clientType);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData([null, null])]
|
||||
[BitAutoData(ClientType.All, null)]
|
||||
[BitAutoData([null, "test device id"])]
|
||||
[BitAutoData(ClientType.All, "test device id")]
|
||||
public async Task SendPayloadToInstallationAsync_Message_Sent(ClientType? clientType, string? deviceId,
|
||||
string installationId, PushType type, object payload, string identifier,
|
||||
SutProvider<MultiServicePushNotificationService> sutProvider)
|
||||
{
|
||||
await sutProvider.Sut.SendPayloadToInstallationAsync(installationId, type, payload, identifier, deviceId,
|
||||
clientType);
|
||||
|
||||
await sutProvider.GetDependency<IEnumerable<IPushNotificationService>>()
|
||||
.First()
|
||||
.Received(1)
|
||||
.SendPayloadToInstallationAsync(installationId, type, payload, identifier, deviceId, clientType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Platform.Push;
|
||||
using Bit.Core.Settings;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Platform.Push.Internal.Test;
|
||||
namespace Bit.Core.Test.Platform.Push.Services;
|
||||
|
||||
public class NotificationsApiPushNotificationServiceTests
|
||||
{
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Platform.Push.Internal;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Settings;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Platform.Push.Internal.Test;
|
||||
namespace Bit.Core.Test.Platform.Push.Services;
|
||||
|
||||
public class RelayPushNotificationServiceTests
|
||||
{
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Platform.Push.Internal;
|
||||
using Bit.Core.Settings;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Platform.Push.Internal.Test;
|
||||
namespace Bit.Core.Test.Platform.Push.Services;
|
||||
|
||||
public class RelayPushRegistrationServiceTests
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user