Merge branch 'main' into Subscriptions

This commit is contained in:
Marcel Baumgartner
2023-04-04 01:24:50 +02:00
committed by GitHub
30 changed files with 578 additions and 216 deletions

View File

@@ -21,7 +21,10 @@ public class ResourcesController : Controller
{
if (name.Contains(".."))
{
await SecurityLogService.Log(SecurityLogType.PathTransversal, name);
await SecurityLogService.Log(SecurityLogType.PathTransversal, x =>
{
x.Add<string>(name);
});
return NotFound();
}

View File

@@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;
namespace Moonlight.App.Models.Forms;
public class NameModel
{
[Required]
[MinLength(2, ErrorMessage = "Do you think, that works?")]
public string FirstName { get; set; }
[Required]
[MinLength(2, ErrorMessage = "Do you think, that works?")]
public string LastName { get; set; }
}

View File

@@ -0,0 +1,10 @@
using System.ComponentModel.DataAnnotations;
namespace Moonlight.App.Models.Forms;
public class PasswordModel
{
[Required(ErrorMessage = "You need to enter a password")]
[MinLength(8, ErrorMessage = "You need to enter a password with minimum 8 characters in lenght")]
public string Password { get; set; }
}

View File

@@ -0,0 +1,7 @@
namespace Moonlight.App.Models.Log;
public class LogData
{
public Type Type { get; set; }
public string Value { get; set; }
}

View File

@@ -9,5 +9,6 @@ public enum UserStatus
Warned,
Banned,
Disabled,
DataPending
DataPending,
PasswordPending
}

View File

@@ -169,7 +169,11 @@ public class DomainService
}));
}
await AuditLogService.Log(AuditLogType.AddDomainRecord, new[] { d.Id.ToString(), dnsRecord.Name });
await AuditLogService.Log(AuditLogType.AddDomainRecord, x =>
{
x.Add<Domain>(d.Id);
x.Add<DnsRecord>(dnsRecord.Name);
});
}
public async Task UpdateDnsRecord(Domain d, DnsRecord dnsRecord)
@@ -199,7 +203,11 @@ public class DomainService
}));
}
await AuditLogService.Log(AuditLogType.UpdateDomainRecord, new[] { d.Id.ToString(), dnsRecord.Name });
await AuditLogService.Log(AuditLogType.UpdateDomainRecord, x =>
{
x.Add<Domain>(d.Id);
x.Add<DnsRecord>(dnsRecord.Name);
});
}
public async Task DeleteDnsRecord(Domain d, DnsRecord dnsRecord)
@@ -210,7 +218,11 @@ public class DomainService
await Client.Zones.DnsRecords.DeleteAsync(domain.SharedDomain.CloudflareId, dnsRecord.Id)
);
await AuditLogService.Log(AuditLogType.DeleteDomainRecord, new[] { d.Id.ToString(), dnsRecord.Name });
await AuditLogService.Log(AuditLogType.DeleteDomainRecord, x =>
{
x.Add<Domain>(d.Id);
x.Add<DnsRecord>(dnsRecord.Name);
});
}
private Domain EnsureData(Domain domain)

View File

@@ -1,4 +1,5 @@
using Moonlight.App.Database.Entities.LogsEntries;
using Moonlight.App.Models.Log;
using Moonlight.App.Models.Misc;
using Moonlight.App.Repositories.LogEntries;
using Moonlight.App.Services.Sessions;
@@ -19,16 +20,18 @@ public class AuditLogService
HttpContextAccessor = httpContextAccessor;
}
public Task Log(AuditLogType type, params object[] data)
public Task Log(AuditLogType type, Action<AuditLogParameters> data)
{
var ip = GetIp();
var al = new AuditLogParameters();
data(al);
var entry = new AuditLogEntry()
{
Ip = ip,
Type = type,
System = false,
JsonData = data.Length == 0 ? "" : JsonConvert.SerializeObject(data)
JsonData = al.Build()
};
Repository.Add(entry);
@@ -36,13 +39,16 @@ public class AuditLogService
return Task.CompletedTask;
}
public Task LogSystem(AuditLogType type, params object[] data)
public Task LogSystem(AuditLogType type, Action<AuditLogParameters> data)
{
var al = new AuditLogParameters();
data(al);
var entry = new AuditLogEntry()
{
Type = type,
System = true,
JsonData = data.Length == 0 ? "" : JsonConvert.SerializeObject(data)
JsonData = al.Build()
};
Repository.Add(entry);
@@ -62,4 +68,23 @@ public class AuditLogService
return HttpContextAccessor.HttpContext.Connection.RemoteIpAddress!.ToString();
}
public class AuditLogParameters
{
private List<LogData> Data = new List<LogData>();
public void Add<T>(object data)
{
Data.Add(new LogData()
{
Type = typeof(T),
Value = data.ToString()
});
}
internal string Build()
{
return JsonConvert.SerializeObject(Data);
}
}
}

View File

@@ -1,6 +1,7 @@
using System.Diagnostics;
using System.Reflection;
using Moonlight.App.Database.Entities.LogsEntries;
using Moonlight.App.Models.Log;
using Moonlight.App.Repositories.LogEntries;
using Moonlight.App.Services.Sessions;
using Newtonsoft.Json;
@@ -18,15 +19,17 @@ public class ErrorLogService
HttpContextAccessor = httpContextAccessor;
}
public Task Log(Exception exception, params object[] objects)
public Task Log(Exception exception, Action<ErrorLogParameters> data)
{
var ip = GetIp();
var al = new ErrorLogParameters();
data(al);
var entry = new ErrorLogEntry()
{
Ip = ip,
System = false,
JsonData = !objects.Any() ? "" : JsonConvert.SerializeObject(objects),
JsonData = al.Build(),
Class = NameOfCallingClass(),
Stacktrace = exception.ToStringDemystified()
};
@@ -36,12 +39,15 @@ public class ErrorLogService
return Task.CompletedTask;
}
public Task LogSystem(Exception exception, params object[] objects)
public Task LogSystem(Exception exception, Action<ErrorLogParameters> data)
{
var al = new ErrorLogParameters();
data(al);
var entry = new ErrorLogEntry()
{
System = true,
JsonData = !objects.Any() ? "" : JsonConvert.SerializeObject(objects),
JsonData = al.Build(),
Class = NameOfCallingClass(),
Stacktrace = exception.ToStringDemystified()
};
@@ -87,4 +93,23 @@ public class ErrorLogService
return HttpContextAccessor.HttpContext.Connection.RemoteIpAddress!.ToString();
}
public class ErrorLogParameters
{
private List<LogData> Data = new List<LogData>();
public void Add<T>(object data)
{
Data.Add(new LogData()
{
Type = typeof(T),
Value = data.ToString()
});
}
internal string Build()
{
return JsonConvert.SerializeObject(Data);
}
}
}

View File

@@ -1,4 +1,5 @@
using Moonlight.App.Database.Entities.LogsEntries;
using Moonlight.App.Models.Log;
using Moonlight.App.Models.Misc;
using Moonlight.App.Repositories.LogEntries;
using Moonlight.App.Services.Sessions;
@@ -17,16 +18,18 @@ public class SecurityLogService
HttpContextAccessor = httpContextAccessor;
}
public Task Log(SecurityLogType type, params object[] data)
public Task Log(SecurityLogType type, Action<SecurityLogParameters> data)
{
var ip = GetIp();
var al = new SecurityLogParameters();
data(al);
var entry = new SecurityLogEntry()
{
Ip = ip,
Type = type,
System = false,
JsonData = data.Length == 0 ? "" : JsonConvert.SerializeObject(data)
JsonData = al.Build()
};
Repository.Add(entry);
@@ -34,13 +37,16 @@ public class SecurityLogService
return Task.CompletedTask;
}
public Task LogSystem(SecurityLogType type, params object[] data)
public Task LogSystem(SecurityLogType type, Action<SecurityLogParameters> data)
{
var al = new SecurityLogParameters();
data(al);
var entry = new SecurityLogEntry()
{
Type = type,
System = true,
JsonData = data.Length == 0 ? "" : JsonConvert.SerializeObject(data)
JsonData = al.Build()
};
Repository.Add(entry);
@@ -60,4 +66,24 @@ public class SecurityLogService
return HttpContextAccessor.HttpContext.Connection.RemoteIpAddress!.ToString();
}
public class SecurityLogParameters
{
private List<LogData> Data = new List<LogData>();
public void Add<T>(object data)
{
Data.Add(new LogData()
{
Type = typeof(T),
Value = data.ToString()
});
}
internal string Build()
{
return JsonConvert.SerializeObject(Data);
}
}
}

View File

@@ -76,7 +76,10 @@ public class OneTimeJwtService
}
catch (SignatureVerificationException)
{
await SecurityLogService.LogSystem(SecurityLogType.ManipulatedJwt, token);
await SecurityLogService.LogSystem(SecurityLogType.ManipulatedJwt, x =>
{
x.Add<string>(token);
});
return null;
}
catch (Exception e)

View File

@@ -96,7 +96,11 @@ public class ServerService
Action = rawSignal
});
await AuditLogService.Log(AuditLogType.ChangePowerState, new[] { server.Uuid.ToString(), rawSignal });
await AuditLogService.Log(AuditLogType.ChangePowerState, x =>
{
x.Add<Server>(server.Uuid);
x.Add<PowerSignal>(rawSignal);
});
}
public async Task<ServerBackup> CreateBackup(Server server)
@@ -126,7 +130,11 @@ public class ServerService
});
await AuditLogService.Log(AuditLogType.CreateBackup,
new[] { serverData.Uuid.ToString(), backup.Uuid.ToString() });
x =>
{
x.Add<Server>(server.Uuid);
x.Add<ServerBackup>(backup.Uuid);
});
return backup;
}
@@ -164,7 +172,11 @@ public class ServerService
});
await AuditLogService.Log(AuditLogType.RestoreBackup,
new[] { s.Uuid.ToString(), serverBackup.Uuid.ToString() });
x =>
{
x.Add<Server>(server.Uuid);
x.Add<ServerBackup>(serverBackup.Uuid);
});
}
public async Task DeleteBackup(Server server, ServerBackup serverBackup)
@@ -186,7 +198,11 @@ public class ServerService
await MessageService.Emit("wings.backups.delete", backup);
await AuditLogService.Log(AuditLogType.DeleteBackup,
new[] { serverBackup.Uuid.ToString(), serverBackup.Uuid.ToString() });
x =>
{
x.Add<Server>(server.Uuid);
x.Add<ServerBackup>(backup.Uuid);
});
}
public async Task<string> DownloadBackup(Server s, ServerBackup serverBackup)
@@ -200,7 +216,11 @@ public class ServerService
});
await AuditLogService.Log(AuditLogType.DownloadBackup,
new[] { serverBackup.Uuid.ToString(), serverBackup.Uuid.ToString() });
x =>
{
x.Add<Server>(server.Uuid);
x.Add<ServerBackup>(serverBackup.Uuid);
});
return $"https://{server.Node.Fqdn}:{server.Node.HttpPort}/download/backup?token={token}";
}
@@ -305,13 +325,20 @@ public class ServerService
StartOnCompletion = false
});
await AuditLogService.Log(AuditLogType.CreateServer, newServerData.Uuid.ToString());
await AuditLogService.Log(AuditLogType.CreateServer, x =>
{
x.Add<Server>(newServerData.Uuid);
});
return newServerData;
}
catch (Exception e)
{
await ErrorLogService.Log(e, new[] { newServerData.Uuid.ToString(), node.Id.ToString() });
await ErrorLogService.Log(e, x =>
{
x.Add<Server>(newServerData.Uuid);
x.Add<Node>(node.Id);
});
ServerRepository.Delete(newServerData);
@@ -325,7 +352,10 @@ public class ServerService
await WingsApiHelper.Post(server.Node, $"api/servers/{server.Uuid}/reinstall", null);
await AuditLogService.Log(AuditLogType.ReinstallServer, server.Uuid.ToString());
await AuditLogService.Log(AuditLogType.ReinstallServer, x =>
{
x.Add<Server>(server.Uuid);
});
}
public async Task<Server> SftpServerLogin(int serverId, int id, string password)
@@ -334,7 +364,10 @@ public class ServerService
if (server == null)
{
await SecurityLogService.LogSystem(SecurityLogType.SftpBruteForce, serverId);
await SecurityLogService.LogSystem(SecurityLogType.SftpBruteForce, x =>
{
x.Add<int>(id);
});
throw new Exception("Server not found");
}

View File

@@ -89,12 +89,15 @@ public class IdentityService
}
catch (SignatureVerificationException)
{
await SecurityLogService.Log(SecurityLogType.ManipulatedJwt, token);
await SecurityLogService.Log(SecurityLogType.ManipulatedJwt, x =>
{
x.Add<string>(token);
});
return null;
}
catch (Exception e)
{
await ErrorLogService.Log(e);
await ErrorLogService.Log(e, x => {});
return null;
}
@@ -130,7 +133,7 @@ public class IdentityService
}
catch (Exception e)
{
await ErrorLogService.Log(e);
await ErrorLogService.Log(e, x => {});
return null;
}
}

View File

@@ -1,4 +1,5 @@
using Moonlight.App.Models.Misc;
using Moonlight.App.Database.Entities;
using Moonlight.App.Models.Misc;
using Moonlight.App.Repositories;
using Moonlight.App.Services.LogServices;
using Moonlight.App.Services.Sessions;
@@ -51,7 +52,10 @@ public class TotpService
UserRepository.Update(user);
await AuditLogService.Log(AuditLogType.EnableTotp, user.Email);
await AuditLogService.Log(AuditLogType.EnableTotp, x =>
{
x.Add<User>(user.Email);
});
}
public async Task EnforceTotpLogin()
@@ -70,7 +74,10 @@ public class TotpService
UserRepository.Update(user);
await AuditLogService.Log(AuditLogType.DisableTotp, user.Email);
await AuditLogService.Log(AuditLogType.DisableTotp,x =>
{
x.Add<User>(user.Email);
});
}
private string GenerateSecret()

View File

@@ -77,7 +77,10 @@ public class UserService
});
await MailService.SendMail(user!, "register", values => {});
await AuditLogService.Log(AuditLogType.Register, user.Email);
await AuditLogService.Log(AuditLogType.Register, x =>
{
x.Add<User>(user.Email);
});
return await GenerateToken(user);
}
@@ -91,7 +94,11 @@ public class UserService
if (user == null)
{
await SecurityLogService.Log(SecurityLogType.LoginFail, new[] { email, password });
await SecurityLogService.Log(SecurityLogType.LoginFail, x =>
{
x.Add<User>(email);
x.Add<string>(password);
});
throw new DisplayException("Email and password combination not found");
}
@@ -100,7 +107,11 @@ public class UserService
return user.TotpEnabled;
}
await SecurityLogService.Log(SecurityLogType.LoginFail, new[] { email, password });
await SecurityLogService.Log(SecurityLogType.LoginFail, x =>
{
x.Add<User>(email);
x.Add<string>(password);
});
throw new DisplayException("Email and password combination not found");;
}
@@ -125,18 +136,28 @@ public class UserService
if (totpCodeValid)
{
await AuditLogService.Log(AuditLogType.Login, email);
await AuditLogService.Log(AuditLogType.Login, x =>
{
x.Add<User>(email);
});
return await GenerateToken(user, true);
}
else
{
await SecurityLogService.Log(SecurityLogType.LoginFail, new[] { email, password });
await SecurityLogService.Log(SecurityLogType.LoginFail, x =>
{
x.Add<User>(email);
x.Add<string>(password);
});
throw new DisplayException("2FA code invalid");
}
}
else
{
await AuditLogService.Log(AuditLogType.Login, email);
await AuditLogService.Log(AuditLogType.Login, x =>
{
x.Add<User>(email);
});
return await GenerateToken(user!, true);
}
}
@@ -149,7 +170,10 @@ public class UserService
if (isSystemAction)
{
await AuditLogService.LogSystem(AuditLogType.ChangePassword, user.Email);
await AuditLogService.LogSystem(AuditLogType.ChangePassword, x=>
{
x.Add<User>(user.Email);
});
}
else
{
@@ -160,7 +184,10 @@ public class UserService
values.Add("Location", "In your walls");
});
await AuditLogService.Log(AuditLogType.ChangePassword, user.Email);
await AuditLogService.Log(AuditLogType.ChangePassword, x =>
{
x.Add<User>(user.Email);
});
}
}
@@ -170,17 +197,27 @@ public class UserService
if (user == null)
{
await SecurityLogService.LogSystem(SecurityLogType.SftpBruteForce, id);
await SecurityLogService.LogSystem(SecurityLogType.SftpBruteForce, x =>
{
x.Add<int>(id);
});
throw new Exception("Invalid username");
}
if (BCrypt.Net.BCrypt.Verify(password, user.Password))
{
await AuditLogService.LogSystem(AuditLogType.Login, user.Email);
await AuditLogService.LogSystem(AuditLogType.Login, x =>
{
x.Add<User>(user.Email);
});
return user;
}
await SecurityLogService.LogSystem(SecurityLogType.SftpBruteForce, new[] { id.ToString(), password });
await SecurityLogService.LogSystem(SecurityLogType.SftpBruteForce, x =>
{
x.Add<int>(id);
x.Add<string>(password);
});
throw new Exception("Invalid userid or password");
}
@@ -218,7 +255,7 @@ public class UserService
var newPassword = StringHelper.GenerateString(16);
await ChangePassword(user, newPassword, true);
await AuditLogService.Log(AuditLogType.PasswordReset);
await AuditLogService.Log(AuditLogType.PasswordReset, x => {});
await MailService.SendMail(user, "passwordReset", values =>
{