1
0
mirror of https://github.com/bitwarden/server.git synced 2024-12-23 17:07:42 +01:00

log events to various organization indexes as well

This commit is contained in:
Kyle Spearrin 2017-12-01 12:14:46 -05:00
parent d94c2a8f50
commit 0662fc2163
8 changed files with 75 additions and 22 deletions

View File

@ -190,9 +190,8 @@ namespace Bit.Core.IdentityServer
var deviceName = context.Request.Raw["DeviceName"]?.ToString();
var devicePushToken = context.Request.Raw["DevicePushToken"]?.ToString();
DeviceType type;
if(string.IsNullOrWhiteSpace(deviceIdentifier) || string.IsNullOrWhiteSpace(deviceType) ||
string.IsNullOrWhiteSpace(deviceName) || !Enum.TryParse(deviceType, out type))
string.IsNullOrWhiteSpace(deviceName) || !Enum.TryParse(deviceType, out DeviceType type))
{
return null;
}

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using Bit.Core.Enums;
using Microsoft.WindowsAzure.Storage.Table;
namespace Bit.Core.Models.Data

View File

@ -10,6 +10,6 @@ namespace Bit.Core.Repositories
{
Task<ICollection<EventTableEntity>> GetManyByUserAsync(Guid userId, DateTime startDate, DateTime endDate);
Task CreateAsync(ITableEntity entity);
Task CreateManyAsync(IEnumerable<ITableEntity> entities);
Task CreateManyAsync(IList<ITableEntity> entities);
}
}

View File

@ -54,30 +54,47 @@ namespace Bit.Core.Repositories.TableStorage
await Table.ExecuteAsync(TableOperation.Insert(entity));
}
public async Task CreateManyAsync(IEnumerable<ITableEntity> entities)
public async Task CreateManyAsync(IList<ITableEntity> entities)
{
if(!entities?.Any() ?? true)
{
return;
}
// A batch insert can only contain 100 entities at a time
var iterations = entities.Count() / 100;
for(var i = 0; i <= iterations; i++)
if(entities.Count == 1)
{
var batch = new TableBatchOperation();
var batchEntities = entities.Skip(i * 100).Take(100);
if(!batchEntities.Any())
await CreateAsync(entities.First());
return;
}
var entityGroups = entities.GroupBy(e => e.PartitionKey);
foreach(var group in entityGroups)
{
var groupEntities = group.ToList();
if(groupEntities.Count == 1)
{
break;
await CreateAsync(groupEntities.First());
continue;
}
foreach(var entity in batchEntities)
// A batch insert can only contain 100 entities at a time
var iterations = groupEntities.Count / 100;
for(var i = 0; i <= iterations; i++)
{
batch.InsertOrReplace(entity);
}
var batch = new TableBatchOperation();
var batchEntities = groupEntities.Skip(i * 100).Take(100);
if(!batchEntities.Any())
{
break;
}
await Table.ExecuteBatchAsync(batch);
foreach(var entity in batchEntities)
{
batch.InsertOrReplace(entity);
}
await Table.ExecuteBatchAsync(batch);
}
}
}
}

View File

@ -7,5 +7,6 @@ namespace Bit.Core.Services
public interface IEventService
{
Task LogUserEventAsync(Guid userId, EventType type);
Task LogUserEventAsync(Guid userId, CurrentContext currentContext, EventType type);
}
}

View File

@ -3,26 +3,58 @@ using System;
using Bit.Core.Enums;
using Bit.Core.Repositories;
using Bit.Core.Models.Data;
using System.Linq;
using System.Collections.Generic;
using Microsoft.WindowsAzure.Storage.Table;
namespace Bit.Core.Services
{
public class EventService : IEventService
{
private readonly IEventRepository _eventRepository;
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly GlobalSettings _globalSettings;
public EventService(
IEventRepository eventRepository,
IOrganizationUserRepository organizationUserRepository,
GlobalSettings globalSettings)
{
_eventRepository = eventRepository;
_organizationUserRepository = organizationUserRepository;
_globalSettings = globalSettings;
}
public async Task LogUserEventAsync(Guid userId, EventType type)
{
var userEvent = new UserEvent(userId, type);
await _eventRepository.CreateAsync(userEvent);
var events = new List<ITableEntity> { new UserEvent(userId, type) };
var orgs = await _organizationUserRepository.GetManyByUserAsync(userId);
var orgEvents = orgs.Where(o => o.Status == OrganizationUserStatusType.Confirmed)
.Select(o => new UserEvent(userId, o.Id, type));
if(orgEvents.Any())
{
events.AddRange(orgEvents);
await _eventRepository.CreateManyAsync(events);
}
else
{
await _eventRepository.CreateAsync(events.First());
}
}
public async Task LogUserEventAsync(Guid userId, CurrentContext currentContext, EventType type)
{
var events = new List<ITableEntity> { new UserEvent(userId, type) };
var orgEvents = currentContext.Organizations.Select(o => new UserEvent(userId, o.Id, type));
if(orgEvents.Any())
{
events.AddRange(orgEvents);
await _eventRepository.CreateManyAsync(events);
}
else
{
await _eventRepository.CreateAsync(events.First());
}
}
}
}

View File

@ -425,7 +425,7 @@ namespace Bit.Core.Services
user.Key = key;
await _userRepository.ReplaceAsync(user);
await _eventService.LogUserEventAsync(user.Id, EventType.User_ChangedPassword);
await _eventService.LogUserEventAsync(user.Id, _currentContext, EventType.User_ChangedPassword);
return IdentityResult.Success;
}
@ -503,7 +503,7 @@ namespace Bit.Core.Services
user.TwoFactorRecoveryCode = CoreHelpers.SecureRandomString(32, upper: false, special: false);
}
await SaveUserAsync(user);
await _eventService.LogUserEventAsync(user.Id, EventType.User_Enabled2fa);
await _eventService.LogUserEventAsync(user.Id, _currentContext, EventType.User_Enabled2fa);
}
public async Task DisableTwoFactorProviderAsync(User user, TwoFactorProviderType type)
@ -517,7 +517,7 @@ namespace Bit.Core.Services
providers.Remove(type);
user.SetTwoFactorProviders(providers);
await SaveUserAsync(user);
await _eventService.LogUserEventAsync(user.Id, EventType.User_Disabled2fa);
await _eventService.LogUserEventAsync(user.Id, _currentContext, EventType.User_Disabled2fa);
}
public async Task<bool> RecoverTwoFactorAsync(string email, string masterPassword, string recoveryCode)
@ -542,7 +542,7 @@ namespace Bit.Core.Services
user.TwoFactorProviders = null;
user.TwoFactorRecoveryCode = CoreHelpers.SecureRandomString(32, upper: false, special: false);
await SaveUserAsync(user);
await _eventService.LogUserEventAsync(user.Id, EventType.User_Recovered2fa);
await _eventService.LogUserEventAsync(user.Id, _currentContext, EventType.User_Recovered2fa);
return true;
}

View File

@ -10,5 +10,10 @@ namespace Bit.Core.Services
{
return Task.FromResult(0);
}
public Task LogUserEventAsync(Guid userId, CurrentContext currentContext, EventType type)
{
return Task.FromResult(0);
}
}
}