Skip to content

Commit c2d56fc

Browse files
Consumer API: Make File's Owner and OwnerSignature required (#503)
* Change Base64 strings to byte arrays in DTO * Make non-null fields required in data classes * Add PropertyGroup Nullable to File projects * Remove call to deleted script * Make Owner and OwnerSignature required, validate it correctly * Make DeletedBy null in response * Add DB migration to make Owner property non-null with default value of "" * Fix Schroedinger's Whitespace (File was not completely CRLF) * Make OwnerSignature, CipherHash and EncryptedProperties base64 strings again * Remove trailing whitespace
1 parent 1ca8f29 commit c2d56fc

File tree

17 files changed

+380
-39
lines changed

17 files changed

+380
-39
lines changed

Modules/Files/src/Files.Application/Files.Application.csproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<Nullable>enable</Nullable>
5+
</PropertyGroup>
26

37
<ItemGroup>
48
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />

Modules/Files/src/Files.Application/Files/Commands/CreateFile/CreateFileCommand.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ namespace Backbone.Modules.Files.Application.Files.Commands.CreateFile;
77
[ApplyQuotasForMetrics("NumberOfFiles", "UsedFileStorageSpace")]
88
public class CreateFileCommand : IRequest<CreateFileResponse>
99
{
10-
public byte[] FileContent { get; set; }
10+
public required byte[] FileContent { get; set; }
1111

12-
public IdentityAddress Owner { get; set; }
13-
public byte[] OwnerSignature { get; set; }
12+
public required IdentityAddress Owner { get; set; }
13+
public required byte[] OwnerSignature { get; set; }
1414

15-
public byte[] CipherHash { get; set; }
15+
public required byte[] CipherHash { get; set; }
1616

17-
public DateTime ExpiresAt { get; set; }
17+
public required DateTime ExpiresAt { get; set; }
1818

19-
public byte[] EncryptedProperties { get; set; }
19+
public required byte[] EncryptedProperties { get; set; }
2020
}

Modules/Files/src/Files.Application/Files/Commands/CreateFile/CreateFileCommandValidator.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,10 @@ public CreateFileCommandValidator()
2323
.GreaterThan(SystemTime.UtcNow).WithMessage("'{PropertyName}' must be in the future.").WithErrorCode(GenericApplicationErrors.Validation.InvalidPropertyValue().Code);
2424

2525
RuleFor(m => m.Owner)
26-
.NotEmpty()
27-
.When(m => m.OwnerSignature is { Length: > 0 })
28-
.WithMessage(m => $"{nameof(m.Owner)} and {nameof(m.OwnerSignature)} have to be provided either both or none.");
26+
.DetailedNotEmpty();
2927

3028
RuleFor(m => m.OwnerSignature)
31-
.NumberOfBytes(0, 512);
29+
.NumberOfBytes(1, 512);
3230

3331
RuleFor(r => r.EncryptedProperties)
3432
.NumberOfBytes(0, 1.Mebibytes());

Modules/Files/src/Files.Application/Files/Commands/CreateFile/CreateFileResponse.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,24 @@ namespace Backbone.Modules.Files.Application.Files.Commands.CreateFile;
88

99
public class CreateFileResponse : IHaveCustomMapping
1010
{
11-
public FileId Id { get; set; }
11+
public required FileId Id { get; set; }
1212

13-
public DateTime CreatedAt { get; set; }
14-
public IdentityAddress CreatedBy { get; set; }
15-
public DeviceId CreatedByDevice { get; set; }
13+
public required DateTime CreatedAt { get; set; }
14+
public required IdentityAddress CreatedBy { get; set; }
15+
public required DeviceId CreatedByDevice { get; set; }
1616

17-
public DateTime ModifiedAt { get; set; }
18-
public IdentityAddress ModifiedBy { get; set; }
17+
public required DateTime ModifiedAt { get; set; }
18+
public required IdentityAddress ModifiedBy { get; set; }
1919
public DateTime? DeletedAt { get; set; }
20-
public IdentityAddress DeletedBy { get; set; }
20+
public IdentityAddress? DeletedBy { get; set; }
2121

22-
public IdentityAddress Owner { get; set; }
23-
public byte[] OwnerSignature { get; set; }
22+
public required IdentityAddress Owner { get; set; }
23+
public required byte[] OwnerSignature { get; set; }
2424

25-
public long CipherSize { get; set; }
26-
public byte[] CipherHash { get; set; }
25+
public required long CipherSize { get; set; }
26+
public required byte[] CipherHash { get; set; }
2727

28-
public DateTime ExpiresAt { get; set; }
28+
public required DateTime ExpiresAt { get; set; }
2929

3030
public void CreateMappings(Profile configuration)
3131
{

Modules/Files/src/Files.Application/Files/Commands/CreateFile/Handler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public async Task<CreateFileResponse> Handle(CreateFileCommand request, Cancella
2929
_userContext.GetAddress(),
3030
_userContext.GetDeviceId(),
3131
request.Owner,
32-
request.OwnerSignature ?? Array.Empty<byte>(),
32+
request.OwnerSignature,
3333
request.CipherHash,
3434
request.FileContent,
3535
request.FileContent.LongLength,

Modules/Files/src/Files.ConsumerApi/Controllers/FilesController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public async Task<IActionResult> UploadFile([FromForm] CreateFileDTO dto, Cancel
4949
ExpiresAt = dto.ExpiresAt,
5050
CipherHash = UrlBase64.Decode(dto.CipherHash),
5151
Owner = dto.Owner,
52-
OwnerSignature = dto.OwnerSignature == null ? null : UrlBase64.Decode(dto.OwnerSignature),
52+
OwnerSignature = UrlBase64.Decode(dto.OwnerSignature),
5353
EncryptedProperties = UrlBase64.Decode(dto.EncryptedProperties)
5454
};
5555

Modules/Files/src/Files.ConsumerApi/DTOs/CreateFileDTO.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ namespace Backbone.Modules.Files.ConsumerApi.DTOs;
55

66
public class CreateFileDTO
77
{
8-
public IFormFile Content { get; set; }
9-
public IdentityAddress? Owner { get; set; }
10-
public string? OwnerSignature { get; set; }
8+
public required IFormFile Content { get; set; }
9+
public required IdentityAddress Owner { get; set; }
10+
public required string OwnerSignature { get; set; }
1111

12-
public string CipherHash { get; set; }
12+
public required string CipherHash { get; set; }
1313

14-
public DateTime ExpiresAt { get; set; }
14+
public required DateTime ExpiresAt { get; set; }
1515

16-
public string EncryptedProperties { get; set; }
16+
public required string EncryptedProperties { get; set; }
1717
}

Modules/Files/src/Files.Domain/Entities/File.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public File(IdentityAddress createdBy, DeviceId createdByDevice, IdentityAddress
4545
public IdentityAddress? DeletedBy { get; set; }
4646
public DeviceId? DeletedByDevice { get; set; }
4747

48-
public IdentityAddress? Owner { get; set; }
48+
public IdentityAddress Owner { get; set; }
4949
public byte[] OwnerSignature { get; set; }
5050

5151
public long CipherSize { get; set; }

Modules/Files/src/Files.Infrastructure.Database.Postgres/Migrations/20240124085123_SetOwnerRequiredWithDefaultValue.Designer.cs

Lines changed: 119 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using Microsoft.EntityFrameworkCore.Migrations;
2+
3+
#nullable disable
4+
5+
namespace Backbone.Modules.Files.Infrastructure.Database.Postgres.Migrations
6+
{
7+
/// <inheritdoc />
8+
public partial class SetOwnerRequiredWithDefaultValue : Migration
9+
{
10+
/// <inheritdoc />
11+
protected override void Up(MigrationBuilder migrationBuilder)
12+
{
13+
migrationBuilder.AlterColumn<string>(
14+
name: "Owner",
15+
table: "FileMetadata",
16+
type: "character(36)",
17+
unicode: false,
18+
fixedLength: true,
19+
maxLength: 36,
20+
nullable: false,
21+
defaultValue: "",
22+
oldClrType: typeof(string),
23+
oldType: "character(36)",
24+
oldUnicode: false,
25+
oldFixedLength: true,
26+
oldMaxLength: 36,
27+
oldNullable: true);
28+
}
29+
30+
/// <inheritdoc />
31+
protected override void Down(MigrationBuilder migrationBuilder)
32+
{
33+
migrationBuilder.AlterColumn<string>(
34+
name: "Owner",
35+
table: "FileMetadata",
36+
type: "character(36)",
37+
unicode: false,
38+
fixedLength: true,
39+
maxLength: 36,
40+
nullable: true,
41+
oldClrType: typeof(string),
42+
oldType: "character(36)",
43+
oldUnicode: false,
44+
oldFixedLength: true,
45+
oldMaxLength: 36);
46+
}
47+
}
48+
}

Modules/Files/src/Files.Infrastructure.Database.Postgres/Migrations/FilesDbContextModelSnapshot.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
1717
{
1818
#pragma warning disable 612, 618
1919
modelBuilder
20-
.HasAnnotation("ProductVersion", "7.0.5")
20+
.HasAnnotation("ProductVersion", "8.0.0")
2121
.HasAnnotation("Relational:MaxIdentifierLength", 63);
2222

2323
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
@@ -94,6 +94,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
9494
.IsFixedLength();
9595

9696
b.Property<string>("Owner")
97+
.IsRequired()
9798
.HasMaxLength(36)
9899
.IsUnicode(false)
99100
.HasColumnType("character(36)")

0 commit comments

Comments
 (0)