diff --git a/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/Projects/CreateProjectCommand.cs b/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/Projects/CreateProjectCommand.cs index ad05ffc5e..d54644e29 100644 --- a/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/Projects/CreateProjectCommand.cs +++ b/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/Projects/CreateProjectCommand.cs @@ -28,16 +28,16 @@ public class CreateProjectCommand : ICreateProjectCommand _currentContext = currentContext; } - public async Task CreateAsync(Project project, Guid id, ClientType clientType) + public async Task CreateAsync(Project project, Guid id, IdentityClientType identityClientType) { - if (clientType != ClientType.User && clientType != ClientType.ServiceAccount) + if (identityClientType != IdentityClientType.User && identityClientType != IdentityClientType.ServiceAccount) { throw new NotFoundException(); } var createdProject = await _projectRepository.CreateAsync(project); - if (clientType == ClientType.User) + if (identityClientType == IdentityClientType.User) { var orgUser = await _organizationUserRepository.GetByOrganizationAsync(createdProject.OrganizationId, id); @@ -52,7 +52,7 @@ public class CreateProjectCommand : ICreateProjectCommand await _accessPolicyRepository.CreateManyAsync(new List { accessPolicy }); } - else if (clientType == ClientType.ServiceAccount) + else if (identityClientType == IdentityClientType.ServiceAccount) { var serviceAccountProjectAccessPolicy = new ServiceAccountProjectAccessPolicy() { diff --git a/bitwarden_license/src/Commercial.Core/SecretsManager/Queries/AccessClientQuery.cs b/bitwarden_license/src/Commercial.Core/SecretsManager/Queries/AccessClientQuery.cs index 101734506..8847ee293 100644 --- a/bitwarden_license/src/Commercial.Core/SecretsManager/Queries/AccessClientQuery.cs +++ b/bitwarden_license/src/Commercial.Core/SecretsManager/Queries/AccessClientQuery.cs @@ -21,7 +21,7 @@ public class AccessClientQuery : IAccessClientQuery ClaimsPrincipal claimsPrincipal, Guid organizationId) { var orgAdmin = await _currentContext.OrganizationAdmin(organizationId); - var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin); + var accessClient = AccessClientHelper.ToAccessClient(_currentContext.IdentityClientType, orgAdmin); var userId = _userService.GetProperUserId(claimsPrincipal).Value; return (accessClient, userId); } diff --git a/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Commands/Projects/CreateProjectCommandTests.cs b/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Commands/Projects/CreateProjectCommandTests.cs index 9f9fbf35e..cc79657ca 100644 --- a/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Commands/Projects/CreateProjectCommandTests.cs +++ b/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Commands/Projects/CreateProjectCommandTests.cs @@ -30,7 +30,7 @@ public class CreateProjectCommandTests .CreateAsync(Arg.Any()) .Returns(data); - await sutProvider.Sut.CreateAsync(data, userId, sutProvider.GetDependency().ClientType); + await sutProvider.Sut.CreateAsync(data, userId, sutProvider.GetDependency().IdentityClientType); await sutProvider.GetDependency().Received(1) .CreateAsync(Arg.Is(data)); diff --git a/src/Api/SecretsManager/Controllers/ProjectsController.cs b/src/Api/SecretsManager/Controllers/ProjectsController.cs index a436e9601..a6929bc19 100644 --- a/src/Api/SecretsManager/Controllers/ProjectsController.cs +++ b/src/Api/SecretsManager/Controllers/ProjectsController.cs @@ -57,7 +57,7 @@ public class ProjectsController : Controller var userId = _userService.GetProperUserId(User).Value; var orgAdmin = await _currentContext.OrganizationAdmin(organizationId); - var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin); + var accessClient = AccessClientHelper.ToAccessClient(_currentContext.IdentityClientType, orgAdmin); var projects = await _projectRepository.GetManyByOrganizationIdAsync(organizationId, userId, accessClient); @@ -84,7 +84,7 @@ public class ProjectsController : Controller } var userId = _userService.GetProperUserId(User).Value; - var result = await _createProjectCommand.CreateAsync(project, userId, _currentContext.ClientType); + var result = await _createProjectCommand.CreateAsync(project, userId, _currentContext.IdentityClientType); // Creating a project means you have read & write permission. return new ProjectResponseModel(result, true, true); @@ -124,7 +124,7 @@ public class ProjectsController : Controller var userId = _userService.GetProperUserId(User).Value; var orgAdmin = await _currentContext.OrganizationAdmin(project.OrganizationId); - var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin); + var accessClient = AccessClientHelper.ToAccessClient(_currentContext.IdentityClientType, orgAdmin); var access = await _projectRepository.AccessToProjectAsync(id, userId, accessClient); diff --git a/src/Api/SecretsManager/Controllers/SecretsController.cs b/src/Api/SecretsManager/Controllers/SecretsController.cs index 8e93f3d79..9997e7502 100644 --- a/src/Api/SecretsManager/Controllers/SecretsController.cs +++ b/src/Api/SecretsManager/Controllers/SecretsController.cs @@ -85,7 +85,7 @@ public class SecretsController : Controller var userId = _userService.GetProperUserId(User).Value; var orgAdmin = await _currentContext.OrganizationAdmin(organizationId); - var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin); + var accessClient = AccessClientHelper.ToAccessClient(_currentContext.IdentityClientType, orgAdmin); var secrets = await _secretRepository.GetManyDetailsByOrganizationIdAsync(organizationId, userId, accessClient); @@ -136,7 +136,7 @@ public class SecretsController : Controller var userId = _userService.GetProperUserId(User).Value; var orgAdmin = await _currentContext.OrganizationAdmin(secret.OrganizationId); - var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin); + var accessClient = AccessClientHelper.ToAccessClient(_currentContext.IdentityClientType, orgAdmin); var access = await _secretRepository.AccessToSecretAsync(id, userId, accessClient); @@ -145,7 +145,7 @@ public class SecretsController : Controller throw new NotFoundException(); } - if (_currentContext.ClientType == ClientType.ServiceAccount) + if (_currentContext.IdentityClientType == IdentityClientType.ServiceAccount) { await _eventService.LogServiceAccountSecretEventAsync(userId, secret, EventType.Secret_Retrieved); @@ -167,7 +167,7 @@ public class SecretsController : Controller var userId = _userService.GetProperUserId(User).Value; var orgAdmin = await _currentContext.OrganizationAdmin(project.OrganizationId); - var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin); + var accessClient = AccessClientHelper.ToAccessClient(_currentContext.IdentityClientType, orgAdmin); var secrets = await _secretRepository.GetManyDetailsByProjectIdAsync(projectId, userId, accessClient); @@ -311,7 +311,7 @@ public class SecretsController : Controller private async Task LogSecretsRetrievalAsync(Guid organizationId, IEnumerable secrets) { - if (_currentContext.ClientType == ClientType.ServiceAccount) + if (_currentContext.IdentityClientType == IdentityClientType.ServiceAccount) { var userId = _userService.GetProperUserId(User)!.Value; var org = await _organizationRepository.GetByIdAsync(organizationId); diff --git a/src/Api/SecretsManager/Controllers/ServiceAccountsController.cs b/src/Api/SecretsManager/Controllers/ServiceAccountsController.cs index 28fb96710..8de53bc1e 100644 --- a/src/Api/SecretsManager/Controllers/ServiceAccountsController.cs +++ b/src/Api/SecretsManager/Controllers/ServiceAccountsController.cs @@ -81,7 +81,7 @@ public class ServiceAccountsController : Controller var userId = _userService.GetProperUserId(User).Value; var orgAdmin = await _currentContext.OrganizationAdmin(organizationId); - var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin); + var accessClient = AccessClientHelper.ToAccessClient(_currentContext.IdentityClientType, orgAdmin); var results = await _serviceAccountSecretsDetailsQuery.GetManyByOrganizationIdAsync(organizationId, userId, accessClient, diff --git a/src/Core/Context/CurrentContext.cs b/src/Core/Context/CurrentContext.cs index 8143216f3..cbbcb9f20 100644 --- a/src/Core/Context/CurrentContext.cs +++ b/src/Core/Context/CurrentContext.cs @@ -39,7 +39,7 @@ public class CurrentContext : ICurrentContext public virtual int? BotScore { get; set; } public virtual string ClientId { get; set; } public virtual Version ClientVersion { get; set; } - public virtual ClientType ClientType { get; set; } + public virtual IdentityClientType IdentityClientType { get; set; } public virtual Guid? ServiceAccountOrganizationId { get; set; } public CurrentContext( @@ -151,11 +151,11 @@ public class CurrentContext : ICurrentContext var clientType = GetClaimValue(claimsDict, Claims.Type); if (clientType != null) { - Enum.TryParse(clientType, out ClientType c); - ClientType = c; + Enum.TryParse(clientType, out IdentityClientType c); + IdentityClientType = c; } - if (ClientType == ClientType.ServiceAccount) + if (IdentityClientType == IdentityClientType.ServiceAccount) { ServiceAccountOrganizationId = new Guid(GetClaimValue(claimsDict, Claims.Organization)); } diff --git a/src/Core/Context/ICurrentContext.cs b/src/Core/Context/ICurrentContext.cs index e41c660d4..e3f737698 100644 --- a/src/Core/Context/ICurrentContext.cs +++ b/src/Core/Context/ICurrentContext.cs @@ -23,7 +23,7 @@ public interface ICurrentContext List Organizations { get; set; } Guid? InstallationId { get; set; } Guid? OrganizationId { get; set; } - ClientType ClientType { get; set; } + IdentityClientType IdentityClientType { get; set; } bool IsBot { get; set; } bool MaybeBot { get; set; } int? BotScore { get; set; } diff --git a/src/Core/Enums/AccessClientType.cs b/src/Core/Enums/AccessClientType.cs index b2b198616..fb757c6dd 100644 --- a/src/Core/Enums/AccessClientType.cs +++ b/src/Core/Enums/AccessClientType.cs @@ -12,19 +12,19 @@ public enum AccessClientType public static class AccessClientHelper { - public static AccessClientType ToAccessClient(ClientType clientType, bool bypassAccessCheck = false) + public static AccessClientType ToAccessClient(IdentityClientType identityClientType, bool bypassAccessCheck = false) { if (bypassAccessCheck) { return AccessClientType.NoAccessCheck; } - return clientType switch + return identityClientType switch { - ClientType.User => AccessClientType.User, - ClientType.Organization => AccessClientType.Organization, - ClientType.ServiceAccount => AccessClientType.ServiceAccount, - _ => throw new ArgumentOutOfRangeException(nameof(clientType), clientType, null), + IdentityClientType.User => AccessClientType.User, + IdentityClientType.Organization => AccessClientType.Organization, + IdentityClientType.ServiceAccount => AccessClientType.ServiceAccount, + _ => throw new ArgumentOutOfRangeException(nameof(identityClientType), identityClientType, null), }; } } diff --git a/src/Core/NotificationCenter/Enums/ClientType.cs b/src/Core/Enums/ClientType.cs similarity index 88% rename from src/Core/NotificationCenter/Enums/ClientType.cs rename to src/Core/Enums/ClientType.cs index 88742cee8..4e95584e8 100644 --- a/src/Core/NotificationCenter/Enums/ClientType.cs +++ b/src/Core/Enums/ClientType.cs @@ -1,7 +1,7 @@ #nullable enable using System.ComponentModel.DataAnnotations; -namespace Bit.Core.NotificationCenter.Enums; +namespace Bit.Core.Enums; public enum ClientType : byte { diff --git a/src/Core/Identity/ClientType.cs b/src/Core/Identity/IdentityClientType.cs similarity index 71% rename from src/Core/Identity/ClientType.cs rename to src/Core/Identity/IdentityClientType.cs index 8952657df..bd5b68ff6 100644 --- a/src/Core/Identity/ClientType.cs +++ b/src/Core/Identity/IdentityClientType.cs @@ -1,6 +1,6 @@ namespace Bit.Core.Identity; -public enum ClientType : byte +public enum IdentityClientType : byte { User = 0, Organization = 1, diff --git a/src/Core/NotificationCenter/Entities/Notification.cs b/src/Core/NotificationCenter/Entities/Notification.cs index 7cec5471f..7ab318752 100644 --- a/src/Core/NotificationCenter/Entities/Notification.cs +++ b/src/Core/NotificationCenter/Entities/Notification.cs @@ -1,6 +1,7 @@ #nullable enable using System.ComponentModel.DataAnnotations; using Bit.Core.Entities; +using Bit.Core.Enums; using Bit.Core.NotificationCenter.Enums; using Bit.Core.Utilities; diff --git a/src/Core/NotificationCenter/Repositories/INotificationRepository.cs b/src/Core/NotificationCenter/Repositories/INotificationRepository.cs index cce8eaf8b..623e759df 100644 --- a/src/Core/NotificationCenter/Repositories/INotificationRepository.cs +++ b/src/Core/NotificationCenter/Repositories/INotificationRepository.cs @@ -1,6 +1,6 @@ #nullable enable +using Bit.Core.Enums; using Bit.Core.NotificationCenter.Entities; -using Bit.Core.NotificationCenter.Enums; using Bit.Core.NotificationCenter.Models.Filter; using Bit.Core.Repositories; diff --git a/src/Core/SecretsManager/Commands/Projects/Interfaces/ICreateProjectCommand.cs b/src/Core/SecretsManager/Commands/Projects/Interfaces/ICreateProjectCommand.cs index 307252865..db377e220 100644 --- a/src/Core/SecretsManager/Commands/Projects/Interfaces/ICreateProjectCommand.cs +++ b/src/Core/SecretsManager/Commands/Projects/Interfaces/ICreateProjectCommand.cs @@ -5,5 +5,5 @@ namespace Bit.Core.SecretsManager.Commands.Projects.Interfaces; public interface ICreateProjectCommand { - Task CreateAsync(Project project, Guid userId, ClientType clientType); + Task CreateAsync(Project project, Guid userId, IdentityClientType identityClientType); } diff --git a/src/Core/Services/Implementations/LaunchDarklyFeatureService.cs b/src/Core/Services/Implementations/LaunchDarklyFeatureService.cs index 26ab33841..0bee58fc1 100644 --- a/src/Core/Services/Implementations/LaunchDarklyFeatureService.cs +++ b/src/Core/Services/Implementations/LaunchDarklyFeatureService.cs @@ -1,4 +1,5 @@ using Bit.Core.Context; +using Bit.Core.Identity; using Bit.Core.Settings; using Bit.Core.Utilities; using LaunchDarkly.Logging; @@ -153,9 +154,9 @@ public class LaunchDarklyFeatureService : IFeatureService var builder = LaunchDarkly.Sdk.Context.MultiBuilder(); - switch (_currentContext.ClientType) + switch (_currentContext.IdentityClientType) { - case Identity.ClientType.User: + case IdentityClientType.User: { ContextBuilder ldUser; if (_currentContext.UserId.HasValue) @@ -182,7 +183,7 @@ public class LaunchDarklyFeatureService : IFeatureService } break; - case Identity.ClientType.Organization: + case IdentityClientType.Organization: { if (_currentContext.OrganizationId.HasValue) { @@ -196,7 +197,7 @@ public class LaunchDarklyFeatureService : IFeatureService } break; - case Identity.ClientType.ServiceAccount: + case IdentityClientType.ServiceAccount: { if (_currentContext.UserId.HasValue) { diff --git a/src/Core/Utilities/DeviceTypes.cs b/src/Core/Utilities/DeviceTypes.cs index 3398eb8f4..ea34c7fd8 100644 --- a/src/Core/Utilities/DeviceTypes.cs +++ b/src/Core/Utilities/DeviceTypes.cs @@ -4,21 +4,56 @@ namespace Bit.Core.Utilities; public static class DeviceTypes { - public static IReadOnlyCollection MobileTypes { get; } = new[] - { + public static IReadOnlyCollection MobileTypes { get; } = + [ DeviceType.Android, DeviceType.iOS, - DeviceType.AndroidAmazon, - }; + DeviceType.AndroidAmazon + ]; - public static IReadOnlyCollection DesktopTypes { get; } = new[] - { + public static IReadOnlyCollection DesktopTypes { get; } = + [ DeviceType.LinuxDesktop, DeviceType.MacOsDesktop, DeviceType.WindowsDesktop, DeviceType.UWP, DeviceType.WindowsCLI, DeviceType.MacOsCLI, - DeviceType.LinuxCLI, - }; + DeviceType.LinuxCLI + ]; + + + public static IReadOnlyCollection BrowserExtensionTypes { get; } = + [ + DeviceType.ChromeExtension, + DeviceType.FirefoxExtension, + DeviceType.OperaExtension, + DeviceType.EdgeExtension, + DeviceType.VivaldiExtension, + DeviceType.SafariExtension + ]; + + public static IReadOnlyCollection BrowserTypes { get; } = + [ + DeviceType.ChromeBrowser, + DeviceType.FirefoxBrowser, + DeviceType.OperaBrowser, + DeviceType.EdgeBrowser, + DeviceType.IEBrowser, + DeviceType.SafariBrowser, + DeviceType.VivaldiBrowser, + DeviceType.UnknownBrowser + ]; + + private static ClientType ToClientType(DeviceType? deviceType) + { + return deviceType switch + { + not null when MobileTypes.Contains(deviceType.Value) => ClientType.Mobile, + not null when DesktopTypes.Contains(deviceType.Value) => ClientType.Desktop, + not null when BrowserExtensionTypes.Contains(deviceType.Value) => ClientType.Browser, + not null when BrowserTypes.Contains(deviceType.Value) => ClientType.Web, + _ => ClientType.All + }; + } } diff --git a/src/Identity/IdentityServer/ClientStore.cs b/src/Identity/IdentityServer/ClientStore.cs index 6fd64ec21..3f1c1c2fd 100644 --- a/src/Identity/IdentityServer/ClientStore.cs +++ b/src/Identity/IdentityServer/ClientStore.cs @@ -128,7 +128,7 @@ public class ClientStore : IClientStore Claims = new List { new(JwtClaimTypes.Subject, apiKey.ServiceAccountId.ToString()), - new(Claims.Type, ClientType.ServiceAccount.ToString()), + new(Claims.Type, IdentityClientType.ServiceAccount.ToString()), }, }; @@ -160,7 +160,7 @@ public class ClientStore : IClientStore { new(JwtClaimTypes.Subject, user.Id.ToString()), new(JwtClaimTypes.AuthenticationMethod, "Application", "external"), - new(Claims.Type, ClientType.User.ToString()), + new(Claims.Type, IdentityClientType.User.ToString()), }; var orgs = await _currentContext.OrganizationMembershipAsync(_organizationUserRepository, user.Id); var providers = await _currentContext.ProviderMembershipAsync(_providerUserRepository, user.Id); @@ -218,7 +218,7 @@ public class ClientStore : IClientStore Claims = new List { new(JwtClaimTypes.Subject, org.Id.ToString()), - new(Claims.Type, ClientType.Organization.ToString()), + new(Claims.Type, IdentityClientType.Organization.ToString()), }, }; } diff --git a/src/Infrastructure.Dapper/NotificationCenter/Repositories/NotificationRepository.cs b/src/Infrastructure.Dapper/NotificationCenter/Repositories/NotificationRepository.cs index a5b914a58..40bfd4b0e 100644 --- a/src/Infrastructure.Dapper/NotificationCenter/Repositories/NotificationRepository.cs +++ b/src/Infrastructure.Dapper/NotificationCenter/Repositories/NotificationRepository.cs @@ -1,7 +1,7 @@ #nullable enable using System.Data; +using Bit.Core.Enums; using Bit.Core.NotificationCenter.Entities; -using Bit.Core.NotificationCenter.Enums; using Bit.Core.NotificationCenter.Models.Filter; using Bit.Core.NotificationCenter.Repositories; using Bit.Core.Settings; diff --git a/src/Infrastructure.EntityFramework/NotificationCenter/Repositories/NotificationRepository.cs b/src/Infrastructure.EntityFramework/NotificationCenter/Repositories/NotificationRepository.cs index 61372f229..03ae63c59 100644 --- a/src/Infrastructure.EntityFramework/NotificationCenter/Repositories/NotificationRepository.cs +++ b/src/Infrastructure.EntityFramework/NotificationCenter/Repositories/NotificationRepository.cs @@ -1,6 +1,6 @@ #nullable enable using AutoMapper; -using Bit.Core.NotificationCenter.Enums; +using Bit.Core.Enums; using Bit.Core.NotificationCenter.Models.Filter; using Bit.Core.NotificationCenter.Repositories; using Bit.Infrastructure.EntityFramework.NotificationCenter.Models; diff --git a/test/Api.Test/SecretsManager/Controllers/ProjectsControllerTests.cs b/test/Api.Test/SecretsManager/Controllers/ProjectsControllerTests.cs index eb7991a0a..a031318b2 100644 --- a/test/Api.Test/SecretsManager/Controllers/ProjectsControllerTests.cs +++ b/test/Api.Test/SecretsManager/Controllers/ProjectsControllerTests.cs @@ -115,12 +115,12 @@ public class ProjectsControllerTests var resultProject = data.ToProject(orgId); - sutProvider.GetDependency().CreateAsync(default, default, sutProvider.GetDependency().ClientType) + sutProvider.GetDependency().CreateAsync(default, default, sutProvider.GetDependency().IdentityClientType) .ReturnsForAnyArgs(resultProject); await Assert.ThrowsAsync(() => sutProvider.Sut.CreateAsync(orgId, data)); await sutProvider.GetDependency().DidNotReceiveWithAnyArgs() - .CreateAsync(Arg.Any(), Arg.Any(), sutProvider.GetDependency().ClientType); + .CreateAsync(Arg.Any(), Arg.Any(), sutProvider.GetDependency().IdentityClientType); } [Theory] @@ -138,7 +138,7 @@ public class ProjectsControllerTests await Assert.ThrowsAsync(() => sutProvider.Sut.CreateAsync(orgId, data)); await sutProvider.GetDependency().DidNotReceiveWithAnyArgs() - .CreateAsync(Arg.Any(), Arg.Any(), sutProvider.GetDependency().ClientType); + .CreateAsync(Arg.Any(), Arg.Any(), sutProvider.GetDependency().IdentityClientType); } [Theory] @@ -153,13 +153,13 @@ public class ProjectsControllerTests var resultProject = data.ToProject(orgId); - sutProvider.GetDependency().CreateAsync(default, default, sutProvider.GetDependency().ClientType) + sutProvider.GetDependency().CreateAsync(default, default, sutProvider.GetDependency().IdentityClientType) .ReturnsForAnyArgs(resultProject); await sutProvider.Sut.CreateAsync(orgId, data); await sutProvider.GetDependency().Received(1) - .CreateAsync(Arg.Any(), Arg.Any(), sutProvider.GetDependency().ClientType); + .CreateAsync(Arg.Any(), Arg.Any(), sutProvider.GetDependency().IdentityClientType); } [Theory]