mirror of
https://github.com/bitwarden/server
synced 2026-03-01 19:01:14 +00:00
PM-15084: Push notifications to installation id.
This enables the Notification Center created global notifications to be sent to affected devices of the same server installation. All clients connected to any of the server instance of that installation id would receive it. This is useful for notifying all clients of an installation about upcoming maintenance. This works both for Self-Hosted, but also for Cloud, assuming an installation id is set.
This commit is contained in:
@@ -29,6 +29,9 @@ public interface IPushNotificationService
|
||||
Task PushAuthRequestAsync(AuthRequest authRequest);
|
||||
Task PushAuthRequestResponseAsync(AuthRequest authRequest);
|
||||
|
||||
Task SendPayloadToInstallationAsync(string installationId, PushType type, object payload, string? identifier,
|
||||
string? deviceId = null, ClientType? clientType = null);
|
||||
|
||||
Task SendPayloadToUserAsync(string userId, PushType type, object payload, string? identifier,
|
||||
string? deviceId = null, ClientType? clientType = null);
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Bit.Core.Services;
|
||||
public interface IPushRegistrationService
|
||||
{
|
||||
Task CreateOrUpdateRegistrationAsync(string pushToken, string deviceId, string userId,
|
||||
string identifier, DeviceType type, IEnumerable<string> organizationIds);
|
||||
string identifier, DeviceType type, IEnumerable<string> organizationIds, string installationId);
|
||||
Task DeleteRegistrationAsync(string deviceId);
|
||||
Task AddUserRegistrationOrganizationAsync(IEnumerable<string> deviceIds, string organizationId);
|
||||
Task DeleteUserRegistrationOrganizationAsync(IEnumerable<string> deviceIds, string organizationId);
|
||||
|
||||
@@ -6,6 +6,7 @@ using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models;
|
||||
using Bit.Core.NotificationCenter.Entities;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Tools.Entities;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Vault.Entities;
|
||||
@@ -18,13 +19,16 @@ public class AzureQueuePushNotificationService : IPushNotificationService
|
||||
{
|
||||
private readonly QueueClient _queueClient;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
|
||||
public AzureQueuePushNotificationService(
|
||||
[FromKeyedServices("notifications")] QueueClient queueClient,
|
||||
IHttpContextAccessor httpContextAccessor)
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IGlobalSettings globalSettings)
|
||||
{
|
||||
_queueClient = queueClient;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
public async Task PushSyncCipherCreateAsync(Cipher cipher, IEnumerable<Guid> collectionIds)
|
||||
@@ -172,6 +176,7 @@ public class AzureQueuePushNotificationService : IPushNotificationService
|
||||
Id = notification.Id,
|
||||
UserId = notification.UserId,
|
||||
OrganizationId = notification.OrganizationId,
|
||||
InstallationId = notification.Global ? _globalSettings.Installation.Id : null,
|
||||
ClientType = notification.ClientType,
|
||||
RevisionDate = notification.RevisionDate
|
||||
};
|
||||
@@ -186,6 +191,7 @@ public class AzureQueuePushNotificationService : IPushNotificationService
|
||||
Id = notification.Id,
|
||||
UserId = notification.UserId,
|
||||
OrganizationId = notification.OrganizationId,
|
||||
InstallationId = notification.Global ? _globalSettings.Installation.Id : null,
|
||||
ClientType = notification.ClientType,
|
||||
RevisionDate = notification.RevisionDate,
|
||||
ReadDate = notificationStatus?.ReadDate,
|
||||
@@ -230,6 +236,11 @@ public class AzureQueuePushNotificationService : IPushNotificationService
|
||||
return currentContext?.DeviceIdentifier;
|
||||
}
|
||||
|
||||
public Task SendPayloadToInstallationAsync(string installationId, PushType type, object payload, string? identifier,
|
||||
string? deviceId = null, ClientType? clientType = null) =>
|
||||
// Noop
|
||||
Task.CompletedTask;
|
||||
|
||||
public Task SendPayloadToUserAsync(string userId, PushType type, object payload, string? identifier,
|
||||
string? deviceId = null, ClientType? clientType = null)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Settings;
|
||||
|
||||
namespace Bit.Core.Services;
|
||||
|
||||
@@ -12,15 +13,18 @@ public class DeviceService : IDeviceService
|
||||
private readonly IDeviceRepository _deviceRepository;
|
||||
private readonly IPushRegistrationService _pushRegistrationService;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
|
||||
public DeviceService(
|
||||
IDeviceRepository deviceRepository,
|
||||
IPushRegistrationService pushRegistrationService,
|
||||
IOrganizationUserRepository organizationUserRepository)
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
IGlobalSettings globalSettings)
|
||||
{
|
||||
_deviceRepository = deviceRepository;
|
||||
_pushRegistrationService = pushRegistrationService;
|
||||
_organizationUserRepository = organizationUserRepository;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
public async Task SaveAsync(Device device)
|
||||
@@ -41,7 +45,8 @@ public class DeviceService : IDeviceService
|
||||
.Select(ou => ou.OrganizationId.ToString());
|
||||
|
||||
await _pushRegistrationService.CreateOrUpdateRegistrationAsync(device.PushToken, device.Id.ToString(),
|
||||
device.UserId.ToString(), device.Identifier, device.Type, organizationIdsString);
|
||||
device.UserId.ToString(), device.Identifier, device.Type, organizationIdsString,
|
||||
_globalSettings.Installation.Id.ToString());
|
||||
}
|
||||
|
||||
public async Task ClearTokenAsync(Device device)
|
||||
|
||||
@@ -132,6 +132,14 @@ public class MultiServicePushNotificationService : IPushNotificationService
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SendPayloadToInstallationAsync(string installationId, PushType type, object payload, string? identifier,
|
||||
string? deviceId = null, ClientType? clientType = null)
|
||||
{
|
||||
PushToServices((s) =>
|
||||
s.SendPayloadToInstallationAsync(installationId, type, payload, identifier, deviceId, clientType));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task SendPayloadToUserAsync(string userId, PushType type, object payload, string? identifier,
|
||||
string? deviceId = null, ClientType? clientType = null)
|
||||
{
|
||||
|
||||
@@ -12,8 +12,14 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Bit.Core.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Sends non-mobile push notifications to the Azure Queue Api, later received by Notifications Api.
|
||||
/// Used by Cloud-Hosted environments.
|
||||
/// Received by AzureQueueHostedService message receiver in Notifications project.
|
||||
/// </summary>
|
||||
public class NotificationsApiPushNotificationService : BaseIdentityClientService, IPushNotificationService
|
||||
{
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public NotificationsApiPushNotificationService(
|
||||
@@ -30,6 +36,7 @@ public class NotificationsApiPushNotificationService : BaseIdentityClientService
|
||||
globalSettings.InternalIdentityKey,
|
||||
logger)
|
||||
{
|
||||
_globalSettings = globalSettings;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
@@ -179,6 +186,7 @@ public class NotificationsApiPushNotificationService : BaseIdentityClientService
|
||||
Id = notification.Id,
|
||||
UserId = notification.UserId,
|
||||
OrganizationId = notification.OrganizationId,
|
||||
InstallationId = notification.Global ? _globalSettings.Installation.Id : null,
|
||||
ClientType = notification.ClientType,
|
||||
RevisionDate = notification.RevisionDate
|
||||
};
|
||||
@@ -193,6 +201,7 @@ public class NotificationsApiPushNotificationService : BaseIdentityClientService
|
||||
Id = notification.Id,
|
||||
UserId = notification.UserId,
|
||||
OrganizationId = notification.OrganizationId,
|
||||
InstallationId = notification.Global ? _globalSettings.Installation.Id : null,
|
||||
ClientType = notification.ClientType,
|
||||
RevisionDate = notification.RevisionDate,
|
||||
ReadDate = notificationStatus?.ReadDate,
|
||||
@@ -236,6 +245,11 @@ public class NotificationsApiPushNotificationService : BaseIdentityClientService
|
||||
return currentContext?.DeviceIdentifier;
|
||||
}
|
||||
|
||||
public Task SendPayloadToInstallationAsync(string installationId, PushType type, object payload, string? identifier,
|
||||
string? deviceId = null, ClientType? clientType = null) =>
|
||||
// Noop
|
||||
Task.CompletedTask;
|
||||
|
||||
public Task SendPayloadToUserAsync(string userId, PushType type, object payload, string? identifier,
|
||||
string? deviceId = null, ClientType? clientType = null)
|
||||
{
|
||||
|
||||
@@ -15,9 +15,15 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Bit.Core.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Sends mobile push notifications to the Bitwarden Cloud API, then relayed to Azure Notification Hub.
|
||||
/// Used by Self-Hosted environments.
|
||||
/// Received by PushController endpoint in Api project.
|
||||
/// </summary>
|
||||
public class RelayPushNotificationService : BaseIdentityClientService, IPushNotificationService
|
||||
{
|
||||
private readonly IDeviceRepository _deviceRepository;
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public RelayPushNotificationService(
|
||||
@@ -36,6 +42,7 @@ public class RelayPushNotificationService : BaseIdentityClientService, IPushNoti
|
||||
logger)
|
||||
{
|
||||
_deviceRepository = deviceRepository;
|
||||
_globalSettings = globalSettings;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
@@ -197,18 +204,25 @@ public class RelayPushNotificationService : BaseIdentityClientService, IPushNoti
|
||||
Id = notification.Id,
|
||||
UserId = notification.UserId,
|
||||
OrganizationId = notification.OrganizationId,
|
||||
InstallationId = notification.Global ? _globalSettings.Installation.Id : null,
|
||||
ClientType = notification.ClientType,
|
||||
RevisionDate = notification.RevisionDate
|
||||
};
|
||||
|
||||
if (notification.UserId.HasValue)
|
||||
if (notification.Global)
|
||||
{
|
||||
await SendPayloadToInstallationAsync(PushType.SyncNotificationCreate, message, true,
|
||||
notification.ClientType);
|
||||
}
|
||||
else if (notification.UserId.HasValue)
|
||||
{
|
||||
await SendPayloadToUserAsync(notification.UserId.Value, PushType.SyncNotificationCreate, message, true,
|
||||
notification.ClientType);
|
||||
}
|
||||
else if (notification.OrganizationId.HasValue)
|
||||
{
|
||||
await SendPayloadToOrganizationAsync(notification.OrganizationId.Value, PushType.SyncNotificationCreate, message,
|
||||
await SendPayloadToOrganizationAsync(notification.OrganizationId.Value, PushType.SyncNotificationCreate,
|
||||
message,
|
||||
true, notification.ClientType);
|
||||
}
|
||||
}
|
||||
@@ -220,24 +234,45 @@ public class RelayPushNotificationService : BaseIdentityClientService, IPushNoti
|
||||
Id = notification.Id,
|
||||
UserId = notification.UserId,
|
||||
OrganizationId = notification.OrganizationId,
|
||||
InstallationId = notification.Global ? _globalSettings.Installation.Id : null,
|
||||
ClientType = notification.ClientType,
|
||||
RevisionDate = notification.RevisionDate,
|
||||
ReadDate = notificationStatus?.ReadDate,
|
||||
DeletedDate = notificationStatus?.DeletedDate
|
||||
};
|
||||
|
||||
if (notification.UserId.HasValue)
|
||||
if (notification.Global)
|
||||
{
|
||||
await SendPayloadToInstallationAsync(PushType.SyncNotificationUpdate, message, true,
|
||||
notification.ClientType);
|
||||
}
|
||||
else if (notification.UserId.HasValue)
|
||||
{
|
||||
await SendPayloadToUserAsync(notification.UserId.Value, PushType.SyncNotificationUpdate, message, true,
|
||||
notification.ClientType);
|
||||
}
|
||||
else if (notification.OrganizationId.HasValue)
|
||||
{
|
||||
await SendPayloadToOrganizationAsync(notification.OrganizationId.Value, PushType.SyncNotificationUpdate, message,
|
||||
true, notification.ClientType);
|
||||
await SendPayloadToOrganizationAsync(notification.OrganizationId.Value, PushType.SyncNotificationUpdate,
|
||||
message, true, notification.ClientType);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SendPayloadToInstallationAsync(PushType type, object payload, bool excludeCurrentContext,
|
||||
ClientType? clientType = null)
|
||||
{
|
||||
var request = new PushSendRequestModel
|
||||
{
|
||||
InstallationId = _globalSettings.Installation.Id.ToString(),
|
||||
Type = type,
|
||||
Payload = payload,
|
||||
ClientType = clientType
|
||||
};
|
||||
|
||||
await AddCurrentContextAsync(request, excludeCurrentContext);
|
||||
await SendAsync(HttpMethod.Post, "push/send", request);
|
||||
}
|
||||
|
||||
private async Task SendPayloadToUserAsync(Guid userId, PushType type, object payload, bool excludeCurrentContext,
|
||||
ClientType? clientType = null)
|
||||
{
|
||||
@@ -287,6 +322,10 @@ public class RelayPushNotificationService : BaseIdentityClientService, IPushNoti
|
||||
}
|
||||
}
|
||||
|
||||
public Task SendPayloadToInstallationAsync(string installationId, PushType type, object payload, string? identifier,
|
||||
string? deviceId = null, ClientType? clientType = null) =>
|
||||
throw new NotImplementedException();
|
||||
|
||||
public Task SendPayloadToUserAsync(string userId, PushType type, object payload, string? identifier,
|
||||
string? deviceId = null, ClientType? clientType = null)
|
||||
{
|
||||
|
||||
@@ -25,7 +25,7 @@ public class RelayPushRegistrationService : BaseIdentityClientService, IPushRegi
|
||||
}
|
||||
|
||||
public async Task CreateOrUpdateRegistrationAsync(string pushToken, string deviceId, string userId,
|
||||
string identifier, DeviceType type, IEnumerable<string> organizationIds)
|
||||
string identifier, DeviceType type, IEnumerable<string> organizationIds, string installationId)
|
||||
{
|
||||
var requestModel = new PushRegistrationRequestModel
|
||||
{
|
||||
@@ -34,7 +34,8 @@ public class RelayPushRegistrationService : BaseIdentityClientService, IPushRegi
|
||||
PushToken = pushToken,
|
||||
Type = type,
|
||||
UserId = userId,
|
||||
OrganizationIds = organizationIds
|
||||
OrganizationIds = organizationIds,
|
||||
InstallationId = installationId
|
||||
};
|
||||
await SendAsync(HttpMethod.Post, "push/register", requestModel);
|
||||
}
|
||||
|
||||
@@ -100,6 +100,9 @@ public class NoopPushNotificationService : IPushNotificationService
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SendPayloadToInstallationAsync(string installationId, PushType type, object payload, string? identifier,
|
||||
string? deviceId = null, ClientType? clientType = null) => Task.CompletedTask;
|
||||
|
||||
public Task SendPayloadToUserAsync(string userId, PushType type, object payload, string? identifier,
|
||||
string? deviceId = null, ClientType? clientType = null)
|
||||
{
|
||||
@@ -108,5 +111,6 @@ public class NoopPushNotificationService : IPushNotificationService
|
||||
|
||||
public Task PushSyncNotificationCreateAsync(Notification notification) => Task.CompletedTask;
|
||||
|
||||
public Task PushSyncNotificationUpdateAsync(Notification notification, NotificationStatus? notificationStatus) => Task.CompletedTask;
|
||||
public Task PushSyncNotificationUpdateAsync(Notification notification, NotificationStatus? notificationStatus) =>
|
||||
Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ public class NoopPushRegistrationService : IPushRegistrationService
|
||||
}
|
||||
|
||||
public Task CreateOrUpdateRegistrationAsync(string pushToken, string deviceId, string userId,
|
||||
string identifier, DeviceType type, IEnumerable<string> organizationIds)
|
||||
string identifier, DeviceType type, IEnumerable<string> organizationIds, string installationId)
|
||||
{
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user