mirror of
https://github.com/bitwarden/server
synced 2026-01-14 06:23:46 +00:00
added AuthType prop to send related models with test coverage and debt cleanup
This commit is contained in:
@@ -44,7 +44,7 @@ public class SendRotationValidator : IRotationValidator<IEnumerable<SendWithIdRe
|
||||
throw new BadRequestException("All existing sends must be included in the rotation.");
|
||||
}
|
||||
|
||||
result.Add(send.ToSend(existing, _sendAuthorizationService));
|
||||
result.Add(send.UpdateSend(existing, _sendAuthorizationService));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -92,7 +92,7 @@ public class SendsController : Controller
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var sendResponse = new SendAccessResponseModel(send, _globalSettings);
|
||||
var sendResponse = new SendAccessResponseModel(send);
|
||||
if (send.UserId.HasValue && !send.HideEmail.GetValueOrDefault())
|
||||
{
|
||||
var creator = await _userService.GetUserByIdAsync(send.UserId.Value);
|
||||
@@ -295,7 +295,7 @@ public class SendsController : Controller
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
await _nonAnonymousSendCommand.SaveSendAsync(model.ToSend(send, _sendAuthorizationService));
|
||||
await _nonAnonymousSendCommand.SaveSendAsync(model.UpdateSend(send, _sendAuthorizationService));
|
||||
return new SendResponseModel(send);
|
||||
}
|
||||
|
||||
@@ -309,7 +309,10 @@ public class SendsController : Controller
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
// This endpoint exists because PUT preserves existing Password/Emails when not provided.
|
||||
// This allows clients to update other fields without re-submitting sensitive auth data.
|
||||
send.Password = null;
|
||||
send.AuthType = AuthType.None;
|
||||
await _nonAnonymousSendCommand.SaveSendAsync(send);
|
||||
return new SendResponseModel(send);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,11 @@ public class SendRequestModel
|
||||
/// </summary>
|
||||
public SendType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the authentication method required to access this Send.
|
||||
/// </summary>
|
||||
public AuthType? AuthType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Estimated length of the file accompanying the send. <see langword="null"/> when
|
||||
/// <see cref="Type"/> is <see cref="SendType.Text"/>.
|
||||
@@ -125,7 +130,7 @@ public class SendRequestModel
|
||||
Type = Type,
|
||||
UserId = (Guid?)userId
|
||||
};
|
||||
ToSend(send, sendAuthorizationService);
|
||||
send = UpdateSend(send, sendAuthorizationService);
|
||||
return send;
|
||||
}
|
||||
|
||||
@@ -155,8 +160,7 @@ public class SendRequestModel
|
||||
/// <param name="existingSend">The send to update</param>
|
||||
/// <param name="sendAuthorizationService">Hashes the send password.</param>
|
||||
/// <returns>The send object</returns>
|
||||
// FIXME: rename to `UpdateSend`
|
||||
public Send ToSend(Send existingSend, ISendAuthorizationService sendAuthorizationService)
|
||||
public Send UpdateSend(Send existingSend, ISendAuthorizationService sendAuthorizationService)
|
||||
{
|
||||
existingSend = ToSendBase(existingSend, sendAuthorizationService);
|
||||
switch (existingSend.Type)
|
||||
@@ -249,11 +253,29 @@ public class SendRequestModel
|
||||
var emails = Emails.Split(',', RemoveEmptyEntries | TrimEntries);
|
||||
existingSend.Emails = string.Join(", ", emails);
|
||||
existingSend.Password = null;
|
||||
existingSend.AuthType = Core.Tools.Enums.AuthType.Email;
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(Password))
|
||||
{
|
||||
existingSend.Password = authorizationService.HashPassword(Password);
|
||||
existingSend.Emails = null;
|
||||
existingSend.AuthType = Core.Tools.Enums.AuthType.Password;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Neither Password nor Emails provided - preserve existing values and infer AuthType
|
||||
if (!string.IsNullOrWhiteSpace(existingSend.Password))
|
||||
{
|
||||
existingSend.AuthType = Core.Tools.Enums.AuthType.Password;
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(existingSend.Emails))
|
||||
{
|
||||
existingSend.AuthType = Core.Tools.Enums.AuthType.Email;
|
||||
}
|
||||
else
|
||||
{
|
||||
existingSend.AuthType = Core.Tools.Enums.AuthType.None;
|
||||
}
|
||||
}
|
||||
|
||||
existingSend.Disabled = Disabled.GetValueOrDefault();
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using System.Text.Json;
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Tools.Entities;
|
||||
using Bit.Core.Tools.Enums;
|
||||
using Bit.Core.Tools.Models.Data;
|
||||
@@ -20,17 +19,13 @@ public class SendAccessResponseModel : ResponseModel
|
||||
/// Instantiates a send access response model
|
||||
/// </summary>
|
||||
/// <param name="send">Content to transmit to the client.</param>
|
||||
/// <param name="globalSettings">
|
||||
/// Settings that control response generation.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// Thrown when <paramref name="send"/> is <see langword="null" />
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// Thrown when <paramref name="send" /> has an invalid <see cref="Send.Type"/>.
|
||||
/// </exception>
|
||||
// FIXME: remove `globalSettings` variable
|
||||
public SendAccessResponseModel(Send send, GlobalSettings globalSettings)
|
||||
public SendAccessResponseModel(Send send)
|
||||
: base("send-access")
|
||||
{
|
||||
if (send == null)
|
||||
@@ -40,6 +35,7 @@ public class SendAccessResponseModel : ResponseModel
|
||||
|
||||
Id = CoreHelpers.Base64UrlEncode(send.Id.ToByteArray());
|
||||
Type = send.Type;
|
||||
AuthType = send.AuthType;
|
||||
|
||||
SendData sendData;
|
||||
switch (send.Type)
|
||||
@@ -72,6 +68,11 @@ public class SendAccessResponseModel : ResponseModel
|
||||
/// </summary>
|
||||
public SendType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the authentication method required to access this Send.
|
||||
/// </summary>
|
||||
public AuthType? AuthType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Label for the send. This is only visible to the owner of the send.
|
||||
/// </summary>
|
||||
|
||||
@@ -37,6 +37,9 @@ public class SendResponseModel : ResponseModel
|
||||
Id = send.Id;
|
||||
AccessId = CoreHelpers.Base64UrlEncode(send.Id.ToByteArray());
|
||||
Type = send.Type;
|
||||
AuthType = send.AuthType ?? (!string.IsNullOrWhiteSpace(send.Password)
|
||||
? AuthType = Core.Tools.Enums.AuthType.Password
|
||||
: (!string.IsNullOrWhiteSpace(send.Emails)? Core.Tools.Enums.AuthType.Email : Core.Tools.Enums.AuthType.None));
|
||||
Key = send.Key;
|
||||
MaxAccessCount = send.MaxAccessCount;
|
||||
AccessCount = send.AccessCount;
|
||||
@@ -84,6 +87,11 @@ public class SendResponseModel : ResponseModel
|
||||
/// </summary>
|
||||
public SendType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the authentication method required to access this Send.
|
||||
/// </summary>
|
||||
public AuthType? AuthType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Label for the send.
|
||||
/// </summary>
|
||||
|
||||
@@ -37,6 +37,12 @@ public class Send : ITableObject<Guid>
|
||||
/// </summary>
|
||||
public SendType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the authentication method required to access this Send.
|
||||
/// </summary>
|
||||
/// <seealso cref="Tools.Enums.AuthType"/>
|
||||
public AuthType? AuthType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Stores data containing or pointing to the transmitted secret. JSON.
|
||||
/// </summary>
|
||||
|
||||
25
src/Core/Tools/Enums/AuthType.cs
Normal file
25
src/Core/Tools/Enums/AuthType.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Bit.Core.Tools.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the authentication method required to access a Send.
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public enum AuthType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Email-based OTP authentication
|
||||
/// </summary>
|
||||
Email = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Password-based authentication
|
||||
/// </summary>
|
||||
Password = 1,
|
||||
|
||||
/// <summary>
|
||||
/// No authentication required
|
||||
/// </summary>
|
||||
None = 2
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Text.Json;
|
||||
using AutoFixture.Xunit2;
|
||||
using Bit.Api.Models.Response;
|
||||
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.Entities;
|
||||
@@ -173,4 +174,583 @@ public class SendsControllerTests : IDisposable
|
||||
Assert.Empty(result.Data);
|
||||
await _sendOwnerQuery.Received(1).GetOwned(Arg.Any<ClaimsPrincipal>());
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Post_WithPassword_InfersAuthTypePassword(Guid userId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "key",
|
||||
Text = new SendTextModel { Text = "text" },
|
||||
Password = "password",
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Post(request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(AuthType.Password, result.AuthType);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.AuthType == AuthType.Password &&
|
||||
s.Password != null &&
|
||||
s.Emails == null &&
|
||||
s.UserId == userId &&
|
||||
s.Type == SendType.Text));
|
||||
_userService.Received(1).GetProperUserId(Arg.Any<ClaimsPrincipal>());
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Post_WithEmails_InfersAuthTypeEmail(Guid userId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "key",
|
||||
Text = new SendTextModel { Text = "text" },
|
||||
Emails = "test@example.com",
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Post(request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(AuthType.Email, result.AuthType);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.AuthType == AuthType.Email &&
|
||||
s.Emails != null &&
|
||||
s.Password == null &&
|
||||
s.UserId == userId &&
|
||||
s.Type == SendType.Text));
|
||||
_userService.Received(1).GetProperUserId(Arg.Any<ClaimsPrincipal>());
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Post_WithoutPasswordOrEmails_InfersAuthTypeNone(Guid userId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "key",
|
||||
Text = new SendTextModel { Text = "text" },
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Post(request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(AuthType.None, result.AuthType);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.AuthType == AuthType.None &&
|
||||
s.Password == null &&
|
||||
s.Emails == null &&
|
||||
s.UserId == userId &&
|
||||
s.Type == SendType.Text));
|
||||
_userService.Received(1).GetProperUserId(Arg.Any<ClaimsPrincipal>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AuthType.Password)]
|
||||
[InlineData(AuthType.Email)]
|
||||
[InlineData(AuthType.None)]
|
||||
public async Task Access_ReturnsCorrectAuthType(AuthType authType)
|
||||
{
|
||||
var sendId = Guid.NewGuid();
|
||||
var accessId = CoreHelpers.Base64UrlEncode(sendId.ToByteArray());
|
||||
var send = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new Dictionary<string, string>()),
|
||||
AuthType = authType
|
||||
};
|
||||
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(send);
|
||||
_sendAuthorizationService.AccessAsync(send, "pwd123").Returns(SendAccessResult.Granted);
|
||||
|
||||
var request = new SendAccessRequestModel();
|
||||
var actionResult = await _sut.Access(accessId, request);
|
||||
var response = (actionResult as ObjectResult)?.Value as SendAccessResponseModel;
|
||||
|
||||
Assert.NotNull(response);
|
||||
Assert.Equal(authType, response.AuthType);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(AuthType.Password)]
|
||||
[InlineData(AuthType.Email)]
|
||||
[InlineData(AuthType.None)]
|
||||
public async Task Get_ReturnsCorrectAuthType(AuthType authType)
|
||||
{
|
||||
var sendId = Guid.NewGuid();
|
||||
var send = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("a", "b", "c", false)),
|
||||
AuthType = authType
|
||||
};
|
||||
|
||||
_sendOwnerQuery.Get(sendId, Arg.Any<ClaimsPrincipal>()).Returns(send);
|
||||
|
||||
var result = await _sut.Get(sendId.ToString());
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(authType, result.AuthType);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Put_WithValidSend_UpdatesSuccessfully(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = userId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Old", "Old notes", "Old text", false)),
|
||||
AuthType = AuthType.None
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "updated-key",
|
||||
Text = new SendTextModel { Text = "updated text" },
|
||||
Password = "new-password",
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Put(sendId.ToString(), request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(sendId, result.Id);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s => s.Id == sendId));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Put_WithNonExistentSend_ThrowsNotFoundException(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
_sendRepository.GetByIdAsync(sendId).Returns((Send)null);
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "key",
|
||||
Text = new SendTextModel { Text = "text" },
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => _sut.Put(sendId.ToString(), request));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Put_WithWrongUser_ThrowsNotFoundException(Guid userId, Guid otherUserId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = otherUserId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Old", "Old notes", "Old text", false))
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "key",
|
||||
Text = new SendTextModel { Text = "text" },
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => _sut.Put(sendId.ToString(), request));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task PutRemovePassword_WithValidSend_RemovesPasswordAndSetsAuthTypeNone(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = userId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Test", "Notes", "Text", false)),
|
||||
Password = "hashed-password",
|
||||
AuthType = AuthType.Password
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
var result = await _sut.PutRemovePassword(sendId.ToString());
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(sendId, result.Id);
|
||||
Assert.Equal(AuthType.None, result.AuthType);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.Id == sendId &&
|
||||
s.Password == null &&
|
||||
s.AuthType == AuthType.None));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task PutRemovePassword_WithNonExistentSend_ThrowsNotFoundException(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
_sendRepository.GetByIdAsync(sendId).Returns((Send)null);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => _sut.PutRemovePassword(sendId.ToString()));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task PutRemovePassword_WithWrongUser_ThrowsNotFoundException(Guid userId, Guid otherUserId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = otherUserId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Test", "Notes", "Text", false)),
|
||||
Password = "hashed-password"
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => _sut.PutRemovePassword(sendId.ToString()));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Delete_WithValidSend_DeletesSuccessfully(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = userId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Test", "Notes", "Text", false))
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
await _sut.Delete(sendId.ToString());
|
||||
|
||||
await _nonAnonymousSendCommand.Received(1).DeleteSendAsync(Arg.Is<Send>(s => s.Id == sendId));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Delete_WithNonExistentSend_ThrowsNotFoundException(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
_sendRepository.GetByIdAsync(sendId).Returns((Send)null);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => _sut.Delete(sendId.ToString()));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Delete_WithWrongUser_ThrowsNotFoundException(Guid userId, Guid otherUserId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = otherUserId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Test", "Notes", "Text", false))
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => _sut.Delete(sendId.ToString()));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task PostFile_WithPassword_InfersAuthTypePassword(Guid userId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
_nonAnonymousSendCommand.SaveFileSendAsync(Arg.Any<Send>(), Arg.Any<SendFileData>(), Arg.Any<long>())
|
||||
.Returns("https://example.com/upload")
|
||||
.AndDoes(callInfo =>
|
||||
{
|
||||
var send = callInfo.ArgAt<Send>(0);
|
||||
var data = callInfo.ArgAt<SendFileData>(1);
|
||||
send.Data = JsonSerializer.Serialize(data);
|
||||
});
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.File,
|
||||
Key = "key",
|
||||
File = new SendFileModel { FileName = "test.txt" },
|
||||
FileLength = 1024L,
|
||||
Password = "password",
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.PostFile(request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotNull(result.SendResponse);
|
||||
Assert.Equal(AuthType.Password, result.SendResponse.AuthType);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveFileSendAsync(
|
||||
Arg.Is<Send>(s =>
|
||||
s.AuthType == AuthType.Password &&
|
||||
s.Password != null &&
|
||||
s.Emails == null &&
|
||||
s.UserId == userId),
|
||||
Arg.Any<SendFileData>(),
|
||||
1024L);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task PostFile_WithEmails_InfersAuthTypeEmail(Guid userId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
_nonAnonymousSendCommand.SaveFileSendAsync(Arg.Any<Send>(), Arg.Any<SendFileData>(), Arg.Any<long>())
|
||||
.Returns("https://example.com/upload")
|
||||
.AndDoes(callInfo =>
|
||||
{
|
||||
var send = callInfo.ArgAt<Send>(0);
|
||||
var data = callInfo.ArgAt<SendFileData>(1);
|
||||
send.Data = JsonSerializer.Serialize(data);
|
||||
});
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.File,
|
||||
Key = "key",
|
||||
File = new SendFileModel { FileName = "test.txt" },
|
||||
FileLength = 1024L,
|
||||
Emails = "test@example.com",
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.PostFile(request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotNull(result.SendResponse);
|
||||
Assert.Equal(AuthType.Email, result.SendResponse.AuthType);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveFileSendAsync(
|
||||
Arg.Is<Send>(s =>
|
||||
s.AuthType == AuthType.Email &&
|
||||
s.Emails != null &&
|
||||
s.Password == null &&
|
||||
s.UserId == userId),
|
||||
Arg.Any<SendFileData>(),
|
||||
1024L);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task PostFile_WithoutPasswordOrEmails_InfersAuthTypeNone(Guid userId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
_nonAnonymousSendCommand.SaveFileSendAsync(Arg.Any<Send>(), Arg.Any<SendFileData>(), Arg.Any<long>())
|
||||
.Returns("https://example.com/upload")
|
||||
.AndDoes(callInfo =>
|
||||
{
|
||||
var send = callInfo.ArgAt<Send>(0);
|
||||
var data = callInfo.ArgAt<SendFileData>(1);
|
||||
send.Data = JsonSerializer.Serialize(data);
|
||||
});
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.File,
|
||||
Key = "key",
|
||||
File = new SendFileModel { FileName = "test.txt" },
|
||||
FileLength = 1024L,
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.PostFile(request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotNull(result.SendResponse);
|
||||
Assert.Equal(AuthType.None, result.SendResponse.AuthType);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveFileSendAsync(
|
||||
Arg.Is<Send>(s =>
|
||||
s.AuthType == AuthType.None &&
|
||||
s.Password == null &&
|
||||
s.Emails == null &&
|
||||
s.UserId == userId),
|
||||
Arg.Any<SendFileData>(),
|
||||
1024L);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Put_ChangingFromPasswordToEmails_UpdatesAuthTypeToEmail(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = userId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Old", "Old notes", "Old text", false)),
|
||||
Password = "hashed-password",
|
||||
AuthType = AuthType.Password
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "updated-key",
|
||||
Text = new SendTextModel { Text = "updated text" },
|
||||
Emails = "new@example.com",
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Put(sendId.ToString(), request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(sendId, result.Id);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.Id == sendId &&
|
||||
s.AuthType == AuthType.Email &&
|
||||
s.Emails != null &&
|
||||
s.Password == null));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Put_ChangingFromEmailToPassword_UpdatesAuthTypeToPassword(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = userId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Old", "Old notes", "Old text", false)),
|
||||
Emails = "old@example.com",
|
||||
AuthType = AuthType.Email
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "updated-key",
|
||||
Text = new SendTextModel { Text = "updated text" },
|
||||
Password = "new-password",
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Put(sendId.ToString(), request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(sendId, result.Id);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.Id == sendId &&
|
||||
s.AuthType == AuthType.Password &&
|
||||
s.Password != null &&
|
||||
s.Emails == null));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Put_WithoutPasswordOrEmails_PreservesExistingPassword(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = userId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Old", "Old notes", "Old text", false)),
|
||||
Password = "hashed-password",
|
||||
AuthType = AuthType.Password
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "updated-key",
|
||||
Text = new SendTextModel { Text = "updated text" },
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Put(sendId.ToString(), request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(sendId, result.Id);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.Id == sendId &&
|
||||
s.AuthType == AuthType.Password &&
|
||||
s.Password == "hashed-password" &&
|
||||
s.Emails == null));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Put_WithoutPasswordOrEmails_PreservesExistingEmails(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = userId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Old", "Old notes", "Old text", false)),
|
||||
Emails = "test@example.com",
|
||||
AuthType = AuthType.Email
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "updated-key",
|
||||
Text = new SendTextModel { Text = "updated text" },
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Put(sendId.ToString(), request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(sendId, result.Id);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.Id == sendId &&
|
||||
s.AuthType == AuthType.Email &&
|
||||
s.Emails == "test@example.com" &&
|
||||
s.Password == null));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task Put_WithoutPasswordOrEmails_PreservesNoneAuthType(Guid userId, Guid sendId)
|
||||
{
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
var existingSend = new Send
|
||||
{
|
||||
Id = sendId,
|
||||
UserId = userId,
|
||||
Type = SendType.Text,
|
||||
Data = JsonSerializer.Serialize(new SendTextData("Old", "Old notes", "Old text", false)),
|
||||
Password = null,
|
||||
Emails = null,
|
||||
AuthType = AuthType.None
|
||||
};
|
||||
_sendRepository.GetByIdAsync(sendId).Returns(existingSend);
|
||||
|
||||
var request = new SendRequestModel
|
||||
{
|
||||
Type = SendType.Text,
|
||||
Key = "updated-key",
|
||||
Text = new SendTextModel { Text = "updated text" },
|
||||
DeletionDate = DateTime.UtcNow.AddDays(7)
|
||||
};
|
||||
|
||||
var result = await _sut.Put(sendId.ToString(), request);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(sendId, result.Id);
|
||||
await _nonAnonymousSendCommand.Received(1).SaveSendAsync(Arg.Is<Send>(s =>
|
||||
s.Id == sendId &&
|
||||
s.AuthType == AuthType.None &&
|
||||
s.Password == null &&
|
||||
s.Emails == null));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user