mirror of
https://github.com/bitwarden/server.git
synced 2025-07-02 16:42:50 -05:00
hub api notifications
This commit is contained in:
@ -52,6 +52,30 @@ namespace Bit.Core.Services
|
||||
protected HttpClient IdentityClient { get; private set; }
|
||||
protected string AccessToken { get; private set; }
|
||||
|
||||
protected async Task SendAsync(HttpMethod method, string path, object requestModel = null)
|
||||
{
|
||||
var tokenStateResponse = await HandleTokenStateAsync();
|
||||
if(!tokenStateResponse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var message = new TokenHttpRequestMessage(requestModel, AccessToken)
|
||||
{
|
||||
Method = method,
|
||||
RequestUri = new Uri(string.Concat(Client.BaseAddress, path))
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await Client.SendAsync(message);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
_logger.LogError(12334, e, "Failed to send to {0}.", message.RequestUri.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task<bool> HandleTokenStateAsync()
|
||||
{
|
||||
if(_nextAuthAttempt.HasValue && DateTime.UtcNow > _nextAuthAttempt.Value)
|
||||
@ -119,8 +143,11 @@ namespace Bit.Core.Services
|
||||
public TokenHttpRequestMessage(object requestObject, string token)
|
||||
: this(token)
|
||||
{
|
||||
var stringContent = JsonConvert.SerializeObject(requestObject);
|
||||
Content = new StringContent(stringContent, Encoding.UTF8, "application/json");
|
||||
if(requestObject != null)
|
||||
{
|
||||
var stringContent = JsonConvert.SerializeObject(requestObject);
|
||||
Content = new StringContent(stringContent, Encoding.UTF8, "application/json");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,169 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Models.Table;
|
||||
using Bit.Core.Enums;
|
||||
using Newtonsoft.Json;
|
||||
using Bit.Core.Models;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
public class HubApiPushNotificationService : BaseIdentityClientService, IPushNotificationService
|
||||
{
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
private JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
};
|
||||
|
||||
public HubApiPushNotificationService(
|
||||
GlobalSettings globalSettings,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
ILogger<HubApiPushNotificationService> logger)
|
||||
: base(
|
||||
globalSettings.BaseServiceUri.InternalHub,
|
||||
globalSettings.BaseServiceUri.InternalIdentity,
|
||||
"internal",
|
||||
$"internal.{globalSettings.ProjectName}",
|
||||
globalSettings.InternalIdentityKey,
|
||||
logger)
|
||||
{
|
||||
_globalSettings = globalSettings;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public async Task PushSyncCipherCreateAsync(Cipher cipher)
|
||||
{
|
||||
await PushCipherAsync(cipher, PushType.SyncCipherCreate);
|
||||
}
|
||||
|
||||
public async Task PushSyncCipherUpdateAsync(Cipher cipher)
|
||||
{
|
||||
await PushCipherAsync(cipher, PushType.SyncCipherUpdate);
|
||||
}
|
||||
|
||||
public async Task PushSyncCipherDeleteAsync(Cipher cipher)
|
||||
{
|
||||
await PushCipherAsync(cipher, PushType.SyncLoginDelete);
|
||||
}
|
||||
|
||||
private async Task PushCipherAsync(Cipher cipher, PushType type)
|
||||
{
|
||||
if(cipher.OrganizationId.HasValue)
|
||||
{
|
||||
var message = new SyncCipherPushNotification
|
||||
{
|
||||
Id = cipher.Id,
|
||||
OrganizationId = cipher.OrganizationId,
|
||||
RevisionDate = cipher.RevisionDate,
|
||||
};
|
||||
|
||||
await SendMessageAsync(type, message, true);
|
||||
}
|
||||
else if(cipher.UserId.HasValue)
|
||||
{
|
||||
var message = new SyncCipherPushNotification
|
||||
{
|
||||
Id = cipher.Id,
|
||||
UserId = cipher.UserId,
|
||||
RevisionDate = cipher.RevisionDate,
|
||||
};
|
||||
|
||||
await SendMessageAsync(type, message, true);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task PushSyncFolderCreateAsync(Folder folder)
|
||||
{
|
||||
await PushFolderAsync(folder, PushType.SyncFolderCreate);
|
||||
}
|
||||
|
||||
public async Task PushSyncFolderUpdateAsync(Folder folder)
|
||||
{
|
||||
await PushFolderAsync(folder, PushType.SyncFolderUpdate);
|
||||
}
|
||||
|
||||
public async Task PushSyncFolderDeleteAsync(Folder folder)
|
||||
{
|
||||
await PushFolderAsync(folder, PushType.SyncFolderDelete);
|
||||
}
|
||||
|
||||
private async Task PushFolderAsync(Folder folder, PushType type)
|
||||
{
|
||||
var message = new SyncFolderPushNotification
|
||||
{
|
||||
Id = folder.Id,
|
||||
UserId = folder.UserId,
|
||||
RevisionDate = folder.RevisionDate
|
||||
};
|
||||
|
||||
await SendMessageAsync(type, message, true);
|
||||
}
|
||||
|
||||
public async Task PushSyncCiphersAsync(Guid userId)
|
||||
{
|
||||
await PushSyncUserAsync(userId, PushType.SyncCiphers);
|
||||
}
|
||||
|
||||
public async Task PushSyncVaultAsync(Guid userId)
|
||||
{
|
||||
await PushSyncUserAsync(userId, PushType.SyncVault);
|
||||
}
|
||||
|
||||
public async Task PushSyncOrgKeysAsync(Guid userId)
|
||||
{
|
||||
await PushSyncUserAsync(userId, PushType.SyncOrgKeys);
|
||||
}
|
||||
|
||||
public async Task PushSyncSettingsAsync(Guid userId)
|
||||
{
|
||||
await PushSyncUserAsync(userId, PushType.SyncSettings);
|
||||
}
|
||||
|
||||
private async Task PushSyncUserAsync(Guid userId, PushType type)
|
||||
{
|
||||
var message = new SyncUserPushNotification
|
||||
{
|
||||
UserId = userId,
|
||||
Date = DateTime.UtcNow
|
||||
};
|
||||
|
||||
await SendMessageAsync(type, message, false);
|
||||
}
|
||||
|
||||
private async Task SendMessageAsync<T>(PushType type, T payload, bool excludeCurrentContext)
|
||||
{
|
||||
var contextId = GetContextIdentifier(excludeCurrentContext);
|
||||
var request = new PushNotificationData<T>(type, payload, contextId);
|
||||
await SendAsync(HttpMethod.Post, "/notification", request);
|
||||
}
|
||||
|
||||
private string GetContextIdentifier(bool excludeCurrentContext)
|
||||
{
|
||||
if(!excludeCurrentContext)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var currentContext = _httpContextAccessor?.HttpContext?.
|
||||
RequestServices.GetService(typeof(CurrentContext)) as CurrentContext;
|
||||
return currentContext?.DeviceIdentifier;
|
||||
}
|
||||
|
||||
public Task SendPayloadToUserAsync(string userId, PushType type, object payload, string identifier)
|
||||
{
|
||||
// Noop
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public Task SendPayloadToOrganizationAsync(string orgId, PushType type, object payload, string identifier)
|
||||
{
|
||||
// Noop
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
}
|
||||
}
|
@ -143,7 +143,7 @@ namespace Bit.Core.Services
|
||||
ExcludeCurrentContext(request);
|
||||
}
|
||||
|
||||
await SendAsync(request);
|
||||
await SendAsync(HttpMethod.Post, "/push/send", request);
|
||||
}
|
||||
|
||||
private async Task SendPayloadToOrganizationAsync(Guid orgId, PushType type, object payload, bool excludeCurrentContext)
|
||||
@ -160,31 +160,7 @@ namespace Bit.Core.Services
|
||||
ExcludeCurrentContext(request);
|
||||
}
|
||||
|
||||
await SendAsync(request);
|
||||
}
|
||||
|
||||
private async Task SendAsync(PushSendRequestModel requestModel)
|
||||
{
|
||||
var tokenStateResponse = await HandleTokenStateAsync();
|
||||
if(!tokenStateResponse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var message = new TokenHttpRequestMessage(requestModel, AccessToken)
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(string.Concat(Client.BaseAddress, "/push/send"))
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await Client.SendAsync(message);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
_logger.LogError(12334, e, "Unable to send push notification.");
|
||||
}
|
||||
await SendAsync(HttpMethod.Post, "/push/send", request);
|
||||
}
|
||||
|
||||
private void ExcludeCurrentContext(PushSendRequestModel request)
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http;
|
||||
using System;
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.Enums;
|
||||
using System.Linq;
|
||||
@ -30,12 +29,6 @@ namespace Bit.Core.Services
|
||||
public async Task CreateOrUpdateRegistrationAsync(string pushToken, string deviceId, string userId,
|
||||
string identifier, DeviceType type)
|
||||
{
|
||||
var tokenStateResponse = await HandleTokenStateAsync();
|
||||
if(!tokenStateResponse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var requestModel = new PushRegistrationRequestModel
|
||||
{
|
||||
DeviceId = deviceId,
|
||||
@ -44,45 +37,12 @@ namespace Bit.Core.Services
|
||||
Type = type,
|
||||
UserId = userId
|
||||
};
|
||||
|
||||
var message = new TokenHttpRequestMessage(requestModel, AccessToken)
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri(string.Concat(Client.BaseAddress, "/push/register"))
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await Client.SendAsync(message);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
_logger.LogError(12335, e, "Unable to create push registration.");
|
||||
}
|
||||
await SendAsync(HttpMethod.Post, "/push/register", requestModel);
|
||||
}
|
||||
|
||||
public async Task DeleteRegistrationAsync(string deviceId)
|
||||
{
|
||||
var tokenStateResponse = await HandleTokenStateAsync();
|
||||
if(!tokenStateResponse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var message = new TokenHttpRequestMessage(AccessToken)
|
||||
{
|
||||
Method = HttpMethod.Delete,
|
||||
RequestUri = new Uri(string.Concat(Client.BaseAddress, "/push/", deviceId))
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await Client.SendAsync(message);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
_logger.LogError(12336, e, "Unable to delete push registration.");
|
||||
}
|
||||
await SendAsync(HttpMethod.Delete, string.Concat("/push/", deviceId));
|
||||
}
|
||||
|
||||
public async Task AddUserRegistrationOrganizationAsync(IEnumerable<string> deviceIds, string organizationId)
|
||||
@ -92,27 +52,8 @@ namespace Bit.Core.Services
|
||||
return;
|
||||
}
|
||||
|
||||
var tokenStateResponse = await HandleTokenStateAsync();
|
||||
if(!tokenStateResponse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var requestModel = new PushUpdateRequestModel(deviceIds, organizationId);
|
||||
var message = new TokenHttpRequestMessage(requestModel, AccessToken)
|
||||
{
|
||||
Method = HttpMethod.Put,
|
||||
RequestUri = new Uri(string.Concat(Client.BaseAddress, "/push/add-organization"))
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await Client.SendAsync(message);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
_logger.LogError(12337, e, "Unable to add user org push registration.");
|
||||
}
|
||||
await SendAsync(HttpMethod.Put, "/push/add-organization", requestModel);
|
||||
}
|
||||
|
||||
public async Task DeleteUserRegistrationOrganizationAsync(IEnumerable<string> deviceIds, string organizationId)
|
||||
@ -122,27 +63,8 @@ namespace Bit.Core.Services
|
||||
return;
|
||||
}
|
||||
|
||||
var tokenStateResponse = await HandleTokenStateAsync();
|
||||
if(!tokenStateResponse)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var requestModel = new PushUpdateRequestModel(deviceIds, organizationId);
|
||||
var message = new TokenHttpRequestMessage(requestModel, AccessToken)
|
||||
{
|
||||
Method = HttpMethod.Put,
|
||||
RequestUri = new Uri(string.Concat(Client.BaseAddress, "/push/delete-organization"))
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
await Client.SendAsync(message);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
_logger.LogError(12338, e, "Unable to delete user org push registration.");
|
||||
}
|
||||
await SendAsync(HttpMethod.Put, "/push/delete-organization", requestModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user