diff options
author | 杨宇千 <crupest@outlook.com> | 2019-08-19 00:01:09 +0800 |
---|---|---|
committer | 杨宇千 <crupest@outlook.com> | 2019-08-19 00:01:09 +0800 |
commit | ee113b27d276524f29560f00e944851bf5bdf6a8 (patch) | |
tree | b108cae68db2040b14d576d3813ab4711777fbad | |
parent | d0d75c3ca33c5e802132107c467be20212d64fb5 (diff) | |
download | timeline-ee113b27d276524f29560f00e944851bf5bdf6a8.tar.gz timeline-ee113b27d276524f29560f00e944851bf5bdf6a8.tar.bz2 timeline-ee113b27d276524f29560f00e944851bf5bdf6a8.zip |
Add validator.
-rw-r--r-- | Timeline.Tests/UserAvatarServiceTest.cs | 14 | ||||
-rw-r--r-- | Timeline/Services/UserAvatarService.cs | 44 | ||||
-rw-r--r-- | Timeline/Timeline.csproj | 1 | ||||
-rw-r--r-- | nuget.config | 7 |
4 files changed, 58 insertions, 8 deletions
diff --git a/Timeline.Tests/UserAvatarServiceTest.cs b/Timeline.Tests/UserAvatarServiceTest.cs index a8e0562b..d767958a 100644 --- a/Timeline.Tests/UserAvatarServiceTest.cs +++ b/Timeline.Tests/UserAvatarServiceTest.cs @@ -24,7 +24,15 @@ namespace Timeline.Tests }
}
- public class UserAvatarServiceTest : IDisposable, IClassFixture<MockDefaultUserAvatarProvider>
+ public class MockUserAvatarValidator : IUserAvatarValidator
+ {
+ public Task<(bool, string)> Validate(Avatar avatar)
+ {
+ return Task.FromResult((true, "Validate succeed."));
+ }
+ }
+
+ public class UserAvatarServiceTest : IDisposable, IClassFixture<MockDefaultUserAvatarProvider>, IClassFixture<MockUserAvatarValidator>
{
private static Avatar MockAvatar { get; } = new Avatar
{
@@ -45,14 +53,14 @@ namespace Timeline.Tests private readonly UserAvatarService _service;
- public UserAvatarServiceTest(ITestOutputHelper outputHelper, MockDefaultUserAvatarProvider mockDefaultUserAvatarProvider)
+ public UserAvatarServiceTest(ITestOutputHelper outputHelper, MockDefaultUserAvatarProvider mockDefaultUserAvatarProvider, MockUserAvatarValidator mockUserAvatarValidator)
{
_mockDefaultUserAvatarProvider = mockDefaultUserAvatarProvider;
_loggerFactory = MyTestLoggerFactory.Create(outputHelper);
_database = new TestDatabase();
- _service = new UserAvatarService(_loggerFactory.CreateLogger<UserAvatarService>(), _database.DatabaseContext, _mockDefaultUserAvatarProvider);
+ _service = new UserAvatarService(_loggerFactory.CreateLogger<UserAvatarService>(), _database.DatabaseContext, _mockDefaultUserAvatarProvider, mockUserAvatarValidator);
}
public void Dispose()
diff --git a/Timeline/Services/UserAvatarService.cs b/Timeline/Services/UserAvatarService.cs index 4f11978c..2a73cde5 100644 --- a/Timeline/Services/UserAvatarService.cs +++ b/Timeline/Services/UserAvatarService.cs @@ -2,6 +2,8 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.Formats;
using System;
using System.IO;
using System.Linq;
@@ -45,6 +47,11 @@ namespace Timeline.Services Task<Avatar> GetDefaultAvatar();
}
+ public interface IUserAvatarValidator
+ {
+ Task<(bool valid, string message)> Validate(Avatar avatar);
+ }
+
public interface IUserAvatarService
{
/// <summary>
@@ -87,6 +94,31 @@ namespace Timeline.Services }
}
+ public class UserAvatarValidator : IUserAvatarValidator
+ {
+ public Task<(bool valid, string message)> Validate(Avatar avatar)
+ {
+ return Task.Run(() =>
+ {
+ try
+ {
+ using (var image = Image.Load(avatar.Data, out IImageFormat format))
+ {
+ if (!format.MimeTypes.Contains(avatar.Type))
+ return (false, "Image's actual mime type is not the specified one.");
+ if (image.Width != image.Height)
+ return (false, "Image is not a square, aka width is not equal to height.");
+ }
+ return (true, "A good avatar.");
+ }
+ catch (UnknownImageFormatException e)
+ {
+ return (false, $"Failed to decode image. Exception: {e} .");
+ }
+ });
+ }
+ }
+
public class UserAvatarService : IUserAvatarService
{
@@ -95,12 +127,14 @@ namespace Timeline.Services private readonly DatabaseContext _database;
private readonly IDefaultUserAvatarProvider _defaultUserAvatarProvider;
+ private readonly IUserAvatarValidator _avatarValidator;
- public UserAvatarService(ILogger<UserAvatarService> logger, DatabaseContext database, IDefaultUserAvatarProvider defaultUserAvatarProvider)
+ public UserAvatarService(ILogger<UserAvatarService> logger, DatabaseContext database, IDefaultUserAvatarProvider defaultUserAvatarProvider, IUserAvatarValidator avatarValidator)
{
_logger = logger;
_database = database;
_defaultUserAvatarProvider = defaultUserAvatarProvider;
+ _avatarValidator = avatarValidator;
}
public async Task<Avatar> GetAvatar(string username)
@@ -157,11 +191,15 @@ namespace Timeline.Services {
_database.UserAvatars.Remove(avatarEntity);
await _database.SaveChangesAsync();
+ _logger.LogInformation("Removed an entry in user_avatars.");
}
}
else
{
- // TODO: Use image library to check the format to prohibit bad data.
+ (bool valid, string message) = await _avatarValidator.Validate(avatar);
+ if (!valid)
+ throw new AvatarDataException(avatar, $"Failed to validate image. {message}");
+
if (avatarEntity == null)
{
user.Avatar = new UserAvatar
@@ -176,6 +214,7 @@ namespace Timeline.Services avatarEntity.Data = avatar.Data;
}
await _database.SaveChangesAsync();
+ _logger.LogInformation("Added or modified an entry in user_avatars.");
}
}
}
@@ -186,6 +225,7 @@ namespace Timeline.Services {
services.AddScoped<IUserAvatarService, UserAvatarService>();
services.AddSingleton<IDefaultUserAvatarProvider, DefaultUserAvatarProvider>();
+ services.AddSingleton<IUserAvatarValidator, UserAvatarValidator>();
}
}
}
diff --git a/Timeline/Timeline.csproj b/Timeline/Timeline.csproj index 29ff3354..3855e0d1 100644 --- a/Timeline/Timeline.csproj +++ b/Timeline/Timeline.csproj @@ -12,5 +12,6 @@ <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.3" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.2.0" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql.Design" Version="1.1.2" />
+ <PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-dev002868" />
</ItemGroup>
</Project>
diff --git a/nuget.config b/nuget.config index 22519a86..e1fc7cfe 100644 --- a/nuget.config +++ b/nuget.config @@ -1,8 +1,9 @@ -<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
- <clear/>
- <add key="nuget.org" value="https://api.nuget.org/v3/index.json"/>
+ <clear />
+ <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="aspnetcore-dev" value="https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json" />
+ <add key="imagesharp-dev" value="https://www.myget.org/F/sixlabors/api/v3/index.json" />
</packageSources>
</configuration>
|