feat(release): prepare 1.1.0 candidate

This commit is contained in:
Yun Chan 2026-08-29 18:33:45 +09:00
parent 5a34f66981
commit 5205dcdfa9
736 changed files with 115667 additions and 12203 deletions

View file

@ -1,10 +1,14 @@
using System;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
using D3ROVoice.Api.Dtos;
using D3ROVoice.Api.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;
namespace D3ROVoice.Api.Controllers;
@ -13,18 +17,45 @@ namespace D3ROVoice.Api.Controllers;
public class AuthController : ControllerBase
{
private readonly IAuthService _authService;
private readonly IConfiguration _configuration;
public AuthController(IAuthService authService)
public AuthController(IAuthService authService, IConfiguration configuration)
{
_authService = authService;
_configuration = configuration;
}
[HttpPost("register")]
public async Task<IActionResult> Register([FromBody] RegisterDto dto)
[EnableRateLimiting("auth")]
[RequestSizeLimit(16 * 1024)]
public async Task<IActionResult> Register(
[FromBody] RegisterDto dto,
[FromHeader(Name = "X-D3RO-Bootstrap-Token")] string? bootstrapToken)
{
if (string.IsNullOrWhiteSpace(dto.Email) || string.IsNullOrWhiteSpace(dto.Password))
var normalizedEmail = dto.Email?.Trim().ToLowerInvariant() ?? string.Empty;
if (
normalizedEmail.Length is < 3 or > 150
|| !MailAddress.TryCreate(normalizedEmail, out var parsedEmail)
|| !string.Equals(parsedEmail.Address, normalizedEmail, StringComparison.OrdinalIgnoreCase)
|| string.IsNullOrWhiteSpace(dto.Password)
)
{
return BadRequest(new { message = "이메일과 비밀번호를 입력해주세요." });
return BadRequest(new { message = "유효한 이메일과 비밀번호를 입력해주세요." });
}
var configuredToken = _configuration["ADMIN_BOOTSTRAP_TOKEN"];
if (
string.IsNullOrWhiteSpace(configuredToken)
|| Encoding.UTF8.GetByteCount(configuredToken) < 32
)
{
return StatusCode(503, new { message = "관리자 초기 등록이 비활성화되어 있습니다." });
}
var configuredDigest = SHA256.HashData(Encoding.UTF8.GetBytes(configuredToken));
var providedDigest = SHA256.HashData(Encoding.UTF8.GetBytes(bootstrapToken ?? string.Empty));
if (!CryptographicOperations.FixedTimeEquals(configuredDigest, providedDigest))
{
return Unauthorized(new { message = "관리자 초기 등록 토큰이 올바르지 않습니다." });
}
try
@ -39,9 +70,17 @@ public class AuthController : ControllerBase
}
[HttpPost("login")]
[EnableRateLimiting("auth")]
[RequestSizeLimit(16 * 1024)]
public async Task<IActionResult> Login([FromBody] LoginDto dto)
{
if (string.IsNullOrWhiteSpace(dto.Email) || string.IsNullOrWhiteSpace(dto.Password))
var normalizedEmail = dto.Email?.Trim().ToLowerInvariant() ?? string.Empty;
if (
normalizedEmail.Length is < 3 or > 150
|| !MailAddress.TryCreate(normalizedEmail, out _)
|| string.IsNullOrWhiteSpace(dto.Password)
|| dto.Password.Length > 256
)
{
return BadRequest(new { message = "이메일과 비밀번호를 입력해주세요." });
}