diff --git a/LANCommander.SDK/Enums/VPNStatus.cs b/LANCommander.SDK/Enums/VPNStatus.cs new file mode 100644 index 00000000..d6ea99f4 --- /dev/null +++ b/LANCommander.SDK/Enums/VPNStatus.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.Enums +{ + public enum VPNStatus + { + Disconnected, + Connected, + } +} diff --git a/LANCommander.SDK/Enums/VPNType.cs b/LANCommander.SDK/Enums/VPNType.cs new file mode 100644 index 00000000..7dbad984 --- /dev/null +++ b/LANCommander.SDK/Enums/VPNType.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.Enums +{ + public enum VPNType + { + ZeroTier = 1 + } +} diff --git a/LANCommander.SDK/VPN/Clients/IVPNClient.cs b/LANCommander.SDK/VPN/Clients/IVPNClient.cs new file mode 100644 index 00000000..54ccbf20 --- /dev/null +++ b/LANCommander.SDK/VPN/Clients/IVPNClient.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.VPN.Clients +{ + public interface IVPNClient + { + bool Connect(); + bool Disconnect(); + VPNConnectionStatus GetStatus(); + } +} diff --git a/LANCommander.SDK/VPN/Clients/ZeroTierClient.cs b/LANCommander.SDK/VPN/Clients/ZeroTierClient.cs new file mode 100644 index 00000000..cb140576 --- /dev/null +++ b/LANCommander.SDK/VPN/Clients/ZeroTierClient.cs @@ -0,0 +1,174 @@ +using LANCommander.SDK.VPN.Configurations; +using LANCommander.SDK.VPN.Exceptions; +using LANCommander.SDK.VPN.Models.ZeroTier; +using RestSharp; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; + +namespace LANCommander.SDK.VPN.Clients +{ + public class ZeroTierClient : IVPNClient + { + private ZeroTierConfiguration Configuration; + private RestClient ZeroTierServiceClient; + private Client Client; + private string Token; + private const string BaseUrl = "http://localhost:9993"; + + public ZeroTierClient(ZeroTierConfiguration configuration, Client client) { + Configuration = configuration; + Client = client; + + ZeroTierServiceClient = new RestClient(BaseUrl); + + var tokenPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "ZeroTier", "One", "authtoken.secret"); + + if (File.Exists(tokenPath)) + Token = File.ReadAllText(tokenPath); + else + throw new ClientInitializationException("Could not read the token"); + } + + public bool Connect() + { + try + { + var task = PostRequest($"/network/{Configuration.NetworkId}", new UpdateNetworkSettingsRequest + { + AllowDefault = false, + AllowDNS = true, + AllowManaged = true, + AllowGlobal = false + }); + + task.Wait(); + + var response = task.Result; + + Client.PostRequest("/api/ZeroTier/ApproveNode", new ApproveNodeRequest + { + NodeId = response.Id + }); + } + catch (Exception ex) + { + return false; + } + + return true; + } + + public bool Disconnect() + { + try + { + var status = GetNodeStatus(); + + var task = DeleteRequest($"/network/{Configuration.NetworkId}"); + + task.Wait(); + + var response = task.Result; + + if (response.Result) + { + Client.PostRequest("/api/ZeroTier/RemoveNode", new ApproveNodeRequest + { + NodeId = status.Address + }); + } + + return response.Result; + } + catch (Exception ex) + { + return false; + } + } + + public VPNConnectionStatus GetStatus() + { + try + { + var response = GetNodeStatus(); + + return new VPNConnectionStatus + { + Connected = response.Online, + Status = response.Online ? "Connected" : "Not Connected" + }; + } + catch (Exception ex) + { + return null; + } + } + + private NodeStatusResponse GetNodeStatus() + { + var task = GetRequest("/status"); + + task.Wait(); + + var response = task.Result; + + return response; + } + + private async Task PostRequest(string route, object body) + { + if (Token == null) + return default; + + var request = new RestRequest(route) + .AddJsonBody(body) + .AddHeader("X-ZT1-AUTH", Token); + + var response = await ZeroTierServiceClient.PostAsync(request); + + return response; + } + + private async Task PostRequest(string route) + { + if (Token == null) + return default; + + var request = new RestRequest(route) + .AddHeader("X-ZT1-AUTH", Token); + + var response = await ZeroTierServiceClient.PostAsync(request); + + return response; + } + + private async Task GetRequest(string route) + { + if (Token == null) + return default; + + var request = new RestRequest(route) + .AddHeader("X-ZT1-AUTH", Token); + + var response = await ZeroTierServiceClient.GetAsync(request); + + return response; + } + + private async Task DeleteRequest(string route) + { + if (Token == null) + return default; + + var request = new RestRequest(route) + .AddHeader("X-ZT1-AUTH", Token); + + var response = await ZeroTierServiceClient.DeleteAsync(request); + + return response; + } + } +} diff --git a/LANCommander.SDK/VPN/Configurations/VPNConfiguration.cs b/LANCommander.SDK/VPN/Configurations/VPNConfiguration.cs new file mode 100644 index 00000000..1310f3d1 --- /dev/null +++ b/LANCommander.SDK/VPN/Configurations/VPNConfiguration.cs @@ -0,0 +1,13 @@ +using LANCommander.SDK.Enums; +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.VPN.Configurations +{ + public class VPNConfiguration + { + public VPNType Type { get; set; } + public object Data { get; set; } + } +} diff --git a/LANCommander.SDK/VPN/Configurations/ZeroTierConfiguration.cs b/LANCommander.SDK/VPN/Configurations/ZeroTierConfiguration.cs new file mode 100644 index 00000000..35fd9a6b --- /dev/null +++ b/LANCommander.SDK/VPN/Configurations/ZeroTierConfiguration.cs @@ -0,0 +1,12 @@ +using LANCommander.SDK.Enums; +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.VPN.Configurations +{ + public class ZeroTierConfiguration + { + public string NetworkId { get; set; } + } +} diff --git a/LANCommander.SDK/VPN/ConnectionStatus.cs b/LANCommander.SDK/VPN/ConnectionStatus.cs new file mode 100644 index 00000000..3e062465 --- /dev/null +++ b/LANCommander.SDK/VPN/ConnectionStatus.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.VPN +{ + public class VPNConnectionStatus + { + public bool Connected { get; set; } + public string Status { get; set; } + } +} diff --git a/LANCommander.SDK/VPN/Exceptions/ClientConnectionException.cs b/LANCommander.SDK/VPN/Exceptions/ClientConnectionException.cs new file mode 100644 index 00000000..2eda92d7 --- /dev/null +++ b/LANCommander.SDK/VPN/Exceptions/ClientConnectionException.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.VPN.Exceptions +{ + public class ClientConnectionException : Exception + { + public ClientConnectionException(string message) : base(message) { } + } +} diff --git a/LANCommander.SDK/VPN/Exceptions/ClientInitializationException.cs b/LANCommander.SDK/VPN/Exceptions/ClientInitializationException.cs new file mode 100644 index 00000000..acdd2ddc --- /dev/null +++ b/LANCommander.SDK/VPN/Exceptions/ClientInitializationException.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.VPN.Exceptions +{ + public class ClientInitializationException : Exception + { + public ClientInitializationException(string message) : base(message) { } + } +} diff --git a/LANCommander.SDK/VPN/Exceptions/ZeroTier/ServiceNotInstalledException.cs b/LANCommander.SDK/VPN/Exceptions/ZeroTier/ServiceNotInstalledException.cs new file mode 100644 index 00000000..0b03b1ef --- /dev/null +++ b/LANCommander.SDK/VPN/Exceptions/ZeroTier/ServiceNotInstalledException.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.VPN.Exceptions.ZeroTier +{ + public class ServiceNotInstalledException : Exception + { + public ServiceNotInstalledException(string message) : base(message) { } + } +} diff --git a/LANCommander.SDK/VPN/Models/ZeroTier/ApproveNodeRequest.cs b/LANCommander.SDK/VPN/Models/ZeroTier/ApproveNodeRequest.cs new file mode 100644 index 00000000..934b1308 --- /dev/null +++ b/LANCommander.SDK/VPN/Models/ZeroTier/ApproveNodeRequest.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.VPN.Models.ZeroTier +{ + public class ApproveNodeRequest + { + public string NodeId { get; set; } + } +} diff --git a/LANCommander.SDK/VPN/Models/ZeroTier/LeaveNetworkRequest.cs b/LANCommander.SDK/VPN/Models/ZeroTier/LeaveNetworkRequest.cs new file mode 100644 index 00000000..a7c78405 --- /dev/null +++ b/LANCommander.SDK/VPN/Models/ZeroTier/LeaveNetworkRequest.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.VPN.Models.ZeroTier +{ + public class LeaveNetworkRequest + { + public string NetworkId { get; set; } + } +} diff --git a/LANCommander.SDK/VPN/Models/ZeroTier/LeaveNetworkResponse.cs b/LANCommander.SDK/VPN/Models/ZeroTier/LeaveNetworkResponse.cs new file mode 100644 index 00000000..5ebd213b --- /dev/null +++ b/LANCommander.SDK/VPN/Models/ZeroTier/LeaveNetworkResponse.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.VPN.Models.ZeroTier +{ + public class LeaveNetworkResponse + { + public bool Result { get; set; } + } +} diff --git a/LANCommander.SDK/VPN/Models/ZeroTier/NodeStatusResponse.cs b/LANCommander.SDK/VPN/Models/ZeroTier/NodeStatusResponse.cs new file mode 100644 index 00000000..0c452785 --- /dev/null +++ b/LANCommander.SDK/VPN/Models/ZeroTier/NodeStatusResponse.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.VPN.Models.ZeroTier +{ + public class NodeStatusResponse + { + public string Address { get; set; } + public bool Online { get; set; } + public bool TcpFallbackActive { get; set; } + } +} diff --git a/LANCommander.SDK/VPN/Models/ZeroTier/RemoveNodeRequest.cs b/LANCommander.SDK/VPN/Models/ZeroTier/RemoveNodeRequest.cs new file mode 100644 index 00000000..90ae2a5a --- /dev/null +++ b/LANCommander.SDK/VPN/Models/ZeroTier/RemoveNodeRequest.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.VPN.Models.ZeroTier +{ + public class RemoveNodeRequest + { + public string NodeId { get; set; } + } +} diff --git a/LANCommander.SDK/VPN/Models/ZeroTier/UpdateNetworkSettingsRequest.cs b/LANCommander.SDK/VPN/Models/ZeroTier/UpdateNetworkSettingsRequest.cs new file mode 100644 index 00000000..040642e2 --- /dev/null +++ b/LANCommander.SDK/VPN/Models/ZeroTier/UpdateNetworkSettingsRequest.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.VPN.Models.ZeroTier +{ + public class UpdateNetworkSettingsRequest + { + public bool AllowDNS { get; set; } + public bool AllowDefault { get; set; } + public bool AllowManaged { get; set; } + public bool AllowGlobal { get; set; } + } +} diff --git a/LANCommander.SDK/VPN/Models/ZeroTier/UpdateNetworkSettingsResponse.cs b/LANCommander.SDK/VPN/Models/ZeroTier/UpdateNetworkSettingsResponse.cs new file mode 100644 index 00000000..ff16c301 --- /dev/null +++ b/LANCommander.SDK/VPN/Models/ZeroTier/UpdateNetworkSettingsResponse.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LANCommander.SDK.VPN.Models.ZeroTier +{ + public class UpdateNetworkSettingsResponse + { + public string Id { get; set; } + } +} diff --git a/LANCommander.SDK/VPNService.cs b/LANCommander.SDK/VPNService.cs new file mode 100644 index 00000000..6695f9b8 --- /dev/null +++ b/LANCommander.SDK/VPNService.cs @@ -0,0 +1,63 @@ +using LANCommander.SDK.VPN; +using LANCommander.SDK.VPN.Clients; +using LANCommander.SDK.VPN.Configurations; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace LANCommander.SDK +{ + public class VPNService + { + private readonly ILogger Logger; + private Client Client { get; set; } + + public delegate void OnConnectedHandler(object sender); + public event OnConnectedHandler OnConnected; + + public delegate void OnDisconnectedHandler(object sender); + public event OnDisconnectedHandler OnDisconnected; + + private IVPNClient VPNClient; + + public VPNService(Client client) + { + Client = client; + } + + public VPNService(Client client, ILogger logger) + { + Client = client; + Logger = logger; + } + + public void Init() + { + var configuration = Client.GetRequest("/api/VPN/Configuration"); + + switch (configuration.Type) + { + case Enums.VPNType.ZeroTier: + VPNClient = new ZeroTierClient(configuration.Data as ZeroTierConfiguration, Client); + break; + } + } + + public bool Connect() + { + return VPNClient.Connect(); + } + + public bool Disconnect() + { + return VPNClient.Disconnect(); + } + + public VPNConnectionStatus GetStatus() + { + return VPNClient.GetStatus(); + } + } +} diff --git a/LANCommander/Controllers/Api/VPNController.cs b/LANCommander/Controllers/Api/VPNController.cs new file mode 100644 index 00000000..108fde81 --- /dev/null +++ b/LANCommander/Controllers/Api/VPNController.cs @@ -0,0 +1,38 @@ +using LANCommander.Models; +using LANCommander.SDK.VPN.Configurations; +using LANCommander.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace LANCommander.Controllers.Api +{ + [Authorize(AuthenticationSchemes = "Bearer")] + [Route("api/[controller]")] + [ApiController] + public class VPNController : ControllerBase + { + public VPNController() { } + + [HttpGet] + public async Task GetConfiguration() + { + var settings = SettingService.GetSettings(); + var configuration = new VPNConfiguration() + { + Type = SDK.Enums.VPNType.ZeroTier + }; + + switch (settings.VPN.Type) + { + case SDK.Enums.VPNType.ZeroTier: + configuration.Data = new ZeroTierConfiguration + { + NetworkId = (settings.VPN.Configuration as LANCommanderZeroTierSettings).NetworkId + }; + break; + } + + return configuration; + } + } +} diff --git a/LANCommander/Controllers/Api/ZeroTierController.cs b/LANCommander/Controllers/Api/ZeroTierController.cs new file mode 100644 index 00000000..246c9443 --- /dev/null +++ b/LANCommander/Controllers/Api/ZeroTierController.cs @@ -0,0 +1,74 @@ +using LANCommander.Data.Models; +using LANCommander.Models; +using LANCommander.SDK.VPN.Models.ZeroTier; +using LANCommander.Services; +using LANCommander.Services.VPNServices; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; + +namespace LANCommander.Controllers.Api +{ + [Authorize(AuthenticationSchemes = "Bearer")] + [Route("api/[controller]")] + [ApiController] + public class ZeroTierController : ControllerBase + { + private readonly ZeroTierService ZeroTierService; + private readonly UserManager UserManager; + private readonly RoleManager RoleManager; + + public ZeroTierController(ZeroTierService zeroTierService, UserManager userManager, RoleManager roleManager) + { + ZeroTierService = zeroTierService; + UserManager = userManager; + RoleManager = roleManager; + } + + [HttpPost] + public async Task ApproveNode(ApproveNodeRequest request) + { + var settings = SettingService.GetSettings(); + + var user = await UserManager.FindByNameAsync(User.Identity.Name); + var roleNames = await UserManager.GetRolesAsync(user); + + bool allowed = false; + + foreach (var roleName in roleNames) + { + var role = await RoleManager.FindByNameAsync(roleName); + + if (role != null && settings.VPN.AllowedRoles.Contains(role.Id)) + { + allowed = true; + break; + } + } + + if (!allowed) + return Forbid(); + + var config = settings.VPN.Configuration as LANCommanderZeroTierSettings; + + await ZeroTierService.ApproveNode(config.NetworkId, user.UserName); + + return Ok(); + } + + [HttpPost] + public async Task RemoveNode(RemoveNodeRequest request) + { + var settings = SettingService.GetSettings(); + + var user = await UserManager.FindByNameAsync(User.Identity.Name); + + // Do we add any check here that the user is authorized to do VPN stuff? + // We should at least do a check that they own that + + await ZeroTierService.RemoveNode(request.NodeId); + + return Ok(); + } + } +} diff --git a/LANCommander/Models/Settings.cs b/LANCommander/Models/Settings.cs index 2253d419..f7d423fa 100644 --- a/LANCommander/Models/Settings.cs +++ b/LANCommander/Models/Settings.cs @@ -1,4 +1,5 @@ -using NLog.Targets; +using LANCommander.SDK.Enums; +using NLog.Targets; namespace LANCommander.Models { @@ -23,6 +24,7 @@ namespace LANCommander.Models public LANCommanderArchiveSettings Archives { get; set; } = new LANCommanderArchiveSettings(); public LANCommanderMediaSettings Media { get; set; } = new LANCommanderMediaSettings(); public LANCommanderIPXRelaySettings IPXRelay { get; set; } = new LANCommanderIPXRelaySettings(); + public LANCommanderVPNSettings VPN { get; set; } = new LANCommanderVPNSettings(); public LANCommanderWikiSettings Wiki { get; set; } = new LANCommanderWikiSettings(); public LANCommanderUpdateSettings Update { get; set; } = new LANCommanderUpdateSettings(); public LANCommanderLogSettings Logs { get; set; } = new LANCommanderLogSettings(); @@ -90,6 +92,20 @@ namespace LANCommander.Models public bool Logging { get; set; } = false; } + public class LANCommanderVPNSettings + { + public bool Enabled { get; set; } = false; + public IEnumerable AllowedRoles { get; set; } + public VPNType Type { get; set; } = VPNType.ZeroTier; + public object Configuration { get; set; } + } + + public class LANCommanderZeroTierSettings + { + public string NetworkId { get; set; } + public string ApiKey { get; set; } + } + public class LANCommanderWikiSettings { public bool Enabled { get; set; } = false; diff --git a/LANCommander/Models/ZeroTier/MemberConfig.cs b/LANCommander/Models/ZeroTier/MemberConfig.cs new file mode 100644 index 00000000..29ddd316 --- /dev/null +++ b/LANCommander/Models/ZeroTier/MemberConfig.cs @@ -0,0 +1,8 @@ +namespace LANCommander.Models.ZeroTier +{ + public class MemberConfig + { + public bool ActiveBridge { get; set; } + public bool Authorized { get; set; } + } +} diff --git a/LANCommander/Models/ZeroTier/ModifyMemberRequest.cs b/LANCommander/Models/ZeroTier/ModifyMemberRequest.cs new file mode 100644 index 00000000..96d12a6d --- /dev/null +++ b/LANCommander/Models/ZeroTier/ModifyMemberRequest.cs @@ -0,0 +1,10 @@ +namespace LANCommander.Models.ZeroTier +{ + public class ModifyMemberRequest + { + public bool Hidden { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public MemberConfig Config { get; set; } + } +} diff --git a/LANCommander/Services/VPNServices/ZeroTierService.cs b/LANCommander/Services/VPNServices/ZeroTierService.cs new file mode 100644 index 00000000..9b85a0cd --- /dev/null +++ b/LANCommander/Services/VPNServices/ZeroTierService.cs @@ -0,0 +1,92 @@ +using LANCommander.Models; +using LANCommander.Models.ZeroTier; +using RestSharp; + +namespace LANCommander.Services.VPNServices +{ + public class ZeroTierService + { + private const string BaseUrl = "https://api.zerotier.com/api/v1"; + private RestClient Client { get; set; } + private LANCommanderZeroTierSettings Configuration { get; set; } + + public ZeroTierService() { + Client = new RestClient(BaseUrl); + + var settings = SettingService.GetSettings(); + + Configuration = settings.VPN.Configuration as LANCommanderZeroTierSettings; + } + + public async Task ApproveNode(string nodeId, string username) + { + await PostRequestAsync($"/network/{Configuration.NetworkId}/member/{nodeId}", new ModifyMemberRequest + { + Hidden = false, + Name = username, + Config = new MemberConfig + { + Authorized = true + } + }); + } + + public async Task RemoveNode(string nodeId) + { + await DeleteRequest($"/network/{Configuration.NetworkId}/member/{nodeId}"); + } + + private async Task PostRequestAsync(string route, object body) + { + if (String.IsNullOrWhiteSpace(Configuration.ApiKey)) + return default; + + var request = new RestRequest(route) + .AddJsonBody(body) + .AddHeader("Authorization", $"token {Configuration.ApiKey}"); + + var response = await Client.PostAsync(request); + + return response; + } + + private async Task PostRequestAsync(string route) + { + if (String.IsNullOrWhiteSpace(Configuration.ApiKey)) + return default; + + var request = new RestRequest(route) + .AddHeader("Authorization", $"token {Configuration.ApiKey}"); + + var response = await Client.PostAsync(request); + + return response; + } + + private async Task GetRequest(string route) + { + if (String.IsNullOrWhiteSpace(Configuration.ApiKey)) + return default; + + var request = new RestRequest(route) + .AddHeader("Authorization", $"token {Configuration.ApiKey}"); + + var response = await Client.GetAsync(request); + + return response; + } + + private async Task DeleteRequest(string route) + { + if (String.IsNullOrWhiteSpace(Configuration.ApiKey)) + return default; + + var request = new RestRequest(route) + .AddHeader("Authorization", $"token {Configuration.ApiKey}"); + + var response = await Client.DeleteAsync(request); + + return response; + } + } +} diff --git a/LANCommander/UI/Pages/Settings/VPN/Forms/ZeroTier.razor b/LANCommander/UI/Pages/Settings/VPN/Forms/ZeroTier.razor new file mode 100644 index 00000000..2fd2ac19 --- /dev/null +++ b/LANCommander/UI/Pages/Settings/VPN/Forms/ZeroTier.razor @@ -0,0 +1,28 @@ +@using LANCommander.Models +@using LANCommander.SDK.VPN.Configurations + + + + + +@code { + [Parameter] public string Value { get; set; } = ""; + [Parameter] public EventCallback ValueChanged { get; set; } + + [Parameter] public LANCommanderZeroTierSettings Configuration { get; set; } = new LANCommanderZeroTierSettings(); + [Parameter] public EventCallback ConfigurationChanged { get; set; } + + protected override async Task OnInitializedAsync() + { + if (Configuration == null) + { + Configuration = new LANCommanderZeroTierSettings(); + await ConfigurationChanged.InvokeAsync(Configuration); + } + } + + async Task Changed() + { + await ConfigurationChanged.InvokeAsync(Configuration); + } +} diff --git a/LANCommander/UI/Pages/Settings/VPN/Index.razor b/LANCommander/UI/Pages/Settings/VPN/Index.razor new file mode 100644 index 00000000..6f536952 --- /dev/null +++ b/LANCommander/UI/Pages/Settings/VPN/Index.razor @@ -0,0 +1,95 @@ +@page "/Settings/VPN" +@using LANCommander.SDK.VPN.Configurations +@using Microsoft.EntityFrameworkCore +@using LANCommander.Models; +@using LANCommander.Extensions +@using LANCommander.SDK.Enums +@layout SettingsLayout +@inject SettingService SettingService +@inject IMessageService MessageService +@inject RoleManager RoleManager +@attribute [Authorize(Roles = "Administrator")] + + + +
+
+ + + + + + + + + + + + + @switch (context.VPN.Type) + { + case VPNType.ZeroTier: + + break; + } + + + + + +
+ +@code { + LANCommanderSettings Settings; + + ICollection Roles = new List(); + IEnumerable AllowedRolesTransferItems { get; set; } = new List(); + List AllowedRolesTargetKeys { get; set; } = new List(); + ICollection SelectedAllowedRoles = new List(); + + protected override async Task OnInitializedAsync() + { + Settings = SettingService.GetSettings(); + Roles = await RoleManager.Roles.ToListAsync(); + + SelectedAllowedRoles = Roles.Where(r => Settings.VPN.AllowedRoles.Contains(r.Id)).ToList(); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + AllowedRolesTransferItems = Roles.Select(r => new TransferItem() + { + Key = r.Id.ToString(), + Title = r.Name + }); + + if (SelectedAllowedRoles != null) + AllowedRolesTargetKeys = SelectedAllowedRoles.Select(i => i.Id.ToString()).ToList(); + } + } + + async Task OnChangeAllowedRoles(TransferChangeArgs e) + { + SelectedAllowedRoles = Roles.Where(r => e.TargetKeys.Contains(r.Id.ToString())).ToList(); + + Settings.VPN.AllowedRoles = SelectedAllowedRoles.Select(r => r.Id); + } + + private void Save() + { + try + { + SettingService.SaveSettings(Settings); + MessageService.Success("Settings saved!"); + } + catch + { + MessageService.Error("An unknown error occurred."); + } + } +}