Skip to content

Commit

Permalink
Add server version compatibility check for Fido2Credentials on sharin…
Browse files Browse the repository at this point in the history
…g with org (#3328)

* Added compatibility checks.

* Refactored into separate methods for easier removal.

* Added check on ShareMany

* Updated method order to be consistent.

* Linting
  • Loading branch information
trmartin4 authored Oct 6, 2023
1 parent b85f32c commit 96ef1b0
Showing 1 changed file with 27 additions and 13 deletions.
40 changes: 27 additions & 13 deletions src/Api/Vault/Controllers/CiphersController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ public async Task<CipherResponseModel> Put(Guid id, [FromBody] CipherRequestMode
throw new NotFoundException();
}

ValidateItemLevelEncryptionIsAvailable(cipher);
ValidateClientVersionForItemLevelEncryptionSupport(cipher);
ValidateClientVersionForFido2CredentialSupport(cipher);

var collectionIds = (await _collectionCipherRepository.GetManyByUserIdCipherIdAsync(userId, id)).Select(c => c.CollectionId).ToList();
var modelOrgId = string.IsNullOrWhiteSpace(model.OrganizationId) ?
Expand All @@ -191,14 +192,6 @@ public async Task<CipherResponseModel> Put(Guid id, [FromBody] CipherRequestMode
"then try again.");
}

// Temporary protection against old clients overwriting and deleting Fido2Keys
// Response model used to re-use logic for parsing 'data' property
var cipherModel = new CipherResponseModel(cipher, _globalSettings);
if (cipherModel.Login?.Fido2Credentials != null && _currentContext.ClientVersion < _fido2KeyCipherMinimumVersion)
{
throw new BadRequestException("Please update your client to edit this item.");
}

await _cipherService.SaveDetailsAsync(model.ToCipherDetails(cipher), userId, model.LastKnownRevisionDate, collectionIds);

var response = new CipherResponseModel(cipher, _globalSettings);
Expand All @@ -212,7 +205,8 @@ public async Task<CipherMiniResponseModel> PutAdmin(Guid id, [FromBody] CipherRe
var userId = _userService.GetProperUserId(User).Value;
var cipher = await _cipherRepository.GetOrganizationDetailsByIdAsync(id);

ValidateItemLevelEncryptionIsAvailable(cipher);
ValidateClientVersionForItemLevelEncryptionSupport(cipher);
ValidateClientVersionForFido2CredentialSupport(cipher);

if (cipher == null || !cipher.OrganizationId.HasValue ||
!await _currentContext.EditAnyCollection(cipher.OrganizationId.Value))
Expand Down Expand Up @@ -277,6 +271,9 @@ public async Task<CipherResponseModel> PutShare(string id, [FromBody] CipherShar
throw new NotFoundException();
}

ValidateClientVersionForItemLevelEncryptionSupport(cipher);
ValidateClientVersionForFido2CredentialSupport(cipher);

var original = cipher.Clone();
await _cipherService.ShareAsync(original, model.Cipher.ToCipher(cipher), new Guid(model.Cipher.OrganizationId),
model.CollectionIds.Select(c => new Guid(c)), userId, model.Cipher.LastKnownRevisionDate);
Expand Down Expand Up @@ -539,7 +536,12 @@ public async Task PutShareMany([FromBody] CipherBulkShareRequestModel model)
throw new BadRequestException("Trying to move ciphers that you do not own.");
}

shareCiphers.Add((cipher.ToCipher(ciphersDict[cipher.Id.Value]), cipher.LastKnownRevisionDate));
var existingCipher = ciphersDict[cipher.Id.Value];

ValidateClientVersionForItemLevelEncryptionSupport(existingCipher);
ValidateClientVersionForFido2CredentialSupport(existingCipher);

shareCiphers.Add((cipher.ToCipher(existingCipher), cipher.LastKnownRevisionDate));
}

await _cipherService.ShareManyAsync(shareCiphers, organizationId,
Expand Down Expand Up @@ -592,7 +594,7 @@ await _cipherRepository.GetOrganizationDetailsByIdAsync(idGuid) :
throw new NotFoundException();
}

ValidateItemLevelEncryptionIsAvailable(cipher);
ValidateClientVersionForItemLevelEncryptionSupport(cipher);

if (request.FileSize > CipherService.MAX_FILE_SIZE)
{
Expand Down Expand Up @@ -814,11 +816,23 @@ private void ValidateAttachment()
}
}

private void ValidateItemLevelEncryptionIsAvailable(Cipher cipher)
private void ValidateClientVersionForItemLevelEncryptionSupport(Cipher cipher)
{
if (cipher.Key != null && _currentContext.ClientVersion < _cipherKeyEncryptionMinimumVersion)
{
throw new BadRequestException("Cannot edit item. Update to the latest version of Bitwarden and try again.");
}
}

private void ValidateClientVersionForFido2CredentialSupport(Cipher cipher)
{
if (cipher.Type == Core.Vault.Enums.CipherType.Login)
{
var loginData = JsonSerializer.Deserialize<CipherLoginData>(cipher.Data);
if (loginData?.Fido2Credentials != null && _currentContext.ClientVersion < _fido2KeyCipherMinimumVersion)
{
throw new BadRequestException("Cannot edit item. Update to the latest version of Bitwarden and try again.");
}
}
}
}

0 comments on commit 96ef1b0

Please sign in to comment.