diff --git a/Application/MinimalAPI/APIMappings.cs b/Application/MinimalAPI/APIMappings.cs
new file mode 100644
index 0000000..fc12024
--- /dev/null
+++ b/Application/MinimalAPI/APIMappings.cs
@@ -0,0 +1,164 @@
+using AutoMapper;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.HttpResults;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Routing;
+using Microsoft.Extensions.Caching.Memory;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.IdentityModel.Tokens;
+using MikrotikAPI;
+using MTWireGuard.Application.Models;
+using MTWireGuard.Application.Models.Mikrotik;
+using MTWireGuard.Application.Repositories;
+using System;
+using System.Collections.Generic;
+using System.IdentityModel.Tokens.Jwt;
+using System.IO;
+using System.Linq;
+using System.Security.Claims;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace MTWireGuard.Application.MinimalAPI
+{
+ public static class APIMappings
+ {
+ public static RouteGroupBuilder MapGeneralApi(this RouteGroupBuilder group)
+ {
+ // Retreive updates from Mikrotik
+ group.MapPost(Endpoints.Usage, TrafficUsageUpdate);
+ // Map auth endpoints
+ group.MapGroup(Endpoints.Auth)
+ .MapAuthAPI();
+ // Map wireguard users endpoints
+ group.MapGroup(Endpoints.User)
+ .MapUserApi()
+ .RequireAuthorization();
+ // Map wireguard servers endpoints
+ group.MapGroup(Endpoints.Server)
+ .MapServerApi()
+ .RequireAuthorization();
+ // Map IP pool endpoints
+ group.MapGroup(Endpoints.IPPool)
+ .MapIPPoolsApi()
+ .RequireAuthorization();
+ // Map configuration endpoints
+ group.MapGroup(Endpoints.Configuration)
+ .MapConfigurationApi()
+ .RequireAuthorization();
+
+ return group;
+ }
+ private static RouteGroupBuilder MapAuthAPI(this RouteGroupBuilder group)
+ {
+ group.MapGet(Endpoints.Logout, AuthController.Logout);
+ group.MapPost(Endpoints.Login, AuthController.Login);
+ return group;
+ }
+ private static RouteGroupBuilder MapUserApi(this RouteGroupBuilder group)
+ {
+ group.MapGet("/", UserController.GetAll);
+ group.MapGet("/{id}", UserController.GetById);
+ group.MapGet($"{Endpoints.QR}/{{id}}", UserController.GetQR);
+ group.MapGet($"{Endpoints.File}/{{id}}", UserController.GetFile);
+ group.MapPost("/", UserController.Create);
+ group.MapPut("/{id}", UserController.Update);
+ group.MapPatch($"{Endpoints.Sync}/{{id}}", UserController.Sync);
+ group.MapPatch($"{Endpoints.Activation}/{{id}}", UserController.Activation);
+ group.MapDelete("/{id}", UserController.Delete);
+
+ return group;
+ }
+ private static RouteGroupBuilder MapServerApi(this RouteGroupBuilder group)
+ {
+ group.MapGet("/", ServerController.GetAll);
+ group.MapPost("/", ServerController.Create);
+ group.MapPut("/{id}", ServerController.Update);
+ group.MapDelete("/{id}", ServerController.Delete);
+ group.MapPatch($"{Endpoints.Activation}/{{id}}", ServerController.Activation);
+
+ return group;
+ }
+ private static RouteGroupBuilder MapIPPoolsApi(this RouteGroupBuilder group)
+ {
+ group.MapGet("/", IPPoolController.GetAll);
+ group.MapPost("/", IPPoolController.Create);
+ group.MapPut("/{id}", IPPoolController.Update);
+ group.MapDelete("/{id}", IPPoolController.Delete);
+
+ return group;
+ }
+ private static RouteGroupBuilder MapConfigurationApi(this RouteGroupBuilder group)
+ {
+ group.MapGet(Endpoints.Logs, async ([FromServices] IMikrotikRepository API) => await API.GetLogsAsync()).
+ RequireAuthorization();
+ group.MapGet(Endpoints.Resources, ConfigurationController.Resources).
+ RequireAuthorization();
+ group.MapGet(Endpoints.DNS, ConfigurationController.DNS)
+ .RequireAuthorization();
+ group.MapPut(Endpoints.DNS, ConfigurationController.DNSUpdate)
+ .RequireAuthorization();
+ group.MapGet(Endpoints.Identity, ConfigurationController.Identity)
+ .RequireAuthorization();
+ group.MapPut(Endpoints.Identity, ConfigurationController.IdentityUpdate)
+ .RequireAuthorization();
+ group.MapGet(Endpoints.Information, ConfigurationController.Information)
+ .RequireAuthorization();
+ return group;
+ }
+
+ ///
+ /// Retrieve and handle WG peer traffic usage
+ ///
+ public static async Task> TrafficUsageUpdate(
+ [FromServices] IMapper mapper,
+ [FromServices] DBContext dbContext,
+ [FromServices] IMikrotikRepository mikrotikRepository,
+ HttpContext context)
+ {
+
+ StreamReader reader = new(context.Request.Body);
+ string body = await reader.ReadToEndAsync();
+
+ var list = Helper.ParseTrafficUsage(body);
+ var updates = mapper.Map>(list);
+
+ if (updates == null || updates.Count < 1) return TypedResults.Problem("Empty data");
+
+ Helper.HandleUserTraffics(updates, dbContext, mikrotikRepository);
+
+ return TypedResults.Accepted("Done");
+ }
+ }
+
+ internal static class Endpoints
+ {
+ // Groups
+ public const string Auth = "/Auth";
+ public const string User = "/Users";
+ public const string Server = "/Servers";
+ public const string IPPool = "/IPPools";
+ public const string Configuration = "/Config";
+
+ // Endpoints
+ // Auth
+ public const string Login = "/Login";
+ public const string Logout = "/Logout";
+ // Users, Servers
+ public const string Activation = "/Activation";
+ public const string File = "/File";
+ public const string QR = "/QR";
+ public const string Sync = "/Sync";
+ // Configuration
+ public const string DNS = "/DNS";
+ public const string Identity = "/Identity";
+ public const string Logs = "/Logs";
+ public const string Resources = "/Resources";
+ public const string Information = "/Information";
+ // Retrival
+ public const string Usage = "/Usage";
+ }
+}
diff --git a/Application/MinimalAPI/AuthController.cs b/Application/MinimalAPI/AuthController.cs
new file mode 100644
index 0000000..41b80d3
--- /dev/null
+++ b/Application/MinimalAPI/AuthController.cs
@@ -0,0 +1,86 @@
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.HttpResults;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Caching.Memory;
+using MTWireGuard.Application.Models.Requests;
+using MTWireGuard.Application.Repositories;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MTWireGuard.Application.MinimalAPI
+{
+ internal class AuthController
+ {
+ public static async Task> Login([FromBody] LoginRequest login)
+ {
+ try
+ {
+ string MT_IP = Environment.GetEnvironmentVariable("MT_IP");
+ string MT_USER = Environment.GetEnvironmentVariable("MT_USER");
+ string MT_PASS = Environment.GetEnvironmentVariable("MT_PASS") ?? "";
+
+ if (login.Username == MT_USER && login.Password == MT_PASS)
+ {
+ HttpClientHandler handler = new()
+ {
+ ServerCertificateCustomValidationCallback = delegate { return true; }
+ };
+ using HttpClient httpClient = new(handler);
+ using var request = new HttpRequestMessage(new HttpMethod("GET"), $"https://{MT_IP}/rest/");
+ string base64authorization = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{MT_USER}:{MT_PASS}"));
+ request.Headers.TryAddWithoutValidation("Authorization", $"Basic {base64authorization}");
+
+ HttpResponseMessage response = await httpClient.SendAsync(request);
+ var resp = await response.Content.ReadAsStringAsync();
+
+ var claims = new List
+ {
+ new(ClaimTypes.Role, "Administrator"),
+ };
+
+ var claimsIdentity = new ClaimsIdentity(
+ claims, CookieAuthenticationDefaults.AuthenticationScheme);
+
+ var authProperties = new AuthenticationProperties
+ {
+ AllowRefresh = true,
+ IsPersistent = true
+ };
+
+ var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
+
+ return TypedResults.SignIn(claimsPrincipal, authProperties, CookieAuthenticationDefaults.AuthenticationScheme);
+ }
+ else
+ {
+ return TypedResults.Unauthorized();
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ return TypedResults.Problem(
+ detail: ex.Message,
+ type: ex.GetType().Name);
+ }
+ }
+
+ public static async Task Logout(
+ [FromServices] IMikrotikRepository API,
+ HttpContext context)
+ {
+ // Clear the existing external cookie
+ await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
+ var sessionId = await API.GetCurrentSessionID();
+ var kill = await API.KillJob(sessionId);
+ return TypedResults.SignOut();
+ }
+ }
+}
diff --git a/Application/MinimalAPI/ConfigurationController.cs b/Application/MinimalAPI/ConfigurationController.cs
new file mode 100644
index 0000000..f529b6f
--- /dev/null
+++ b/Application/MinimalAPI/ConfigurationController.cs
@@ -0,0 +1,113 @@
+using Microsoft.AspNetCore.Http.HttpResults;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using MTWireGuard.Application.Models.Mikrotik;
+using MTWireGuard.Application.Repositories;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using AutoMapper;
+using MTWireGuard.Application.Models.Models.Responses;
+using MTWireGuard.Application.Models.Requests;
+using MTWireGuard.Application.Models;
+using MikrotikAPI.Models;
+using Newtonsoft.Json;
+
+namespace MTWireGuard.Application.MinimalAPI
+{
+ internal class ConfigurationController
+ {
+ public static async Task> Resources(
+ [FromServices] IMikrotikRepository API)
+ {
+ var info = await API.GetInfo();
+ var ramUsed = 100 - info.FreeRAMPercentage;
+ var hddUsed = 100 - info.FreeHDDPercentage;
+
+ var output = new JsonResult(new
+ {
+ HDD = new
+ {
+ Total = info.TotalHDD,
+ Used = info.UsedHDD,
+ Free = info.FreeHDD,
+ Percentage = Convert.ToByte(hddUsed)
+ },
+ RAM = new
+ {
+ Total = info.TotalRAM,
+ Used = info.UsedRAM,
+ Free = info.FreeRAM,
+ Percentage = Convert.ToByte(ramUsed)
+ },
+ info.CPULoad,
+ info.UPTime
+ }).Value;
+ return TypedResults.Ok(output);
+ }
+
+ public static async Task, ProblemHttpResult>> DNS(
+ [FromServices] IMikrotikRepository API)
+ {
+ return TypedResults.Ok(await API.GetDNS());
+ }
+
+ public static async Task> Information(
+ [FromServices] IMikrotikRepository API)
+ {
+ var info = await API.GetInfo();
+ var identity = await API.GetName();
+ var dns = await API.GetDNS();
+
+ var dnsValues = new List();
+ dnsValues.AddRange(dns.Servers.Split(','));
+ dnsValues.AddRange(dns.DynamicServers.Split(','));
+
+ var output = new JsonResult(new
+ {
+ Identity = identity.Name,
+ DNS = dnsValues,
+ Device = new
+ {
+ info.BoardName,
+ info.Architecture
+ },
+ info.Version,
+ IP = Environment.GetEnvironmentVariable("MT_PUBLIC_IP")
+ }).Value;
+ return TypedResults.Ok(output);
+ }
+
+ public static async Task, ProblemHttpResult>> Identity(
+ [FromServices] IMikrotikRepository API)
+ {
+ return TypedResults.Ok(await API.GetName());
+ }
+
+ public static async Task> IdentityUpdate(
+ [FromServices] IMikrotikRepository API,
+ [FromServices] IMapper mapper,
+ [FromBody] UpdateIdentityRequest request)
+ {
+ var model = mapper.Map(request);
+ var update = await API.SetName(model);
+ var message = mapper.Map(update);
+ return TypedResults.Ok(message);
+ }
+
+ public static async Task> DNSUpdate(
+ [FromServices] IMikrotikRepository API,
+ [FromServices] IMapper mapper,
+ [FromBody] UpdateDNSRequest request)
+ {
+ var model = mapper.Map(request);
+ model.Servers.Remove(string.Empty);
+ model.Servers.Remove(" ");
+ var update = await API.SetDNS(model);
+ var message = mapper.Map(update);
+ return TypedResults.Ok(message);
+ }
+ }
+}
diff --git a/Application/MinimalAPI/IPPoolController.cs b/Application/MinimalAPI/IPPoolController.cs
new file mode 100644
index 0000000..334e1c4
--- /dev/null
+++ b/Application/MinimalAPI/IPPoolController.cs
@@ -0,0 +1,61 @@
+using Microsoft.AspNetCore.Http.HttpResults;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using MTWireGuard.Application.Models.Mikrotik;
+using MTWireGuard.Application.Repositories;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using AutoMapper;
+using MTWireGuard.Application.Models.Models.Responses;
+using MTWireGuard.Application.Models.Requests;
+using MTWireGuard.Application.Models;
+using MikrotikAPI.Models;
+
+namespace MTWireGuard.Application.MinimalAPI
+{
+ internal class IPPoolController
+ {
+ public static async Task>, NotFound>> GetAll([FromServices] IMikrotikRepository API)
+ {
+ var ippools = await API.GetIPPools();
+ return ippools.Any() ? TypedResults.Ok(ippools) : TypedResults.NotFound();
+ }
+
+ public static async Task> Create(
+ [FromServices] IMikrotikRepository API,
+ [FromServices] IMapper mapper,
+ [FromBody] CreatePoolRequest request)
+ {
+ var model = mapper.Map(request);
+ var make = await API.CreateIPPool(model);
+ var message = mapper.Map(make);
+ return TypedResults.Ok(message);
+ }
+
+ public static async Task> Update(
+ [FromServices] IMikrotikRepository API,
+ [FromServices] IMapper mapper,
+ int id,
+ [FromBody] UpdateIPPoolRequest request)
+ {
+ request.Id = id;
+ var model = mapper.Map(request);
+ var update = await API.UpdateIPPool(model);
+ var message = mapper.Map(update);
+ return TypedResults.Ok(message);
+ }
+
+ public static async Task> Delete(
+ [FromServices] IMikrotikRepository API,
+ [FromServices] IMapper mapper,
+ int id)
+ {
+ var delete = await API.DeleteIPPool(id);
+ var message = mapper.Map(delete);
+ return TypedResults.Ok(message);
+ }
+ }
+}
diff --git a/Application/MinimalAPI/ServerController.cs b/Application/MinimalAPI/ServerController.cs
new file mode 100644
index 0000000..955abf8
--- /dev/null
+++ b/Application/MinimalAPI/ServerController.cs
@@ -0,0 +1,81 @@
+using Microsoft.AspNetCore.Http.HttpResults;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using MTWireGuard.Application.Models.Mikrotik;
+using MTWireGuard.Application.Repositories;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using AutoMapper;
+using MTWireGuard.Application.Models.Models.Responses;
+using MTWireGuard.Application.Models.Requests;
+using MTWireGuard.Application.Models;
+
+namespace MTWireGuard.Application.MinimalAPI
+{
+ internal class ServerController
+ {
+ public static async Task>, NotFound>> GetAll([FromServices] IMikrotikRepository API)
+ {
+ var servers = await API.GetServersAsync();
+ //if (servers.Any())
+ //{
+ // var traffics = await API.GetServersTraffic();
+ // return TypedResults.Ok(servers);
+ //}
+ //else
+ // TypedResults.NotFound();
+ return servers.Any() ? TypedResults.Ok(servers) : TypedResults.NotFound();
+ }
+
+ public static async Task> Create(
+ [FromServices] IMikrotikRepository API,
+ [FromServices] IMapper mapper,
+ [FromBody] CreateServerRequest request)
+ {
+ var model = mapper.Map(request);
+ var make = await API.CreateServer(model);
+ var message = mapper.Map(make);
+ return TypedResults.Ok(message);
+ }
+
+ public static async Task> Update(
+ [FromServices] IMikrotikRepository API,
+ [FromServices] IMapper mapper,
+ int id,
+ [FromBody] UpdateServerRequest request)
+ //HttpRequest httpRequest)
+ {
+ //var request = await httpRequest.ReadFromJsonAsync();
+ request.Id = id;
+ var model = mapper.Map(request);
+ var update = await API.UpdateServer(model);
+ var message = mapper.Map(update);
+ return TypedResults.Ok(message);
+ }
+
+ public static async Task> Delete(
+ [FromServices] IMikrotikRepository API,
+ [FromServices] IMapper mapper,
+ [FromRoute] int id)
+ {
+ var delete = await API.DeleteServer(id);
+ var message = mapper.Map(delete);
+ return TypedResults.Ok(message);
+ }
+
+ public static async Task> Activation(
+ [FromServices] IMikrotikRepository API,
+ [FromServices] IMapper mapper,
+ [FromRoute] int id,
+ ChangeStateRequest request)
+ {
+ request.Id = id;
+ var active = (!request.Enabled) ? await API.EnableServer(request.Id) : await API.DisableServer(request.Id);
+ var message = mapper.Map(active);
+ return TypedResults.Ok(message);
+ }
+ }
+}
diff --git a/Application/MinimalAPI/UserController.cs b/Application/MinimalAPI/UserController.cs
new file mode 100644
index 0000000..219c4b3
--- /dev/null
+++ b/Application/MinimalAPI/UserController.cs
@@ -0,0 +1,118 @@
+using Microsoft.AspNetCore.Http.HttpResults;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Caching.Memory;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MTWireGuard.Application.Repositories;
+using Microsoft.AspNetCore.Mvc;
+using MTWireGuard.Application.Models.Mikrotik;
+using AutoMapper;
+using MTWireGuard.Application.Models.Requests;
+using MTWireGuard.Application.Models.Models.Responses;
+using MTWireGuard.Application.Models;
+
+namespace MTWireGuard.Application.MinimalAPI
+{
+ internal class UserController
+ {
+ public static async Task>, NotFound>> GetAll([FromServices] IMikrotikRepository API, HttpContext context)
+ {
+ var script = await API.RunScript("SendActivityUpdates");
+ var users = await API.GetUsersAsync();
+ if (users.Count > 0)
+ return TypedResults.Ok(users);
+ return TypedResults.NotFound();
+ }
+
+ public static async Task, NotFound>> GetById([FromServices] IMikrotikRepository API, int id)
+ {
+ var user = await API.GetUser(id);
+ if (user != null)
+ return TypedResults.Ok(user);
+ return TypedResults.NotFound();
+ }
+
+ public static async Task> GetQR([FromServices] IMikrotikRepository API, int id)
+ {
+ string config = await API.GetQRCodeBase64(id);
+ return TypedResults.Ok(config);
+ }
+
+ public static async Task GetFile([FromServices] IMikrotikRepository API, int id)
+ {
+ string config = await API.GetUserTunnelConfig(id);
+
+ byte[] bytesInStream = Encoding.UTF8.GetBytes(config);
+
+ var user = await API.GetUser(id);
+ string filename = string.IsNullOrWhiteSpace(user.Name) ? user.Interface : user.Name;
+ return TypedResults.File(
+ fileContents: bytesInStream,
+ fileDownloadName: filename);
+ }
+
+ public static async Task> Create(
+ [FromServices] IMikrotikRepository API,
+ [FromServices] IMapper mapper,
+ [FromBody] CreateClientRequest request)
+ //HttpRequest request)
+ {
+ //var ucm = await request.ReadFromJsonAsync();
+ var model = mapper.Map(request);
+ var make = await API.CreateUser(model);
+ var message = mapper.Map(make);
+ return TypedResults.Ok(message);
+ }
+
+ public static async Task> Update(
+ [FromServices] IMikrotikRepository API,
+ [FromServices] IMapper mapper,
+ int id,
+ UpdateClientRequest request)
+ {
+ request.ID = id;
+ var model = mapper.Map(request);
+ var update = await API.UpdateUser(model);
+ var message = mapper.Map(update);
+ return TypedResults.Ok(message);
+ }
+
+ public static async Task> Sync(
+ [FromServices] IMikrotikRepository API,
+ [FromServices] IMapper mapper,
+ int id,
+ SyncUserRequest request)
+ {
+ request.ID = id;
+ var model = mapper.Map(request);
+ var update = await API.SyncUser(model);
+ var message = mapper.Map(update);
+ return TypedResults.Ok(message);
+ }
+
+ public static async Task> Delete(
+ [FromServices] IMikrotikRepository API,
+ [FromServices] IMapper mapper,
+ [FromRoute] int id)
+ {
+ var delete = await API.DeleteUser(id);
+ var message = mapper.Map(delete);
+ return TypedResults.Ok(message);
+ }
+
+ public static async Task> Activation(
+ [FromServices] IMikrotikRepository API,
+ [FromServices] IMapper mapper,
+ [FromRoute] int id,
+ ChangeStateRequest request)
+ {
+ request.Id = id;
+ var active = (!request.Enabled) ? await API.EnableUser(request.Id) : await API.DisableUser(request.Id);
+ var message = mapper.Map(active);
+ return TypedResults.Ok(message);
+ }
+ }
+}