diff --git a/src/Api/Auth/Controllers/AccountsController.cs b/src/Api/Auth/Controllers/AccountsController.cs index 1094c2f61b..2d4a52cefa 100644 --- a/src/Api/Auth/Controllers/AccountsController.cs +++ b/src/Api/Auth/Controllers/AccountsController.cs @@ -401,9 +401,9 @@ public class AccountsController : Controller var hasPremiumFromOrg = await _userService.HasPremiumFromOrganization(user); var organizationIdsClaimingActiveUser = await GetOrganizationIdsClaimingUserAsync(user.Id); - var userAccountKeysData = await _userAccountKeysQuery.Run(user); + var accountKeysResponse = new PrivateKeysResponseModel(await _userAccountKeysQuery.Run(user)); - var response = new ProfileResponseModel(user, userAccountKeysData, organizationUserDetails, providerUserDetails, + var response = new ProfileResponseModel(user, accountKeysResponse, organizationUserDetails, providerUserDetails, providerUserOrganizationDetails, twoFactorEnabled, hasPremiumFromOrg, organizationIdsClaimingActiveUser); return response; @@ -438,7 +438,7 @@ public class AccountsController : Controller var organizationIdsClaimingActiveUser = await GetOrganizationIdsClaimingUserAsync(user.Id); var userAccountKeysData = await _userAccountKeysQuery.Run(user); - var response = new ProfileResponseModel(user, userAccountKeysData, null, null, null, twoFactorEnabled, hasPremiumFromOrg, organizationIdsClaimingActiveUser); + var response = new ProfileResponseModel(user, new PrivateKeysResponseModel(userAccountKeysData), null, null, null, twoFactorEnabled, hasPremiumFromOrg, organizationIdsClaimingActiveUser); return response; } @@ -456,9 +456,9 @@ public class AccountsController : Controller var userTwoFactorEnabled = await _twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(user); var userHasPremiumFromOrganization = await _userService.HasPremiumFromOrganization(user); var organizationIdsClaimingActiveUser = await GetOrganizationIdsClaimingUserAsync(user.Id); - var userAccountKeysData = await _userAccountKeysQuery.Run(user); + var accountKeys = new PrivateKeysResponseModel(await _userAccountKeysQuery.Run(user)); - var response = new ProfileResponseModel(user, userAccountKeysData, null, null, null, userTwoFactorEnabled, userHasPremiumFromOrganization, organizationIdsClaimingActiveUser); + var response = new ProfileResponseModel(user, accountKeys, null, null, null, userTwoFactorEnabled, userHasPremiumFromOrganization, organizationIdsClaimingActiveUser); return response; } diff --git a/src/Api/Billing/Controllers/AccountsController.cs b/src/Api/Billing/Controllers/AccountsController.cs index b67a9d1b81..f5c6dd5a58 100644 --- a/src/Api/Billing/Controllers/AccountsController.cs +++ b/src/Api/Billing/Controllers/AccountsController.cs @@ -59,7 +59,7 @@ public class AccountsController( var userTwoFactorEnabled = await twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(user); var userHasPremiumFromOrganization = await userService.HasPremiumFromOrganization(user); var organizationIdsClaimingActiveUser = await GetOrganizationIdsClaimingUserAsync(user.Id); - var userAccountKeysData = await userAccountKeysQuery.Run(user); + var userAccountKeysData = new PrivateKeysResponseModel(await userAccountKeysQuery.Run(user)); var profile = new ProfileResponseModel(user, userAccountKeysData, null, null, null, userTwoFactorEnabled, userHasPremiumFromOrganization, organizationIdsClaimingActiveUser); diff --git a/src/Api/KeyManagement/Controllers/UsersController.cs b/src/Api/KeyManagement/Controllers/UsersController.cs index 20405476ac..1d69d9c937 100644 --- a/src/Api/KeyManagement/Controllers/UsersController.cs +++ b/src/Api/KeyManagement/Controllers/UsersController.cs @@ -1,6 +1,6 @@ using Bit.Api.KeyManagement.Models.Response; +using Bit.Api.KeyManagement.Queries; using Bit.Core.Exceptions; -using Bit.Core.KeyManagement.Repositories; using Bit.Core.Repositories; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -10,19 +10,10 @@ namespace Bit.Api.Controllers; [Route("users")] [Authorize("Application")] -public class UsersController : Controller +public class UsersController( + IUserRepository _userRepository, + IUserAccountKeysQuery _userAccountKeysQuery) : Controller { - private readonly IUserRepository _userRepository; - private readonly IUserSignatureKeyPairRepository _signatureKeyPairRepository; - - public UsersController( - IUserRepository userRepository, - IUserSignatureKeyPairRepository signatureKeyPairRepository) - { - _userRepository = userRepository; - _signatureKeyPairRepository = signatureKeyPairRepository; - } - [HttpGet("{id}/public-key")] public async Task Get(string id) { @@ -46,9 +37,11 @@ public class UsersController : Controller throw new NotFoundException(); } - var signingKeys = await _signatureKeyPairRepository.GetByUserIdAsync(guidId); - var verifyingKey = signingKeys?.VerifyingKey; - - return new PublicKeysResponseModel(verifyingKey, user.PublicKey, null); + var accountKeys = await _userAccountKeysQuery.Run(user); + if (accountKeys == null) + { + throw new NotFoundException("User account keys not found."); + } + return new PublicKeysResponseModel(accountKeys); } } diff --git a/src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs b/src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs index 78620ccdc1..fb9e2d4685 100644 --- a/src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs +++ b/src/Api/KeyManagement/Models/Response/PrivateKeysResponseModel.cs @@ -13,8 +13,10 @@ namespace Bit.Api.Models.Response; /// public class PrivateKeysResponseModel : ResponseModel { - public PrivateKeysResponseModel(UserAccountKeysData accountKeys) : base("accountKeys") + [System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute] + public PrivateKeysResponseModel(UserAccountKeysData accountKeys) : base("privateKeys") { + PublicKeyEncryptionKeyPair = accountKeys.PublicKeyEncryptionKeyPairData; if (accountKeys == null) { throw new ArgumentNullException(nameof(accountKeys)); @@ -24,11 +26,6 @@ public class PrivateKeysResponseModel : ResponseModel { SignatureKeyPair = accountKeys.SignatureKeyPairData; } - PublicKeyEncryptionKeyPair = accountKeys.PublicKeyEncryptionKeyPairData; - } - - public PrivateKeysResponseModel() : base("privateKeys") - { } // Not all accounts have signature keys, but all accounts have public encryption keys. diff --git a/src/Api/KeyManagement/Models/Response/PublicKeysResponseModel.cs b/src/Api/KeyManagement/Models/Response/PublicKeysResponseModel.cs index 0d1f75fa56..5d3e6ffa21 100644 --- a/src/Api/KeyManagement/Models/Response/PublicKeysResponseModel.cs +++ b/src/Api/KeyManagement/Models/Response/PublicKeysResponseModel.cs @@ -11,9 +11,11 @@ namespace Bit.Api.KeyManagement.Models.Response; /// public class PublicKeysResponseModel : ResponseModel { + [System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute] public PublicKeysResponseModel(UserAccountKeysData accountKeys) : base("publicKeys") { + PublicKey = accountKeys.PublicKeyEncryptionKeyPairData.PublicKey; if (accountKeys == null) { throw new ArgumentNullException(nameof(accountKeys)); @@ -24,11 +26,9 @@ public class PublicKeysResponseModel : ResponseModel SignedPublicKey = accountKeys.PublicKeyEncryptionKeyPairData.SignedPublicKey; VerifyingKey = accountKeys.SignatureKeyPairData.VerifyingKey; } - PublicKey = accountKeys.PublicKeyEncryptionKeyPairData.PublicKey; } public string? VerifyingKey { get; set; } public string? SignedPublicKey { get; set; } - [System.Obsolete("Use SignedPublicKey for new code, if it is not null.")] public required string PublicKey { get; set; } } diff --git a/src/Api/Models/Response/ProfileResponseModel.cs b/src/Api/Models/Response/ProfileResponseModel.cs index 64ce16c1b2..11b1108838 100644 --- a/src/Api/Models/Response/ProfileResponseModel.cs +++ b/src/Api/Models/Response/ProfileResponseModel.cs @@ -2,7 +2,6 @@ using Bit.Api.AdminConsole.Models.Response.Providers; using Bit.Core.AdminConsole.Models.Data.Provider; using Bit.Core.Entities; -using Bit.Core.KeyManagement.Models.Data; using Bit.Core.Models.Api; using Bit.Core.Models.Data.Organizations.OrganizationUsers; @@ -11,7 +10,7 @@ namespace Bit.Api.Models.Response; public class ProfileResponseModel : ResponseModel { public ProfileResponseModel(User user, - UserAccountKeysData userAccountKeysData, + PrivateKeysResponseModel privateKeysResponseModel, IEnumerable organizationsUserDetails, IEnumerable providerUserDetails, IEnumerable providerUserOrganizationDetails, @@ -34,7 +33,7 @@ public class ProfileResponseModel : ResponseModel TwoFactorEnabled = twoFactorEnabled; Key = user.Key; PrivateKey = user.PrivateKey; - AccountKeys = userAccountKeysData; + AccountKeys = privateKeysResponseModel; SecurityStamp = user.SecurityStamp; ForcePasswordReset = user.ForcePasswordReset; UsesKeyConnector = user.UsesKeyConnector; @@ -62,7 +61,7 @@ public class ProfileResponseModel : ResponseModel public string Key { get; set; } [Obsolete("Use AccountKeys instead.")] public string PrivateKey { get; set; } - public UserAccountKeysData AccountKeys { get; set; } + public PrivateKeysResponseModel AccountKeys { get; set; } public string SecurityStamp { get; set; } public bool ForcePasswordReset { get; set; } public bool UsesKeyConnector { get; set; } diff --git a/src/Api/Vault/Controllers/SyncController.cs b/src/Api/Vault/Controllers/SyncController.cs index 37d99db059..503d06c59a 100644 --- a/src/Api/Vault/Controllers/SyncController.cs +++ b/src/Api/Vault/Controllers/SyncController.cs @@ -1,4 +1,5 @@ -using Bit.Api.Vault.Models.Response; +using Bit.Api.Models.Response; +using Bit.Api.Vault.Models.Response; using Bit.Core; using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Enums.Provider; @@ -124,7 +125,7 @@ public class SyncController : Controller SignatureKeyPairData = signingKeys, }; - var response = new SyncResponseModel(_globalSettings, user, userAccountKeysData, userTwoFactorEnabled, userHasPremiumFromOrganization, organizationAbilities, + var response = new SyncResponseModel(_globalSettings, user, new PrivateKeysResponseModel(userAccountKeysData), userTwoFactorEnabled, userHasPremiumFromOrganization, organizationAbilities, organizationIdsClaimingActiveUser, organizationUserDetails, providerUserDetails, providerUserOrganizationDetails, folders, collections, ciphers, collectionCiphersGroupDict, excludeDomains, policies, sends); return response; diff --git a/src/Api/Vault/Models/Response/SyncResponseModel.cs b/src/Api/Vault/Models/Response/SyncResponseModel.cs index 485b59a1d1..a75a713927 100644 --- a/src/Api/Vault/Models/Response/SyncResponseModel.cs +++ b/src/Api/Vault/Models/Response/SyncResponseModel.cs @@ -4,7 +4,6 @@ using Bit.Api.Tools.Models.Response; using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Models.Data.Provider; using Bit.Core.Entities; -using Bit.Core.KeyManagement.Models.Data; using Bit.Core.Models.Api; using Bit.Core.Models.Data; using Bit.Core.Models.Data.Organizations; @@ -21,7 +20,7 @@ public class SyncResponseModel : ResponseModel public SyncResponseModel( GlobalSettings globalSettings, User user, - UserAccountKeysData userAccountKeysData, + PrivateKeysResponseModel privateKeysResponseModel, bool userTwoFactorEnabled, bool userHasPremiumFromOrganization, IDictionary organizationAbilities, @@ -38,7 +37,7 @@ public class SyncResponseModel : ResponseModel IEnumerable sends) : base("sync") { - Profile = new ProfileResponseModel(user, userAccountKeysData, organizationUserDetails, providerUserDetails, + Profile = new ProfileResponseModel(user, privateKeysResponseModel, organizationUserDetails, providerUserDetails, providerUserOrganizationDetails, userTwoFactorEnabled, userHasPremiumFromOrganization, organizationIdsClaimingingUser); Folders = folders.Select(f => new FolderResponseModel(f)); Ciphers = ciphers.Select(cipher =>