using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.RateLimiting; using Nuuru.Server.Services; namespace Nuuru.Server.Controllers { [ApiController] [Route("api/captcha")] [AllowAnonymous] public class CaptchaController : ControllerBase { private readonly ISiteSettingsService _siteSettings; private readonly IBuiltInCaptchaService _builtIn; public CaptchaController( ISiteSettingsService siteSettings, IBuiltInCaptchaService builtIn) { _siteSettings = siteSettings; _builtIn = builtIn; } [HttpGet("challenge")] [EnableRateLimiting("captcha")] public async Task GetChallenge() { var provider = await _siteSettings.GetCaptchaProviderAsync(); if (provider == "builtin") { var challenge = await _builtIn.GenerateChallengeAsync(); return Ok(new { guid = challenge.Guid, image = challenge.Base64Image }); } return BadRequest(new { error = "No challenge-based captcha provider is active." }); } [HttpPost("verify")] [EnableRateLimiting("captcha")] public async Task Verify([FromBody] CaptchaVerifyRequest request) { var provider = await _siteSettings.GetCaptchaProviderAsync(); if (provider == "builtin") { if (string.IsNullOrWhiteSpace(request.Answer)) return BadRequest(new { error = "Answer is required for this captcha type." }); var token = _builtIn.VerifyAnswer(request.Guid, request.Answer); return token != null ? Ok(new { success = true, token }) : Ok(new { success = false, token = (string?)null }); } return BadRequest(new { error = "No challenge-based captcha provider is active." }); } } public class CaptchaVerifyRequest { public string Guid { get; set; } = string.Empty; public string? Answer { get; set; } } }