From 0f0cd3beeb26827d93557c9b6eb59a75349b7b7b Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Thu, 25 Jul 2019 15:34:14 -0400 Subject: [PATCH] handle bulk cipher events more efficiently --- src/Core/Services/IEventService.cs | 2 + .../Services/Implementations/EventService.cs | 30 +++++++- .../NoopImplementations/NoopEventService.cs | 6 ++ src/Events/Controllers/CollectController.cs | 75 ++++++++++--------- 4 files changed, 72 insertions(+), 41 deletions(-) diff --git a/src/Core/Services/IEventService.cs b/src/Core/Services/IEventService.cs index e7901e96de..cb0fa70287 100644 --- a/src/Core/Services/IEventService.cs +++ b/src/Core/Services/IEventService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; using Bit.Core.Enums; using Bit.Core.Models.Table; @@ -9,6 +10,7 @@ namespace Bit.Core.Services { Task LogUserEventAsync(Guid userId, EventType type, DateTime? date = null); Task LogCipherEventAsync(Cipher cipher, EventType type, DateTime? date = null); + Task LogCipherEventsAsync(IEnumerable> events); Task LogCollectionEventAsync(Collection collection, EventType type, DateTime? date = null); Task LogGroupEventAsync(Group group, EventType type, DateTime? date = null); Task LogOrganizationUserEventAsync(OrganizationUser organizationUser, EventType type, DateTime? date = null); diff --git a/src/Core/Services/Implementations/EventService.cs b/src/Core/Services/Implementations/EventService.cs index 3df4af31c6..043f1786cf 100644 --- a/src/Core/Services/Implementations/EventService.cs +++ b/src/Core/Services/Implementations/EventService.cs @@ -68,11 +68,34 @@ namespace Bit.Core.Services } 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> events) + { + var cipherEvents = new List(); + 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 BuildCipherEventMessageAsync(Cipher cipher, EventType type, DateTime? date = null) { // Only logging organization cipher events for now. if(!cipher.OrganizationId.HasValue || (!_currentContext?.UserId.HasValue ?? true)) { - return; + return null; } if(cipher.OrganizationId.HasValue) @@ -80,11 +103,11 @@ namespace Bit.Core.Services var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync(); if(!CanUseEvents(orgAbilities, cipher.OrganizationId.Value)) { - return; + return null; } } - var e = new EventMessage(_currentContext) + return new EventMessage(_currentContext) { OrganizationId = cipher.OrganizationId, UserId = cipher.OrganizationId.HasValue ? null : cipher.UserId, @@ -93,7 +116,6 @@ namespace Bit.Core.Services ActingUserId = _currentContext?.UserId, Date = date.GetValueOrDefault(DateTime.UtcNow) }; - await _eventWriteService.CreateAsync(e); } public async Task LogCollectionEventAsync(Collection collection, EventType type, DateTime? date = null) diff --git a/src/Core/Services/NoopImplementations/NoopEventService.cs b/src/Core/Services/NoopImplementations/NoopEventService.cs index 95a603f938..462c4e1f48 100644 --- a/src/Core/Services/NoopImplementations/NoopEventService.cs +++ b/src/Core/Services/NoopImplementations/NoopEventService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; using Bit.Core.Enums; using Bit.Core.Models.Table; @@ -12,6 +13,11 @@ namespace Bit.Core.Services return Task.FromResult(0); } + public Task LogCipherEventsAsync(IEnumerable> events) + { + return Task.FromResult(0); + } + public Task LogCollectionEventAsync(Collection collection, EventType type, DateTime? date = null) { return Task.FromResult(0); diff --git a/src/Events/Controllers/CollectController.cs b/src/Events/Controllers/CollectController.cs index d64d562c66..304c3b164f 100644 --- a/src/Events/Controllers/CollectController.cs +++ b/src/Events/Controllers/CollectController.cs @@ -1,8 +1,10 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Bit.Core; using Bit.Core.Enums; +using Bit.Core.Models.Table; using Bit.Core.Repositories; using Bit.Core.Services; using Bit.Events.Models; @@ -36,46 +38,45 @@ namespace Bit.Events.Controllers { return new BadRequestResult(); } + var cipherEvents = new List>(); foreach(var eventModel in model) { - await LogEventAsync(eventModel); + switch(eventModel.Type) + { + // User events + case EventType.User_ClientExportedVault: + await _eventService.LogUserEventAsync(_currentContext.UserId.Value, eventModel.Type, eventModel.Date); + break; + // Cipher events + case EventType.Cipher_ClientAutofilled: + case EventType.Cipher_ClientCopiedHiddenField: + case EventType.Cipher_ClientCopiedPassword: + case EventType.Cipher_ClientCopiedCardCode: + case EventType.Cipher_ClientToggledCardCodeVisible: + case EventType.Cipher_ClientToggledHiddenFieldVisible: + case EventType.Cipher_ClientToggledPasswordVisible: + case EventType.Cipher_ClientViewed: + if(!eventModel.CipherId.HasValue) + { + continue; + } + var cipher = await _cipherRepository.GetByIdAsync(eventModel.CipherId.Value, + _currentContext.UserId.Value); + if(cipher == null) + { + continue; + } + cipherEvents.Add(new Tuple(cipher, eventModel.Type, eventModel.Date)); + break; + default: + continue; + } + } + if(cipherEvents.Any()) + { + await _eventService.LogCipherEventsAsync(cipherEvents); } return new OkResult(); } - - private async Task LogEventAsync(EventModel model) - { - switch(model.Type) - { - // User events - case EventType.User_ClientExportedVault: - await _eventService.LogUserEventAsync(_currentContext.UserId.Value, model.Type, model.Date); - break; - // Cipher events - case EventType.Cipher_ClientAutofilled: - case EventType.Cipher_ClientCopiedHiddenField: - case EventType.Cipher_ClientCopiedPassword: - case EventType.Cipher_ClientCopiedCardCode: - case EventType.Cipher_ClientToggledCardCodeVisible: - case EventType.Cipher_ClientToggledHiddenFieldVisible: - case EventType.Cipher_ClientToggledPasswordVisible: - case EventType.Cipher_ClientViewed: - if(!model.CipherId.HasValue) - { - return false; - } - var cipher = await _cipherRepository.GetByIdAsync(model.CipherId.Value, - _currentContext.UserId.Value); - if(cipher == null) - { - return false; - } - await _eventService.LogCipherEventAsync(cipher, model.Type, model.Date); - break; - default: - return false; - } - return true; - } } }