mirror of
https://github.com/bitwarden/server.git
synced 2025-05-29 23:34:53 -05:00
log events to various organization indexes as well
This commit is contained in:
parent
d94c2a8f50
commit
0662fc2163
@ -190,9 +190,8 @@ namespace Bit.Core.IdentityServer
|
|||||||
var deviceName = context.Request.Raw["DeviceName"]?.ToString();
|
var deviceName = context.Request.Raw["DeviceName"]?.ToString();
|
||||||
var devicePushToken = context.Request.Raw["DevicePushToken"]?.ToString();
|
var devicePushToken = context.Request.Raw["DevicePushToken"]?.ToString();
|
||||||
|
|
||||||
DeviceType type;
|
|
||||||
if(string.IsNullOrWhiteSpace(deviceIdentifier) || string.IsNullOrWhiteSpace(deviceType) ||
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Bit.Core.Enums;
|
|
||||||
using Microsoft.WindowsAzure.Storage.Table;
|
using Microsoft.WindowsAzure.Storage.Table;
|
||||||
|
|
||||||
namespace Bit.Core.Models.Data
|
namespace Bit.Core.Models.Data
|
||||||
|
@ -10,6 +10,6 @@ namespace Bit.Core.Repositories
|
|||||||
{
|
{
|
||||||
Task<ICollection<EventTableEntity>> GetManyByUserAsync(Guid userId, DateTime startDate, DateTime endDate);
|
Task<ICollection<EventTableEntity>> GetManyByUserAsync(Guid userId, DateTime startDate, DateTime endDate);
|
||||||
Task CreateAsync(ITableEntity entity);
|
Task CreateAsync(ITableEntity entity);
|
||||||
Task CreateManyAsync(IEnumerable<ITableEntity> entities);
|
Task CreateManyAsync(IList<ITableEntity> entities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,30 +54,47 @@ namespace Bit.Core.Repositories.TableStorage
|
|||||||
await Table.ExecuteAsync(TableOperation.Insert(entity));
|
await Table.ExecuteAsync(TableOperation.Insert(entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task CreateManyAsync(IEnumerable<ITableEntity> entities)
|
public async Task CreateManyAsync(IList<ITableEntity> entities)
|
||||||
{
|
{
|
||||||
if(!entities?.Any() ?? true)
|
if(!entities?.Any() ?? true)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A batch insert can only contain 100 entities at a time
|
if(entities.Count == 1)
|
||||||
var iterations = entities.Count() / 100;
|
|
||||||
for(var i = 0; i <= iterations; i++)
|
|
||||||
{
|
{
|
||||||
var batch = new TableBatchOperation();
|
await CreateAsync(entities.First());
|
||||||
var batchEntities = entities.Skip(i * 100).Take(100);
|
return;
|
||||||
if(!batchEntities.Any())
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,5 +7,6 @@ namespace Bit.Core.Services
|
|||||||
public interface IEventService
|
public interface IEventService
|
||||||
{
|
{
|
||||||
Task LogUserEventAsync(Guid userId, EventType type);
|
Task LogUserEventAsync(Guid userId, EventType type);
|
||||||
|
Task LogUserEventAsync(Guid userId, CurrentContext currentContext, EventType type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,26 +3,58 @@ using System;
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.WindowsAzure.Storage.Table;
|
||||||
|
|
||||||
namespace Bit.Core.Services
|
namespace Bit.Core.Services
|
||||||
{
|
{
|
||||||
public class EventService : IEventService
|
public class EventService : IEventService
|
||||||
{
|
{
|
||||||
private readonly IEventRepository _eventRepository;
|
private readonly IEventRepository _eventRepository;
|
||||||
|
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
|
|
||||||
public EventService(
|
public EventService(
|
||||||
IEventRepository eventRepository,
|
IEventRepository eventRepository,
|
||||||
|
IOrganizationUserRepository organizationUserRepository,
|
||||||
GlobalSettings globalSettings)
|
GlobalSettings globalSettings)
|
||||||
{
|
{
|
||||||
_eventRepository = eventRepository;
|
_eventRepository = eventRepository;
|
||||||
|
_organizationUserRepository = organizationUserRepository;
|
||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task LogUserEventAsync(Guid userId, EventType type)
|
public async Task LogUserEventAsync(Guid userId, EventType type)
|
||||||
{
|
{
|
||||||
var userEvent = new UserEvent(userId, type);
|
var events = new List<ITableEntity> { new UserEvent(userId, type) };
|
||||||
await _eventRepository.CreateAsync(userEvent);
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -425,7 +425,7 @@ namespace Bit.Core.Services
|
|||||||
user.Key = key;
|
user.Key = key;
|
||||||
|
|
||||||
await _userRepository.ReplaceAsync(user);
|
await _userRepository.ReplaceAsync(user);
|
||||||
await _eventService.LogUserEventAsync(user.Id, EventType.User_ChangedPassword);
|
await _eventService.LogUserEventAsync(user.Id, _currentContext, EventType.User_ChangedPassword);
|
||||||
|
|
||||||
return IdentityResult.Success;
|
return IdentityResult.Success;
|
||||||
}
|
}
|
||||||
@ -503,7 +503,7 @@ namespace Bit.Core.Services
|
|||||||
user.TwoFactorRecoveryCode = CoreHelpers.SecureRandomString(32, upper: false, special: false);
|
user.TwoFactorRecoveryCode = CoreHelpers.SecureRandomString(32, upper: false, special: false);
|
||||||
}
|
}
|
||||||
await SaveUserAsync(user);
|
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)
|
public async Task DisableTwoFactorProviderAsync(User user, TwoFactorProviderType type)
|
||||||
@ -517,7 +517,7 @@ namespace Bit.Core.Services
|
|||||||
providers.Remove(type);
|
providers.Remove(type);
|
||||||
user.SetTwoFactorProviders(providers);
|
user.SetTwoFactorProviders(providers);
|
||||||
await SaveUserAsync(user);
|
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)
|
public async Task<bool> RecoverTwoFactorAsync(string email, string masterPassword, string recoveryCode)
|
||||||
@ -542,7 +542,7 @@ namespace Bit.Core.Services
|
|||||||
user.TwoFactorProviders = null;
|
user.TwoFactorProviders = null;
|
||||||
user.TwoFactorRecoveryCode = CoreHelpers.SecureRandomString(32, upper: false, special: false);
|
user.TwoFactorRecoveryCode = CoreHelpers.SecureRandomString(32, upper: false, special: false);
|
||||||
await SaveUserAsync(user);
|
await SaveUserAsync(user);
|
||||||
await _eventService.LogUserEventAsync(user.Id, EventType.User_Recovered2fa);
|
await _eventService.LogUserEventAsync(user.Id, _currentContext, EventType.User_Recovered2fa);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -10,5 +10,10 @@ namespace Bit.Core.Services
|
|||||||
{
|
{
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task LogUserEventAsync(Guid userId, CurrentContext currentContext, EventType type)
|
||||||
|
{
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user