1
0
mirror of https://github.com/bitwarden/server synced 2026-01-30 16:23:37 +00:00

Add WebauthnPRFOptions to syncResponse

This commit is contained in:
Anders Åberg
2025-09-25 10:44:35 +02:00
parent ba0723c0ed
commit 0a2aa0c27d
4 changed files with 35 additions and 6 deletions

View File

@@ -18,6 +18,7 @@ using Bit.Core.Settings;
using Bit.Core.Tools.Repositories;
using Bit.Core.Vault.Models.Data;
using Bit.Core.Vault.Repositories;
using Bit.Core.Auth.Repositories;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
@@ -42,6 +43,7 @@ public class SyncController : Controller
private readonly IFeatureService _featureService;
private readonly IApplicationCacheService _applicationCacheService;
private readonly ITwoFactorIsEnabledQuery _twoFactorIsEnabledQuery;
private readonly IWebAuthnCredentialRepository _webAuthnCredentialRepository;
public SyncController(
IUserService userService,
@@ -57,7 +59,8 @@ public class SyncController : Controller
ICurrentContext currentContext,
IFeatureService featureService,
IApplicationCacheService applicationCacheService,
ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery)
ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery,
IWebAuthnCredentialRepository webAuthnCredentialRepository)
{
_userService = userService;
_folderRepository = folderRepository;
@@ -73,6 +76,7 @@ public class SyncController : Controller
_featureService = featureService;
_applicationCacheService = applicationCacheService;
_twoFactorIsEnabledQuery = twoFactorIsEnabledQuery;
_webAuthnCredentialRepository = webAuthnCredentialRepository;
}
[HttpGet("")]
@@ -115,10 +119,11 @@ public class SyncController : Controller
var organizationIdsClaimingActiveUser = organizationClaimingActiveUser.Select(o => o.Id);
var organizationAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
var webAuthnCredentials = await _webAuthnCredentialRepository.GetManyByUserIdAsync(user.Id);
var response = new SyncResponseModel(_globalSettings, user, userTwoFactorEnabled, userHasPremiumFromOrganization, organizationAbilities,
organizationIdsClaimingActiveUser, organizationUserDetails, providerUserDetails, providerUserOrganizationDetails,
folders, collections, ciphers, collectionCiphersGroupDict, excludeDomains, policies, sends);
folders, collections, ciphers, collectionCiphersGroupDict, excludeDomains, policies, sends, webAuthnCredentials);
return response;
}

View File

@@ -16,6 +16,9 @@ using Bit.Core.Settings;
using Bit.Core.Tools.Entities;
using Bit.Core.Vault.Entities;
using Bit.Core.Vault.Models.Data;
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models.Api.Response;
namespace Bit.Api.Vault.Models.Response;
@@ -37,7 +40,8 @@ public class SyncResponseModel() : ResponseModel("sync")
IDictionary<Guid, IGrouping<Guid, CollectionCipher>> collectionCiphersDict,
bool excludeDomains,
IEnumerable<Policy> policies,
IEnumerable<Send> sends)
IEnumerable<Send> sends,
IEnumerable<WebAuthnCredential> webAuthnCredentials)
: this()
{
Profile = new ProfileResponseModel(user, organizationUserDetails, providerUserDetails,
@@ -55,6 +59,16 @@ public class SyncResponseModel() : ResponseModel("sync")
Domains = excludeDomains ? null : new DomainsResponseModel(user, false);
Policies = policies?.Select(p => new PolicyResponseModel(p)) ?? new List<PolicyResponseModel>();
Sends = sends.Select(s => new SendResponseModel(s, globalSettings));
var webAuthnPrfOptions = webAuthnCredentials
.Where(c => c.GetPrfStatus() == WebAuthnPrfStatus.Enabled)
.Select(c => new WebAuthnPrfDecryptionOption(
c.EncryptedPrivateKey,
c.EncryptedUserKey,
c.CredentialId,
[] // transports as empty array
))
.ToArray();
UserDecryption = new UserDecryptionResponseModel
{
MasterPasswordUnlock = user.HasMasterPassword()
@@ -70,7 +84,8 @@ public class SyncResponseModel() : ResponseModel("sync")
MasterKeyEncryptedUserKey = user.Key!,
Salt = user.Email.ToLowerInvariant()
}
: null
: null,
WebAuthnPrfOptions = webAuthnPrfOptions.Length > 0 ? webAuthnPrfOptions : null
};
}

View File

@@ -1,4 +1,7 @@
namespace Bit.Core.KeyManagement.Models.Response;
using System.Text.Json.Serialization;
using Bit.Core.Auth.Models.Api.Response;
namespace Bit.Core.KeyManagement.Models.Response;
public class UserDecryptionResponseModel
{
@@ -6,4 +9,10 @@ public class UserDecryptionResponseModel
/// Returns the unlock data when the user has a master password that can be used to decrypt their vault.
/// </summary>
public MasterPasswordUnlockResponseModel? MasterPasswordUnlock { get; set; }
/// <summary>
/// Gets or sets the WebAuthn PRF decryption keys.
/// </summary>
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public WebAuthnPrfDecryptionOption[]? WebAuthnPrfOptions { get; set; }
}

View File

@@ -57,7 +57,7 @@ public class UserDecryptionOptionsBuilder : IUserDecryptionOptionsBuilder
public IUserDecryptionOptionsBuilder WithDevice(Device device)
{
_device = device;>
_device = device;
return this;
}