1
0
mirror of https://github.com/bitwarden/server synced 2026-02-13 15:04:03 +00:00

[PM-31483] adding guard for when email verification FF is disabled (#6927)

* [PM-31483] adding guard for when email verification FF is disabled

* [PM-31483] removing need for client fallback endpoint

* [PM-31483] fixing test after main merge

* [PM-31483] changing error when email protected send should not be allowed to be viewed
This commit is contained in:
Alex Dragovich
2026-02-12 13:58:44 -08:00
committed by GitHub
parent cde8ceca31
commit 94f7266feb
3 changed files with 77 additions and 11 deletions

View File

@@ -303,7 +303,8 @@ public class Startup
{
swaggerDoc.Servers =
[
new() {
new()
{
Url = globalSettings.BaseServiceUri.Api,
}
];

View File

@@ -82,11 +82,9 @@ public class SendsController : Controller
throw new BadRequestException("Could not locate send");
}
/* This guard can be removed once feature flag is retired*/
var sendEmailOtpEnabled = _featureService.IsEnabled(FeatureFlagKeys.SendEmailOTP);
if (sendEmailOtpEnabled && send.AuthType == AuthType.Email && send.Emails is not null)
if (send.AuthType == AuthType.Email && send.Emails is not null)
{
return new UnauthorizedResult();
throw new NotFoundException();
}
var sendAuthResult =
@@ -137,11 +135,9 @@ public class SendsController : Controller
throw new BadRequestException("Could not locate send");
}
/* This guard can be removed once feature flag is retired*/
var sendEmailOtpEnabled = _featureService.IsEnabled(FeatureFlagKeys.SendEmailOTP);
if (sendEmailOtpEnabled && send.AuthType == AuthType.Email && send.Emails is not null)
if (send.AuthType == AuthType.Email && send.Emails is not null)
{
return new UnauthorizedResult();
throw new NotFoundException();
}
var (url, result) = await _anonymousSendCommand.GetSendFileDownloadUrlAsync(send, fileId,
@@ -229,7 +225,6 @@ public class SendsController : Controller
}
[Authorize(Policy = Policies.Send)]
// [RequireFeature(FeatureFlagKeys.SendEmailOTP)] /* Uncomment once client fallback re-try logic is added */
[HttpPost("access/")]
public async Task<IActionResult> AccessUsingAuth()
{
@@ -240,6 +235,13 @@ public class SendsController : Controller
throw new BadRequestException("Could not locate send");
}
/* This guard can be removed once feature flag is retired*/
var sendEmailOtpEnabled = _featureService.IsEnabled(FeatureFlagKeys.SendEmailOTP);
if (!sendEmailOtpEnabled && send.AuthType == AuthType.Email && send.Emails is not null)
{
throw new NotFoundException();
}
if (!INonAnonymousSendCommand.SendCanBeAccessed(send))
{
throw new NotFoundException();
@@ -270,7 +272,6 @@ public class SendsController : Controller
}
[Authorize(Policy = Policies.Send)]
// [RequireFeature(FeatureFlagKeys.SendEmailOTP)] /* Uncomment once client fallback re-try logic is added */
[HttpPost("access/file/{fileId}")]
public async Task<IActionResult> GetSendFileDownloadDataUsingAuth(string fileId)
{
@@ -282,6 +283,13 @@ public class SendsController : Controller
throw new BadRequestException("Could not locate send");
}
/* This guard can be removed once feature flag is retired*/
var sendEmailOtpEnabled = _featureService.IsEnabled(FeatureFlagKeys.SendEmailOTP);
if (!sendEmailOtpEnabled && send.AuthType == AuthType.Email && send.Emails is not null)
{
throw new NotFoundException();
}
var (url, result) = await _nonAnonymousSendCommand.GetSendFileDownloadUrlAsync(send, fileId);
if (result.Equals(SendAccessResult.Denied))

View File

@@ -6,6 +6,7 @@ using Bit.Api.Tools.Controllers;
using Bit.Api.Tools.Models;
using Bit.Api.Tools.Models.Request;
using Bit.Api.Tools.Models.Response;
using Bit.Core;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Platform.Push;
@@ -80,6 +81,8 @@ public class SendsControllerTests : IDisposable
send.Id = default;
send.Type = SendType.Text;
send.Data = JsonSerializer.Serialize(new Dictionary<string, string>());
send.AuthType = AuthType.None;
send.Emails = null;
send.HideEmail = true;
_sendRepository.GetByIdAsync(Arg.Any<Guid>()).Returns(send);
@@ -793,6 +796,33 @@ public class SendsControllerTests : IDisposable
await _userService.Received(1).GetUserByIdAsync(creator.Id);
}
[Theory, AutoData]
public async Task AccessUsingAuth_WithEmailProtectedSend_WithFfDisabled_ReturnsUnauthorizedResult(Guid sendId, User creator)
{
var send = new Send
{
Id = sendId,
UserId = creator.Id,
Type = SendType.Text,
Data = JsonSerializer.Serialize(new SendTextData("Test", "Notes", "Text", false)),
HideEmail = false,
DeletionDate = DateTime.UtcNow.AddDays(7),
ExpirationDate = null,
Disabled = false,
AccessCount = 0,
AuthType = AuthType.Email,
Emails = "test@example.com",
MaxAccessCount = null
};
var user = CreateUserWithSendIdClaim(sendId);
_sut.ControllerContext = CreateControllerContextWithUser(user);
_sendRepository.GetByIdAsync(sendId).Returns(send);
_userService.GetUserByIdAsync(creator.Id).Returns(creator);
_featureService.IsEnabled(FeatureFlagKeys.SendEmailOTP).Returns(false);
await Assert.ThrowsAsync<NotFoundException>(() => _sut.AccessUsingAuth());
}
[Theory, AutoData]
public async Task AccessUsingAuth_WithHideEmail_DoesNotIncludeCreatorIdentifier(Guid sendId, User creator)
{
@@ -1036,6 +1066,33 @@ public class SendsControllerTests : IDisposable
await _nonAnonymousSendCommand.Received(1).GetSendFileDownloadUrlAsync(send, fileId);
}
[Theory, AutoData]
public async Task GetSendFileDownloadDataUsingAuth_WithEmailProtectedSend_WithFfDisabled_ReturnsUnauthorizedResult(
Guid sendId, string fileId, string expectedUrl)
{
var fileData = new SendFileData("Test File", "Notes", "document.pdf") { Id = fileId, Size = 2048 };
var send = new Send
{
Id = sendId,
Type = SendType.File,
Data = JsonSerializer.Serialize(fileData),
DeletionDate = DateTime.UtcNow.AddDays(7),
ExpirationDate = null,
Disabled = false,
AccessCount = 0,
AuthType = AuthType.Email,
Emails = "test@example.com",
MaxAccessCount = null
};
var user = CreateUserWithSendIdClaim(sendId);
_sut.ControllerContext = CreateControllerContextWithUser(user);
_sendRepository.GetByIdAsync(sendId).Returns(send);
_sendFileStorageService.GetSendFileDownloadUrlAsync(send, fileId).Returns(expectedUrl);
_featureService.IsEnabled(FeatureFlagKeys.SendEmailOTP).Returns(false);
await Assert.ThrowsAsync<NotFoundException>(() => _sut.GetSendFileDownloadDataUsingAuth(fileId));
}
[Theory, AutoData]
public async Task GetSendFileDownloadDataUsingAuth_WithNonExistentSend_ThrowsBadRequestException(
Guid sendId, string fileId)