Files
server/src/Core/Services/Implementations/EventService.cs

232 lines
8.6 KiB
C#
Raw Normal View History

using System.Threading.Tasks;
using System;
using Bit.Core.Enums;
using Bit.Core.Repositories;
using Bit.Core.Models.Data;
using System.Linq;
using System.Collections.Generic;
2017-12-01 14:06:16 -05:00
using Bit.Core.Models.Table;
using Bit.Core.Context;
using Bit.Core.Settings;
namespace Bit.Core.Services
{
public class EventService : IEventService
{
2017-12-04 09:58:07 -05:00
private readonly IEventWriteService _eventWriteService;
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IApplicationCacheService _applicationCacheService;
private readonly ICurrentContext _currentContext;
private readonly GlobalSettings _globalSettings;
public EventService(
2017-12-04 09:58:07 -05:00
IEventWriteService eventWriteService,
IOrganizationUserRepository organizationUserRepository,
IApplicationCacheService applicationCacheService,
ICurrentContext currentContext,
GlobalSettings globalSettings)
{
2017-12-04 09:58:07 -05:00
_eventWriteService = eventWriteService;
_organizationUserRepository = organizationUserRepository;
_applicationCacheService = applicationCacheService;
2017-12-01 14:06:16 -05:00
_currentContext = currentContext;
_globalSettings = globalSettings;
}
public async Task LogUserEventAsync(Guid userId, EventType type, DateTime? date = null)
{
2017-12-08 23:09:50 -05:00
var events = new List<IEvent>
{
new EventMessage(_currentContext)
2017-12-08 23:09:50 -05:00
{
UserId = userId,
2017-12-14 16:41:52 -05:00
ActingUserId = userId,
2017-12-08 23:09:50 -05:00
Type = type,
Date = date.GetValueOrDefault(DateTime.UtcNow)
2017-12-08 23:09:50 -05:00
}
};
2017-12-01 14:06:16 -05:00
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
var orgs = await _currentContext.OrganizationMembershipAsync(_organizationUserRepository, userId);
var orgEvents = orgs.Where(o => CanUseEvents(orgAbilities, o.Id))
.Select(o => new EventMessage(_currentContext)
{
OrganizationId = o.Id,
UserId = userId,
ActingUserId = userId,
Type = type,
Date = DateTime.UtcNow
});
if (orgEvents.Any())
{
events.AddRange(orgEvents);
2017-12-04 09:58:07 -05:00
await _eventWriteService.CreateManyAsync(events);
}
else
{
2017-12-04 09:58:07 -05:00
await _eventWriteService.CreateAsync(events.First());
}
}
2017-12-01 14:06:16 -05:00
public async Task LogCipherEventAsync(Cipher cipher, EventType type, DateTime? date = null)
{
var e = await BuildCipherEventMessageAsync(cipher, type, date);
if (e != null)
{
await _eventWriteService.CreateAsync(e);
}
}
public async Task LogCipherEventsAsync(IEnumerable<Tuple<Cipher, EventType, DateTime?>> events)
{
var cipherEvents = new List<IEvent>();
foreach (var ev in events)
{
var e = await BuildCipherEventMessageAsync(ev.Item1, ev.Item2, ev.Item3);
if (e != null)
{
cipherEvents.Add(e);
}
}
await _eventWriteService.CreateManyAsync(cipherEvents);
}
private async Task<EventMessage> BuildCipherEventMessageAsync(Cipher cipher, EventType type, DateTime? date = null)
2017-12-01 14:06:16 -05:00
{
2017-12-12 15:04:14 -05:00
// Only logging organization cipher events for now.
if (!cipher.OrganizationId.HasValue || (!_currentContext?.UserId.HasValue ?? true))
2017-12-01 14:06:16 -05:00
{
return null;
2017-12-01 14:06:16 -05:00
}
if (cipher.OrganizationId.HasValue)
{
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
if (!CanUseEvents(orgAbilities, cipher.OrganizationId.Value))
{
return null;
}
}
return new EventMessage(_currentContext)
2017-12-08 23:09:50 -05:00
{
OrganizationId = cipher.OrganizationId,
UserId = cipher.OrganizationId.HasValue ? null : cipher.UserId,
CipherId = cipher.Id,
Type = type,
ActingUserId = _currentContext?.UserId,
Date = date.GetValueOrDefault(DateTime.UtcNow)
2017-12-08 23:09:50 -05:00
};
}
public async Task LogCollectionEventAsync(Collection collection, EventType type, DateTime? date = null)
{
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
if (!CanUseEvents(orgAbilities, collection.OrganizationId))
{
return;
}
var e = new EventMessage(_currentContext)
2017-12-08 23:09:50 -05:00
{
OrganizationId = collection.OrganizationId,
CollectionId = collection.Id,
Type = type,
2017-12-12 15:23:45 -05:00
ActingUserId = _currentContext?.UserId,
Date = date.GetValueOrDefault(DateTime.UtcNow)
2017-12-08 23:09:50 -05:00
};
2017-12-04 09:58:07 -05:00
await _eventWriteService.CreateAsync(e);
}
public async Task LogGroupEventAsync(Group group, EventType type, DateTime? date = null)
{
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
if (!CanUseEvents(orgAbilities, group.OrganizationId))
{
return;
}
var e = new EventMessage(_currentContext)
2017-12-08 23:09:50 -05:00
{
OrganizationId = group.OrganizationId,
GroupId = group.Id,
Type = type,
2017-12-12 15:23:45 -05:00
ActingUserId = _currentContext?.UserId,
Date = date.GetValueOrDefault(DateTime.UtcNow)
2017-12-08 23:09:50 -05:00
};
2017-12-04 09:58:07 -05:00
await _eventWriteService.CreateAsync(e);
}
2020-01-15 09:43:49 -05:00
public async Task LogPolicyEventAsync(Policy policy, EventType type, DateTime? date = null)
{
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
if (!CanUseEvents(orgAbilities, policy.OrganizationId))
2020-01-15 09:43:49 -05:00
{
return;
}
var e = new EventMessage(_currentContext)
{
OrganizationId = policy.OrganizationId,
PolicyId = policy.Id,
Type = type,
ActingUserId = _currentContext?.UserId,
Date = date.GetValueOrDefault(DateTime.UtcNow)
};
await _eventWriteService.CreateAsync(e);
}
public async Task LogOrganizationUserEventAsync(OrganizationUser organizationUser, EventType type,
Support large organization sync (#1311) * Increase organization max seat size from 30k to 2b (#1274) * Increase organization max seat size from 30k to 2b * PR review. Do not modify unless state matches expected * Organization sync simultaneous event reporting (#1275) * Split up azure messages according to max size * Allow simultaneous login of organization user events * Early resolve small event lists * Clarify logic Co-authored-by: Chad Scharf <3904944+cscharf@users.noreply.github.com> * Improve readability This comes at the cost of multiple serializations, but the improvement in wire-time should more than make up for this on message where serialization time matters Co-authored-by: Chad Scharf <3904944+cscharf@users.noreply.github.com> * Queue emails (#1286) * Extract common Azure queue methods * Do not use internal entity framework namespace * Prefer IEnumerable to IList unless needed All of these implementations were just using `Count == 1`, which is easily replicated. This will be used when abstracting Azure queues * Add model for azure queue message * Abstract Azure queue for reuse * Creat service to enqueue mail messages for later processing Azure queue mail service uses Azure queues. Blocking just blocks until all the work is done -- This is how emailing works today * Provide mail queue service to DI * Queue organization invite emails for later processing All emails can later be added to this queue * Create Admin hosted service to process enqueued mail messages * Prefer constructors to static generators * Mass delete organization users (#1287) * Add delete many to Organization Users * Correct formatting * Remove erroneous migration * Clarify parameter name * Formatting fixes * Simplify bump account revision sproc * Formatting fixes * Match file names to objects * Indicate if large import is expected * Early pull all existing users we were planning on inviting (#1290) * Early pull all existing users we were planning on inviting * Improve sproc name * Batch upsert org users (#1289) * Add UpsertMany sprocs to OrganizationUser * Add method to create TVPs from any object. Uses DbOrder attribute to generate. Sproc will fail unless TVP column order matches that of the db type * Combine migrations * Correct formatting * Include sql objects in sql project * Keep consisten parameter names * Batch deletes for performance * Correct formatting * consolidate migrations * Use batch methods in OrganizationImport * Declare @BatchSize * Transaction names limited to 32 chars Drop sproc before creating it if it exists * Update import tests * Allow for more users in org upgrades * Fix formatting * Improve class hierarchy structure * Use name tuple types * Fix formatting * Front load all reflection * Format constructor * Simplify ToTvp as class-specific extension Co-authored-by: Chad Scharf <3904944+cscharf@users.noreply.github.com>
2021-05-17 09:43:02 -05:00
DateTime? date = null) =>
await LogOrganizationUserEventsAsync(new[] { (organizationUser, type, date) });
public async Task LogOrganizationUserEventsAsync(IEnumerable<(OrganizationUser, EventType, DateTime?)> events)
{
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
Support large organization sync (#1311) * Increase organization max seat size from 30k to 2b (#1274) * Increase organization max seat size from 30k to 2b * PR review. Do not modify unless state matches expected * Organization sync simultaneous event reporting (#1275) * Split up azure messages according to max size * Allow simultaneous login of organization user events * Early resolve small event lists * Clarify logic Co-authored-by: Chad Scharf <3904944+cscharf@users.noreply.github.com> * Improve readability This comes at the cost of multiple serializations, but the improvement in wire-time should more than make up for this on message where serialization time matters Co-authored-by: Chad Scharf <3904944+cscharf@users.noreply.github.com> * Queue emails (#1286) * Extract common Azure queue methods * Do not use internal entity framework namespace * Prefer IEnumerable to IList unless needed All of these implementations were just using `Count == 1`, which is easily replicated. This will be used when abstracting Azure queues * Add model for azure queue message * Abstract Azure queue for reuse * Creat service to enqueue mail messages for later processing Azure queue mail service uses Azure queues. Blocking just blocks until all the work is done -- This is how emailing works today * Provide mail queue service to DI * Queue organization invite emails for later processing All emails can later be added to this queue * Create Admin hosted service to process enqueued mail messages * Prefer constructors to static generators * Mass delete organization users (#1287) * Add delete many to Organization Users * Correct formatting * Remove erroneous migration * Clarify parameter name * Formatting fixes * Simplify bump account revision sproc * Formatting fixes * Match file names to objects * Indicate if large import is expected * Early pull all existing users we were planning on inviting (#1290) * Early pull all existing users we were planning on inviting * Improve sproc name * Batch upsert org users (#1289) * Add UpsertMany sprocs to OrganizationUser * Add method to create TVPs from any object. Uses DbOrder attribute to generate. Sproc will fail unless TVP column order matches that of the db type * Combine migrations * Correct formatting * Include sql objects in sql project * Keep consisten parameter names * Batch deletes for performance * Correct formatting * consolidate migrations * Use batch methods in OrganizationImport * Declare @BatchSize * Transaction names limited to 32 chars Drop sproc before creating it if it exists * Update import tests * Allow for more users in org upgrades * Fix formatting * Improve class hierarchy structure * Use name tuple types * Fix formatting * Front load all reflection * Format constructor * Simplify ToTvp as class-specific extension Co-authored-by: Chad Scharf <3904944+cscharf@users.noreply.github.com>
2021-05-17 09:43:02 -05:00
var eventMessages = new List<IEvent>();
foreach (var (organizationUser, type, date) in events)
{
Support large organization sync (#1311) * Increase organization max seat size from 30k to 2b (#1274) * Increase organization max seat size from 30k to 2b * PR review. Do not modify unless state matches expected * Organization sync simultaneous event reporting (#1275) * Split up azure messages according to max size * Allow simultaneous login of organization user events * Early resolve small event lists * Clarify logic Co-authored-by: Chad Scharf <3904944+cscharf@users.noreply.github.com> * Improve readability This comes at the cost of multiple serializations, but the improvement in wire-time should more than make up for this on message where serialization time matters Co-authored-by: Chad Scharf <3904944+cscharf@users.noreply.github.com> * Queue emails (#1286) * Extract common Azure queue methods * Do not use internal entity framework namespace * Prefer IEnumerable to IList unless needed All of these implementations were just using `Count == 1`, which is easily replicated. This will be used when abstracting Azure queues * Add model for azure queue message * Abstract Azure queue for reuse * Creat service to enqueue mail messages for later processing Azure queue mail service uses Azure queues. Blocking just blocks until all the work is done -- This is how emailing works today * Provide mail queue service to DI * Queue organization invite emails for later processing All emails can later be added to this queue * Create Admin hosted service to process enqueued mail messages * Prefer constructors to static generators * Mass delete organization users (#1287) * Add delete many to Organization Users * Correct formatting * Remove erroneous migration * Clarify parameter name * Formatting fixes * Simplify bump account revision sproc * Formatting fixes * Match file names to objects * Indicate if large import is expected * Early pull all existing users we were planning on inviting (#1290) * Early pull all existing users we were planning on inviting * Improve sproc name * Batch upsert org users (#1289) * Add UpsertMany sprocs to OrganizationUser * Add method to create TVPs from any object. Uses DbOrder attribute to generate. Sproc will fail unless TVP column order matches that of the db type * Combine migrations * Correct formatting * Include sql objects in sql project * Keep consisten parameter names * Batch deletes for performance * Correct formatting * consolidate migrations * Use batch methods in OrganizationImport * Declare @BatchSize * Transaction names limited to 32 chars Drop sproc before creating it if it exists * Update import tests * Allow for more users in org upgrades * Fix formatting * Improve class hierarchy structure * Use name tuple types * Fix formatting * Front load all reflection * Format constructor * Simplify ToTvp as class-specific extension Co-authored-by: Chad Scharf <3904944+cscharf@users.noreply.github.com>
2021-05-17 09:43:02 -05:00
if (!CanUseEvents(orgAbilities, organizationUser.OrganizationId))
{
continue;
}
eventMessages.Add(new EventMessage
{
OrganizationId = organizationUser.OrganizationId,
UserId = organizationUser.UserId,
OrganizationUserId = organizationUser.Id,
Type = type,
ActingUserId = _currentContext?.UserId,
Date = date.GetValueOrDefault(DateTime.UtcNow)
});
}
Support large organization sync (#1311) * Increase organization max seat size from 30k to 2b (#1274) * Increase organization max seat size from 30k to 2b * PR review. Do not modify unless state matches expected * Organization sync simultaneous event reporting (#1275) * Split up azure messages according to max size * Allow simultaneous login of organization user events * Early resolve small event lists * Clarify logic Co-authored-by: Chad Scharf <3904944+cscharf@users.noreply.github.com> * Improve readability This comes at the cost of multiple serializations, but the improvement in wire-time should more than make up for this on message where serialization time matters Co-authored-by: Chad Scharf <3904944+cscharf@users.noreply.github.com> * Queue emails (#1286) * Extract common Azure queue methods * Do not use internal entity framework namespace * Prefer IEnumerable to IList unless needed All of these implementations were just using `Count == 1`, which is easily replicated. This will be used when abstracting Azure queues * Add model for azure queue message * Abstract Azure queue for reuse * Creat service to enqueue mail messages for later processing Azure queue mail service uses Azure queues. Blocking just blocks until all the work is done -- This is how emailing works today * Provide mail queue service to DI * Queue organization invite emails for later processing All emails can later be added to this queue * Create Admin hosted service to process enqueued mail messages * Prefer constructors to static generators * Mass delete organization users (#1287) * Add delete many to Organization Users * Correct formatting * Remove erroneous migration * Clarify parameter name * Formatting fixes * Simplify bump account revision sproc * Formatting fixes * Match file names to objects * Indicate if large import is expected * Early pull all existing users we were planning on inviting (#1290) * Early pull all existing users we were planning on inviting * Improve sproc name * Batch upsert org users (#1289) * Add UpsertMany sprocs to OrganizationUser * Add method to create TVPs from any object. Uses DbOrder attribute to generate. Sproc will fail unless TVP column order matches that of the db type * Combine migrations * Correct formatting * Include sql objects in sql project * Keep consisten parameter names * Batch deletes for performance * Correct formatting * consolidate migrations * Use batch methods in OrganizationImport * Declare @BatchSize * Transaction names limited to 32 chars Drop sproc before creating it if it exists * Update import tests * Allow for more users in org upgrades * Fix formatting * Improve class hierarchy structure * Use name tuple types * Fix formatting * Front load all reflection * Format constructor * Simplify ToTvp as class-specific extension Co-authored-by: Chad Scharf <3904944+cscharf@users.noreply.github.com>
2021-05-17 09:43:02 -05:00
await _eventWriteService.CreateManyAsync(eventMessages);
}
public async Task LogOrganizationEventAsync(Organization organization, EventType type, DateTime? date = null)
{
if (!organization.Enabled || !organization.UseEvents)
{
return;
}
var e = new EventMessage(_currentContext)
2017-12-08 23:09:50 -05:00
{
OrganizationId = organization.Id,
Type = type,
2017-12-12 15:23:45 -05:00
ActingUserId = _currentContext?.UserId,
Date = date.GetValueOrDefault(DateTime.UtcNow)
2017-12-08 23:09:50 -05:00
};
2017-12-04 09:58:07 -05:00
await _eventWriteService.CreateAsync(e);
2017-12-01 14:06:16 -05:00
}
private bool CanUseEvents(IDictionary<Guid, OrganizationAbility> orgAbilities, Guid orgId)
{
return orgAbilities != null && orgAbilities.ContainsKey(orgId) &&
orgAbilities[orgId].Enabled && orgAbilities[orgId].UseEvents;
}
}
}