1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-06 13:38:13 -05:00

notification hub push registration service

This commit is contained in:
Kyle Spearrin 2017-05-26 00:50:27 -04:00
parent e3cba6204b
commit c95d39f563
18 changed files with 163 additions and 11 deletions

View File

@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Authorization;
using Bit.Core.Models.Api;
using Bit.Core.Exceptions;
using Bit.Core.Models.Table;
using Microsoft.AspNetCore.Identity;
using Bit.Core.Services;
namespace Bit.Api.Controllers
@ -109,7 +108,13 @@ namespace Bit.Api.Controllers
[HttpPost("identifier/{identifier}/clear-token")]
public async Task PutClearToken(string identifier)
{
await _deviceRepository.ClearPushTokenByIdentifierAsync(identifier);
var device = await _deviceRepository.GetByIdentifierAsync(identifier, _userService.GetProperUserId(User).Value);
if(device == null)
{
throw new NotFoundException();
}
await _deviceService.ClearTokenAsync(device);
}
[HttpDelete("{id}")]
@ -122,7 +127,7 @@ namespace Bit.Api.Controllers
throw new NotFoundException();
}
await _deviceRepository.DeleteAsync(device);
await _deviceService.DeleteAsync(device);
}
}
}

View File

@ -30,6 +30,10 @@
"documentDb": {
"uri": "SECRET",
"key": "SECRET"
},
"notificationHub": {
"connectionString": "SECRET",
"hubName": "SECRET"
}
},
"IpRateLimitOptions": {

View File

@ -30,6 +30,10 @@
"documentDb": {
"uri": "SECRET",
"key": "SECRET"
},
"notificationHub": {
"connectionString": "SECRET",
"hubName": "SECRET"
}
},
"billingSettings": {

View File

@ -20,6 +20,7 @@
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="1.1.3" />
<PackageReference Include="Dapper" Version="1.50.2" />
<PackageReference Include="Microsoft.Azure.NotificationHubs" Version="1.0.8" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="1.1.2" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />

View File

@ -16,6 +16,7 @@
OperaBrowser = 11,
EdgeBrowser = 12,
IEBrowser = 13,
UnknownBrowser = 14
UnknownBrowser = 14,
AndroidAmazon = 15
}
}

View File

@ -13,6 +13,7 @@
public virtual IdentityServerSettings IdentityServer { get; set; } = new IdentityServerSettings();
public virtual DataProtectionSettings DataProtection { get; set; } = new DataProtectionSettings();
public virtual DocumentDbSettings DocumentDb { get; set; } = new DocumentDbSettings();
public virtual NotificationHubSettings NotificationHub { get; set; } = new NotificationHubSettings();
public class SqlServerSettings
{
@ -54,5 +55,11 @@
public string Uri { get; set; }
public string Key { get; set; }
}
public class NotificationHubSettings
{
public string ConnectionString { get; set; }
public string HubName { get; set; }
}
}
}

View File

@ -10,12 +10,14 @@ using Bit.Core.Models.Table;
using Microsoft.AspNetCore.Builder;
using Microsoft.IdentityModel.Tokens;
using Bit.Core.Repositories;
using Bit.Core.Services;
namespace Bit.Core.Identity
{
public class JwtBearerSignInManager
{
private readonly IDeviceRepository _deviceRepository;
private readonly IDeviceService _deviceService;
public JwtBearerSignInManager(
UserManager<User> userManager,
@ -25,7 +27,8 @@ namespace Bit.Core.Identity
IOptions<JwtBearerIdentityOptions> jwtIdentityOptionsAccessor,
IOptions<JwtBearerOptions> jwtOptionsAccessor,
ILogger<JwtBearerSignInManager> logger,
IDeviceRepository deviceRepository)
IDeviceRepository deviceRepository,
IDeviceService deviceService)
{
UserManager = userManager;
Context = contextAccessor.HttpContext;
@ -34,6 +37,7 @@ namespace Bit.Core.Identity
JwtIdentityOptions = jwtIdentityOptionsAccessor?.Value ?? new JwtBearerIdentityOptions();
JwtBearerOptions = jwtOptionsAccessor?.Value ?? new JwtBearerOptions();
_deviceRepository = deviceRepository;
_deviceService = deviceService;
}
internal UserManager<User> UserManager { get; set; }
@ -75,7 +79,7 @@ namespace Bit.Core.Identity
if(existingDevice == null)
{
device.UserId = user.Id;
await _deviceRepository.CreateAsync(device);
await _deviceService.SaveAsync(device);
}
}
@ -117,7 +121,7 @@ namespace Bit.Core.Identity
if(existingDevice == null)
{
device.UserId = user.Id;
await _deviceRepository.CreateAsync(device);
await _deviceService.SaveAsync(device);
}
}

View File

@ -16,6 +16,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Bit.Core.Services;
namespace Bit.Core.IdentityServer
{
@ -26,18 +27,21 @@ namespace Bit.Core.IdentityServer
private JwtBearerOptions _jwtBearerOptions;
private JwtBearerIdentityOptions _jwtBearerIdentityOptions;
private readonly IDeviceRepository _deviceRepository;
private readonly IDeviceService _deviceService;
public ResourceOwnerPasswordValidator(
UserManager<User> userManager,
IOptions<IdentityOptions> identityOptionsAccessor,
IOptions<JwtBearerIdentityOptions> jwtIdentityOptionsAccessor,
IDeviceRepository deviceRepository)
IDeviceRepository deviceRepository,
IDeviceService deviceService)
{
_userManager = userManager;
_identityOptions = identityOptionsAccessor?.Value ?? new IdentityOptions();
_jwtBearerIdentityOptions = jwtIdentityOptionsAccessor?.Value;
_jwtBearerOptions = Core.Identity.JwtBearerAppBuilderExtensions.BuildJwtBearerOptions(_jwtBearerIdentityOptions);
_jwtBearerOptions = Identity.JwtBearerAppBuilderExtensions.BuildJwtBearerOptions(_jwtBearerIdentityOptions);
_deviceRepository = deviceRepository;
_deviceService = deviceService;
}
public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
@ -222,7 +226,7 @@ namespace Bit.Core.IdentityServer
if(existingDevice == null)
{
device.UserId = user.Id;
await _deviceRepository.CreateAsync(device);
await _deviceService.SaveAsync(device);
return device;
}

View File

@ -6,5 +6,7 @@ namespace Bit.Core.Services
public interface IDeviceService
{
Task SaveAsync(Device device);
Task ClearTokenAsync(Device device);
Task DeleteAsync(Device device);
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Threading.Tasks;
using Bit.Core.Models.Table;
namespace Bit.Core.Services
{
public interface IPushRegistrationService
{
Task CreateOrUpdateRegistrationAsync(Device device);
Task DeleteRegistrationAsync(Guid deviceId);
}
}

View File

@ -8,11 +8,14 @@ namespace Bit.Core.Services
public class DeviceService : IDeviceService
{
private readonly IDeviceRepository _deviceRepository;
private readonly IPushRegistrationService _pushRegistrationService;
public DeviceService(
IDeviceRepository deviceRepository)
IDeviceRepository deviceRepository,
IPushRegistrationService pushRegistrationService)
{
_deviceRepository = deviceRepository;
_pushRegistrationService = pushRegistrationService;
}
public async Task SaveAsync(Device device)
@ -26,6 +29,20 @@ namespace Bit.Core.Services
device.RevisionDate = DateTime.UtcNow;
await _deviceRepository.ReplaceAsync(device);
}
await _pushRegistrationService.CreateOrUpdateRegistrationAsync(device);
}
public async Task ClearTokenAsync(Device device)
{
await _deviceRepository.ClearPushTokenByIdentifierAsync(device.Identifier);
await _pushRegistrationService.DeleteRegistrationAsync(device.Id);
}
public async Task DeleteAsync(Device device)
{
await _deviceRepository.DeleteAsync(device);
await _pushRegistrationService.DeleteRegistrationAsync(device.Id);
}
}
}

View File

@ -0,0 +1,66 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Azure.NotificationHubs;
using Bit.Core.Models.Table;
namespace Bit.Core.Services
{
public class NotificationHubPushRegistrationService : IPushRegistrationService
{
private readonly NotificationHubClient _client;
public NotificationHubPushRegistrationService(GlobalSettings globalSettings)
{
_client = NotificationHubClient.CreateClientFromConnectionString(globalSettings.NotificationHub.ConnectionString,
globalSettings.NotificationHub.HubName);
}
public async Task CreateOrUpdateRegistrationAsync(Device device)
{
if(string.IsNullOrWhiteSpace(device.PushToken))
{
return;
}
var installation = new Installation
{
InstallationId = device.Id.ToString(),
PushChannel = device.PushToken
};
installation.Tags = new List<string>
{
"userId:" + device.UserId.ToString()
};
if(!string.IsNullOrWhiteSpace(device.Identifier))
{
installation.Tags.Add("identifier:" + device.Identifier);
}
switch(device.Type)
{
case Enums.DeviceType.Android:
installation.Platform = NotificationPlatform.Gcm;
break;
case Enums.DeviceType.iOS:
installation.Platform = NotificationPlatform.Apns;
break;
case Enums.DeviceType.AndroidAmazon:
installation.Platform = NotificationPlatform.Adm;
break;
default:
break;
}
await _client.CreateOrUpdateInstallationAsync(installation);
}
public async Task DeleteRegistrationAsync(Guid deviceId)
{
await _client.DeleteInstallationAsync(deviceId.ToString());
}
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Threading.Tasks;
using Bit.Core.Models.Table;
namespace Bit.Core.Services
{
public class NoopPushRegistrationService : IPushRegistrationService
{
public Task CreateOrUpdateRegistrationAsync(Device device)
{
return Task.FromResult(0);
}
public Task DeleteRegistrationAsync(Guid deviceId)
{
return Task.FromResult(0);
}
}
}

View File

@ -52,6 +52,7 @@ namespace Bit.Core.Utilities
services.AddSingleton<IMailService, SendGridMailService>();
services.AddSingleton<IPushService, PushSharpPushService>();
services.AddSingleton<IBlockIpService, AzureQueueBlockIpService>();
services.AddSingleton<IPushRegistrationService, NotificationHubPushRegistrationService>();
}
public static void AddNoopServices(this IServiceCollection services)
@ -59,6 +60,7 @@ namespace Bit.Core.Utilities
services.AddSingleton<IMailService, NoopMailService>();
services.AddSingleton<IPushService, NoopPushService>();
services.AddSingleton<IBlockIpService, NoopBlockIpService>();
services.AddSingleton<IPushRegistrationService, NoopPushRegistrationService>();
}
public static IdentityBuilder AddCustomIdentityServices(

View File

@ -30,6 +30,10 @@
"documentDb": {
"uri": "SECRET",
"key": "SECRET"
},
"notificationHub": {
"connectionString": "SECRET",
"hubName": "SECRET"
}
}
}