diff --git a/Application/ApplicationServiceRegister.cs b/Application/ApplicationServiceRegister.cs index d3e4d1d..34cfb30 100644 --- a/Application/ApplicationServiceRegister.cs +++ b/Application/ApplicationServiceRegister.cs @@ -1,5 +1,6 @@ -using Microsoft.Extensions.DependencyInjection; -using MTWireGuard; +using Hangfire; +using Hangfire.Storage.SQLite; +using Microsoft.Extensions.DependencyInjection; using MTWireGuard.Application.Mapper; using MTWireGuard.Application.Repositories; using MTWireGuard.Application.Services; @@ -14,6 +15,13 @@ namespace MTWireGuard.Application // Add DBContext services.AddDbContext(ServiceLifetime.Singleton); + // Add HangFire + services.AddHangfire(config => + { + config.UseSQLiteStorage(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "MikrotikWireguard.db")); + }); + services.AddHangfireServer(); + // Auto Mapper Configurations services.AddSingleton(); services.AddSingleton(); @@ -28,6 +36,7 @@ namespace MTWireGuard.Application // Add Mikrotik API Service services.AddSingleton(); + } } } diff --git a/Application/MTWireGuard.Application.csproj b/Application/MTWireGuard.Application.csproj index 880ef54..99e2497 100644 --- a/Application/MTWireGuard.Application.csproj +++ b/Application/MTWireGuard.Application.csproj @@ -8,6 +8,9 @@ + + + diff --git a/Application/Mapper/PeerMapping.cs b/Application/Mapper/PeerMapping.cs index 334eacc..399ac7c 100644 --- a/Application/Mapper/PeerMapping.cs +++ b/Application/Mapper/PeerMapping.cs @@ -38,7 +38,9 @@ namespace MTWireGuard.Application.Mapper .ForMember(dest => dest.UploadBytes, opt => opt.MapFrom(src => Convert.ToInt64(src.TX))) .ForMember(dest => dest.DownloadBytes, - opt => opt.MapFrom(src => Convert.ToInt64(src.RX))); + opt => opt.MapFrom(src => Convert.ToInt64(src.RX))) + .ForMember(dest => dest.Expire, + opt => opt.MapFrom(src => ExpireDateToString(src))); // WGPeer CreateMap(); @@ -48,7 +50,9 @@ namespace MTWireGuard.Application.Mapper opt => opt.MapFrom(src => $"*{src.Id:X}")); // DBUser - CreateMap(); + CreateMap() + .ForMember(dest => dest.Expire, + opt => opt.MapFrom(src => ExpireStringToDate(src.Expire))); CreateMap(); CreateMap() .ForMember(dest => dest.Id, @@ -68,6 +72,23 @@ namespace MTWireGuard.Application.Mapper return (db.Users.ToList().Find(u => u.Id == Convert.ToInt32(source.Id[1..], 16)) != null) ? db.Users.ToList().Find(u => u.Id == Convert.ToInt32(source.Id[1..], 16)).PrivateKey : ""; } + private DateTime GetPeerExpire(WGPeer source) + { + var db = Provider.GetService(); + return (db.Users.ToList().Find(u => u.Id == Convert.ToInt32(source.Id[1..], 16)) != null) ? db.Users.ToList().Find(u => u.Id == Convert.ToInt32(source.Id[1..], 16)).Expire ?? new() : new(); + } + + private string ExpireDateToString(WGPeer source) + { + var expireDate = GetPeerExpire(source); + return expireDate != new DateTime() ? expireDate.ToString() : "Unlimited"; + } + + private DateTime ExpireStringToDate(string expire) + { + return expire == "Unlimited" ? new() : Convert.ToDateTime(expire); + } + private bool HasDifferences(WGPeer source) { var db = Provider.GetService(); diff --git a/Application/Migrations/20230602191549_ExpireField.Designer.cs b/Application/Migrations/20230602191549_ExpireField.Designer.cs new file mode 100644 index 0000000..e311a45 --- /dev/null +++ b/Application/Migrations/20230602191549_ExpireField.Designer.cs @@ -0,0 +1,59 @@ +// +using System; +using MTWireGuard.Application; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace MTWireGuard.Application.Migrations +{ + [DbContext(typeof(DBContext))] + [Migration("20230602191549_ExpireField")] + partial class ExpireField + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.5"); + + modelBuilder.Entity("MTWireGuard.Application.Models.Mikrotik.WGPeerDBModel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Expire") + .HasColumnType("TEXT"); + + b.Property("ExpireID") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("PrivateKey") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PublicKey") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("PrivateKey") + .IsUnique(); + + b.HasIndex("PublicKey") + .IsUnique(); + + b.ToTable("Users"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Application/Migrations/20230602191549_ExpireField.cs b/Application/Migrations/20230602191549_ExpireField.cs new file mode 100644 index 0000000..0f4e0d0 --- /dev/null +++ b/Application/Migrations/20230602191549_ExpireField.cs @@ -0,0 +1,57 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MTWireGuard.Application.Migrations +{ + /// + public partial class ExpireField : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Name", + table: "Users", + type: "TEXT", + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT"); + + migrationBuilder.AddColumn( + name: "Expire", + table: "Users", + type: "TEXT", + nullable: true); + + migrationBuilder.AddColumn( + name: "ExpireID", + table: "Users", + type: "INTEGER", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Expire", + table: "Users"); + + migrationBuilder.DropColumn( + name: "ExpireID", + table: "Users"); + + migrationBuilder.AlterColumn( + name: "Name", + table: "Users", + type: "TEXT", + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "TEXT", + oldNullable: true); + } + } +} diff --git a/Application/Migrations/DBContextModelSnapshot.cs b/Application/Migrations/DBContextModelSnapshot.cs index dd99923..9c53140 100644 --- a/Application/Migrations/DBContextModelSnapshot.cs +++ b/Application/Migrations/DBContextModelSnapshot.cs @@ -1,5 +1,6 @@ // -using MTWireGuard; +using System; +using MTWireGuard.Application; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; @@ -14,16 +15,21 @@ namespace MTWireGuard.Application.Migrations protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "7.0.1"); + modelBuilder.HasAnnotation("ProductVersion", "7.0.5"); - modelBuilder.Entity("MTWireGuard.Models.Mikrotik.WGPeerDBModel", b => + modelBuilder.Entity("MTWireGuard.Application.Models.Mikrotik.WGPeerDBModel", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); + b.Property("Expire") + .HasColumnType("TEXT"); + + b.Property("ExpireID") + .HasColumnType("INTEGER"); + b.Property("Name") - .IsRequired() .HasColumnType("TEXT"); b.Property("PrivateKey") diff --git a/Application/Models/Mikrotik/WGPeer.cs b/Application/Models/Mikrotik/WGPeer.cs index ec1bd4c..9ace923 100644 --- a/Application/Models/Mikrotik/WGPeer.cs +++ b/Application/Models/Mikrotik/WGPeer.cs @@ -11,6 +11,8 @@ namespace MTWireGuard.Application.Models.Mikrotik public string? Name { get; set; } public string PrivateKey { get; set; } public string PublicKey { get; set; } + public DateTime? Expire { get; set; } + public int? ExpireID { get; set; } } public class WGPeerViewModel @@ -28,6 +30,7 @@ namespace MTWireGuard.Application.Models.Mikrotik public long DownloadBytes { get; set; } public long UploadBytes { get; set; } public bool IsDifferent { get; set; } + public string Expire { get; set; } } public class UserCreateModel @@ -42,6 +45,7 @@ namespace MTWireGuard.Application.Models.Mikrotik public string PublicKey { get; set; } public string PresharedKey { get; set; } public string PersistentKeepalive { get; set; } + public DateTime Expire { get; set; } } public class UserSyncModel @@ -64,5 +68,6 @@ namespace MTWireGuard.Application.Models.Mikrotik public string PrivateKey { get; set; } public string PresharedKey { get; set; } public int PersistentKeepalive { get; set; } + public DateTime Expire { get; set; } } } diff --git a/Application/Services/HangfireManager.cs b/Application/Services/HangfireManager.cs new file mode 100644 index 0000000..2d6004b --- /dev/null +++ b/Application/Services/HangfireManager.cs @@ -0,0 +1,20 @@ +using Hangfire; +using Hangfire.Storage; +using MTWireGuard.Application.Repositories; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MTWireGuard.Application.Services +{ + public class HangfireManager + { + public static int SetUserExpiration(int userID, DateTime expireDate) + { + return int.Parse(BackgroundJob.Schedule(mikrotik => mikrotik.DisableUser(userID), expireDate)); + } + } +} diff --git a/Application/Services/MTAPI.cs b/Application/Services/MTAPI.cs index ae8c0b1..4f371e6 100644 --- a/Application/Services/MTAPI.cs +++ b/Application/Services/MTAPI.cs @@ -21,7 +21,7 @@ namespace MTWireGuard.Application.Services string MT_IP = Environment.GetEnvironmentVariable("MT_IP"); string MT_USER = Environment.GetEnvironmentVariable("MT_USER"); string MT_PASS = Environment.GetEnvironmentVariable("MT_PASS"); - this.wrapper = new(MT_IP, MT_USER, MT_PASS); + wrapper = new(MT_IP, MT_USER, MT_PASS); } public async Task> GetLogsAsync() { @@ -144,12 +144,16 @@ namespace MTWireGuard.Application.Services if (model.Success) { var item = model.Item as MikrotikAPI.Models.WGPeer; + var userID = Convert.ToInt32(item.Id[1..], 16); + var expireID = (peer.Expire != new DateTime()) ? HangfireManager.SetUserExpiration(userID, peer.Expire) : 0; await dbContext.Users.AddAsync(new() { - Id = Convert.ToInt32(item.Id[1..], 16), + Id = userID, Name = peer.Name, PrivateKey = peer.PrivateKey, - PublicKey = peer.PublicKey + PublicKey = peer.PublicKey, + Expire = peer.Expire, + ExpireID = expireID }); await dbContext.SaveChangesAsync(); } @@ -211,6 +215,7 @@ namespace MTWireGuard.Application.Services { var exists = await dbContext.Users.FindAsync(user.Id); dbContext.ChangeTracker.Clear(); + var expireID = (user.Expire != new DateTime()) ? HangfireManager.SetUserExpiration(user.Id, user.Expire) : 0; if (exists != null) { dbContext.Users.Update(new() @@ -218,7 +223,9 @@ namespace MTWireGuard.Application.Services Id = user.Id, Name = user.Name ?? exists.Name, PrivateKey = user.PrivateKey ?? exists.PrivateKey, - PublicKey = user.PublicKey ?? exists.PublicKey + PublicKey = user.PublicKey ?? exists.PublicKey, + Expire = user.Expire, + ExpireID = expireID }); } else @@ -227,7 +234,9 @@ namespace MTWireGuard.Application.Services Id = user.Id, Name = user.Name, PublicKey = user.PublicKey, - PrivateKey = user.PrivateKey + PrivateKey = user.PrivateKey, + Expire = user.Expire, + ExpireID = expireID }); await dbContext.SaveChangesAsync(); } @@ -305,11 +314,9 @@ namespace MTWireGuard.Application.Services if (disposing) { // Free any other managed objects here. - // } // Free any unmanaged objects here. - // disposed = true; } } diff --git a/MikrotikAPI/MikrotikAPI.csproj b/MikrotikAPI/MikrotikAPI.csproj index 96e8a44..f958b97 100644 --- a/MikrotikAPI/MikrotikAPI.csproj +++ b/MikrotikAPI/MikrotikAPI.csproj @@ -7,7 +7,6 @@ - diff --git a/MikrotikAPI/Models/WGPeer.cs b/MikrotikAPI/Models/WGPeer.cs index 9274c06..816d802 100644 --- a/MikrotikAPI/Models/WGPeer.cs +++ b/MikrotikAPI/Models/WGPeer.cs @@ -1,5 +1,4 @@ -using Microsoft.EntityFrameworkCore; -using Newtonsoft.Json; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel; diff --git a/UI/MTWireGuard.csproj b/UI/MTWireGuard.csproj index 86c20d9..b6e266d 100644 --- a/UI/MTWireGuard.csproj +++ b/UI/MTWireGuard.csproj @@ -12,6 +12,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/UI/Mapper/RequestProfile.cs b/UI/Mapper/RequestProfile.cs index 2af4687..1d5fc18 100644 --- a/UI/Mapper/RequestProfile.cs +++ b/UI/Mapper/RequestProfile.cs @@ -17,7 +17,9 @@ namespace MTWireGuard.Mapper .ForMember(dest => dest.EndpointAddress, opt => opt.MapFrom(src => src.Endpoint)) .ForMember(dest => dest.PersistentKeepalive, - opt => opt.MapFrom(src => src.KeepAlive.ToString())); + opt => opt.MapFrom(src => src.KeepAlive.ToString())) + .ForMember(dest => dest.Expire, + opt => opt.MapFrom(src => Convert.ToDateTime(src.Expire))); CreateMap(); @@ -25,7 +27,9 @@ namespace MTWireGuard.Mapper .ForMember(dest => dest.EndpointAddress, opt => opt.MapFrom(src => src.Endpoint)) .ForMember(dest => dest.PersistentKeepalive, - opt => opt.MapFrom(src => src.KeepAlive)); + opt => opt.MapFrom(src => src.KeepAlive)) + .ForMember(dest => dest.Expire, + opt => opt.MapFrom(src => Convert.ToDateTime(src.Expire))); // Server Request CreateMap() diff --git a/UI/Models/Requests/CreateClientRequest.cs b/UI/Models/Requests/CreateClientRequest.cs index 1a51c48..f4680ec 100644 --- a/UI/Models/Requests/CreateClientRequest.cs +++ b/UI/Models/Requests/CreateClientRequest.cs @@ -12,5 +12,6 @@ public string Interface { get; set; } public int KeepAlive { get; set; } public bool Enabled { get; set; } + public string Expire { get; set; } } } diff --git a/UI/Models/Requests/UpdateClientRequest.cs b/UI/Models/Requests/UpdateClientRequest.cs index 2f8e879..5539b59 100644 --- a/UI/Models/Requests/UpdateClientRequest.cs +++ b/UI/Models/Requests/UpdateClientRequest.cs @@ -12,5 +12,6 @@ public string PublicKey { get; set; } public string Interface { get; set; } public int KeepAlive { get; set; } + public string Expire { get; set; } } } diff --git a/UI/Pages/Clients.cshtml b/UI/Pages/Clients.cshtml index 452e4e4..77d5685 100644 --- a/UI/Pages/Clients.cshtml +++ b/UI/Pages/Clients.cshtml @@ -20,8 +20,8 @@ Name Interface Address - Public-Key Traffic + Expire Status diff --git a/UI/Pages/Clients.cshtml.cs b/UI/Pages/Clients.cshtml.cs index 1e03853..8706e29 100644 --- a/UI/Pages/Clients.cshtml.cs +++ b/UI/Pages/Clients.cshtml.cs @@ -57,10 +57,6 @@ namespace MTWireGuard.Pages var make = await API.CreateUser(model); var message = mapper.Map(make); return new ToastResult(message); - /* - string status = make.Code == "200" ? "success" : "danger"; - string title = make.Code == "200" ? make.Title : $"[{make.Code}] {make.Title}"; - return new ToastResult(title, make.Description, status);*/ } public async Task OnPostDelete(DeleteRequest request) @@ -68,10 +64,6 @@ namespace MTWireGuard.Pages var delete = await API.DeleteUser(request.Id); var message = mapper.Map(delete); return new ToastResult(message); - /* - string status = delete.Code == "200" ? "success" : "danger"; - string title = delete.Code == "200" ? delete.Title : $"[{delete.Code}] {delete.Title}"; - return new ToastResult(title, delete.Description, status);*/ } public async Task OnPostUpdate(UpdateClientRequest request) @@ -80,10 +72,6 @@ namespace MTWireGuard.Pages var update = await API.UpdateUser(model); var message = mapper.Map(update); return new ToastResult(message); - /* - string status = update.Code == "200" ? "success" : "danger"; - string title = update.Code == "200" ? update.Title : $"[{update.Code}] {update.Title}"; - return new ToastResult(title, update.Description, status);*/ } public async Task OnPostSyncAsync(SyncUserRequest request) @@ -92,10 +80,6 @@ namespace MTWireGuard.Pages var update = await API.SyncUser(model); var message = mapper.Map(update); return new ToastResult(message); - /* - string status = update.Code == "200" ? "success" : "danger"; - string title = update.Code == "200" ? update.Title : $"[{update.Code}] {update.Title}"; - return new ToastResult(title, update.Description, status);*/ } public async Task OnGetEnableAsync(ChangeStateRequest request) @@ -107,10 +91,6 @@ namespace MTWireGuard.Pages result = await API.DisableUser(request.Id); var message = mapper.Map(result); return new ToastResult(message); - /* - string status = result.Code == "200" ? "success" : "danger"; - string title = result.Code == "200" ? result.Title : $"[{result.Code}] {result.Title}"; - return new ToastResult(title, result.Description, status);*/ } } } diff --git a/UI/Pages/Components/CreateClientForm/CreateClientForm.cshtml b/UI/Pages/Components/CreateClientForm/CreateClientForm.cshtml index 86123f2..66969db 100644 --- a/UI/Pages/Components/CreateClientForm/CreateClientForm.cshtml +++ b/UI/Pages/Components/CreateClientForm/CreateClientForm.cshtml @@ -17,7 +17,7 @@
- @foreach (var server in Servers) { @@ -71,7 +71,16 @@
- + +
+
+
+ +
+ + + +
diff --git a/UI/Pages/Components/UpdateClientModal/UpdateClientModal.cshtml b/UI/Pages/Components/UpdateClientModal/UpdateClientModal.cshtml index f871993..7edaff5 100644 --- a/UI/Pages/Components/UpdateClientModal/UpdateClientModal.cshtml +++ b/UI/Pages/Components/UpdateClientModal/UpdateClientModal.cshtml @@ -22,7 +22,7 @@
- @foreach (var server in Servers) { @if (server.IsEnabled) @@ -86,6 +86,15 @@
+
+ +
+ + + + +
+