aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Timeline.Tests/Controllers/TokenControllerTest.cs21
-rw-r--r--Timeline.Tests/Timeline.Tests.csproj49
-rw-r--r--Timeline/Controllers/TokenController.cs6
-rw-r--r--Timeline/Entities/DatabaseContext.cs10
-rw-r--r--Timeline/Entities/UserAvatar.cs6
-rw-r--r--Timeline/Entities/UserDetail.cs10
-rw-r--r--Timeline/Helpers/InvalidModelResponseFactory.cs1
-rw-r--r--Timeline/Helpers/Log.cs2
-rw-r--r--Timeline/Models/Http/Common.cs4
-rw-r--r--Timeline/Models/Http/Token.cs12
-rw-r--r--Timeline/Models/Http/User.cs12
-rw-r--r--Timeline/Models/UserDetail.cs12
-rw-r--r--Timeline/Services/JwtService.cs8
-rw-r--r--Timeline/Startup.cs2
-rw-r--r--Timeline/Timeline.csproj7
15 files changed, 99 insertions, 63 deletions
diff --git a/Timeline.Tests/Controllers/TokenControllerTest.cs b/Timeline.Tests/Controllers/TokenControllerTest.cs
index 60ba75dc..8b1cf071 100644
--- a/Timeline.Tests/Controllers/TokenControllerTest.cs
+++ b/Timeline.Tests/Controllers/TokenControllerTest.cs
@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using System;
+using System.Collections.Generic;
using System.Threading.Tasks;
using Timeline.Controllers;
using Timeline.Models.Http;
@@ -90,6 +91,26 @@ namespace Timeline.Tests.Controllers
.Which.User.Should().BeEquivalentTo(MockUser.User.Info);
}
+ public static IEnumerable<object[]> Verify_BadRequest_Data()
+ {
+ yield return new object[] { new JwtTokenVerifyException(JwtTokenVerifyException.ErrorCodes.Expired), Verify.Expired };
+ yield return new object[] { new JwtTokenVerifyException(JwtTokenVerifyException.ErrorCodes.IdClaimBadFormat), Verify.BadFormat };
+ yield return new object[] { new BadTokenVersionException(), Verify.OldVersion };
+ yield return new object[] { new UserNotExistException(), Verify.UserNotExist };
+ }
+
+ [Theory]
+ [MemberData(nameof(Verify_BadRequest_Data))]
+ public async Task Verify_BadRequest(Exception e, int code)
+ {
+ const string token = "aaaaaaaaaaaaaa";
+ _mockUserService.Setup(s => s.VerifyToken(token)).ThrowsAsync(e);
+ var action = await _controller.Verify(new VerifyTokenRequest { Token = token });
+ action.Should().BeAssignableTo<BadRequestObjectResult>()
+ .Which.Value.Should().BeAssignableTo<CommonResponse>()
+ .Which.Code.Should().Be(code);
+ }
+
// TODO! Verify unit tests
}
}
diff --git a/Timeline.Tests/Timeline.Tests.csproj b/Timeline.Tests/Timeline.Tests.csproj
index 36bc03bc..3f88f174 100644
--- a/Timeline.Tests/Timeline.Tests.csproj
+++ b/Timeline.Tests/Timeline.Tests.csproj
@@ -1,28 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
- <PropertyGroup>
- <TargetFramework>netcoreapp3.0</TargetFramework>
- </PropertyGroup>
+ <PropertyGroup>
+ <TargetFramework>netcoreapp3.0</TargetFramework>
- <ItemGroup>
- <PackageReference Include="coverlet.collector" Version="1.1.0">
- <PrivateAssets>all</PrivateAssets>
- <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
- </PackageReference>
- <PackageReference Include="FluentAssertions" Version="5.9.0" />
- <PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
- <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.0.0" />
- <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.0.0" />
- <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
- <PackageReference Include="Moq" Version="4.13.0" />
- <PackageReference Include="xunit" Version="2.4.1" />
- <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
- <PrivateAssets>all</PrivateAssets>
- <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
- </PackageReference>
- </ItemGroup>
+ <LangVersion>8.0</LangVersion>
+ <Nullable>enable</Nullable>
+ </PropertyGroup>
- <ItemGroup>
- <ProjectReference Include="..\Timeline\Timeline.csproj" />
- </ItemGroup>
+ <ItemGroup>
+ <PackageReference Include="coverlet.collector" Version="1.1.0">
+ <PrivateAssets>all</PrivateAssets>
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+ </PackageReference>
+ <PackageReference Include="FluentAssertions" Version="5.9.0" />
+ <PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
+ <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.0.0" />
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.0.0" />
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" />
+ <PackageReference Include="Moq" Version="4.13.0" />
+ <PackageReference Include="xunit" Version="2.4.1" />
+ <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
+ <PrivateAssets>all</PrivateAssets>
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
+ </PackageReference>
+ </ItemGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\Timeline\Timeline.csproj" />
+ </ItemGroup>
</Project>
diff --git a/Timeline/Controllers/TokenController.cs b/Timeline/Controllers/TokenController.cs
index 2e661695..ce5786ca 100644
--- a/Timeline/Controllers/TokenController.cs
+++ b/Timeline/Controllers/TokenController.cs
@@ -54,7 +54,7 @@ namespace Timeline.Controllers
[AllowAnonymous]
public async Task<IActionResult> Create([FromBody] CreateTokenRequest request)
{
- void LogFailure(string reason, Exception e = null)
+ void LogFailure(string reason, Exception? e = null)
{
_logger.LogInformation(e, Log.Format("Attemp to login failed.",
("Reason", reason),
@@ -100,7 +100,7 @@ namespace Timeline.Controllers
[AllowAnonymous]
public async Task<IActionResult> Verify([FromBody] VerifyTokenRequest request)
{
- void LogFailure(string reason, Exception e = null, params (string, object)[] otherProperties)
+ void LogFailure(string reason, Exception? e = null, params (string, object?)[] otherProperties)
{
var properties = new (string, object)[2 + otherProperties.Length];
properties[0] = ("Reason", reason);
@@ -125,7 +125,7 @@ namespace Timeline.Controllers
{
const string message = "Token is expired.";
var innerException = e.InnerException as SecurityTokenExpiredException;
- LogFailure(message, e, ("Expires", innerException.Expires), ("Current Time", _clock.GetCurrentTime()));
+ LogFailure(message, e, ("Expires", innerException?.Expires), ("Current Time", _clock.GetCurrentTime()));
return BadRequest(new CommonResponse(ErrorCodes.Http.Token.Verify.Expired, message));
}
else
diff --git a/Timeline/Entities/DatabaseContext.cs b/Timeline/Entities/DatabaseContext.cs
index d9815660..550db216 100644
--- a/Timeline/Entities/DatabaseContext.cs
+++ b/Timeline/Entities/DatabaseContext.cs
@@ -17,20 +17,20 @@ namespace Timeline.Entities
public long Id { get; set; }
[Column("name"), MaxLength(26), Required]
- public string Name { get; set; }
+ public string Name { get; set; } = default!;
[Column("password"), Required]
- public string EncryptedPassword { get; set; }
+ public string EncryptedPassword { get; set; } = default!;
[Column("roles"), Required]
- public string RoleString { get; set; }
+ public string RoleString { get; set; } = default!;
[Column("version"), Required]
public long Version { get; set; }
- public UserAvatar Avatar { get; set; }
+ public UserAvatar? Avatar { get; set; }
- public UserDetailEntity Detail { get; set; }
+ public UserDetailEntity? Detail { get; set; }
}
public class DatabaseContext : DbContext
diff --git a/Timeline/Entities/UserAvatar.cs b/Timeline/Entities/UserAvatar.cs
index d549aea5..d47bb28b 100644
--- a/Timeline/Entities/UserAvatar.cs
+++ b/Timeline/Entities/UserAvatar.cs
@@ -11,13 +11,13 @@ namespace Timeline.Entities
public long Id { get; set; }
[Column("data")]
- public byte[] Data { get; set; }
+ public byte[]? Data { get; set; }
[Column("type")]
- public string Type { get; set; }
+ public string? Type { get; set; }
[Column("etag"), MaxLength(30)]
- public string ETag { get; set; }
+ public string? ETag { get; set; }
[Column("last_modified"), Required]
public DateTime LastModified { get; set; }
diff --git a/Timeline/Entities/UserDetail.cs b/Timeline/Entities/UserDetail.cs
index bc14dbe6..e02d15c4 100644
--- a/Timeline/Entities/UserDetail.cs
+++ b/Timeline/Entities/UserDetail.cs
@@ -10,19 +10,19 @@ namespace Timeline.Entities
public long Id { get; set; }
[Column("nickname"), MaxLength(15)]
- public string Nickname { get; set; }
+ public string? Nickname { get; set; }
[Column("qq"), MaxLength(15)]
- public string QQ { get; set; }
+ public string? QQ { get; set; }
[Column("email"), MaxLength(50)]
- public string Email { get; set; }
+ public string? Email { get; set; }
[Column("phone_number"), MaxLength(15)]
- public string PhoneNumber { get; set; }
+ public string? PhoneNumber { get; set; }
[Column("description")]
- public string Description { get; set; }
+ public string? Description { get; set; }
public long UserId { get; set; }
}
diff --git a/Timeline/Helpers/InvalidModelResponseFactory.cs b/Timeline/Helpers/InvalidModelResponseFactory.cs
index c792e845..643c99ac 100644
--- a/Timeline/Helpers/InvalidModelResponseFactory.cs
+++ b/Timeline/Helpers/InvalidModelResponseFactory.cs
@@ -6,6 +6,7 @@ namespace Timeline.Helpers
{
public static class InvalidModelResponseFactory
{
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods")]
public static IActionResult Factory(ActionContext context)
{
var modelState = context.ModelState;
diff --git a/Timeline/Helpers/Log.cs b/Timeline/Helpers/Log.cs
index 64391cd1..8deebf1d 100644
--- a/Timeline/Helpers/Log.cs
+++ b/Timeline/Helpers/Log.cs
@@ -25,7 +25,7 @@ namespace Timeline.Helpers
public static class Log
{
- public static string Format(string summary, params (string, object)[] properties)
+ public static string Format(string summary, params (string, object?)[] properties)
{
var builder = new StringBuilder();
builder.Append(summary);
diff --git a/Timeline/Models/Http/Common.cs b/Timeline/Models/Http/Common.cs
index 83e6a072..6f6dbc1e 100644
--- a/Timeline/Models/Http/Common.cs
+++ b/Timeline/Models/Http/Common.cs
@@ -38,8 +38,8 @@ namespace Timeline.Models.Http
Message = message;
}
- public int? Code { get; set; }
- public string Message { get; set; }
+ public int Code { get; set; }
+ public string? Message { get; set; }
}
public class CommonDataResponse<T> : CommonResponse
diff --git a/Timeline/Models/Http/Token.cs b/Timeline/Models/Http/Token.cs
index 615b6d8a..ea8b59ed 100644
--- a/Timeline/Models/Http/Token.cs
+++ b/Timeline/Models/Http/Token.cs
@@ -5,9 +5,9 @@ namespace Timeline.Models.Http
public class CreateTokenRequest
{
[Required]
- public string Username { get; set; }
+ public string Username { get; set; } = default!;
[Required]
- public string Password { get; set; }
+ public string Password { get; set; } = default!;
// in days, optional
[Range(1, 365)]
public int? Expire { get; set; }
@@ -15,18 +15,18 @@ namespace Timeline.Models.Http
public class CreateTokenResponse
{
- public string Token { get; set; }
- public UserInfo User { get; set; }
+ public string Token { get; set; } = default!;
+ public UserInfo User { get; set; } = default!;
}
public class VerifyTokenRequest
{
[Required]
- public string Token { get; set; }
+ public string Token { get; set; } = default!;
}
public class VerifyTokenResponse
{
- public UserInfo User { get; set; }
+ public UserInfo User { get; set; } = default!;
}
}
diff --git a/Timeline/Models/Http/User.cs b/Timeline/Models/Http/User.cs
index 4308a19c..98406fec 100644
--- a/Timeline/Models/Http/User.cs
+++ b/Timeline/Models/Http/User.cs
@@ -6,31 +6,31 @@ namespace Timeline.Models.Http
public class UserPutRequest
{
[Required]
- public string Password { get; set; }
+ public string Password { get; set; } = default!;
[Required]
public bool? Administrator { get; set; }
}
public class UserPatchRequest
{
- public string Password { get; set; }
+ public string? Password { get; set; }
public bool? Administrator { get; set; }
}
public class ChangeUsernameRequest
{
[Required]
- public string OldUsername { get; set; }
+ public string OldUsername { get; set; } = default!;
[Required, ValidateWith(typeof(UsernameValidator))]
- public string NewUsername { get; set; }
+ public string NewUsername { get; set; } = default!;
}
public class ChangePasswordRequest
{
[Required]
- public string OldPassword { get; set; }
+ public string OldPassword { get; set; } = default!;
[Required]
- public string NewPassword { get; set; }
+ public string NewPassword { get; set; } = default!;
}
}
diff --git a/Timeline/Models/UserDetail.cs b/Timeline/Models/UserDetail.cs
index 1a6c0c6a..302e3bb1 100644
--- a/Timeline/Models/UserDetail.cs
+++ b/Timeline/Models/UserDetail.cs
@@ -8,21 +8,21 @@ namespace Timeline.Models
public class UserDetail
{
[MaxLength(10)]
- public string Nickname { get; set; }
+ public string? Nickname { get; set; }
[ValidateWith(typeof(UserDetailValidators.QQValidator))]
[JsonProperty(PropertyName = "qq")]
- public string QQ { get; set; }
+ public string? QQ { get; set; }
[ValidateWith(typeof(UserDetailValidators.EMailValidator))]
- public string Email { get; set; }
+ public string? Email { get; set; }
[ValidateWith(typeof(UserDetailValidators.PhoneNumberValidator))]
- public string PhoneNumber { get; set; }
+ public string? PhoneNumber { get; set; }
- public string Description { get; set; }
+ public string? Description { get; set; }
- private static string CoerceEmptyToNull(string value)
+ private static string? CoerceEmptyToNull(string? value)
{
if (string.IsNullOrEmpty(value))
return null;
diff --git a/Timeline/Services/JwtService.cs b/Timeline/Services/JwtService.cs
index 350c5e80..90d0c217 100644
--- a/Timeline/Services/JwtService.cs
+++ b/Timeline/Services/JwtService.cs
@@ -33,6 +33,12 @@ namespace Timeline.Services
public const int Expired = -2001;
}
+ private const string message = "Jwt token is bad.";
+
+ public JwtTokenVerifyException() : base(message) { }
+ public JwtTokenVerifyException(string message) : base(message) { }
+ public JwtTokenVerifyException(string message, Exception inner) : base(message, inner) { }
+
public JwtTokenVerifyException(int code) : base(GetErrorMessage(code)) { ErrorCode = code; }
public JwtTokenVerifyException(string message, int code) : base(message) { ErrorCode = code; }
public JwtTokenVerifyException(Exception inner, int code) : base(GetErrorMessage(code), inner) { ErrorCode = code; }
@@ -41,7 +47,7 @@ namespace Timeline.Services
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
- public int ErrorCode { get; private set; }
+ public int ErrorCode { get; set; }
private static string GetErrorMessage(int errorCode)
{
diff --git a/Timeline/Startup.cs b/Timeline/Startup.cs
index fc570fdd..ddbe0840 100644
--- a/Timeline/Startup.cs
+++ b/Timeline/Startup.cs
@@ -13,6 +13,7 @@ using Timeline.Services;
namespace Timeline
{
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1822:Mark members as static")]
public class Startup
{
public Startup(IConfiguration configuration, IWebHostEnvironment environment)
@@ -69,6 +70,7 @@ namespace Timeline
services.AddMemoryCache();
}
+
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app)
{
diff --git a/Timeline/Timeline.csproj b/Timeline/Timeline.csproj
index 836dfb47..c634563a 100644
--- a/Timeline/Timeline.csproj
+++ b/Timeline/Timeline.csproj
@@ -4,6 +4,9 @@
<IsPackable>false</IsPackable>
<UserSecretsId>1f6fb74d-4277-4bc0-aeea-b1fc5ffb0b43</UserSecretsId>
<Authors>crupest</Authors>
+
+ <LangVersion>8.0</LangVersion>
+ <Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
@@ -15,8 +18,8 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.6">
- <PrivateAssets>all</PrivateAssets>
- <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+ <PrivateAssets>all</PrivateAssets>
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.0.0-rc1.final" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql.Design" Version="1.1.2" />