91 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			91 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System.ComponentModel.DataAnnotations;
 | |
| using DysonNetwork.Shared.Models;
 | |
| using Microsoft.AspNetCore.Authorization;
 | |
| using Microsoft.AspNetCore.Mvc;
 | |
| using Microsoft.EntityFrameworkCore;
 | |
| using NodaTime;
 | |
| 
 | |
| namespace DysonNetwork.Pass.Auth;
 | |
| 
 | |
| [ApiController]
 | |
| [Route("/api/auth/keys")]
 | |
| public class ApiKeyController(AppDatabase db, AuthService auth) : ControllerBase
 | |
| {
 | |
|     [HttpGet]
 | |
|     [Authorize]
 | |
|     public async Task<IActionResult> GetKeys([FromQuery] int offset = 0, [FromQuery] int take = 20)
 | |
|     {
 | |
|         if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
 | |
| 
 | |
|         var query = db.ApiKeys
 | |
|             .Where(e => e.AccountId == currentUser.Id)
 | |
|             .AsQueryable();
 | |
| 
 | |
|         var totalCount = await query.CountAsync();
 | |
|         Response.Headers["X-Total"] = totalCount.ToString();
 | |
| 
 | |
|         var keys = await query
 | |
|             .Skip(offset)
 | |
|             .Take(take)
 | |
|             .ToListAsync();
 | |
|         return Ok(keys);
 | |
|     }
 | |
| 
 | |
|     [HttpGet("{id:guid}")]
 | |
|     [Authorize]
 | |
|     public async Task<IActionResult> GetKey(Guid id)
 | |
|     {
 | |
|         if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
 | |
| 
 | |
|         var key = await db.ApiKeys
 | |
|             .Where(e => e.AccountId == currentUser.Id)
 | |
|             .Where(e => e.Id == id)
 | |
|             .FirstOrDefaultAsync();
 | |
|         if (key == null) return NotFound();
 | |
|         return Ok(key);
 | |
|     }
 | |
| 
 | |
|     public class ApiKeyRequest
 | |
|     {
 | |
|         [MaxLength(1024)] public string? Label { get; set; }
 | |
|         public Instant? ExpiredAt { get; set; }
 | |
|     }
 | |
| 
 | |
|     [HttpPost]
 | |
|     [Authorize]
 | |
|     public async Task<IActionResult> CreateKey([FromBody] ApiKeyRequest request)
 | |
|     {
 | |
|         if (string.IsNullOrWhiteSpace(request.Label))
 | |
|             return BadRequest("Label is required");
 | |
|         if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
 | |
| 
 | |
|         var key = await auth.CreateApiKey(currentUser.Id, request.Label, request.ExpiredAt);
 | |
|         key.Key = await auth.IssueApiKeyToken(key);
 | |
|         return Ok(key);
 | |
|     }
 | |
| 
 | |
|     [HttpPost("{id:guid}/rotate")]
 | |
|     [Authorize]
 | |
|     public async Task<IActionResult> RotateKey(Guid id)
 | |
|     {
 | |
|         if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
 | |
|         
 | |
|         var key = await auth.GetApiKey(id, currentUser.Id);
 | |
|         if(key is null) return NotFound();
 | |
|         key = await auth.RotateApiKeyToken(key);
 | |
|         key.Key = await auth.IssueApiKeyToken(key);
 | |
|         return Ok(key);
 | |
|     }
 | |
| 
 | |
|     [HttpDelete("{id:guid}")]
 | |
|     [Authorize]
 | |
|     public async Task<IActionResult> DeleteKey(Guid id)
 | |
|     {
 | |
|         if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized();
 | |
|         
 | |
|         var key = await auth.GetApiKey(id, currentUser.Id);
 | |
|         if(key is null) return NotFound();
 | |
|         await auth.RevokeApiKeyToken(key);
 | |
|         return NoContent();
 | |
|     }
 | |
| } |