Add project files

This commit is contained in:
Sean Greenawalt 2025-05-10 05:16:40 -04:00
commit 8cf01ead74
Signed by: seang96
GPG key ID: 504F02B511005571
40 changed files with 3967 additions and 0 deletions

View file

@ -0,0 +1,109 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using StalwartSimpleLoginMiddleware.Contexts;
using StalwartSimpleLoginMiddleware.Entities;
using StalwartSimpleLoginMiddleware.Models;
using StalwartSimpleLoginMiddleware.Utilities;
namespace StalwartSimpleLoginMiddleware.Controllers;
[ApiController]
[Authorize(Roles = "Admin")]
[Route("api/[controller]/[action]")]
public class AdminController : ControllerBase
{
private readonly ApiKeyContext context;
public AdminController(ApiKeyContext context)
{
this.context = context;
}
[HttpGet]
public async Task<ApiKey[]> ListApiKeys([FromQuery] int page = 0, [FromQuery] int limit = 100)
{
return await context.ApiKeys
.Include(apiKey => apiKey.Members)
.Skip(page * limit)
.Take(limit).ToArrayAsync();
}
[HttpGet]
public async Task<ApiKey> GetApiKey([FromQuery] string key)
{
var apiKey = await context.ApiKeys
.Include(apiKey => apiKey.Members)
.Select(apiKey => new ApiKey
{
Key = apiKey.Key,
OwnerEmail = apiKey.OwnerEmail,
IsAdmin = apiKey.IsAdmin,
Members = apiKey.Members.ToArray()
})
.FirstOrDefaultAsync(apiKey => apiKey.Key == key);
if (apiKey == null) throw new BadHttpRequestException("API Key is invalid.");
return apiKey;
}
[HttpPost]
public async Task<ActionResult> UpdateApiKeyOwnerEmail([FromBody] UpdateOwnerEmailInput input)
{
var rows = await context.ApiKeys.Where(apiKey => apiKey.Key == input.ApiKey)
.ExecuteUpdateAsync(apiKey => apiKey.SetProperty(p => p.OwnerEmail, input.OwnerEmail));
if (rows == 0) return NotFound();
return Ok();
}
[HttpPost]
public async Task<ActionResult> CreateApiKey([FromBody] ApiKeyInput newApiKeyInput)
{
if (string.IsNullOrEmpty(ApiKeyHelper.GetEmailDomain(newApiKeyInput.OwnerEmail)))
return BadRequest("Owner Email must be a valid email address.");
var apiKey = new ApiKey
{
Key = ApiKeyHelper.GenerateKey(),
OwnerEmail = newApiKeyInput.OwnerEmail,
IsAdmin = newApiKeyInput.IsAdmin,
Members = newApiKeyInput.Members.Select(m => new Member { Email = m.Email, IsExternal = m.IsExternal })
.ToArray()
};
context.ApiKeys.Add(apiKey);
await context.SaveChangesAsync();
return CreatedAtAction(nameof(GetApiKey), new { key = apiKey.Key }, apiKey);
}
[HttpPost]
public async Task<ActionResult> CreateApiKeyMember([FromBody] AddApiKeyMemberInput input)
{
var member = new Member
{
ApiKeyId = input.ApiKey,
Email = input.Member.Email,
IsExternal = input.Member.IsExternal
};
context.Members.Add(member);
await context.SaveChangesAsync();
return CreatedAtAction(nameof(GetApiKey), new { key = input.ApiKey });
}
[HttpDelete]
public async Task<ActionResult> DeleteApiKey([FromQuery] string key)
{
var rows = await context.ApiKeys.Where(apiKey => apiKey.Key == key)
.ExecuteDeleteAsync();
if (rows == 0) return NotFound();
return Ok();
}
[HttpDelete]
public async Task<ActionResult> DeleteApiKeyMemberEmail([FromQuery] string key, [FromQuery] string email)
{
var rows = await context.Members.Where(member => member.ApiKeyId == key)
.Where(member => member.Email == email)
.ExecuteDeleteAsync();
if (rows == 0) return NotFound();
return Ok();
}
}

View file

@ -0,0 +1,56 @@
using AdOrbitSDK;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using StalwartSimpleLoginMiddleware.Models;
using StalwartSimpleLoginMiddleware.Services;
namespace StalwartSimpleLoginMiddleware.Controllers;
[ApiController]
[Authorize]
[Route("api/[controller]")]
public class AliasController(StalwartClient stalwartClient) : ControllerBase
{
[Route("random/new")]
[HttpPost]
public async Task<IActionResult> NewRandomAlias([FromQuery] string? hostname,
[FromQuery] string? mode,
[FromBody] NewRandomAliasInput body)
{
var apiKeyAccessor = HttpContext.RequestServices.GetRequiredService<IApiKeyAccessor>();
var randomAlias = Get8CharacterRandomString();
var client = await stalwartClient.GetClient();
var requestBody = new Body2
{
Type = "list",
Name = randomAlias,
Description = body.Note,
Emails = new List<object> { $"{randomAlias}@{apiKeyAccessor.Metadata.Domain}" },
Members = apiKeyAccessor.Metadata.Members as ICollection<object>,
ExternalMembers = apiKeyAccessor.Metadata.ExternalMembers as ICollection<object>
};
await client.PrincipalPOSTAsync(requestBody);
return Created(null as string, new NewRandomAliasOutput
{
CreationDate = DateTime.Today.Date,
CreationTimestamp = DateTime.Now.Ticks,
Email = requestBody.Emails?.OfType<string>().FirstOrDefault() ?? string.Empty,
Alias = requestBody.Emails?.OfType<string>().FirstOrDefault() ?? string.Empty,
Name = requestBody.Name ?? string.Empty,
Enabled = true,
Id = new Random().Next(),
Mailbox = new Mailbox { Id = new Random().Next(), Email = apiKeyAccessor.Metadata.Members.First() },
Mailboxes = apiKeyAccessor.Metadata.Members.Concat(apiKeyAccessor.Metadata.ExternalMembers)
.Select(email => new Mailbox { Id = new Random().Next(), Email = email.ToString() }),
Note = body.Note ?? string.Empty,
});
}
private static string Get8CharacterRandomString()
{
var path = Path.GetRandomFileName();
path = path.Replace(".", ""); // Remove period
return path.Substring(0, 8); // Return 8 character string
}
}