1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-07 22:18:17 -05:00

Added Several New Reference Events (#1500)

* added enum values for new events

* hooked up directory sync event

* upgraded the OrganizationUpgrade ReferenceEvent

* Added metadata to the OrganizationUserInvited event noting if this is the first event sent from an organization

* Added metadata to the AdjustedSeats event

* Implemented vaultImported event

* Implemented FirstGroupAdded event

* Implemented FirstCollectionAdded event

* Implemented FirstSecretAdded event type

* Implemented SalesAssisted reference event

* changed events to match updated requirements

* renamed an event enum
This commit is contained in:
Addison Beck 2021-08-10 14:38:58 -04:00 committed by GitHub
parent 2e1df91232
commit 7928b25796
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 98 additions and 25 deletions

View File

@ -9,6 +9,8 @@ using Bit.Core.Models.Table;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Bit.Core.Services; using Bit.Core.Services;
using Bit.Core.Settings; using Bit.Core.Settings;
using Bit.Core.Models.Business;
using Bit.Core.Enums;
namespace Bit.Admin.Controllers namespace Bit.Admin.Controllers
{ {
@ -24,6 +26,7 @@ namespace Bit.Admin.Controllers
private readonly IPaymentService _paymentService; private readonly IPaymentService _paymentService;
private readonly IApplicationCacheService _applicationCacheService; private readonly IApplicationCacheService _applicationCacheService;
private readonly GlobalSettings _globalSettings; private readonly GlobalSettings _globalSettings;
private readonly IReferenceEventService _referenceEventService;
public OrganizationsController( public OrganizationsController(
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
@ -34,7 +37,8 @@ namespace Bit.Admin.Controllers
IPolicyRepository policyRepository, IPolicyRepository policyRepository,
IPaymentService paymentService, IPaymentService paymentService,
IApplicationCacheService applicationCacheService, IApplicationCacheService applicationCacheService,
GlobalSettings globalSettings) GlobalSettings globalSettings,
IReferenceEventService referenceEventService)
{ {
_organizationRepository = organizationRepository; _organizationRepository = organizationRepository;
_organizationUserRepository = organizationUserRepository; _organizationUserRepository = organizationUserRepository;
@ -45,6 +49,7 @@ namespace Bit.Admin.Controllers
_paymentService = paymentService; _paymentService = paymentService;
_applicationCacheService = applicationCacheService; _applicationCacheService = applicationCacheService;
_globalSettings = globalSettings; _globalSettings = globalSettings;
_referenceEventService = referenceEventService;
} }
public async Task<IActionResult> Index(string name = null, string userEmail = null, bool? paid = null, public async Task<IActionResult> Index(string name = null, string userEmail = null, bool? paid = null,
@ -140,6 +145,7 @@ namespace Bit.Admin.Controllers
model.ToOrganization(organization); model.ToOrganization(organization);
await _organizationRepository.ReplaceAsync(organization); await _organizationRepository.ReplaceAsync(organization);
await _applicationCacheService.UpsertOrganizationAbilityAsync(organization); await _applicationCacheService.UpsertOrganizationAbilityAsync(organization);
await _referenceEventService.RaiseEventAsync(new ReferenceEvent(ReferenceEventType.SalesAssisted, organization));
return RedirectToAction("Edit", new { id }); return RedirectToAction("Edit", new { id });
} }

View File

@ -37,6 +37,7 @@ namespace Bit.Core.Context
public virtual bool IsBot { get; set; } public virtual bool IsBot { get; set; }
public virtual bool MaybeBot { get; set; } public virtual bool MaybeBot { get; set; }
public virtual int? BotScore { get; set; } public virtual int? BotScore { get; set; }
public virtual string ClientId { get; set; }
public CurrentContext(IProviderUserRepository providerUserRepository) public CurrentContext(IProviderUserRepository providerUserRepository)
{ {
@ -114,19 +115,19 @@ namespace Bit.Core.Context
UserId = subIdGuid; UserId = subIdGuid;
} }
var clientId = GetClaimValue(claimsDict, "client_id"); ClientId = GetClaimValue(claimsDict, "client_id");
var clientSubject = GetClaimValue(claimsDict, "client_sub"); var clientSubject = GetClaimValue(claimsDict, "client_sub");
var orgApi = false; var orgApi = false;
if (clientSubject != null) if (clientSubject != null)
{ {
if (clientId?.StartsWith("installation.") ?? false) if (ClientId?.StartsWith("installation.") ?? false)
{ {
if (Guid.TryParse(clientSubject, out var idGuid)) if (Guid.TryParse(clientSubject, out var idGuid))
{ {
InstallationId = idGuid; InstallationId = idGuid;
} }
} }
else if (clientId?.StartsWith("organization.") ?? false) else if (ClientId?.StartsWith("organization.") ?? false)
{ {
if (Guid.TryParse(clientSubject, out var idGuid)) if (Guid.TryParse(clientSubject, out var idGuid))
{ {

View File

@ -24,7 +24,7 @@ namespace Bit.Core.Context
bool IsBot { get; set; } bool IsBot { get; set; }
bool MaybeBot { get; set; } bool MaybeBot { get; set; }
int? BotScore { get; set; } int? BotScore { get; set; }
string ClientId { get; set; }
Task BuildAsync(HttpContext httpContext, GlobalSettings globalSettings); Task BuildAsync(HttpContext httpContext, GlobalSettings globalSettings);
Task BuildAsync(ClaimsPrincipal user, GlobalSettings globalSettings); Task BuildAsync(ClaimsPrincipal user, GlobalSettings globalSettings);

View File

@ -0,0 +1,13 @@
namespace Bit.Core.Enums
{
public static class BitwardenClient
{
public const string
Web = "web",
Browser = "browser",
Desktop = "desktop",
Mobile = "mobile",
Cli = "cli",
DirectoryConnector = "connector";
}
}

View File

@ -28,5 +28,17 @@ namespace Bit.Core.Enums
SendCreated, SendCreated,
[EnumMember(Value = "send-accessed")] [EnumMember(Value = "send-accessed")]
SendAccessed, SendAccessed,
[EnumMember(Value = "organization-imported")]
DirectorySynced,
[EnumMember(Value = "vault-imported")]
VaultImported,
[EnumMember(Value = "secret-added")]
CipherCreated,
[EnumMember(Value = "group-created")]
GroupCreated,
[EnumMember(Value = "collection-created")]
CollectionCreated,
[EnumMember(Value = "sales-assisted")]
SalesAssisted
} }
} }

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Bit.Core.Settings; using Bit.Core.Settings;
using Bit.Core.Enums;
namespace Bit.Core.IdentityServer namespace Bit.Core.IdentityServer
{ {
@ -11,12 +12,12 @@ namespace Bit.Core.IdentityServer
{ {
ApiClients = new List<Client> ApiClients = new List<Client>
{ {
new ApiClient(globalSettings, "mobile", 90, 1), new ApiClient(globalSettings, BitwardenClient.Mobile, 90, 1),
new ApiClient(globalSettings, "web", 30, 1), new ApiClient(globalSettings, BitwardenClient.Web, 30, 1),
new ApiClient(globalSettings, "browser", 30, 1), new ApiClient(globalSettings, BitwardenClient.Browser, 30, 1),
new ApiClient(globalSettings, "desktop", 30, 1), new ApiClient(globalSettings, BitwardenClient.Desktop, 30, 1),
new ApiClient(globalSettings, "cli", 30, 1), new ApiClient(globalSettings, BitwardenClient.Cli, 30, 1),
new ApiClient(globalSettings, "connector", 30, 24) new ApiClient(globalSettings, BitwardenClient.DirectoryConnector, 30, 24)
}.ToDictionary(c => c.ClientId); }.ToDictionary(c => c.ClientId);
} }

View File

@ -42,7 +42,12 @@ namespace Bit.Core.Models.Business
public PlanType? PlanType { get; set; } public PlanType? PlanType { get; set; }
public string OldPlanName { get; set; }
public PlanType? OldPlanType { get; set; }
public int? Seats { get; set; } public int? Seats { get; set; }
public int? PreviousSeats { get; set; }
public short? Storage { get; set; } public short? Storage { get; set; }

View File

@ -13,6 +13,7 @@ using Bit.Core.Enums;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Bit.Core.Settings; using Bit.Core.Settings;
using Bit.Core.Models.Api; using Bit.Core.Models.Api;
using Bit.Core.Models.Business;
namespace Bit.Core.Services namespace Bit.Core.Services
{ {
@ -34,6 +35,7 @@ namespace Bit.Core.Services
private readonly IPolicyRepository _policyRepository; private readonly IPolicyRepository _policyRepository;
private readonly GlobalSettings _globalSettings; private readonly GlobalSettings _globalSettings;
private const long _fileSizeLeeway = 1024L * 1024L; // 1MB private const long _fileSizeLeeway = 1024L * 1024L; // 1MB
private readonly IReferenceEventService _referenceEventService;
public CipherService( public CipherService(
ICipherRepository cipherRepository, ICipherRepository cipherRepository,
@ -48,7 +50,8 @@ namespace Bit.Core.Services
IEventService eventService, IEventService eventService,
IUserService userService, IUserService userService,
IPolicyRepository policyRepository, IPolicyRepository policyRepository,
GlobalSettings globalSettings) GlobalSettings globalSettings,
IReferenceEventService referenceEventService)
{ {
_cipherRepository = cipherRepository; _cipherRepository = cipherRepository;
_folderRepository = folderRepository; _folderRepository = folderRepository;
@ -63,6 +66,7 @@ namespace Bit.Core.Services
_userService = userService; _userService = userService;
_policyRepository = policyRepository; _policyRepository = policyRepository;
_globalSettings = globalSettings; _globalSettings = globalSettings;
_referenceEventService = referenceEventService;
} }
public async Task SaveAsync(Cipher cipher, Guid savingUserId, DateTime? lastKnownRevisionDate, public async Task SaveAsync(Cipher cipher, Guid savingUserId, DateTime? lastKnownRevisionDate,
@ -83,6 +87,9 @@ namespace Bit.Core.Services
cipher.UserId = savingUserId; cipher.UserId = savingUserId;
} }
await _cipherRepository.CreateAsync(cipher, collectionIds); await _cipherRepository.CreateAsync(cipher, collectionIds);
await _referenceEventService.RaiseEventAsync(
new ReferenceEvent(ReferenceEventType.CipherCreated, await _organizationRepository.GetByIdAsync(cipher.OrganizationId.Value)));
} }
else else
{ {
@ -727,10 +734,11 @@ namespace Bit.Core.Services
IEnumerable<KeyValuePair<int, int>> collectionRelationships, IEnumerable<KeyValuePair<int, int>> collectionRelationships,
Guid importingUserId) Guid importingUserId)
{ {
if (collections.Count > 0) var org = collections.Count > 0 ?
{ await _organizationRepository.GetByIdAsync(collections[0].OrganizationId) :
var org = await _organizationRepository.GetByIdAsync(collections[0].OrganizationId); await _organizationRepository.GetByIdAsync(ciphers.FirstOrDefault(c => c.OrganizationId.HasValue).OrganizationId.Value);
if (org != null && org.MaxCollections.HasValue)
if (collections.Count > 0 && org != null && org.MaxCollections.HasValue)
{ {
var collectionCount = await _collectionRepository.GetCountByOrganizationIdAsync(org.Id); var collectionCount = await _collectionRepository.GetCountByOrganizationIdAsync(org.Id);
if (org.MaxCollections.Value < (collectionCount + collections.Count)) if (org.MaxCollections.Value < (collectionCount + collections.Count))
@ -739,7 +747,6 @@ namespace Bit.Core.Services
$"{org.MaxCollections.Value} collections."); $"{org.MaxCollections.Value} collections.");
} }
} }
}
// Init. ids for ciphers // Init. ids for ciphers
foreach (var cipher in ciphers) foreach (var cipher in ciphers)
@ -777,6 +784,13 @@ namespace Bit.Core.Services
// push // push
await _pushService.PushSyncVaultAsync(importingUserId); await _pushService.PushSyncVaultAsync(importingUserId);
if (org != null)
{
await _referenceEventService.RaiseEventAsync(
new ReferenceEvent(ReferenceEventType.VaultImported, org));
}
} }
public async Task SoftDeleteAsync(Cipher cipher, Guid deletingUserId, bool orgAdmin = false) public async Task SoftDeleteAsync(Cipher cipher, Guid deletingUserId, bool orgAdmin = false)

View File

@ -5,6 +5,8 @@ using Bit.Core.Models.Table;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using System.Collections.Generic; using System.Collections.Generic;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
using Bit.Core.Models.Business;
using Bit.Core.Enums;
namespace Bit.Core.Services namespace Bit.Core.Services
{ {
@ -16,6 +18,7 @@ namespace Bit.Core.Services
private readonly ICollectionRepository _collectionRepository; private readonly ICollectionRepository _collectionRepository;
private readonly IUserRepository _userRepository; private readonly IUserRepository _userRepository;
private readonly IMailService _mailService; private readonly IMailService _mailService;
private readonly IReferenceEventService _referenceEventService;
public CollectionService( public CollectionService(
IEventService eventService, IEventService eventService,
@ -23,7 +26,8 @@ namespace Bit.Core.Services
IOrganizationUserRepository organizationUserRepository, IOrganizationUserRepository organizationUserRepository,
ICollectionRepository collectionRepository, ICollectionRepository collectionRepository,
IUserRepository userRepository, IUserRepository userRepository,
IMailService mailService) IMailService mailService,
IReferenceEventService referenceEventService)
{ {
_eventService = eventService; _eventService = eventService;
_organizationRepository = organizationRepository; _organizationRepository = organizationRepository;
@ -31,6 +35,7 @@ namespace Bit.Core.Services
_collectionRepository = collectionRepository; _collectionRepository = collectionRepository;
_userRepository = userRepository; _userRepository = userRepository;
_mailService = mailService; _mailService = mailService;
_referenceEventService = referenceEventService;
} }
public async Task SaveAsync(Collection collection, IEnumerable<SelectionReadOnly> groups = null, public async Task SaveAsync(Collection collection, IEnumerable<SelectionReadOnly> groups = null,
@ -76,6 +81,7 @@ namespace Bit.Core.Services
} }
await _eventService.LogCollectionEventAsync(collection, Enums.EventType.Collection_Created); await _eventService.LogCollectionEventAsync(collection, Enums.EventType.Collection_Created);
await _referenceEventService.RaiseEventAsync(new ReferenceEvent(ReferenceEventType.CollectionCreated, org));
} }
else else
{ {

View File

@ -5,6 +5,8 @@ using Bit.Core.Models.Table;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using System.Collections.Generic; using System.Collections.Generic;
using Bit.Core.Models.Data; using Bit.Core.Models.Data;
using Bit.Core.Models.Business;
using Bit.Core.Enums;
namespace Bit.Core.Services namespace Bit.Core.Services
{ {
@ -14,17 +16,20 @@ namespace Bit.Core.Services
private readonly IOrganizationRepository _organizationRepository; private readonly IOrganizationRepository _organizationRepository;
private readonly IOrganizationUserRepository _organizationUserRepository; private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IGroupRepository _groupRepository; private readonly IGroupRepository _groupRepository;
private readonly IReferenceEventService _referenceEventService;
public GroupService( public GroupService(
IEventService eventService, IEventService eventService,
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
IOrganizationUserRepository organizationUserRepository, IOrganizationUserRepository organizationUserRepository,
IGroupRepository groupRepository) IGroupRepository groupRepository,
IReferenceEventService referenceEventService)
{ {
_eventService = eventService; _eventService = eventService;
_organizationRepository = organizationRepository; _organizationRepository = organizationRepository;
_organizationUserRepository = organizationUserRepository; _organizationUserRepository = organizationUserRepository;
_groupRepository = groupRepository; _groupRepository = groupRepository;
_referenceEventService = referenceEventService;
} }
public async Task SaveAsync(Group group, IEnumerable<SelectionReadOnly> collections = null) public async Task SaveAsync(Group group, IEnumerable<SelectionReadOnly> collections = null)
@ -54,6 +59,7 @@ namespace Bit.Core.Services
} }
await _eventService.LogGroupEventAsync(group, Enums.EventType.Group_Created); await _eventService.LogGroupEventAsync(group, Enums.EventType.Group_Created);
await _referenceEventService.RaiseEventAsync(new ReferenceEvent(ReferenceEventType.GroupCreated, org));
} }
else else
{ {

View File

@ -305,6 +305,8 @@ namespace Bit.Core.Services
{ {
PlanName = newPlan.Name, PlanName = newPlan.Name,
PlanType = newPlan.Type, PlanType = newPlan.Type,
OldPlanName = existingPlan.Name,
OldPlanType = existingPlan.Type,
Seats = organization.Seats, Seats = organization.Seats,
Storage = organization.MaxStorageGb, Storage = organization.MaxStorageGb,
}); });
@ -497,14 +499,15 @@ namespace Bit.Core.Services
}); });
} }
organization.Seats = (short?)newSeatTotal;
await _referenceEventService.RaiseEventAsync( await _referenceEventService.RaiseEventAsync(
new ReferenceEvent(ReferenceEventType.AdjustSeats, organization) new ReferenceEvent(ReferenceEventType.AdjustSeats, organization)
{ {
PlanName = plan.Name, PlanName = plan.Name,
PlanType = plan.Type, PlanType = plan.Type,
Seats = organization.Seats, Seats = newSeatTotal,
PreviousSeats = organization.Seats
}); });
organization.Seats = (short?)newSeatTotal;
await ReplaceAndUpdateCache(organization); await ReplaceAndUpdateCache(organization);
return paymentIntentClientSecret; return paymentIntentClientSecret;
} }
@ -1977,6 +1980,12 @@ namespace Bit.Core.Services
} }
} }
} }
if (_currentContext.ClientId == BitwardenClient.DirectoryConnector)
{
await _referenceEventService.RaiseEventAsync(
new ReferenceEvent(ReferenceEventType.DirectorySynced, organization));
}
} }
public async Task RotateApiKeyAsync(Organization organization) public async Task RotateApiKeyAsync(Organization organization)