Clean code Reverse
This commit is contained in:
1
MareAPI
1
MareAPI
Submodule MareAPI deleted from fa9b7bce43
@@ -1,4 +0,0 @@
|
|||||||
[*.cs]
|
|
||||||
|
|
||||||
# MA0048: File name must match type name
|
|
||||||
dotnet_diagnostic.MA0048.severity = suggestion
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
namespace MareSynchronosAuthService.Authentication;
|
|
||||||
|
|
||||||
public record SecretKeyAuthReply(bool Success, string Uid, string Alias, bool TempBan, bool Permaban);
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
namespace MareSynchronosAuthService.Authentication;
|
|
||||||
|
|
||||||
internal record SecretKeyFailedAuthorization
|
|
||||||
{
|
|
||||||
private int failedAttempts = 1;
|
|
||||||
public int FailedAttempts => failedAttempts;
|
|
||||||
public Task ResetTask { get; set; }
|
|
||||||
public void IncreaseFailedAttempts()
|
|
||||||
{
|
|
||||||
Interlocked.Increment(ref failedAttempts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,174 +0,0 @@
|
|||||||
using System.Text.Json.Serialization;
|
|
||||||
using MareSynchronosAuthService.Services;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace MareSynchronosAuthService.Controllers;
|
|
||||||
|
|
||||||
[Authorize]
|
|
||||||
[ApiController]
|
|
||||||
[Route("discovery")]
|
|
||||||
public class DiscoveryController : Controller
|
|
||||||
{
|
|
||||||
private readonly DiscoveryWellKnownProvider _provider;
|
|
||||||
private readonly DiscoveryPresenceService _presence;
|
|
||||||
|
|
||||||
public DiscoveryController(DiscoveryWellKnownProvider provider, DiscoveryPresenceService presence)
|
|
||||||
{
|
|
||||||
_provider = provider;
|
|
||||||
_presence = presence;
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class QueryRequest
|
|
||||||
{
|
|
||||||
[JsonPropertyName("hashes")] public string[] Hashes { get; set; } = Array.Empty<string>();
|
|
||||||
[JsonPropertyName("salt")] public string SaltB64 { get; set; } = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class QueryResponseEntry
|
|
||||||
{
|
|
||||||
[JsonPropertyName("hash")] public string Hash { get; set; } = string.Empty;
|
|
||||||
[JsonPropertyName("token")] public string? Token { get; set; }
|
|
||||||
[JsonPropertyName("uid")] public string Uid { get; set; } = string.Empty;
|
|
||||||
[JsonPropertyName("displayName")] public string? DisplayName { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("query")]
|
|
||||||
public IActionResult Query([FromBody] QueryRequest req)
|
|
||||||
{
|
|
||||||
if (_provider.IsExpired(req.SaltB64))
|
|
||||||
{
|
|
||||||
return BadRequest(new { code = "DISCOVERY_SALT_EXPIRED" });
|
|
||||||
}
|
|
||||||
|
|
||||||
var uid = User?.Claims?.FirstOrDefault(c => c.Type == MareSynchronosShared.Utils.MareClaimTypes.Uid)?.Value ?? string.Empty;
|
|
||||||
if (string.IsNullOrEmpty(uid) || req?.Hashes == null || req.Hashes.Length == 0)
|
|
||||||
return Json(Array.Empty<QueryResponseEntry>());
|
|
||||||
|
|
||||||
List<QueryResponseEntry> matches = new();
|
|
||||||
foreach (var h in req.Hashes.Distinct(StringComparer.Ordinal))
|
|
||||||
{
|
|
||||||
var (found, token, targetUid, displayName) = _presence.TryMatchAndIssueToken(uid, h);
|
|
||||||
if (found)
|
|
||||||
{
|
|
||||||
matches.Add(new QueryResponseEntry { Hash = h, Token = token, Uid = targetUid, DisplayName = displayName });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Json(matches);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class RequestDto
|
|
||||||
{
|
|
||||||
[JsonPropertyName("token")] public string Token { get; set; } = string.Empty;
|
|
||||||
[JsonPropertyName("displayName")] public string? DisplayName { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("request")]
|
|
||||||
public async Task<IActionResult> RequestPair([FromBody] RequestDto req)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(req.Token)) return BadRequest();
|
|
||||||
if (_presence.ValidateToken(req.Token, out var targetUid))
|
|
||||||
{
|
|
||||||
// Phase 3 (minimal): notify target via mare-server internal controller
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var fromUid = User?.Claims?.FirstOrDefault(c => c.Type == MareSynchronosShared.Utils.MareClaimTypes.Uid)?.Value ?? string.Empty;
|
|
||||||
var fromAlias = string.IsNullOrEmpty(req.DisplayName)
|
|
||||||
? (User?.Claims?.FirstOrDefault(c => c.Type == MareSynchronosShared.Utils.MareClaimTypes.Alias)?.Value ?? string.Empty)
|
|
||||||
: req.DisplayName;
|
|
||||||
|
|
||||||
using var http = new HttpClient();
|
|
||||||
// Use same host as public (goes through nginx)
|
|
||||||
var baseUrl = $"{Request.Scheme}://{Request.Host.Value}";
|
|
||||||
var url = new Uri(new Uri(baseUrl), "/main/discovery/notifyRequest");
|
|
||||||
|
|
||||||
// Generate internal JWT
|
|
||||||
var serverToken = HttpContext.RequestServices.GetRequiredService<MareSynchronosShared.Utils.ServerTokenGenerator>().Token;
|
|
||||||
http.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", serverToken);
|
|
||||||
var payload = System.Text.Json.JsonSerializer.Serialize(new { targetUid, fromUid, fromAlias });
|
|
||||||
var resp = await http.PostAsync(url, new StringContent(payload, System.Text.Encoding.UTF8, "application/json"));
|
|
||||||
if (!resp.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
var txt = await resp.Content.ReadAsStringAsync();
|
|
||||||
HttpContext.RequestServices.GetRequiredService<ILogger<DiscoveryController>>()
|
|
||||||
.LogWarning("notifyRequest failed: {code} {reason} {body}", (int)resp.StatusCode, resp.ReasonPhrase, txt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { /* ignore */ }
|
|
||||||
|
|
||||||
return Accepted();
|
|
||||||
}
|
|
||||||
return BadRequest(new { code = "INVALID_TOKEN" });
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class AcceptNotifyDto
|
|
||||||
{
|
|
||||||
[JsonPropertyName("targetUid")] public string TargetUid { get; set; } = string.Empty;
|
|
||||||
[JsonPropertyName("displayName")] public string? DisplayName { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept notification relay (sender -> auth -> main)
|
|
||||||
[HttpPost("acceptNotify")]
|
|
||||||
public async Task<IActionResult> AcceptNotify([FromBody] AcceptNotifyDto req)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(req.TargetUid)) return BadRequest();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var fromUid = User?.Claims?.FirstOrDefault(c => c.Type == MareSynchronosShared.Utils.MareClaimTypes.Uid)?.Value ?? string.Empty;
|
|
||||||
var fromAlias = string.IsNullOrEmpty(req.DisplayName)
|
|
||||||
? (User?.Claims?.FirstOrDefault(c => c.Type == MareSynchronosShared.Utils.MareClaimTypes.Alias)?.Value ?? string.Empty)
|
|
||||||
: req.DisplayName;
|
|
||||||
|
|
||||||
using var http = new HttpClient();
|
|
||||||
var baseUrl = $"{Request.Scheme}://{Request.Host.Value}";
|
|
||||||
var url = new Uri(new Uri(baseUrl), "/main/discovery/notifyAccept");
|
|
||||||
var serverToken = HttpContext.RequestServices.GetRequiredService<MareSynchronosShared.Utils.ServerTokenGenerator>().Token;
|
|
||||||
http.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", serverToken);
|
|
||||||
var payload = System.Text.Json.JsonSerializer.Serialize(new { targetUid = req.TargetUid, fromUid, fromAlias });
|
|
||||||
var resp = await http.PostAsync(url, new StringContent(payload, System.Text.Encoding.UTF8, "application/json"));
|
|
||||||
if (!resp.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
var txt = await resp.Content.ReadAsStringAsync();
|
|
||||||
HttpContext.RequestServices.GetRequiredService<ILogger<DiscoveryController>>()
|
|
||||||
.LogWarning("notifyAccept failed: {code} {reason} {body}", (int)resp.StatusCode, resp.ReasonPhrase, txt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { /* ignore */ }
|
|
||||||
|
|
||||||
return Accepted();
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class PublishRequest
|
|
||||||
{
|
|
||||||
[JsonPropertyName("hashes")] public string[] Hashes { get; set; } = Array.Empty<string>();
|
|
||||||
[JsonPropertyName("displayName")] public string? DisplayName { get; set; }
|
|
||||||
[JsonPropertyName("salt")] public string SaltB64 { get; set; } = string.Empty;
|
|
||||||
[JsonPropertyName("allowRequests")] public bool AllowRequests { get; set; } = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("disable")]
|
|
||||||
public IActionResult Disable()
|
|
||||||
{
|
|
||||||
var uid = User?.Claims?.FirstOrDefault(c => c.Type == MareSynchronosShared.Utils.MareClaimTypes.Uid)?.Value ?? string.Empty;
|
|
||||||
if (string.IsNullOrEmpty(uid)) return Accepted();
|
|
||||||
_presence.Unpublish(uid);
|
|
||||||
return Accepted();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("publish")]
|
|
||||||
public IActionResult Publish([FromBody] PublishRequest req)
|
|
||||||
{
|
|
||||||
if (_provider.IsExpired(req.SaltB64))
|
|
||||||
{
|
|
||||||
return BadRequest(new { code = "DISCOVERY_SALT_EXPIRED" });
|
|
||||||
}
|
|
||||||
var uid = User?.Claims?.FirstOrDefault(c => c.Type == MareSynchronosShared.Utils.MareClaimTypes.Uid)?.Value ?? string.Empty;
|
|
||||||
if (string.IsNullOrEmpty(uid) || req?.Hashes == null || req.Hashes.Length == 0)
|
|
||||||
return Accepted();
|
|
||||||
|
|
||||||
_presence.Publish(uid, req.Hashes, req.DisplayName, req.AllowRequests);
|
|
||||||
return Accepted();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
using MareSynchronos.API.Dto;
|
|
||||||
using MareSynchronos.API.Dto.Account;
|
|
||||||
using MareSynchronos.API.Routes;
|
|
||||||
using MareSynchronosAuthService.Services;
|
|
||||||
using MareSynchronosShared;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using MareSynchronosShared.Models;
|
|
||||||
using MareSynchronosShared.Services;
|
|
||||||
using MareSynchronosShared.Utils;
|
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.IdentityModel.Tokens;
|
|
||||||
using StackExchange.Redis.Extensions.Core.Abstractions;
|
|
||||||
using System.IdentityModel.Tokens.Jwt;
|
|
||||||
using System.Security.Claims;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace MareSynchronosAuthService.Controllers;
|
|
||||||
|
|
||||||
[AllowAnonymous]
|
|
||||||
[Route(MareAuth.Auth)]
|
|
||||||
public class JwtController : Controller
|
|
||||||
{
|
|
||||||
private readonly IHttpContextAccessor _accessor;
|
|
||||||
private readonly IRedisDatabase _redis;
|
|
||||||
private readonly IDbContextFactory<MareDbContext> _mareDbContextFactory;
|
|
||||||
private readonly GeoIPService _geoIPProvider;
|
|
||||||
private readonly SecretKeyAuthenticatorService _secretKeyAuthenticatorService;
|
|
||||||
private readonly AccountRegistrationService _accountRegistrationService;
|
|
||||||
private readonly IConfigurationService<AuthServiceConfiguration> _configuration;
|
|
||||||
|
|
||||||
public JwtController(ILogger<JwtController> logger,
|
|
||||||
IHttpContextAccessor accessor, IDbContextFactory<MareDbContext> mareDbContextFactory,
|
|
||||||
SecretKeyAuthenticatorService secretKeyAuthenticatorService,
|
|
||||||
AccountRegistrationService accountRegistrationService,
|
|
||||||
IConfigurationService<AuthServiceConfiguration> configuration,
|
|
||||||
IRedisDatabase redisDb, GeoIPService geoIPProvider)
|
|
||||||
{
|
|
||||||
_accessor = accessor;
|
|
||||||
_redis = redisDb;
|
|
||||||
_geoIPProvider = geoIPProvider;
|
|
||||||
_mareDbContextFactory = mareDbContextFactory;
|
|
||||||
_secretKeyAuthenticatorService = secretKeyAuthenticatorService;
|
|
||||||
_accountRegistrationService = accountRegistrationService;
|
|
||||||
_configuration = configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
[AllowAnonymous]
|
|
||||||
[HttpPost(MareAuth.Auth_CreateIdent)]
|
|
||||||
public async Task<IActionResult> CreateToken(string auth, string charaIdent)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(auth)) return BadRequest("No Authkey");
|
|
||||||
if (string.IsNullOrEmpty(charaIdent)) return BadRequest("No CharaIdent");
|
|
||||||
|
|
||||||
using var dbContext = await _mareDbContextFactory.CreateDbContextAsync();
|
|
||||||
var ip = _accessor.GetIpAddress();
|
|
||||||
|
|
||||||
var authResult = await _secretKeyAuthenticatorService.AuthorizeAsync(ip, auth);
|
|
||||||
|
|
||||||
var isBanned = await dbContext.BannedUsers.AsNoTracking().AnyAsync(u => u.CharacterIdentification == charaIdent).ConfigureAwait(false);
|
|
||||||
if (isBanned)
|
|
||||||
{
|
|
||||||
var authToBan = dbContext.Auth.SingleOrDefault(a => a.UserUID == authResult.Uid);
|
|
||||||
if (authToBan != null)
|
|
||||||
{
|
|
||||||
authToBan.IsBanned = true;
|
|
||||||
await dbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Unauthorized("Your character is banned from using the service.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!authResult.Success && !authResult.TempBan) return Unauthorized("The provided secret key is invalid. Verify your accounts existence and/or recover the secret key.");
|
|
||||||
if (!authResult.Success && authResult.TempBan) return Unauthorized("Due to an excessive amount of failed authentication attempts you are temporarily banned. Check your Secret Key configuration and try connecting again in 5 minutes.");
|
|
||||||
if (authResult.Permaban)
|
|
||||||
{
|
|
||||||
if (!dbContext.BannedUsers.Any(c => c.CharacterIdentification == charaIdent))
|
|
||||||
{
|
|
||||||
dbContext.BannedUsers.Add(new Banned()
|
|
||||||
{
|
|
||||||
CharacterIdentification = charaIdent,
|
|
||||||
Reason = "Autobanned CharacterIdent (" + authResult.Uid + ")",
|
|
||||||
});
|
|
||||||
|
|
||||||
await dbContext.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
var lodestone = await dbContext.LodeStoneAuth.Include(a => a.User).FirstOrDefaultAsync(c => c.User.UID == authResult.Uid);
|
|
||||||
|
|
||||||
if (lodestone != null)
|
|
||||||
{
|
|
||||||
if (!dbContext.BannedRegistrations.Any(c => c.DiscordIdOrLodestoneAuth == lodestone.HashedLodestoneId))
|
|
||||||
{
|
|
||||||
dbContext.BannedRegistrations.Add(new BannedRegistrations()
|
|
||||||
{
|
|
||||||
DiscordIdOrLodestoneAuth = lodestone.HashedLodestoneId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (!dbContext.BannedRegistrations.Any(c => c.DiscordIdOrLodestoneAuth == lodestone.DiscordId.ToString()))
|
|
||||||
{
|
|
||||||
dbContext.BannedRegistrations.Add(new BannedRegistrations()
|
|
||||||
{
|
|
||||||
DiscordIdOrLodestoneAuth = lodestone.DiscordId.ToString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
await dbContext.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Unauthorized("You are permanently banned.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var existingIdent = await _redis.GetAsync<string>("UID:" + authResult.Uid);
|
|
||||||
if (!string.IsNullOrEmpty(existingIdent) && !string.Equals(existingIdent, charaIdent, StringComparison.Ordinal))
|
|
||||||
return Unauthorized("Already logged in to this account. Reconnect in 60 seconds. If you keep seeing this issue, restart your game.");
|
|
||||||
|
|
||||||
var token = CreateToken(new List<Claim>()
|
|
||||||
{
|
|
||||||
new Claim(MareClaimTypes.Uid, authResult.Uid),
|
|
||||||
new Claim(MareClaimTypes.CharaIdent, charaIdent),
|
|
||||||
new Claim(MareClaimTypes.Alias, authResult.Alias),
|
|
||||||
new Claim(MareClaimTypes.Continent, await _geoIPProvider.GetCountryFromIP(_accessor)),
|
|
||||||
});
|
|
||||||
|
|
||||||
return Content(token.RawData);
|
|
||||||
}
|
|
||||||
|
|
||||||
[AllowAnonymous]
|
|
||||||
[HttpPost(MareAuth.Auth_CreateIdentV2)]
|
|
||||||
public async Task<IActionResult> CreateTokenV2(string auth, string charaIdent)
|
|
||||||
{
|
|
||||||
var tokenResponse = await CreateToken(auth, charaIdent);
|
|
||||||
var tokenContent = tokenResponse as ContentResult;
|
|
||||||
if (tokenContent == null)
|
|
||||||
return tokenResponse;
|
|
||||||
var provider = HttpContext.RequestServices.GetService<DiscoveryWellKnownProvider>();
|
|
||||||
var wk = provider?.GetWellKnownJson(Request.Scheme, Request.Host.Value)
|
|
||||||
?? _configuration.GetValueOrDefault(nameof(AuthServiceConfiguration.WellKnown), string.Empty);
|
|
||||||
return Json(new AuthReplyDto
|
|
||||||
{
|
|
||||||
Token = tokenContent.Content,
|
|
||||||
WellKnown = wk,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[AllowAnonymous]
|
|
||||||
[HttpPost(MareAuth.Auth_Register)]
|
|
||||||
public async Task<IActionResult> Register()
|
|
||||||
{
|
|
||||||
var ua = HttpContext.Request.Headers["User-Agent"][0] ?? "-";
|
|
||||||
var ip = _accessor.GetIpAddress();
|
|
||||||
|
|
||||||
// Legacy endpoint: generate a secret key for the user
|
|
||||||
var computedHash = StringUtils.Sha256String(StringUtils.GenerateRandomString(64) + DateTime.UtcNow.ToString());
|
|
||||||
var hashedKey = StringUtils.Sha256String(computedHash);
|
|
||||||
|
|
||||||
var dto = await _accountRegistrationService.RegisterAccountAsync(ua, ip, hashedKey);
|
|
||||||
|
|
||||||
return Json(new RegisterReplyDto()
|
|
||||||
{
|
|
||||||
Success = dto.Success,
|
|
||||||
ErrorMessage = dto.ErrorMessage,
|
|
||||||
UID = dto.UID,
|
|
||||||
SecretKey = computedHash
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
[AllowAnonymous]
|
|
||||||
[HttpPost(MareAuth.Auth_RegisterV2)]
|
|
||||||
public async Task<IActionResult> RegisterV2(string hashedSecretKey)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(hashedSecretKey)) return BadRequest("No HashedSecretKey");
|
|
||||||
if (hashedSecretKey.Length != 64) return BadRequest("Bad HashedSecretKey");
|
|
||||||
if (!hashedSecretKey.All(char.IsAsciiHexDigitUpper)) return BadRequest("Bad HashedSecretKey");
|
|
||||||
|
|
||||||
var ua = HttpContext.Request.Headers["User-Agent"][0] ?? "-";
|
|
||||||
var ip = _accessor.GetIpAddress();
|
|
||||||
return Json(await _accountRegistrationService.RegisterAccountAsync(ua, ip, hashedSecretKey));
|
|
||||||
}
|
|
||||||
|
|
||||||
private JwtSecurityToken CreateToken(IEnumerable<Claim> authClaims)
|
|
||||||
{
|
|
||||||
var authSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_configuration.GetValue<string>(nameof(MareConfigurationBase.Jwt))));
|
|
||||||
|
|
||||||
var token = new SecurityTokenDescriptor()
|
|
||||||
{
|
|
||||||
Subject = new ClaimsIdentity(authClaims),
|
|
||||||
SigningCredentials = new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256Signature),
|
|
||||||
};
|
|
||||||
|
|
||||||
var handler = new JwtSecurityTokenHandler();
|
|
||||||
return handler.CreateJwtSecurityToken(token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
using MareSynchronosAuthService.Services;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace MareSynchronosAuthService.Controllers;
|
|
||||||
|
|
||||||
[AllowAnonymous]
|
|
||||||
[ApiController]
|
|
||||||
public class WellKnownController : Controller
|
|
||||||
{
|
|
||||||
private readonly DiscoveryWellKnownProvider _provider;
|
|
||||||
|
|
||||||
public WellKnownController(DiscoveryWellKnownProvider provider)
|
|
||||||
{
|
|
||||||
_provider = provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("/.well-known/Umbra/client")]
|
|
||||||
public IActionResult Get()
|
|
||||||
{
|
|
||||||
var json = _provider.GetWellKnownJson(Request.Scheme, Request.Host.Value);
|
|
||||||
return Content(json, "application/json");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<EnableDefaultContentItems>false</EnableDefaultContentItems>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Include="appsettings.Development.json">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="appsettings.json">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="IDisposableAnalyzers" Version="4.0.8">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.212">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="MaxMind.GeoIP2" Version="5.3.0" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.1" />
|
|
||||||
<PackageReference Include="StackExchange.Redis" Version="2.9.11" />
|
|
||||||
<PackageReference Include="StackExchange.Redis.Extensions.Core" Version="10.2.0" />
|
|
||||||
<PackageReference Include="StackExchange.Redis.Extensions.System.Text.Json" Version="10.2.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\MareSynchronosShared\MareSynchronosShared.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
namespace MareSynchronosAuthService;
|
|
||||||
|
|
||||||
public class Program
|
|
||||||
{
|
|
||||||
public static void Main(string[] args)
|
|
||||||
{
|
|
||||||
var hostBuilder = CreateHostBuilder(args);
|
|
||||||
using var host = hostBuilder.Build();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
host.Run();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IHostBuilder CreateHostBuilder(string[] args)
|
|
||||||
{
|
|
||||||
using var loggerFactory = LoggerFactory.Create(builder =>
|
|
||||||
{
|
|
||||||
builder.ClearProviders();
|
|
||||||
builder.AddConsole();
|
|
||||||
});
|
|
||||||
var logger = loggerFactory.CreateLogger<Startup>();
|
|
||||||
return Host.CreateDefaultBuilder(args)
|
|
||||||
.UseSystemd()
|
|
||||||
.ConfigureWebHostDefaults(webBuilder =>
|
|
||||||
{
|
|
||||||
webBuilder.UseContentRoot(AppContext.BaseDirectory);
|
|
||||||
webBuilder.ConfigureLogging((ctx, builder) =>
|
|
||||||
{
|
|
||||||
builder.AddConfiguration(ctx.Configuration.GetSection("Logging"));
|
|
||||||
builder.AddFile(o => o.RootPath = AppContext.BaseDirectory);
|
|
||||||
});
|
|
||||||
webBuilder.UseStartup(ctx => new Startup(ctx.Configuration, logger));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
|
||||||
"iisSettings": {
|
|
||||||
"windowsAuthentication": false,
|
|
||||||
"anonymousAuthentication": true,
|
|
||||||
"iisExpress": {
|
|
||||||
"applicationUrl": "http://localhost:37726",
|
|
||||||
"sslPort": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"profiles": {
|
|
||||||
"http": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"dotnetRunMessages": true,
|
|
||||||
"launchBrowser": true,
|
|
||||||
"applicationUrl": "http://localhost:5056",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IIS Express": {
|
|
||||||
"commandName": "IISExpress",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
using System.Collections.Concurrent;
|
|
||||||
using MareSynchronos.API.Dto.Account;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using MareSynchronosShared.Metrics;
|
|
||||||
using MareSynchronosShared.Services;
|
|
||||||
using MareSynchronosShared.Utils;
|
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using MareSynchronosShared.Models;
|
|
||||||
|
|
||||||
namespace MareSynchronosAuthService.Services;
|
|
||||||
|
|
||||||
internal record IpRegistrationCount
|
|
||||||
{
|
|
||||||
private int count = 1;
|
|
||||||
public int Count => count;
|
|
||||||
public Task ResetTask { get; set; }
|
|
||||||
public CancellationTokenSource ResetTaskCts { get; set; }
|
|
||||||
public void IncreaseCount()
|
|
||||||
{
|
|
||||||
Interlocked.Increment(ref count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AccountRegistrationService
|
|
||||||
{
|
|
||||||
private readonly MareMetrics _metrics;
|
|
||||||
private readonly MareDbContext _mareDbContext;
|
|
||||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
|
||||||
private readonly IConfigurationService<AuthServiceConfiguration> _configurationService;
|
|
||||||
private readonly ILogger<AccountRegistrationService> _logger;
|
|
||||||
private readonly ConcurrentDictionary<string, IpRegistrationCount> _registrationsPerIp = new(StringComparer.Ordinal);
|
|
||||||
|
|
||||||
private Regex _registrationUserAgentRegex = new Regex(@"^MareSynchronos/", RegexOptions.Compiled);
|
|
||||||
|
|
||||||
public AccountRegistrationService(MareMetrics metrics, MareDbContext mareDbContext,
|
|
||||||
IServiceScopeFactory serviceScopeFactory, IConfigurationService<AuthServiceConfiguration> configuration,
|
|
||||||
ILogger<AccountRegistrationService> logger)
|
|
||||||
{
|
|
||||||
_mareDbContext = mareDbContext;
|
|
||||||
_logger = logger;
|
|
||||||
_configurationService = configuration;
|
|
||||||
_metrics = metrics;
|
|
||||||
_serviceScopeFactory = serviceScopeFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<RegisterReplyV2Dto> RegisterAccountAsync(string ua, string ip, string hashedSecretKey)
|
|
||||||
{
|
|
||||||
var reply = new RegisterReplyV2Dto();
|
|
||||||
|
|
||||||
if (!_registrationUserAgentRegex.Match(ua).Success)
|
|
||||||
{
|
|
||||||
reply.ErrorMessage = "User-Agent not allowed";
|
|
||||||
return reply;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_registrationsPerIp.TryGetValue(ip, out var registrationCount)
|
|
||||||
&& registrationCount.Count >= _configurationService.GetValueOrDefault(nameof(AuthServiceConfiguration.RegisterIpLimit), 3))
|
|
||||||
{
|
|
||||||
_logger.LogWarning("Rejecting {ip} for registration spam", ip);
|
|
||||||
|
|
||||||
if (registrationCount.ResetTask == null)
|
|
||||||
{
|
|
||||||
registrationCount.ResetTaskCts = new CancellationTokenSource();
|
|
||||||
|
|
||||||
if (registrationCount.ResetTaskCts != null)
|
|
||||||
registrationCount.ResetTaskCts.Cancel();
|
|
||||||
|
|
||||||
registrationCount.ResetTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await Task.Delay(TimeSpan.FromMinutes(_configurationService.GetValueOrDefault(nameof(AuthServiceConfiguration.RegisterIpDurationInMinutes), 10))).ConfigureAwait(false);
|
|
||||||
|
|
||||||
}).ContinueWith((t) =>
|
|
||||||
{
|
|
||||||
_registrationsPerIp.Remove(ip, out _);
|
|
||||||
}, registrationCount.ResetTaskCts.Token);
|
|
||||||
}
|
|
||||||
reply.ErrorMessage = "Too many registrations from this IP. Please try again later.";
|
|
||||||
return reply;
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = new User();
|
|
||||||
|
|
||||||
var hasValidUid = false;
|
|
||||||
while (!hasValidUid)
|
|
||||||
{
|
|
||||||
var uid = StringUtils.GenerateRandomString(7);
|
|
||||||
if (_mareDbContext.Users.Any(u => u.UID == uid || u.Alias == uid)) continue;
|
|
||||||
user.UID = uid;
|
|
||||||
hasValidUid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make the first registered user on the service to admin
|
|
||||||
if (!await _mareDbContext.Users.AnyAsync().ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
user.IsAdmin = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
user.LastLoggedIn = DateTime.UtcNow;
|
|
||||||
|
|
||||||
var auth = new Auth()
|
|
||||||
{
|
|
||||||
HashedKey = hashedSecretKey,
|
|
||||||
User = user,
|
|
||||||
};
|
|
||||||
|
|
||||||
await _mareDbContext.Users.AddAsync(user).ConfigureAwait(false);
|
|
||||||
await _mareDbContext.Auth.AddAsync(auth).ConfigureAwait(false);
|
|
||||||
await _mareDbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogInformation("User registered: {userUID} from IP {ip}", user.UID, ip);
|
|
||||||
_metrics.IncCounter(MetricsAPI.CounterAccountsCreated);
|
|
||||||
|
|
||||||
reply.Success = true;
|
|
||||||
reply.UID = user.UID;
|
|
||||||
|
|
||||||
RecordIpRegistration(ip);
|
|
||||||
|
|
||||||
return reply;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RecordIpRegistration(string ip)
|
|
||||||
{
|
|
||||||
var whitelisted = _configurationService.GetValueOrDefault(nameof(AuthServiceConfiguration.WhitelistedIps), new List<string>());
|
|
||||||
if (!whitelisted.Any(w => ip.Contains(w, StringComparison.OrdinalIgnoreCase)))
|
|
||||||
{
|
|
||||||
if (_registrationsPerIp.TryGetValue(ip, out var count))
|
|
||||||
{
|
|
||||||
count.IncreaseCount();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
count = _registrationsPerIp[ip] = new IpRegistrationCount();
|
|
||||||
|
|
||||||
if (count.ResetTaskCts != null)
|
|
||||||
count.ResetTaskCts.Cancel();
|
|
||||||
|
|
||||||
count.ResetTaskCts = new CancellationTokenSource();
|
|
||||||
|
|
||||||
count.ResetTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await Task.Delay(TimeSpan.FromMinutes(_configurationService.GetValueOrDefault(nameof(AuthServiceConfiguration.RegisterIpDurationInMinutes), 10))).ConfigureAwait(false);
|
|
||||||
|
|
||||||
}).ContinueWith((t) =>
|
|
||||||
{
|
|
||||||
_registrationsPerIp.Remove(ip, out _);
|
|
||||||
}, count.ResetTaskCts.Token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using System.Collections.Concurrent;
|
|
||||||
|
|
||||||
namespace MareSynchronosAuthService.Services.Discovery;
|
|
||||||
|
|
||||||
public interface IDiscoveryPresenceStore : IDisposable
|
|
||||||
{
|
|
||||||
void Publish(string uid, IEnumerable<string> hashes, string? displayName = null, bool allowRequests = true);
|
|
||||||
void Unpublish(string uid);
|
|
||||||
(bool Found, string? Token, string TargetUid, string? DisplayName) TryMatchAndIssueToken(string requesterUid, string hash);
|
|
||||||
bool ValidateToken(string token, out string targetUid);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
using System.Collections.Concurrent;
|
|
||||||
|
|
||||||
namespace MareSynchronosAuthService.Services.Discovery;
|
|
||||||
|
|
||||||
public sealed class InMemoryPresenceStore : IDiscoveryPresenceStore
|
|
||||||
{
|
|
||||||
private readonly ConcurrentDictionary<string, (string Uid, DateTimeOffset ExpiresAt, string? DisplayName, bool AllowRequests)> _presence = new(StringComparer.Ordinal);
|
|
||||||
private readonly ConcurrentDictionary<string, (string TargetUid, DateTimeOffset ExpiresAt)> _tokens = new(StringComparer.Ordinal);
|
|
||||||
private readonly TimeSpan _presenceTtl;
|
|
||||||
private readonly TimeSpan _tokenTtl;
|
|
||||||
private readonly Timer _cleanupTimer;
|
|
||||||
|
|
||||||
public InMemoryPresenceStore(TimeSpan presenceTtl, TimeSpan tokenTtl)
|
|
||||||
{
|
|
||||||
_presenceTtl = presenceTtl;
|
|
||||||
_tokenTtl = tokenTtl;
|
|
||||||
_cleanupTimer = new Timer(_ => Cleanup(), null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_cleanupTimer.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Cleanup()
|
|
||||||
{
|
|
||||||
var now = DateTimeOffset.UtcNow;
|
|
||||||
foreach (var kv in _presence.ToArray())
|
|
||||||
{
|
|
||||||
if (kv.Value.ExpiresAt <= now) _presence.TryRemove(kv.Key, out _);
|
|
||||||
}
|
|
||||||
foreach (var kv in _tokens.ToArray())
|
|
||||||
{
|
|
||||||
if (kv.Value.ExpiresAt <= now) _tokens.TryRemove(kv.Key, out _);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Publish(string uid, IEnumerable<string> hashes, string? displayName = null, bool allowRequests = true)
|
|
||||||
{
|
|
||||||
var exp = DateTimeOffset.UtcNow.Add(_presenceTtl);
|
|
||||||
foreach (var h in hashes.Distinct(StringComparer.Ordinal))
|
|
||||||
{
|
|
||||||
_presence[h] = (uid, exp, displayName, allowRequests);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Unpublish(string uid)
|
|
||||||
{
|
|
||||||
// Remove all presence hashes owned by this uid
|
|
||||||
foreach (var kv in _presence.ToArray())
|
|
||||||
{
|
|
||||||
if (string.Equals(kv.Value.Uid, uid, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
_presence.TryRemove(kv.Key, out _);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public (bool Found, string? Token, string TargetUid, string? DisplayName) TryMatchAndIssueToken(string requesterUid, string hash)
|
|
||||||
{
|
|
||||||
if (_presence.TryGetValue(hash, out var entry))
|
|
||||||
{
|
|
||||||
// Refresh TTL for this presence whenever it is matched (regardless of AllowRequests)
|
|
||||||
var refreshed = (entry.Uid, DateTimeOffset.UtcNow.Add(_presenceTtl), entry.DisplayName, entry.AllowRequests);
|
|
||||||
_presence[hash] = refreshed;
|
|
||||||
|
|
||||||
if (string.Equals(entry.Uid, requesterUid, StringComparison.Ordinal))
|
|
||||||
return (false, null, string.Empty, null);
|
|
||||||
|
|
||||||
// Visible but requests disabled → no token
|
|
||||||
if (!entry.AllowRequests)
|
|
||||||
return (true, null, entry.Uid, entry.DisplayName);
|
|
||||||
|
|
||||||
var token = Guid.NewGuid().ToString("N");
|
|
||||||
_tokens[token] = (entry.Uid, DateTimeOffset.UtcNow.Add(_tokenTtl));
|
|
||||||
return (true, token, entry.Uid, entry.DisplayName);
|
|
||||||
}
|
|
||||||
return (false, null, string.Empty, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ValidateToken(string token, out string targetUid)
|
|
||||||
{
|
|
||||||
targetUid = string.Empty;
|
|
||||||
if (_tokens.TryGetValue(token, out var info))
|
|
||||||
{
|
|
||||||
if (info.ExpiresAt > DateTimeOffset.UtcNow)
|
|
||||||
{
|
|
||||||
targetUid = info.TargetUid;
|
|
||||||
|
|
||||||
// Optional robustness: refresh TTL for all presence entries of this target
|
|
||||||
var newExp = DateTimeOffset.UtcNow.Add(_presenceTtl);
|
|
||||||
foreach (var kv in _presence.ToArray())
|
|
||||||
{
|
|
||||||
if (string.Equals(kv.Value.Uid, targetUid, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
var v = kv.Value;
|
|
||||||
_presence[kv.Key] = (v.Uid, newExp, v.DisplayName, v.AllowRequests);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
_tokens.TryRemove(token, out _);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
using System.Text.Json;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using StackExchange.Redis;
|
|
||||||
|
|
||||||
namespace MareSynchronosAuthService.Services.Discovery;
|
|
||||||
|
|
||||||
public sealed class RedisPresenceStore : IDiscoveryPresenceStore
|
|
||||||
{
|
|
||||||
private readonly ILogger<RedisPresenceStore> _logger;
|
|
||||||
private readonly IDatabase _db;
|
|
||||||
private readonly TimeSpan _presenceTtl;
|
|
||||||
private readonly TimeSpan _tokenTtl;
|
|
||||||
private readonly JsonSerializerOptions _jsonOpts = new() { DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull };
|
|
||||||
|
|
||||||
public RedisPresenceStore(ILogger<RedisPresenceStore> logger, IConnectionMultiplexer mux, TimeSpan presenceTtl, TimeSpan tokenTtl)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_db = mux.GetDatabase();
|
|
||||||
_presenceTtl = presenceTtl;
|
|
||||||
_tokenTtl = tokenTtl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose() { }
|
|
||||||
|
|
||||||
private static string KeyForHash(string hash) => $"nd:hash:{hash}";
|
|
||||||
private static string KeyForToken(string token) => $"nd:token:{token}";
|
|
||||||
private static string KeyForUidSet(string uid) => $"nd:uid:{uid}";
|
|
||||||
|
|
||||||
public void Publish(string uid, IEnumerable<string> hashes, string? displayName = null, bool allowRequests = true)
|
|
||||||
{
|
|
||||||
var entries = hashes.Distinct(StringComparer.Ordinal).ToArray();
|
|
||||||
if (entries.Length == 0) return;
|
|
||||||
var batch = _db.CreateBatch();
|
|
||||||
foreach (var h in entries)
|
|
||||||
{
|
|
||||||
var key = KeyForHash(h);
|
|
||||||
var payload = JsonSerializer.Serialize(new Presence(uid, displayName, allowRequests), _jsonOpts);
|
|
||||||
batch.StringSetAsync(key, payload, _presenceTtl);
|
|
||||||
// Index this hash under the publisher uid for fast unpublish
|
|
||||||
batch.SetAddAsync(KeyForUidSet(uid), h);
|
|
||||||
batch.KeyExpireAsync(KeyForUidSet(uid), _presenceTtl);
|
|
||||||
}
|
|
||||||
batch.Execute();
|
|
||||||
_logger.LogDebug("RedisPresenceStore: published {count} hashes", entries.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Unpublish(string uid)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var setKey = KeyForUidSet(uid);
|
|
||||||
var members = _db.SetMembers(setKey);
|
|
||||||
if (members is { Length: > 0 })
|
|
||||||
{
|
|
||||||
var batch = _db.CreateBatch();
|
|
||||||
foreach (var m in members)
|
|
||||||
{
|
|
||||||
var hash = (string)m;
|
|
||||||
var key = KeyForHash(hash);
|
|
||||||
// Defensive: only delete if the hash is still owned by this uid
|
|
||||||
var val = _db.StringGet(key);
|
|
||||||
if (val.HasValue)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var p = JsonSerializer.Deserialize<Presence>(val!);
|
|
||||||
if (p != null && string.Equals(p.Uid, uid, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
batch.KeyDeleteAsync(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { /* ignore corrupted */ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Remove the uid index set itself
|
|
||||||
batch.KeyDeleteAsync(setKey);
|
|
||||||
batch.Execute();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// No index set: best-effort, just delete the set key in case it exists
|
|
||||||
_db.KeyDelete(setKey);
|
|
||||||
}
|
|
||||||
_logger.LogDebug("RedisPresenceStore: unpublished all hashes for uid {uid}", uid);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogWarning(ex, "RedisPresenceStore: Unpublish failed for uid {uid}", uid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public (bool Found, string? Token, string TargetUid, string? DisplayName) TryMatchAndIssueToken(string requesterUid, string hash)
|
|
||||||
{
|
|
||||||
var key = KeyForHash(hash);
|
|
||||||
var val = _db.StringGet(key);
|
|
||||||
if (!val.HasValue) return (false, null, string.Empty, null);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var p = JsonSerializer.Deserialize<Presence>(val!);
|
|
||||||
if (p == null || string.IsNullOrEmpty(p.Uid)) return (false, null, string.Empty, null);
|
|
||||||
if (string.Equals(p.Uid, requesterUid, StringComparison.Ordinal)) return (false, null, string.Empty, null);
|
|
||||||
|
|
||||||
// Refresh TTLs for this presence whenever it is matched
|
|
||||||
_db.KeyExpire(KeyForHash(hash), _presenceTtl);
|
|
||||||
_db.KeyExpire(KeyForUidSet(p.Uid), _presenceTtl);
|
|
||||||
|
|
||||||
// Visible but requests disabled → return without token
|
|
||||||
if (!p.AllowRequests)
|
|
||||||
{
|
|
||||||
return (true, null, p.Uid, p.DisplayName);
|
|
||||||
}
|
|
||||||
|
|
||||||
var token = Guid.NewGuid().ToString("N");
|
|
||||||
_db.StringSet(KeyForToken(token), p.Uid, _tokenTtl);
|
|
||||||
return (true, token, p.Uid, p.DisplayName);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return (false, null, string.Empty, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ValidateToken(string token, out string targetUid)
|
|
||||||
{
|
|
||||||
targetUid = string.Empty;
|
|
||||||
var key = KeyForToken(token);
|
|
||||||
var val = _db.StringGet(key);
|
|
||||||
if (!val.HasValue) return false;
|
|
||||||
targetUid = val!;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var setKey = KeyForUidSet(targetUid);
|
|
||||||
var members = _db.SetMembers(setKey);
|
|
||||||
if (members is { Length: > 0 })
|
|
||||||
{
|
|
||||||
var batch = _db.CreateBatch();
|
|
||||||
foreach (var m in members)
|
|
||||||
{
|
|
||||||
var h = (string)m;
|
|
||||||
batch.KeyExpireAsync(KeyForHash(h), _presenceTtl);
|
|
||||||
}
|
|
||||||
batch.KeyExpireAsync(setKey, _presenceTtl);
|
|
||||||
batch.Execute();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Still try to extend the set TTL even if empty
|
|
||||||
_db.KeyExpire(setKey, _presenceTtl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { /* ignore TTL refresh issues */ }
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed record Presence(string Uid, string? DisplayName, bool AllowRequests);
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using MareSynchronosAuthService.Services.Discovery;
|
|
||||||
|
|
||||||
namespace MareSynchronosAuthService.Services;
|
|
||||||
|
|
||||||
public class DiscoveryPresenceService : IHostedService, IDisposable
|
|
||||||
{
|
|
||||||
private readonly ILogger<DiscoveryPresenceService> _logger;
|
|
||||||
private readonly IDiscoveryPresenceStore _store;
|
|
||||||
private readonly TimeSpan _presenceTtl = TimeSpan.FromMinutes(5);
|
|
||||||
private readonly TimeSpan _tokenTtl = TimeSpan.FromMinutes(2);
|
|
||||||
|
|
||||||
public DiscoveryPresenceService(ILogger<DiscoveryPresenceService> logger, IDiscoveryPresenceStore store)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_store = store;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Publish(string uid, IEnumerable<string> hashes, string? displayName = null, bool allowRequests = true)
|
|
||||||
{
|
|
||||||
_store.Publish(uid, hashes, displayName, allowRequests);
|
|
||||||
_logger.LogDebug("Discovery presence published for {uid} with {n} hashes", uid, hashes.Count());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Unpublish(string uid)
|
|
||||||
{
|
|
||||||
_store.Unpublish(uid);
|
|
||||||
_logger.LogDebug("Discovery presence unpublished for {uid}", uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public (bool Found, string? Token, string TargetUid, string? DisplayName) TryMatchAndIssueToken(string requesterUid, string hash)
|
|
||||||
{
|
|
||||||
var res = _store.TryMatchAndIssueToken(requesterUid, hash);
|
|
||||||
return (res.Found, res.Token, res.TargetUid, res.DisplayName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ValidateToken(string token, out string targetUid)
|
|
||||||
{
|
|
||||||
return _store.ValidateToken(token, out targetUid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
(_store as IDisposable)?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace MareSynchronosAuthService.Services;
|
|
||||||
|
|
||||||
public class DiscoveryWellKnownProvider : IHostedService
|
|
||||||
{
|
|
||||||
private readonly ILogger<DiscoveryWellKnownProvider> _logger;
|
|
||||||
private readonly object _lock = new();
|
|
||||||
private byte[] _currentSalt = Array.Empty<byte>();
|
|
||||||
private DateTimeOffset _currentSaltExpiresAt;
|
|
||||||
private byte[] _previousSalt = Array.Empty<byte>();
|
|
||||||
private DateTimeOffset _previousSaltExpiresAt;
|
|
||||||
private readonly TimeSpan _gracePeriod = TimeSpan.FromMinutes(5);
|
|
||||||
private Timer? _rotationTimer;
|
|
||||||
private readonly TimeSpan _saltTtl = TimeSpan.FromDays(30 * 6);
|
|
||||||
private readonly int _refreshSec = 86400; // 24h
|
|
||||||
|
|
||||||
public DiscoveryWellKnownProvider(ILogger<DiscoveryWellKnownProvider> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
RotateSalt();
|
|
||||||
var period = _saltTtl;
|
|
||||||
if (period.TotalMilliseconds > uint.MaxValue - 1)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("DiscoveryWellKnownProvider: salt TTL {ttl} exceeds timer limit, skipping rotation timer in beta", period);
|
|
||||||
_rotationTimer = new Timer(_ => { }, null, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_rotationTimer = new Timer(_ => RotateSalt(), null, period, period);
|
|
||||||
}
|
|
||||||
_logger.LogInformation("DiscoveryWellKnownProvider started. Salt expires at {exp}", _currentSaltExpiresAt);
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
_rotationTimer?.Dispose();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RotateSalt()
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
if (_currentSalt.Length > 0)
|
|
||||||
{
|
|
||||||
_previousSalt = _currentSalt;
|
|
||||||
_previousSaltExpiresAt = DateTimeOffset.UtcNow.Add(_gracePeriod);
|
|
||||||
}
|
|
||||||
_currentSalt = RandomNumberGenerator.GetBytes(32);
|
|
||||||
_currentSaltExpiresAt = DateTimeOffset.UtcNow.Add(_saltTtl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsExpired(string providedSaltB64)
|
|
||||||
{
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
var now = DateTimeOffset.UtcNow;
|
|
||||||
var provided = Convert.FromBase64String(providedSaltB64);
|
|
||||||
|
|
||||||
if (_currentSalt.SequenceEqual(provided) && now <= _currentSaltExpiresAt)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (_previousSalt.Length > 0 && _previousSalt.SequenceEqual(provided) && now <= _previousSaltExpiresAt)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetWellKnownJson(string scheme, string host)
|
|
||||||
{
|
|
||||||
var isHttps = string.Equals(scheme, "https", StringComparison.OrdinalIgnoreCase);
|
|
||||||
var wsScheme = isHttps ? "wss" : "ws";
|
|
||||||
var httpScheme = isHttps ? "https" : "http";
|
|
||||||
|
|
||||||
byte[] salt;
|
|
||||||
DateTimeOffset exp;
|
|
||||||
lock (_lock)
|
|
||||||
{
|
|
||||||
salt = _currentSalt.ToArray();
|
|
||||||
exp = _currentSaltExpiresAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
var root = new WellKnownRoot
|
|
||||||
{
|
|
||||||
ApiUrl = $"{wsScheme}://{host}",
|
|
||||||
HubUrl = $"{wsScheme}://{host}/mare",
|
|
||||||
Features = new() { NearbyDiscovery = true },
|
|
||||||
NearbyDiscovery = new()
|
|
||||||
{
|
|
||||||
Enabled = true,
|
|
||||||
HashAlgo = "sha256",
|
|
||||||
SaltB64 = Convert.ToBase64String(salt),
|
|
||||||
SaltExpiresAt = exp,
|
|
||||||
RefreshSec = _refreshSec,
|
|
||||||
GraceSec = (int)_gracePeriod.TotalSeconds,
|
|
||||||
Endpoints = new()
|
|
||||||
{
|
|
||||||
Publish = $"{httpScheme}://{host}/discovery/publish",
|
|
||||||
Query = $"{httpScheme}://{host}/discovery/query",
|
|
||||||
Request = $"{httpScheme}://{host}/discovery/request",
|
|
||||||
Accept = $"{httpScheme}://{host}/discovery/acceptNotify"
|
|
||||||
},
|
|
||||||
Policies = new()
|
|
||||||
{
|
|
||||||
MaxQueryBatch = 100,
|
|
||||||
MinQueryIntervalMs = 2000,
|
|
||||||
RateLimitPerMin = 30,
|
|
||||||
TokenTtlSec = 120
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return JsonSerializer.Serialize(root, new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull });
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed class WellKnownRoot
|
|
||||||
{
|
|
||||||
[JsonPropertyName("api_url")] public string ApiUrl { get; set; } = string.Empty;
|
|
||||||
[JsonPropertyName("hub_url")] public string HubUrl { get; set; } = string.Empty;
|
|
||||||
[JsonPropertyName("skip_negotiation")] public bool SkipNegotiation { get; set; } = true;
|
|
||||||
[JsonPropertyName("transports")] public string[] Transports { get; set; } = new[] { "websockets" };
|
|
||||||
[JsonPropertyName("features")] public Features Features { get; set; } = new();
|
|
||||||
[JsonPropertyName("nearby_discovery")] public Nearby NearbyDiscovery { get; set; } = new();
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed class Features
|
|
||||||
{
|
|
||||||
[JsonPropertyName("nearby_discovery")] public bool NearbyDiscovery { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed class Nearby
|
|
||||||
{
|
|
||||||
[JsonPropertyName("enabled")] public bool Enabled { get; set; }
|
|
||||||
[JsonPropertyName("hash_algo")] public string HashAlgo { get; set; } = "sha256";
|
|
||||||
[JsonPropertyName("salt_b64")] public string SaltB64 { get; set; } = string.Empty;
|
|
||||||
[JsonPropertyName("salt_expires_at")] public DateTimeOffset SaltExpiresAt { get; set; }
|
|
||||||
[JsonPropertyName("refresh_sec")] public int RefreshSec { get; set; }
|
|
||||||
[JsonPropertyName("grace_sec")] public int GraceSec { get; set; }
|
|
||||||
[JsonPropertyName("endpoints")] public Endpoints Endpoints { get; set; } = new();
|
|
||||||
[JsonPropertyName("policies")] public Policies Policies { get; set; } = new();
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed class Endpoints
|
|
||||||
{
|
|
||||||
[JsonPropertyName("publish")] public string? Publish { get; set; }
|
|
||||||
[JsonPropertyName("query")] public string? Query { get; set; }
|
|
||||||
[JsonPropertyName("request")] public string? Request { get; set; }
|
|
||||||
[JsonPropertyName("accept")] public string? Accept { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed class Policies
|
|
||||||
{
|
|
||||||
[JsonPropertyName("max_query_batch")] public int MaxQueryBatch { get; set; }
|
|
||||||
[JsonPropertyName("min_query_interval_ms")] public int MinQueryIntervalMs { get; set; }
|
|
||||||
[JsonPropertyName("rate_limit_per_min")] public int RateLimitPerMin { get; set; }
|
|
||||||
[JsonPropertyName("token_ttl_sec")] public int TokenTtlSec { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
using MareSynchronosShared;
|
|
||||||
using MareSynchronosShared.Services;
|
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
|
||||||
using MaxMind.GeoIP2;
|
|
||||||
|
|
||||||
namespace MareSynchronosAuthService.Services;
|
|
||||||
|
|
||||||
public class GeoIPService : IHostedService
|
|
||||||
{
|
|
||||||
private readonly ILogger<GeoIPService> _logger;
|
|
||||||
private readonly IConfigurationService<AuthServiceConfiguration> _mareConfiguration;
|
|
||||||
private bool _useGeoIP = false;
|
|
||||||
private string _cityFile = string.Empty;
|
|
||||||
private DatabaseReader? _dbReader;
|
|
||||||
private DateTime _dbLastWriteTime = DateTime.Now;
|
|
||||||
private CancellationTokenSource _fileWriteTimeCheckCts = new();
|
|
||||||
private bool _processingReload = false;
|
|
||||||
|
|
||||||
public GeoIPService(ILogger<GeoIPService> logger,
|
|
||||||
IConfigurationService<AuthServiceConfiguration> mareConfiguration)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_mareConfiguration = mareConfiguration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<string> GetCountryFromIP(IHttpContextAccessor httpContextAccessor)
|
|
||||||
{
|
|
||||||
if (!_useGeoIP)
|
|
||||||
{
|
|
||||||
return "*";
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var ip = httpContextAccessor.GetIpAddress();
|
|
||||||
|
|
||||||
using CancellationTokenSource waitCts = new();
|
|
||||||
waitCts.CancelAfter(TimeSpan.FromSeconds(5));
|
|
||||||
while (_processingReload) await Task.Delay(100, waitCts.Token).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (_dbReader!.TryCity(ip, out var response))
|
|
||||||
{
|
|
||||||
string? continent = response?.Continent.Code;
|
|
||||||
if (!string.IsNullOrEmpty(continent) &&
|
|
||||||
string.Equals(continent, "NA", StringComparison.Ordinal)
|
|
||||||
&& response?.Location.Longitude != null)
|
|
||||||
{
|
|
||||||
if (response.Location.Longitude < -102)
|
|
||||||
{
|
|
||||||
continent = "NA-W";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
continent = "NA-E";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return continent ?? "*";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "*";
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogWarning(ex, "Error handling Geo IP country in request");
|
|
||||||
return "*";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("GeoIP module starting update task");
|
|
||||||
|
|
||||||
var token = _fileWriteTimeCheckCts.Token;
|
|
||||||
_ = PeriodicReloadTask(token);
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task PeriodicReloadTask(CancellationToken token)
|
|
||||||
{
|
|
||||||
while (!token.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_processingReload = true;
|
|
||||||
|
|
||||||
var useGeoIP = _mareConfiguration.GetValueOrDefault(nameof(AuthServiceConfiguration.UseGeoIP), false);
|
|
||||||
var cityFile = _mareConfiguration.GetValueOrDefault(nameof(AuthServiceConfiguration.GeoIPDbCityFile), string.Empty);
|
|
||||||
var lastWriteTime = new FileInfo(cityFile).LastWriteTimeUtc;
|
|
||||||
if (useGeoIP && (!string.Equals(cityFile, _cityFile, StringComparison.OrdinalIgnoreCase) || lastWriteTime != _dbLastWriteTime))
|
|
||||||
{
|
|
||||||
_cityFile = cityFile;
|
|
||||||
if (!File.Exists(_cityFile)) throw new FileNotFoundException($"Could not open GeoIP City Database, path does not exist: {_cityFile}");
|
|
||||||
_dbReader?.Dispose();
|
|
||||||
_dbReader = null;
|
|
||||||
_dbReader = new DatabaseReader(_cityFile);
|
|
||||||
_dbLastWriteTime = lastWriteTime;
|
|
||||||
|
|
||||||
_ = _dbReader.City("8.8.8.8").Continent;
|
|
||||||
|
|
||||||
_logger.LogInformation($"Loaded GeoIP city file from {_cityFile}");
|
|
||||||
|
|
||||||
if (_useGeoIP != useGeoIP)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("GeoIP module is now enabled");
|
|
||||||
_useGeoIP = useGeoIP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_useGeoIP != useGeoIP && !useGeoIP)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("GeoIP module is now disabled");
|
|
||||||
_useGeoIP = useGeoIP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
_logger.LogWarning(e, "Error during periodic GeoIP module reload task, disabling GeoIP");
|
|
||||||
_useGeoIP = false;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_processingReload = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(TimeSpan.FromMinutes(1)).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
_fileWriteTimeCheckCts.Cancel();
|
|
||||||
_fileWriteTimeCheckCts.Dispose();
|
|
||||||
_dbReader?.Dispose();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
using System.Collections.Concurrent;
|
|
||||||
using MareSynchronosAuthService.Authentication;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using MareSynchronosShared.Metrics;
|
|
||||||
using MareSynchronosShared.Services;
|
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace MareSynchronosAuthService.Services;
|
|
||||||
|
|
||||||
public class SecretKeyAuthenticatorService
|
|
||||||
{
|
|
||||||
private readonly MareMetrics _metrics;
|
|
||||||
private readonly MareDbContext _mareDbContext;
|
|
||||||
private readonly IConfigurationService<AuthServiceConfiguration> _configurationService;
|
|
||||||
private readonly ILogger<SecretKeyAuthenticatorService> _logger;
|
|
||||||
private readonly ConcurrentDictionary<string, SecretKeyFailedAuthorization> _failedAuthorizations = new(StringComparer.Ordinal);
|
|
||||||
|
|
||||||
public SecretKeyAuthenticatorService(MareMetrics metrics, MareDbContext mareDbContext,
|
|
||||||
IConfigurationService<AuthServiceConfiguration> configuration, ILogger<SecretKeyAuthenticatorService> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_configurationService = configuration;
|
|
||||||
_metrics = metrics;
|
|
||||||
_mareDbContext = mareDbContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<SecretKeyAuthReply> AuthorizeAsync(string ip, string hashedSecretKey)
|
|
||||||
{
|
|
||||||
_metrics.IncCounter(MetricsAPI.CounterAuthenticationRequests);
|
|
||||||
|
|
||||||
if (_failedAuthorizations.TryGetValue(ip, out var existingFailedAuthorization)
|
|
||||||
&& existingFailedAuthorization.FailedAttempts > _configurationService.GetValueOrDefault(nameof(AuthServiceConfiguration.FailedAuthForTempBan), 5))
|
|
||||||
{
|
|
||||||
if (existingFailedAuthorization.ResetTask == null)
|
|
||||||
{
|
|
||||||
_logger.LogWarning("TempBan {ip} for authorization spam", ip);
|
|
||||||
|
|
||||||
existingFailedAuthorization.ResetTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await Task.Delay(TimeSpan.FromMinutes(_configurationService.GetValueOrDefault(nameof(AuthServiceConfiguration.TempBanDurationInMinutes), 5))).ConfigureAwait(false);
|
|
||||||
|
|
||||||
}).ContinueWith((t) =>
|
|
||||||
{
|
|
||||||
_failedAuthorizations.Remove(ip, out _);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return new(Success: false, Uid: null, TempBan: true, Alias: null, Permaban: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
var authReply = await _mareDbContext.Auth.Include(a => a.User).AsNoTracking()
|
|
||||||
.SingleOrDefaultAsync(u => u.HashedKey == hashedSecretKey).ConfigureAwait(false);
|
|
||||||
|
|
||||||
SecretKeyAuthReply reply = new(authReply != null, authReply?.UserUID, authReply?.User?.Alias ?? string.Empty, TempBan: false, authReply?.IsBanned ?? false);
|
|
||||||
|
|
||||||
if (reply.Success)
|
|
||||||
{
|
|
||||||
_metrics.IncCounter(MetricsAPI.CounterAuthenticationSuccesses);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return AuthenticationFailure(ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
return reply;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SecretKeyAuthReply AuthenticationFailure(string ip)
|
|
||||||
{
|
|
||||||
_metrics.IncCounter(MetricsAPI.CounterAuthenticationFailures);
|
|
||||||
|
|
||||||
_logger.LogWarning("Failed authorization from {ip}", ip);
|
|
||||||
var whitelisted = _configurationService.GetValueOrDefault(nameof(AuthServiceConfiguration.WhitelistedIps), new List<string>());
|
|
||||||
if (!whitelisted.Any(w => ip.Contains(w, StringComparison.OrdinalIgnoreCase)))
|
|
||||||
{
|
|
||||||
if (_failedAuthorizations.TryGetValue(ip, out var auth))
|
|
||||||
{
|
|
||||||
auth.IncreaseFailedAttempts();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_failedAuthorizations[ip] = new SecretKeyFailedAuthorization();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new(Success: false, Uid: null, Alias: null, TempBan: false, Permaban: false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,263 +0,0 @@
|
|||||||
using MareSynchronosAuthService.Controllers;
|
|
||||||
using MareSynchronosShared.Metrics;
|
|
||||||
using MareSynchronosShared.Services;
|
|
||||||
using MareSynchronosShared.Utils;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
|
||||||
using StackExchange.Redis.Extensions.Core.Configuration;
|
|
||||||
using StackExchange.Redis.Extensions.System.Text.Json;
|
|
||||||
using StackExchange.Redis;
|
|
||||||
using System.Net;
|
|
||||||
using MareSynchronosAuthService.Services;
|
|
||||||
using MareSynchronosShared.RequirementHandlers;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
||||||
using Microsoft.IdentityModel.Tokens;
|
|
||||||
using System.Text;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Prometheus;
|
|
||||||
using Microsoft.AspNetCore.HttpOverrides;
|
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
|
||||||
|
|
||||||
namespace MareSynchronosAuthService;
|
|
||||||
|
|
||||||
public class Startup
|
|
||||||
{
|
|
||||||
private readonly IConfiguration _configuration;
|
|
||||||
private ILogger<Startup> _logger;
|
|
||||||
|
|
||||||
public Startup(IConfiguration configuration, ILogger<Startup> logger)
|
|
||||||
{
|
|
||||||
_configuration = configuration;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
|
|
||||||
{
|
|
||||||
var config = app.ApplicationServices.GetRequiredService<IConfigurationService<MareConfigurationBase>>();
|
|
||||||
|
|
||||||
// Respect X-Forwarded-* headers from the reverse proxy so generated links use the public scheme/host
|
|
||||||
app.UseForwardedHeaders(new ForwardedHeadersOptions
|
|
||||||
{
|
|
||||||
ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost | ForwardedHeaders.XForwardedFor
|
|
||||||
});
|
|
||||||
|
|
||||||
app.UseRouting();
|
|
||||||
|
|
||||||
app.UseHttpMetrics();
|
|
||||||
|
|
||||||
app.UseAuthentication();
|
|
||||||
app.UseAuthorization();
|
|
||||||
|
|
||||||
KestrelMetricServer metricServer = new KestrelMetricServer(config.GetValueOrDefault<int>(nameof(MareConfigurationBase.MetricsPort), 4985));
|
|
||||||
metricServer.Start();
|
|
||||||
|
|
||||||
app.UseEndpoints(endpoints =>
|
|
||||||
{
|
|
||||||
endpoints.MapControllers();
|
|
||||||
endpoints.MapHealthChecks("/healthz").WithMetadata(new AllowAnonymousAttribute());
|
|
||||||
|
|
||||||
foreach (var source in endpoints.DataSources.SelectMany(e => e.Endpoints).Cast<RouteEndpoint>())
|
|
||||||
{
|
|
||||||
if (source == null) continue;
|
|
||||||
_logger.LogInformation("Endpoint: {url} ", source.RoutePattern.RawText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ConfigureServices(IServiceCollection services)
|
|
||||||
{
|
|
||||||
var mareConfig = _configuration.GetRequiredSection("MareSynchronos");
|
|
||||||
|
|
||||||
services.AddHttpContextAccessor();
|
|
||||||
|
|
||||||
ConfigureRedis(services, mareConfig);
|
|
||||||
|
|
||||||
services.AddScoped<SecretKeyAuthenticatorService>();
|
|
||||||
services.AddScoped<AccountRegistrationService>();
|
|
||||||
services.AddSingleton<GeoIPService>();
|
|
||||||
|
|
||||||
services.AddHostedService(provider => provider.GetRequiredService<GeoIPService>());
|
|
||||||
|
|
||||||
services.Configure<AuthServiceConfiguration>(_configuration.GetRequiredSection("MareSynchronos"));
|
|
||||||
services.Configure<MareConfigurationBase>(_configuration.GetRequiredSection("MareSynchronos"));
|
|
||||||
|
|
||||||
services.AddSingleton<ServerTokenGenerator>();
|
|
||||||
// Nearby discovery services (well-known + presence)
|
|
||||||
services.AddSingleton<DiscoveryWellKnownProvider>();
|
|
||||||
services.AddHostedService(p => p.GetRequiredService<DiscoveryWellKnownProvider>());
|
|
||||||
|
|
||||||
// Presence store selection
|
|
||||||
var discoveryStore = _configuration.GetValue<string>("NearbyDiscovery:Store") ?? "memory";
|
|
||||||
TimeSpan presenceTtl = TimeSpan.FromMinutes(_configuration.GetValue<int>("NearbyDiscovery:PresenceTtlMinutes", 5));
|
|
||||||
TimeSpan tokenTtl = TimeSpan.FromSeconds(_configuration.GetValue<int>("NearbyDiscovery:TokenTtlSeconds", 120));
|
|
||||||
if (string.Equals(discoveryStore, "redis", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
services.AddSingleton<MareSynchronosAuthService.Services.Discovery.IDiscoveryPresenceStore>(sp =>
|
|
||||||
{
|
|
||||||
var logger = sp.GetRequiredService<ILogger<MareSynchronosAuthService.Services.Discovery.RedisPresenceStore>>();
|
|
||||||
var mux = sp.GetRequiredService<IConnectionMultiplexer>();
|
|
||||||
return new MareSynchronosAuthService.Services.Discovery.RedisPresenceStore(logger, mux, presenceTtl, tokenTtl);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
services.AddSingleton<MareSynchronosAuthService.Services.Discovery.IDiscoveryPresenceStore>(sp => new MareSynchronosAuthService.Services.Discovery.InMemoryPresenceStore(presenceTtl, tokenTtl));
|
|
||||||
}
|
|
||||||
|
|
||||||
services.AddSingleton<DiscoveryPresenceService>();
|
|
||||||
services.AddHostedService(p => p.GetRequiredService<DiscoveryPresenceService>());
|
|
||||||
|
|
||||||
ConfigureAuthorization(services);
|
|
||||||
|
|
||||||
ConfigureDatabase(services, mareConfig);
|
|
||||||
|
|
||||||
ConfigureConfigServices(services);
|
|
||||||
|
|
||||||
ConfigureMetrics(services);
|
|
||||||
|
|
||||||
services.AddHealthChecks();
|
|
||||||
services.AddControllers().ConfigureApplicationPartManager(a =>
|
|
||||||
{
|
|
||||||
a.FeatureProviders.Remove(a.FeatureProviders.OfType<ControllerFeatureProvider>().First());
|
|
||||||
a.FeatureProviders.Add(new AllowedControllersFeatureProvider(typeof(JwtController), typeof(WellKnownController), typeof(DiscoveryController)));
|
|
||||||
});
|
|
||||||
|
|
||||||
services.AddSingleton<DiscoveryWellKnownProvider>();
|
|
||||||
services.AddHostedService(p => p.GetRequiredService<DiscoveryWellKnownProvider>());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ConfigureAuthorization(IServiceCollection services)
|
|
||||||
{
|
|
||||||
services.AddTransient<IAuthorizationHandler, UserRequirementHandler>();
|
|
||||||
|
|
||||||
services.AddOptions<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme)
|
|
||||||
.Configure<IConfigurationService<MareConfigurationBase>>((options, config) =>
|
|
||||||
{
|
|
||||||
options.TokenValidationParameters = new()
|
|
||||||
{
|
|
||||||
ValidateIssuer = false,
|
|
||||||
ValidateLifetime = true,
|
|
||||||
ValidateAudience = false,
|
|
||||||
ValidateIssuerSigningKey = true,
|
|
||||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(config.GetValue<string>(nameof(MareConfigurationBase.Jwt)))),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
services.AddAuthentication(o =>
|
|
||||||
{
|
|
||||||
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
}).AddJwtBearer();
|
|
||||||
|
|
||||||
services.AddAuthorization(options =>
|
|
||||||
{
|
|
||||||
options.DefaultPolicy = new AuthorizationPolicyBuilder()
|
|
||||||
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
|
|
||||||
.RequireAuthenticatedUser().Build();
|
|
||||||
options.AddPolicy("Authenticated", policy =>
|
|
||||||
{
|
|
||||||
policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
|
|
||||||
policy.RequireAuthenticatedUser();
|
|
||||||
});
|
|
||||||
options.AddPolicy("Identified", policy =>
|
|
||||||
{
|
|
||||||
policy.AddRequirements(new UserRequirement(UserRequirements.Identified));
|
|
||||||
|
|
||||||
});
|
|
||||||
options.AddPolicy("Admin", policy =>
|
|
||||||
{
|
|
||||||
policy.AddRequirements(new UserRequirement(UserRequirements.Identified | UserRequirements.Administrator));
|
|
||||||
|
|
||||||
});
|
|
||||||
options.AddPolicy("Moderator", policy =>
|
|
||||||
{
|
|
||||||
policy.AddRequirements(new UserRequirement(UserRequirements.Identified | UserRequirements.Moderator | UserRequirements.Administrator));
|
|
||||||
});
|
|
||||||
options.AddPolicy("Internal", new AuthorizationPolicyBuilder().RequireClaim(MareClaimTypes.Internal, "true").Build());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ConfigureMetrics(IServiceCollection services)
|
|
||||||
{
|
|
||||||
services.AddSingleton<MareMetrics>(m => new MareMetrics(m.GetService<ILogger<MareMetrics>>(), new List<string>
|
|
||||||
{
|
|
||||||
MetricsAPI.CounterAuthenticationCacheHits,
|
|
||||||
MetricsAPI.CounterAuthenticationFailures,
|
|
||||||
MetricsAPI.CounterAuthenticationRequests,
|
|
||||||
MetricsAPI.CounterAuthenticationSuccesses,
|
|
||||||
MetricsAPI.CounterAccountsCreated,
|
|
||||||
}, new List<string>
|
|
||||||
{
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ConfigureRedis(IServiceCollection services, IConfigurationSection mareConfig)
|
|
||||||
{
|
|
||||||
// configure redis for SignalR
|
|
||||||
var redisConnection = mareConfig.GetValue(nameof(ServerConfiguration.RedisConnectionString), string.Empty);
|
|
||||||
|
|
||||||
var options = ConfigurationOptions.Parse(redisConnection);
|
|
||||||
|
|
||||||
var endpoint = options.EndPoints[0];
|
|
||||||
string address = "";
|
|
||||||
int port = 0;
|
|
||||||
if (endpoint is DnsEndPoint dnsEndPoint) { address = dnsEndPoint.Host; port = dnsEndPoint.Port; }
|
|
||||||
if (endpoint is IPEndPoint ipEndPoint) { address = ipEndPoint.Address.ToString(); port = ipEndPoint.Port; }
|
|
||||||
var redisConfiguration = new RedisConfiguration()
|
|
||||||
{
|
|
||||||
AbortOnConnectFail = true,
|
|
||||||
KeyPrefix = "",
|
|
||||||
Hosts = new RedisHost[]
|
|
||||||
{
|
|
||||||
new RedisHost(){ Host = address, Port = port },
|
|
||||||
},
|
|
||||||
AllowAdmin = true,
|
|
||||||
ConnectTimeout = options.ConnectTimeout,
|
|
||||||
Database = 0,
|
|
||||||
Ssl = false,
|
|
||||||
Password = options.Password,
|
|
||||||
ServerEnumerationStrategy = new ServerEnumerationStrategy()
|
|
||||||
{
|
|
||||||
Mode = ServerEnumerationStrategy.ModeOptions.All,
|
|
||||||
TargetRole = ServerEnumerationStrategy.TargetRoleOptions.Any,
|
|
||||||
UnreachableServerAction = ServerEnumerationStrategy.UnreachableServerActionOptions.Throw,
|
|
||||||
},
|
|
||||||
MaxValueLength = 1024,
|
|
||||||
PoolSize = mareConfig.GetValue(nameof(ServerConfiguration.RedisPool), 50),
|
|
||||||
SyncTimeout = options.SyncTimeout,
|
|
||||||
};
|
|
||||||
|
|
||||||
services.AddStackExchangeRedisExtensions<SystemTextJsonSerializer>(redisConfiguration);
|
|
||||||
// Also expose raw multiplexer for custom Redis usage (discovery presence)
|
|
||||||
services.AddSingleton<IConnectionMultiplexer>(_ => ConnectionMultiplexer.Connect(options));
|
|
||||||
}
|
|
||||||
private void ConfigureConfigServices(IServiceCollection services)
|
|
||||||
{
|
|
||||||
services.AddSingleton<IConfigurationService<AuthServiceConfiguration>, MareConfigurationServiceServer<AuthServiceConfiguration>>();
|
|
||||||
services.AddSingleton<IConfigurationService<MareConfigurationBase>, MareConfigurationServiceServer<MareConfigurationBase>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ConfigureDatabase(IServiceCollection services, IConfigurationSection mareConfig)
|
|
||||||
{
|
|
||||||
services.AddDbContextPool<MareDbContext>(options =>
|
|
||||||
{
|
|
||||||
options.UseNpgsql(_configuration.GetConnectionString("DefaultConnection"), builder =>
|
|
||||||
{
|
|
||||||
builder.MigrationsHistoryTable("_efmigrationshistory", "public");
|
|
||||||
builder.MigrationsAssembly("MareSynchronosShared");
|
|
||||||
}).UseSnakeCaseNamingConvention();
|
|
||||||
options.EnableThreadSafetyChecks(false);
|
|
||||||
}, mareConfig.GetValue(nameof(MareConfigurationBase.DbContextPoolSize), 1024));
|
|
||||||
services.AddDbContextFactory<MareDbContext>(options =>
|
|
||||||
{
|
|
||||||
options.UseNpgsql(_configuration.GetConnectionString("DefaultConnection"), builder =>
|
|
||||||
{
|
|
||||||
builder.MigrationsHistoryTable("_efmigrationshistory", "public");
|
|
||||||
builder.MigrationsAssembly("MareSynchronosShared");
|
|
||||||
}).UseSnakeCaseNamingConvention();
|
|
||||||
options.EnableThreadSafetyChecks(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowedHosts": "*",
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"DefaultConnection": "Host=localhost;Port=5432;Username=postgres;Password=postgres;Database=umbra_dev"
|
|
||||||
},
|
|
||||||
"MareSynchronos": {
|
|
||||||
"Jwt": "dev-secret-umbra-abcdefghijklmnopqrstuvwxyz123456",
|
|
||||||
"RedisConnectionString": "localhost:6379,connectTimeout=5000,syncTimeout=5000",
|
|
||||||
"MetricsPort": 4985
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowedHosts": "*"
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio Version 17
|
|
||||||
VisualStudioVersion = 17.2.32602.215
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MareSynchronosServer", "MareSynchronosServer\MareSynchronosServer.csproj", "{029CA97F-E0BA-4172-A191-EA21FB61AD0F}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MareSynchronos.API", "..\MareAPI\MareSynchronosAPI\MareSynchronos.API.csproj", "{326BFB1B-5571-47A6-8513-1FFDB32D53B0}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MareSynchronosShared", "MareSynchronosShared\MareSynchronosShared.csproj", "{67B1461D-E215-4BA8-A64D-E1836724D5E6}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MareSynchronosStaticFilesServer", "MareSynchronosStaticFilesServer\MareSynchronosStaticFilesServer.csproj", "{3C7F43BB-FE4C-48BC-BF42-D24E70E8FCB7}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MareSynchronosServices", "MareSynchronosServices\MareSynchronosServices.csproj", "{E29C8677-AB44-4950-9EB1-D8E70B710A56}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7D5C2B87-5CC9-4FE7-AD13-4C13F6600683}"
|
|
||||||
ProjectSection(SolutionItems) = preProject
|
|
||||||
.editorconfig = .editorconfig
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MareSynchronosAuthService", "MareSynchronosAuthService\MareSynchronosAuthService.csproj", "{D7D4041C-DCD9-4B7A-B423-0F458DFFF3D6}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{029CA97F-E0BA-4172-A191-EA21FB61AD0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{029CA97F-E0BA-4172-A191-EA21FB61AD0F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{029CA97F-E0BA-4172-A191-EA21FB61AD0F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{029CA97F-E0BA-4172-A191-EA21FB61AD0F}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{326BFB1B-5571-47A6-8513-1FFDB32D53B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{326BFB1B-5571-47A6-8513-1FFDB32D53B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{326BFB1B-5571-47A6-8513-1FFDB32D53B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{326BFB1B-5571-47A6-8513-1FFDB32D53B0}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{67B1461D-E215-4BA8-A64D-E1836724D5E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{67B1461D-E215-4BA8-A64D-E1836724D5E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{67B1461D-E215-4BA8-A64D-E1836724D5E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{67B1461D-E215-4BA8-A64D-E1836724D5E6}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{3C7F43BB-FE4C-48BC-BF42-D24E70E8FCB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{3C7F43BB-FE4C-48BC-BF42-D24E70E8FCB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{3C7F43BB-FE4C-48BC-BF42-D24E70E8FCB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{3C7F43BB-FE4C-48BC-BF42-D24E70E8FCB7}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{E29C8677-AB44-4950-9EB1-D8E70B710A56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{E29C8677-AB44-4950-9EB1-D8E70B710A56}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{E29C8677-AB44-4950-9EB1-D8E70B710A56}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{E29C8677-AB44-4950-9EB1-D8E70B710A56}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{D7D4041C-DCD9-4B7A-B423-0F458DFFF3D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{D7D4041C-DCD9-4B7A-B423-0F458DFFF3D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{D7D4041C-DCD9-4B7A-B423-0F458DFFF3D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{D7D4041C-DCD9-4B7A-B423-0F458DFFF3D6}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {78C476A5-6E88-449B-828D-A2465D9D3295}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"isRoot": true,
|
|
||||||
"tools": {
|
|
||||||
"dotnet-ef": {
|
|
||||||
"version": "6.0.9",
|
|
||||||
"commands": [
|
|
||||||
"dotnet-ef"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
using MareSynchronos.API.SignalR;
|
|
||||||
using MareSynchronosServer.Hubs;
|
|
||||||
using MareSynchronosShared.Utils;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Controllers;
|
|
||||||
|
|
||||||
[Route("/msgc")]
|
|
||||||
[Authorize(Policy = "Internal")]
|
|
||||||
public class ClientMessageController : Controller
|
|
||||||
{
|
|
||||||
private ILogger<ClientMessageController> _logger;
|
|
||||||
private IHubContext<MareHub, IMareHub> _hubContext;
|
|
||||||
|
|
||||||
public ClientMessageController(ILogger<ClientMessageController> logger, IHubContext<MareHub, IMareHub> hubContext)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_hubContext = hubContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Route("sendMessage")]
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<IActionResult> SendMessage([FromBody] ClientMessage msg)
|
|
||||||
{
|
|
||||||
bool hasUid = !string.IsNullOrEmpty(msg.UID);
|
|
||||||
|
|
||||||
if (!hasUid)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Sending Message of severity {severity} to all online users: {message}", msg.Severity, msg.Message);
|
|
||||||
await _hubContext.Clients.All.Client_ReceiveServerMessage(msg.Severity, msg.Message).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Sending Message of severity {severity} to user {uid}: {message}", msg.Severity, msg.UID, msg.Message);
|
|
||||||
await _hubContext.Clients.User(msg.UID).Client_ReceiveServerMessage(msg.Severity, msg.Message).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
using MareSynchronos.API.SignalR;
|
|
||||||
using MareSynchronosShared.Utils;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Controllers;
|
|
||||||
|
|
||||||
[Route("/main/discovery")]
|
|
||||||
[Authorize(Policy = "Internal")]
|
|
||||||
public class DiscoveryNotifyController : Controller
|
|
||||||
{
|
|
||||||
private readonly ILogger<DiscoveryNotifyController> _logger;
|
|
||||||
private readonly IHubContext<Hubs.MareHub, IMareHub> _hub;
|
|
||||||
|
|
||||||
public DiscoveryNotifyController(ILogger<DiscoveryNotifyController> logger, IHubContext<Hubs.MareHub, IMareHub> hub)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_hub = hub;
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class NotifyRequestDto
|
|
||||||
{
|
|
||||||
[JsonPropertyName("targetUid")] public string TargetUid { get; set; } = string.Empty;
|
|
||||||
[JsonPropertyName("fromUid")] public string FromUid { get; set; } = string.Empty;
|
|
||||||
[JsonPropertyName("fromAlias")] public string? FromAlias { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("notifyRequest")]
|
|
||||||
public async Task<IActionResult> NotifyRequest([FromBody] NotifyRequestDto dto)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(dto.TargetUid)) return BadRequest();
|
|
||||||
var name = string.IsNullOrEmpty(dto.FromAlias) ? dto.FromUid : dto.FromAlias;
|
|
||||||
var msg = $"Nearby Request: {name} [{dto.FromUid}]";
|
|
||||||
_logger.LogInformation("Discovery notify request to {target} from {from}", dto.TargetUid, name);
|
|
||||||
await _hub.Clients.User(dto.TargetUid).Client_ReceiveServerMessage(MareSynchronos.API.Data.Enum.MessageSeverity.Information, msg);
|
|
||||||
return Accepted();
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class NotifyAcceptDto
|
|
||||||
{
|
|
||||||
[JsonPropertyName("targetUid")] public string TargetUid { get; set; } = string.Empty;
|
|
||||||
[JsonPropertyName("fromUid")] public string FromUid { get; set; } = string.Empty;
|
|
||||||
[JsonPropertyName("fromAlias")] public string? FromAlias { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost("notifyAccept")]
|
|
||||||
public async Task<IActionResult> NotifyAccept([FromBody] NotifyAcceptDto dto)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(dto.TargetUid)) return BadRequest();
|
|
||||||
var name = string.IsNullOrEmpty(dto.FromAlias) ? dto.FromUid : dto.FromAlias;
|
|
||||||
var msg = $"Nearby Accept: {name} [{dto.FromUid}]";
|
|
||||||
_logger.LogInformation("Discovery notify accept to {target} from {from}", dto.TargetUid, name);
|
|
||||||
await _hub.Clients.User(dto.TargetUid).Client_ReceiveServerMessage(MareSynchronos.API.Data.Enum.MessageSeverity.Information, msg);
|
|
||||||
return Accepted();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using MareSynchronos.API.Routes;
|
|
||||||
using MareSynchronos.API.SignalR;
|
|
||||||
using MareSynchronosServer.Hubs;
|
|
||||||
using MareSynchronosServer.Services;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Controllers;
|
|
||||||
|
|
||||||
[Route(MareFiles.Main)]
|
|
||||||
public class MainController : Controller
|
|
||||||
{
|
|
||||||
private IHubContext<MareHub, IMareHub> _hubContext;
|
|
||||||
|
|
||||||
public MainController(ILogger<MainController> logger, IHubContext<MareHub, IMareHub> hubContext)
|
|
||||||
{
|
|
||||||
_hubContext = hubContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet(MareFiles.Main_SendReady)]
|
|
||||||
[Authorize(Policy = "Internal")]
|
|
||||||
public IActionResult SendReadyToClients(string uid, Guid requestId)
|
|
||||||
{
|
|
||||||
_ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await _hubContext.Clients.User(uid).Client_DownloadReady(requestId);
|
|
||||||
});
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,638 +0,0 @@
|
|||||||
using MareSynchronos.API.Data;
|
|
||||||
using MareSynchronos.API.Dto.CharaData;
|
|
||||||
using MareSynchronosServer.Utils;
|
|
||||||
using MareSynchronosShared.Models;
|
|
||||||
using MareSynchronosShared.Utils;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using System.Text.Json;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Hubs;
|
|
||||||
|
|
||||||
public partial class MareHub
|
|
||||||
{
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<CharaDataFullDto?> CharaDataCreate()
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo();
|
|
||||||
|
|
||||||
int uploadCount = DbContext.CharaData.Count(c => c.UploaderUID == UserUID);
|
|
||||||
User user = DbContext.Users.Single(u => u.UID == UserUID);
|
|
||||||
int maximumUploads = _maxCharaDataByUser;
|
|
||||||
if (uploadCount >= maximumUploads)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
string charaDataId = null;
|
|
||||||
while (charaDataId == null)
|
|
||||||
{
|
|
||||||
charaDataId = StringUtils.GenerateRandomString(10, "abcdefghijklmnopqrstuvwxyzABCDEFHIJKLMNOPQRSTUVWXYZ");
|
|
||||||
bool idExists = await DbContext.CharaData.AnyAsync(c => c.UploaderUID == UserUID && c.Id == charaDataId).ConfigureAwait(false);
|
|
||||||
if (idExists)
|
|
||||||
{
|
|
||||||
charaDataId = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DateTime createdDate = DateTime.UtcNow;
|
|
||||||
CharaData charaData = new()
|
|
||||||
{
|
|
||||||
Id = charaDataId,
|
|
||||||
UploaderUID = UserUID,
|
|
||||||
CreatedDate = createdDate,
|
|
||||||
UpdatedDate = createdDate,
|
|
||||||
AccessType = CharaDataAccess.Individuals,
|
|
||||||
ShareType = CharaDataShare.Private,
|
|
||||||
CustomizeData = string.Empty,
|
|
||||||
GlamourerData = string.Empty,
|
|
||||||
ExpiryDate = DateTime.MaxValue,
|
|
||||||
Description = string.Empty,
|
|
||||||
};
|
|
||||||
|
|
||||||
await DbContext.CharaData.AddAsync(charaData).ConfigureAwait(false);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args("SUCCESS", charaDataId));
|
|
||||||
|
|
||||||
return GetCharaDataFullDto(charaData);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<bool> CharaDataDelete(string id)
|
|
||||||
{
|
|
||||||
var existingData = await DbContext.CharaData.SingleOrDefaultAsync(u => u.Id == id && u.UploaderUID == UserUID).ConfigureAwait(false);
|
|
||||||
if (existingData == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args("SUCCESS", id));
|
|
||||||
|
|
||||||
DbContext.Remove(existingData);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogCallWarning(MareHubLogger.Args("FAILURE", id, ex.Message));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<CharaDataDownloadDto?> CharaDataDownload(string id)
|
|
||||||
{
|
|
||||||
CharaData charaData = await GetCharaDataById(id, nameof(CharaDataDownload)).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!string.Equals(charaData.UploaderUID, UserUID, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
charaData.DownloadCount++;
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args("SUCCESS", id));
|
|
||||||
|
|
||||||
return GetCharaDataDownloadDto(charaData);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<CharaDataMetaInfoDto?> CharaDataGetMetainfo(string id)
|
|
||||||
{
|
|
||||||
var charaData = await GetCharaDataById(id, nameof(CharaDataGetMetainfo)).ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args("SUCCESS", id));
|
|
||||||
|
|
||||||
return GetCharaDataMetaInfoDto(charaData);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<List<CharaDataFullDto>> CharaDataGetOwn()
|
|
||||||
{
|
|
||||||
var ownCharaData = await DbContext.CharaData
|
|
||||||
.Include(u => u.Files)
|
|
||||||
.Include(u => u.FileSwaps)
|
|
||||||
.Include(u => u.OriginalFiles)
|
|
||||||
.Include(u => u.AllowedIndividiuals)
|
|
||||||
.ThenInclude(u => u.AllowedUser)
|
|
||||||
.Include(u => u.AllowedIndividiuals)
|
|
||||||
.ThenInclude(u => u.AllowedGroup)
|
|
||||||
.Include(u => u.Poses)
|
|
||||||
.AsSplitQuery()
|
|
||||||
.Where(c => c.UploaderUID == UserUID).ToListAsync().ConfigureAwait(false);
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args("SUCCESS"));
|
|
||||||
return [.. ownCharaData.Select(GetCharaDataFullDto)];
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<CharaDataFullDto?> CharaDataAttemptRestore(string id)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(id));
|
|
||||||
var charaData = await DbContext.CharaData
|
|
||||||
.Include(u => u.Files)
|
|
||||||
.Include(u => u.FileSwaps)
|
|
||||||
.Include(u => u.OriginalFiles)
|
|
||||||
.Include(u => u.AllowedIndividiuals)
|
|
||||||
.ThenInclude(u => u.AllowedUser)
|
|
||||||
.Include(u => u.AllowedIndividiuals)
|
|
||||||
.ThenInclude(u => u.AllowedGroup)
|
|
||||||
.Include(u => u.Poses)
|
|
||||||
.AsSplitQuery()
|
|
||||||
.SingleOrDefaultAsync(s => s.Id == id && s.UploaderUID == UserUID)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
if (charaData == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var currentHashes = charaData.Files.Select(f => f.FileCacheHash).ToList();
|
|
||||||
var missingFiles = charaData.OriginalFiles.Where(c => !currentHashes.Contains(c.Hash, StringComparer.Ordinal)).ToList();
|
|
||||||
|
|
||||||
// now let's see what's on the db still
|
|
||||||
var existingDbFiles = await DbContext.Files
|
|
||||||
.Where(f => missingFiles.Select(k => k.Hash).Distinct().Contains(f.Hash))
|
|
||||||
.ToListAsync()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
// now shove it all back into the db
|
|
||||||
foreach (var dbFile in existingDbFiles)
|
|
||||||
{
|
|
||||||
var missingFileEntry = missingFiles.First(f => string.Equals(f.Hash, dbFile.Hash, StringComparison.Ordinal));
|
|
||||||
charaData.Files.Add(new CharaDataFile()
|
|
||||||
{
|
|
||||||
FileCache = dbFile,
|
|
||||||
GamePath = missingFileEntry.GamePath,
|
|
||||||
Parent = charaData
|
|
||||||
});
|
|
||||||
missingFiles.Remove(missingFileEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existingDbFiles.Any())
|
|
||||||
{
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetCharaDataFullDto(charaData);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<List<CharaDataMetaInfoDto>> CharaDataGetShared()
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo();
|
|
||||||
|
|
||||||
List<CharaData> sharedCharaData = [];
|
|
||||||
var groups = await DbContext.GroupPairs
|
|
||||||
.Where(u => u.GroupUserUID == UserUID)
|
|
||||||
.Select(k => k.GroupGID)
|
|
||||||
.AsNoTracking()
|
|
||||||
.ToListAsync()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
var individualPairs = await GetDirectPairedUnpausedUsers().ConfigureAwait(false);
|
|
||||||
var allPairs = await GetAllPairedUnpausedUsers().ConfigureAwait(false);
|
|
||||||
|
|
||||||
var allSharedDataByPair = await DbContext.CharaData
|
|
||||||
.Include(u => u.Files)
|
|
||||||
.Include(u => u.OriginalFiles)
|
|
||||||
.Include(u => u.AllowedIndividiuals)
|
|
||||||
.Include(u => u.Poses)
|
|
||||||
.Include(u => u.Uploader)
|
|
||||||
.Where(p => p.UploaderUID != UserUID && p.ShareType == CharaDataShare.Shared)
|
|
||||||
.Where(p =>
|
|
||||||
(individualPairs.Contains(p.UploaderUID) && p.AccessType == CharaDataAccess.ClosePairs)
|
|
||||||
|| (allPairs.Contains(p.UploaderUID) && p.AccessType == CharaDataAccess.AllPairs)
|
|
||||||
|| (p.AllowedIndividiuals.Any(u => u.AllowedUserUID == UserUID || (u.AllowedGroupGID != null && groups.Contains(u.AllowedGroupGID)))))
|
|
||||||
.AsSplitQuery()
|
|
||||||
.AsNoTracking()
|
|
||||||
.ToListAsync()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
|
|
||||||
foreach (var charaData in allSharedDataByPair)
|
|
||||||
{
|
|
||||||
sharedCharaData.Add(charaData);
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args("SUCCESS", sharedCharaData.Count));
|
|
||||||
|
|
||||||
return [.. sharedCharaData.Select(GetCharaDataMetaInfoDto)];
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<CharaDataFullDto?> CharaDataUpdate(CharaDataUpdateDto updateDto)
|
|
||||||
{
|
|
||||||
var charaData = await DbContext.CharaData
|
|
||||||
.Include(u => u.Files)
|
|
||||||
.Include(u => u.OriginalFiles)
|
|
||||||
.Include(u => u.AllowedIndividiuals)
|
|
||||||
.ThenInclude(u => u.AllowedUser)
|
|
||||||
.Include(u => u.AllowedIndividiuals)
|
|
||||||
.ThenInclude(u => u.AllowedGroup)
|
|
||||||
.Include(u => u.FileSwaps)
|
|
||||||
.Include(u => u.Poses)
|
|
||||||
.AsSplitQuery()
|
|
||||||
.SingleOrDefaultAsync(u => u.Id == updateDto.Id && u.UploaderUID == UserUID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (charaData == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
bool anyChanges = false;
|
|
||||||
|
|
||||||
if (updateDto.Description != null)
|
|
||||||
{
|
|
||||||
charaData.Description = updateDto.Description;
|
|
||||||
anyChanges = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateDto.ExpiryDate != null)
|
|
||||||
{
|
|
||||||
charaData.ExpiryDate = updateDto.ExpiryDate;
|
|
||||||
anyChanges = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateDto.GlamourerData != null)
|
|
||||||
{
|
|
||||||
charaData.GlamourerData = updateDto.GlamourerData;
|
|
||||||
anyChanges = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateDto.CustomizeData != null)
|
|
||||||
{
|
|
||||||
charaData.CustomizeData = updateDto.CustomizeData;
|
|
||||||
anyChanges = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateDto.ManipulationData != null)
|
|
||||||
{
|
|
||||||
charaData.ManipulationData = updateDto.ManipulationData;
|
|
||||||
anyChanges = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateDto.AccessType != null)
|
|
||||||
{
|
|
||||||
charaData.AccessType = GetAccessType(updateDto.AccessType.Value);
|
|
||||||
anyChanges = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateDto.ShareType != null)
|
|
||||||
{
|
|
||||||
charaData.ShareType = GetShareType(updateDto.ShareType.Value);
|
|
||||||
anyChanges = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateDto.AllowedUsers != null)
|
|
||||||
{
|
|
||||||
var individuals = charaData.AllowedIndividiuals.Where(k => k.AllowedGroup == null).ToList();
|
|
||||||
var allowedUserList = updateDto.AllowedUsers.ToList();
|
|
||||||
foreach (var user in updateDto.AllowedUsers)
|
|
||||||
{
|
|
||||||
if (charaData.AllowedIndividiuals.Any(k => k.AllowedUser != null && (string.Equals(k.AllowedUser.UID, user, StringComparison.Ordinal) || string.Equals(k.AllowedUser.Alias, user, StringComparison.Ordinal))))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var dbUser = await DbContext.Users.SingleOrDefaultAsync(u => u.UID == user || u.Alias == user).ConfigureAwait(false);
|
|
||||||
if (dbUser != null)
|
|
||||||
{
|
|
||||||
charaData.AllowedIndividiuals.Add(new CharaDataAllowance()
|
|
||||||
{
|
|
||||||
AllowedUser = dbUser,
|
|
||||||
Parent = charaData
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var dataUser in individuals.Where(k => !updateDto.AllowedUsers.Contains(k.AllowedUser.UID, StringComparer.Ordinal) && !updateDto.AllowedUsers.Contains(k.AllowedUser.Alias, StringComparer.Ordinal)))
|
|
||||||
{
|
|
||||||
DbContext.Remove(dataUser);
|
|
||||||
charaData.AllowedIndividiuals.Remove(dataUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
anyChanges = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateDto.AllowedGroups != null)
|
|
||||||
{
|
|
||||||
var individualGroups = charaData.AllowedIndividiuals.Where(k => k.AllowedUser == null).ToList();
|
|
||||||
var allowedGroups = updateDto.AllowedGroups.ToList();
|
|
||||||
foreach (var group in updateDto.AllowedGroups)
|
|
||||||
{
|
|
||||||
if (charaData.AllowedIndividiuals.Any(k => k.AllowedGroup != null && (string.Equals(k.AllowedGroup.GID, group, StringComparison.Ordinal) || string.Equals(k.AllowedGroup.Alias, group, StringComparison.Ordinal))))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var groupUser = await DbContext.GroupPairs.Include(u => u.Group).SingleOrDefaultAsync(u => (u.Group.GID == group || u.Group.Alias == group) && u.GroupUserUID == UserUID).ConfigureAwait(false);
|
|
||||||
if (groupUser != null)
|
|
||||||
{
|
|
||||||
charaData.AllowedIndividiuals.Add(new CharaDataAllowance()
|
|
||||||
{
|
|
||||||
AllowedGroup = groupUser.Group,
|
|
||||||
Parent = charaData
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var dataGroup in individualGroups.Where(k => !updateDto.AllowedGroups.Contains(k.AllowedGroup.GID, StringComparer.Ordinal) && !updateDto.AllowedGroups.Contains(k.AllowedGroup.Alias, StringComparer.Ordinal)))
|
|
||||||
{
|
|
||||||
DbContext.Remove(dataGroup);
|
|
||||||
charaData.AllowedIndividiuals.Remove(dataGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
anyChanges = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateDto.FileGamePaths != null)
|
|
||||||
{
|
|
||||||
var originalFiles = charaData.OriginalFiles.ToList();
|
|
||||||
charaData.OriginalFiles.Clear();
|
|
||||||
DbContext.RemoveRange(originalFiles);
|
|
||||||
var files = charaData.Files.ToList();
|
|
||||||
charaData.Files.Clear();
|
|
||||||
DbContext.RemoveRange(files);
|
|
||||||
foreach (var file in updateDto.FileGamePaths)
|
|
||||||
{
|
|
||||||
charaData.Files.Add(new CharaDataFile()
|
|
||||||
{
|
|
||||||
FileCacheHash = file.HashOrFileSwap,
|
|
||||||
GamePath = file.GamePath,
|
|
||||||
Parent = charaData
|
|
||||||
});
|
|
||||||
|
|
||||||
charaData.OriginalFiles.Add(new CharaDataOriginalFile()
|
|
||||||
{
|
|
||||||
Hash = file.HashOrFileSwap,
|
|
||||||
Parent = charaData,
|
|
||||||
GamePath = file.GamePath
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
anyChanges = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateDto.FileSwaps != null)
|
|
||||||
{
|
|
||||||
var fileSwaps = charaData.FileSwaps.ToList();
|
|
||||||
charaData.FileSwaps.Clear();
|
|
||||||
DbContext.RemoveRange(fileSwaps);
|
|
||||||
foreach (var file in updateDto.FileSwaps)
|
|
||||||
{
|
|
||||||
charaData.FileSwaps.Add(new CharaDataFileSwap()
|
|
||||||
{
|
|
||||||
FilePath = file.HashOrFileSwap,
|
|
||||||
GamePath = file.GamePath,
|
|
||||||
Parent = charaData
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
anyChanges = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateDto.Poses != null)
|
|
||||||
{
|
|
||||||
foreach (var pose in updateDto.Poses)
|
|
||||||
{
|
|
||||||
if (pose.Id == null)
|
|
||||||
{
|
|
||||||
charaData.Poses.Add(new CharaDataPose()
|
|
||||||
{
|
|
||||||
Description = pose.Description,
|
|
||||||
Parent = charaData,
|
|
||||||
ParentUploaderUID = UserUID,
|
|
||||||
PoseData = pose.PoseData,
|
|
||||||
WorldData = pose.WorldData == null ? string.Empty : JsonSerializer.Serialize(pose.WorldData),
|
|
||||||
});
|
|
||||||
|
|
||||||
anyChanges = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var associatedPose = charaData.Poses.FirstOrDefault(p => p.Id == pose.Id);
|
|
||||||
if (associatedPose == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (pose.Description == null && pose.PoseData == null && pose.WorldData == null)
|
|
||||||
{
|
|
||||||
charaData.Poses.Remove(associatedPose);
|
|
||||||
DbContext.Remove(associatedPose);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (pose.Description != null)
|
|
||||||
associatedPose.Description = pose.Description;
|
|
||||||
if (pose.WorldData != null)
|
|
||||||
{
|
|
||||||
if (pose.WorldData.Value == default) associatedPose.WorldData = string.Empty;
|
|
||||||
else associatedPose.WorldData = JsonSerializer.Serialize(pose.WorldData.Value);
|
|
||||||
}
|
|
||||||
if (pose.PoseData != null)
|
|
||||||
associatedPose.PoseData = pose.PoseData;
|
|
||||||
}
|
|
||||||
|
|
||||||
anyChanges = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var overflowingPoses = charaData.Poses.Skip(10).ToList();
|
|
||||||
foreach (var overflowing in overflowingPoses)
|
|
||||||
{
|
|
||||||
charaData.Poses.Remove(overflowing);
|
|
||||||
DbContext.Remove(overflowing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (anyChanges)
|
|
||||||
{
|
|
||||||
charaData.UpdatedDate = DateTime.UtcNow;
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args("SUCCESS", anyChanges));
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetCharaDataFullDto(charaData);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CharaDataAccess GetAccessType(AccessTypeDto dataAccess) => dataAccess switch
|
|
||||||
{
|
|
||||||
AccessTypeDto.Public => CharaDataAccess.Public,
|
|
||||||
AccessTypeDto.AllPairs => CharaDataAccess.AllPairs,
|
|
||||||
AccessTypeDto.ClosePairs => CharaDataAccess.ClosePairs,
|
|
||||||
AccessTypeDto.Individuals => CharaDataAccess.Individuals,
|
|
||||||
_ => throw new NotSupportedException(),
|
|
||||||
};
|
|
||||||
|
|
||||||
private static AccessTypeDto GetAccessTypeDto(CharaDataAccess dataAccess) => dataAccess switch
|
|
||||||
{
|
|
||||||
CharaDataAccess.Public => AccessTypeDto.Public,
|
|
||||||
CharaDataAccess.AllPairs => AccessTypeDto.AllPairs,
|
|
||||||
CharaDataAccess.ClosePairs => AccessTypeDto.ClosePairs,
|
|
||||||
CharaDataAccess.Individuals => AccessTypeDto.Individuals,
|
|
||||||
_ => throw new NotSupportedException(),
|
|
||||||
};
|
|
||||||
|
|
||||||
private static CharaDataDownloadDto GetCharaDataDownloadDto(CharaData charaData)
|
|
||||||
{
|
|
||||||
return new CharaDataDownloadDto(charaData.Id, charaData.Uploader.ToUserData())
|
|
||||||
{
|
|
||||||
CustomizeData = charaData.CustomizeData,
|
|
||||||
Description = charaData.Description,
|
|
||||||
FileGamePaths = charaData.Files.Select(k => new GamePathEntry(k.FileCacheHash, k.GamePath)).ToList(),
|
|
||||||
GlamourerData = charaData.GlamourerData,
|
|
||||||
FileSwaps = charaData.FileSwaps.Select(k => new GamePathEntry(k.FilePath, k.GamePath)).ToList(),
|
|
||||||
ManipulationData = charaData.ManipulationData,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private CharaDataFullDto GetCharaDataFullDto(CharaData charaData)
|
|
||||||
{
|
|
||||||
return new CharaDataFullDto(charaData.Id, new(UserUID))
|
|
||||||
{
|
|
||||||
AccessType = GetAccessTypeDto(charaData.AccessType),
|
|
||||||
ShareType = GetShareTypeDto(charaData.ShareType),
|
|
||||||
AllowedUsers = [.. charaData.AllowedIndividiuals.Where(k => !string.IsNullOrEmpty(k.AllowedUserUID)).Select(u => new UserData(u.AllowedUser.UID, u.AllowedUser.Alias))],
|
|
||||||
AllowedGroups = [.. charaData.AllowedIndividiuals.Where(k => !string.IsNullOrEmpty(k.AllowedGroupGID)).Select(k => new GroupData(k.AllowedGroup.GID, k.AllowedGroup.Alias))],
|
|
||||||
CustomizeData = charaData.CustomizeData,
|
|
||||||
Description = charaData.Description,
|
|
||||||
ExpiryDate = charaData.ExpiryDate ?? DateTime.MaxValue,
|
|
||||||
OriginalFiles = charaData.OriginalFiles.Select(k => new GamePathEntry(k.Hash, k.GamePath)).ToList(),
|
|
||||||
FileGamePaths = charaData.Files.Select(k => new GamePathEntry(k.FileCacheHash, k.GamePath)).ToList(),
|
|
||||||
FileSwaps = charaData.FileSwaps.Select(k => new GamePathEntry(k.FilePath, k.GamePath)).ToList(),
|
|
||||||
GlamourerData = charaData.GlamourerData,
|
|
||||||
CreatedDate = charaData.CreatedDate,
|
|
||||||
UpdatedDate = charaData.UpdatedDate,
|
|
||||||
ManipulationData = charaData.ManipulationData,
|
|
||||||
DownloadCount = charaData.DownloadCount,
|
|
||||||
PoseData = [.. charaData.Poses.OrderBy(p => p.Id).Select(k =>
|
|
||||||
{
|
|
||||||
WorldData data = default;
|
|
||||||
|
|
||||||
if(!string.IsNullOrEmpty(k.WorldData)) data = JsonSerializer.Deserialize<WorldData>(k.WorldData);
|
|
||||||
return new PoseEntry(k.Id)
|
|
||||||
{
|
|
||||||
Description = k.Description,
|
|
||||||
PoseData = k.PoseData,
|
|
||||||
WorldData = data
|
|
||||||
};
|
|
||||||
})],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CharaDataMetaInfoDto GetCharaDataMetaInfoDto(CharaData charaData)
|
|
||||||
{
|
|
||||||
var allOrigHashes = charaData.OriginalFiles.Select(k => k.Hash).ToList();
|
|
||||||
var allFileHashes = charaData.Files.Select(f => f.FileCacheHash).ToList();
|
|
||||||
var allHashesPresent = allOrigHashes.TrueForAll(h => allFileHashes.Contains(h, StringComparer.Ordinal));
|
|
||||||
var canBeDownloaded = allHashesPresent &= !string.IsNullOrEmpty(charaData.GlamourerData);
|
|
||||||
return new CharaDataMetaInfoDto(charaData.Id, charaData.Uploader.ToUserData())
|
|
||||||
{
|
|
||||||
CanBeDownloaded = canBeDownloaded,
|
|
||||||
Description = charaData.Description,
|
|
||||||
UpdatedDate = charaData.UpdatedDate,
|
|
||||||
PoseData = [.. charaData.Poses.OrderBy(p => p.Id).Select(k =>
|
|
||||||
{
|
|
||||||
WorldData data = default;
|
|
||||||
if(!string.IsNullOrEmpty(k.WorldData)) data = JsonSerializer.Deserialize<WorldData>(k.WorldData);
|
|
||||||
return new PoseEntry(k.Id)
|
|
||||||
{
|
|
||||||
Description = k.Description,
|
|
||||||
PoseData = k.PoseData,
|
|
||||||
WorldData = data
|
|
||||||
};
|
|
||||||
})],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CharaDataShare GetShareType(ShareTypeDto dataShare) => dataShare switch
|
|
||||||
{
|
|
||||||
ShareTypeDto.Shared => CharaDataShare.Shared,
|
|
||||||
ShareTypeDto.Private => CharaDataShare.Private,
|
|
||||||
_ => throw new NotSupportedException(),
|
|
||||||
};
|
|
||||||
|
|
||||||
private static ShareTypeDto GetShareTypeDto(CharaDataShare dataShare) => dataShare switch
|
|
||||||
{
|
|
||||||
CharaDataShare.Shared => ShareTypeDto.Shared,
|
|
||||||
CharaDataShare.Private => ShareTypeDto.Private,
|
|
||||||
_ => throw new NotSupportedException(),
|
|
||||||
};
|
|
||||||
|
|
||||||
private async Task<bool> CheckCharaDataAllowance(CharaData charaData, List<string> joinedGroups)
|
|
||||||
{
|
|
||||||
// check for self
|
|
||||||
if (string.Equals(charaData.UploaderUID, UserUID, StringComparison.Ordinal))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// check for public access
|
|
||||||
if (charaData.AccessType == CharaDataAccess.Public)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// check for individuals
|
|
||||||
if (charaData.AllowedIndividiuals.Any(u => string.Equals(u.AllowedUserUID, UserUID, StringComparison.Ordinal)))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
var pairInfoUploader = await GetAllPairedUnpausedUsers(charaData.UploaderUID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// check for all pairs
|
|
||||||
if (charaData.AccessType == CharaDataAccess.AllPairs)
|
|
||||||
{
|
|
||||||
if (pairInfoUploader.Any(pair => string.Equals(pair, UserUID, StringComparison.Ordinal)))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for individual pairs
|
|
||||||
if (charaData.AccessType == CharaDataAccess.ClosePairs)
|
|
||||||
{
|
|
||||||
if (pairInfoUploader.Any(pair => string.Equals(pair, UserUID, StringComparison.Ordinal)))
|
|
||||||
{
|
|
||||||
ClientPair callerPair =
|
|
||||||
await DbContext.ClientPairs.AsNoTracking().SingleOrDefaultAsync(w => w.UserUID == UserUID && w.OtherUserUID == charaData.UploaderUID).ConfigureAwait(false);
|
|
||||||
ClientPair uploaderPair =
|
|
||||||
await DbContext.ClientPairs.AsNoTracking().SingleOrDefaultAsync(w => w.UserUID == charaData.UploaderUID && w.OtherUserUID == UserUID).ConfigureAwait(false);
|
|
||||||
return (callerPair != null && uploaderPair != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<CharaData> GetCharaDataById(string id, string methodName)
|
|
||||||
{
|
|
||||||
var splitid = id.Split(":", StringSplitOptions.None);
|
|
||||||
if (splitid.Length != 2)
|
|
||||||
{
|
|
||||||
_logger.LogCallWarning(MareHubLogger.Args("INVALID", id));
|
|
||||||
throw new InvalidOperationException($"Id {id} not in expected format");
|
|
||||||
}
|
|
||||||
|
|
||||||
var charaData = await DbContext.CharaData
|
|
||||||
.Include(u => u.Files)
|
|
||||||
.Include(u => u.FileSwaps)
|
|
||||||
.Include(u => u.AllowedIndividiuals)
|
|
||||||
.Include(u => u.Poses)
|
|
||||||
.Include(u => u.Uploader)
|
|
||||||
.AsSplitQuery()
|
|
||||||
.SingleOrDefaultAsync(c => c.Id == splitid[1] && c.UploaderUID == splitid[0]).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (charaData == null)
|
|
||||||
{
|
|
||||||
_logger.LogCallWarning(MareHubLogger.Args("NOT FOUND", id));
|
|
||||||
throw new InvalidDataException($"No chara data with {id} found");
|
|
||||||
}
|
|
||||||
|
|
||||||
var groups = await DbContext.GroupPairs.Where(u => u.GroupUserUID == UserUID).Select(k => k.GroupGID).ToListAsync()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!await CheckCharaDataAllowance(charaData, groups).ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
_logger.LogCallWarning(MareHubLogger.Args("UNAUTHORIZED", id));
|
|
||||||
throw new UnauthorizedAccessException($"User is not allowed to download {id}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return charaData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
using MareSynchronos.API.Data;
|
|
||||||
using MareSynchronos.API.Data.Enum;
|
|
||||||
using MareSynchronos.API.Dto.Group;
|
|
||||||
using MareSynchronos.API.Dto.User;
|
|
||||||
using MareSynchronosServer.Utils;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Hubs;
|
|
||||||
|
|
||||||
public partial class MareHub
|
|
||||||
{
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public Task UserChatSendMsg(UserDto dto, ChatMessage message)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
// TODO
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task GroupChatSendMsg(GroupDto dto, ChatMessage message)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
var (userExists, groupPair) = await TryValidateUserInGroup(dto.GID, UserUID).ConfigureAwait(false);
|
|
||||||
if (!userExists) return;
|
|
||||||
|
|
||||||
var group = await DbContext.Groups.AsNoTracking().SingleAsync(g => g.GID == dto.GID).ConfigureAwait(false);
|
|
||||||
var sender = await DbContext.Users.AsNoTracking().SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
|
|
||||||
var groupPairs = await DbContext.GroupPairs.AsNoTracking().Include(p => p.GroupUser).Where(p => p.GroupGID == dto.Group.GID).ToListAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (group == null || sender == null) return;
|
|
||||||
|
|
||||||
// TODO: Add and check chat permissions
|
|
||||||
if (group.Alias?.Equals("Umbra", StringComparison.Ordinal) ?? false)
|
|
||||||
{
|
|
||||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, $"Chat is disabled for syncshell '{dto.GroupAliasOrGID}'.").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TOOO: Sign the message
|
|
||||||
var signedMessage = new SignedChatMessage(message, sender.ToUserData())
|
|
||||||
{
|
|
||||||
Timestamp = 0,
|
|
||||||
Signature = "",
|
|
||||||
};
|
|
||||||
|
|
||||||
await Clients.Users(groupPairs.Select(p => p.GroupUserUID)).Client_GroupChatMsg(new(new(group.ToGroupData()), signedMessage)).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
using MareSynchronos.API.Data;
|
|
||||||
using MareSynchronos.API.Data.Enum;
|
|
||||||
using MareSynchronos.API.Dto;
|
|
||||||
using MareSynchronos.API.Dto.CharaData;
|
|
||||||
using MareSynchronos.API.Dto.Chat;
|
|
||||||
using MareSynchronos.API.Dto.Group;
|
|
||||||
using MareSynchronos.API.Dto.User;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Hubs
|
|
||||||
{
|
|
||||||
public partial class MareHub
|
|
||||||
{
|
|
||||||
public Task Client_DownloadReady(Guid requestId) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_GroupChangePermissions(GroupPermissionDto groupPermission) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_GroupChatMsg(GroupChatMsgDto groupChatMsgDto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_GroupDelete(GroupDto groupDto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_GroupPairChangePermissions(GroupPairUserPermissionDto permissionDto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_GroupPairChangeUserInfo(GroupPairUserInfoDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_GroupPairJoined(GroupPairFullInfoDto groupPairInfoDto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_GroupPairLeft(GroupPairDto groupPairDto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_GroupSendFullInfo(GroupFullInfoDto groupInfo) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_GroupSendInfo(GroupInfoDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_ReceiveServerMessage(MessageSeverity messageSeverity, string message) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_UpdateSystemInfo(SystemInfoDto systemInfo) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_UserAddClientPair(UserPairDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_UserChatMsg(UserChatMsgDto userChatMsgDto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_UserReceiveCharacterData(OnlineUserCharaDataDto dataDto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_UserReceiveUploadStatus(UserDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_UserRemoveClientPair(UserDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_UserSendOffline(UserDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_UserSendOnline(OnlineUserIdentDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_UserUpdateOtherPairPermissions(UserPermissionsDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_UserUpdateProfile(UserDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_UserUpdateSelfPairPermissions(UserPermissionsDto dto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
|
|
||||||
public Task Client_GposeLobbyJoin(UserData userData) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
public Task Client_GposeLobbyLeave(UserData userData) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
public Task Client_GposeLobbyPushCharacterData(CharaDataDownloadDto charaDownloadDto) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
public Task Client_GposeLobbyPushPoseData(UserData userData, PoseData poseData) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
public Task Client_GposeLobbyPushWorldData(UserData userData, WorldData worldData) => throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,299 +0,0 @@
|
|||||||
using MareSynchronosShared.Models;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using MareSynchronosServer.Utils;
|
|
||||||
using MareSynchronosShared.Utils;
|
|
||||||
using MareSynchronos.API.Data;
|
|
||||||
using MareSynchronos.API.Dto.Group;
|
|
||||||
using MareSynchronosShared.Metrics;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Hubs;
|
|
||||||
|
|
||||||
public partial class MareHub
|
|
||||||
{
|
|
||||||
public string UserCharaIdent => Context.User?.Claims?.SingleOrDefault(c => string.Equals(c.Type, MareClaimTypes.CharaIdent, StringComparison.Ordinal))?.Value ?? throw new Exception("No Chara Ident in Claims");
|
|
||||||
|
|
||||||
public string UserUID => Context.User?.Claims?.SingleOrDefault(c => string.Equals(c.Type, MareClaimTypes.Uid, StringComparison.Ordinal))?.Value ?? throw new Exception("No UID in Claims");
|
|
||||||
|
|
||||||
public string Continent => Context.User?.Claims?.SingleOrDefault(c => string.Equals(c.Type, MareClaimTypes.Continent, StringComparison.Ordinal))?.Value ?? "UNK";
|
|
||||||
|
|
||||||
private async Task DeleteUser(User user)
|
|
||||||
{
|
|
||||||
var ownPairData = await DbContext.ClientPairs.Where(u => u.User.UID == user.UID).ToListAsync().ConfigureAwait(false);
|
|
||||||
var auth = await DbContext.Auth.SingleAsync(u => u.UserUID == user.UID).ConfigureAwait(false);
|
|
||||||
var lodestone = await DbContext.LodeStoneAuth.SingleOrDefaultAsync(a => a.User.UID == user.UID).ConfigureAwait(false);
|
|
||||||
var groupPairs = await DbContext.GroupPairs.Where(g => g.GroupUserUID == user.UID).ToListAsync().ConfigureAwait(false);
|
|
||||||
var userProfileData = await DbContext.UserProfileData.SingleOrDefaultAsync(u => u.UserUID == user.UID).ConfigureAwait(false);
|
|
||||||
var bannedEntries = await DbContext.GroupBans.Where(u => u.BannedUserUID == user.UID).ToListAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (lodestone != null)
|
|
||||||
{
|
|
||||||
DbContext.Remove(lodestone);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userProfileData != null)
|
|
||||||
{
|
|
||||||
DbContext.Remove(userProfileData);
|
|
||||||
}
|
|
||||||
|
|
||||||
DbContext.ClientPairs.RemoveRange(ownPairData);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
var otherPairData = await DbContext.ClientPairs.Include(u => u.User)
|
|
||||||
.Where(u => u.OtherUser.UID == user.UID).AsNoTracking().ToListAsync().ConfigureAwait(false);
|
|
||||||
foreach (var pair in otherPairData)
|
|
||||||
{
|
|
||||||
await Clients.User(pair.UserUID).Client_UserRemoveClientPair(new(user.ToUserData())).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var pair in groupPairs)
|
|
||||||
{
|
|
||||||
await UserLeaveGroup(new GroupDto(new GroupData(pair.GroupGID)), user.UID).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
_mareMetrics.IncCounter(MetricsAPI.CounterUsersRegisteredDeleted, 1);
|
|
||||||
|
|
||||||
DbContext.GroupBans.RemoveRange(bannedEntries);
|
|
||||||
DbContext.ClientPairs.RemoveRange(otherPairData);
|
|
||||||
DbContext.Users.Remove(user);
|
|
||||||
DbContext.Auth.Remove(auth);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<List<PausedEntry>> GetAllPairedClientsWithPauseState(string? uid = null)
|
|
||||||
{
|
|
||||||
uid ??= UserUID;
|
|
||||||
|
|
||||||
var query = await (from userPair in DbContext.ClientPairs
|
|
||||||
join otherUserPair in DbContext.ClientPairs on userPair.OtherUserUID equals otherUserPair.UserUID
|
|
||||||
where otherUserPair.OtherUserUID == uid && userPair.UserUID == uid
|
|
||||||
select new
|
|
||||||
{
|
|
||||||
UID = Convert.ToString(userPair.OtherUserUID),
|
|
||||||
GID = "DIRECT",
|
|
||||||
PauseStateSelf = userPair.IsPaused,
|
|
||||||
PauseStateOther = otherUserPair.IsPaused,
|
|
||||||
})
|
|
||||||
.Union(
|
|
||||||
(from userGroupPair in DbContext.GroupPairs
|
|
||||||
join otherGroupPair in DbContext.GroupPairs on userGroupPair.GroupGID equals otherGroupPair.GroupGID
|
|
||||||
where
|
|
||||||
userGroupPair.GroupUserUID == uid
|
|
||||||
&& otherGroupPair.GroupUserUID != uid
|
|
||||||
select new
|
|
||||||
{
|
|
||||||
UID = Convert.ToString(otherGroupPair.GroupUserUID),
|
|
||||||
GID = Convert.ToString(otherGroupPair.GroupGID),
|
|
||||||
PauseStateSelf = userGroupPair.IsPaused,
|
|
||||||
PauseStateOther = otherGroupPair.IsPaused,
|
|
||||||
})
|
|
||||||
).AsNoTracking().ToListAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
return query.GroupBy(g => g.UID, g => (g.GID, g.PauseStateSelf, g.PauseStateOther),
|
|
||||||
(key, g) => new PausedEntry
|
|
||||||
{
|
|
||||||
UID = key,
|
|
||||||
PauseStates = g.Select(p => new PauseState() { GID = string.Equals(p.GID, "DIRECT", StringComparison.Ordinal) ? null : p.GID, IsSelfPaused = p.PauseStateSelf, IsOtherPaused = p.PauseStateOther })
|
|
||||||
.ToList(),
|
|
||||||
}, StringComparer.Ordinal).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<List<string>> GetAllPairedUnpausedUsers(string? uid = null)
|
|
||||||
{
|
|
||||||
uid ??= UserUID;
|
|
||||||
var ret = await GetAllPairedClientsWithPauseState(uid).ConfigureAwait(false);
|
|
||||||
return ret.Where(k => !k.IsPaused).Select(k => k.UID).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<List<string>> GetDirectPairedUnpausedUsers(string? uid = null)
|
|
||||||
{
|
|
||||||
uid ??= UserUID;
|
|
||||||
|
|
||||||
var query = await (from userPair in DbContext.ClientPairs
|
|
||||||
join otherUserPair in DbContext.ClientPairs on userPair.OtherUserUID equals otherUserPair.UserUID
|
|
||||||
where otherUserPair.OtherUserUID == uid && userPair.UserUID == uid && !userPair.IsPaused && !otherUserPair.IsPaused
|
|
||||||
select Convert.ToString(userPair.OtherUserUID)).AsNoTracking().ToListAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
return query;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<Dictionary<string, string>> GetOnlineUsers(List<string> uids)
|
|
||||||
{
|
|
||||||
var result = await _redis.GetAllAsync<string>(uids.Select(u => "UID:" + u).ToHashSet(StringComparer.Ordinal)).ConfigureAwait(false);
|
|
||||||
return uids.Where(u => result.TryGetValue("UID:" + u, out var ident) && !string.IsNullOrEmpty(ident)).ToDictionary(u => u, u => result["UID:" + u], StringComparer.Ordinal);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> GetUserIdent(string uid)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(uid)) return string.Empty;
|
|
||||||
return await _redis.GetAsync<string>("UID:" + uid).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task RemoveUserFromRedis()
|
|
||||||
{
|
|
||||||
await _redis.RemoveAsync("UID:" + UserUID, StackExchange.Redis.CommandFlags.FireAndForget).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SendGroupDeletedToAll(List<GroupPair> groupUsers)
|
|
||||||
{
|
|
||||||
foreach (var pair in groupUsers)
|
|
||||||
{
|
|
||||||
var pairIdent = await GetUserIdent(pair.GroupUserUID).ConfigureAwait(false);
|
|
||||||
if (string.IsNullOrEmpty(pairIdent)) continue;
|
|
||||||
|
|
||||||
var pairs = await GetAllPairedClientsWithPauseState(pair.GroupUserUID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
foreach (var groupUserPair in groupUsers.Where(g => !string.Equals(g.GroupUserUID, pair.GroupUserUID, StringComparison.Ordinal)))
|
|
||||||
{
|
|
||||||
await UserGroupLeave(groupUserPair, pairs, pairIdent, pair.GroupUserUID).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<List<string>> SendOfflineToAllPairedUsers()
|
|
||||||
{
|
|
||||||
var usersToSendDataTo = await GetAllPairedUnpausedUsers().ConfigureAwait(false);
|
|
||||||
var self = await DbContext.Users.AsNoTracking().SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
|
|
||||||
await Clients.Users(usersToSendDataTo).Client_UserSendOffline(new(self.ToUserData())).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return usersToSendDataTo;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<List<string>> SendOnlineToAllPairedUsers()
|
|
||||||
{
|
|
||||||
var usersToSendDataTo = await GetAllPairedUnpausedUsers().ConfigureAwait(false);
|
|
||||||
var self = await DbContext.Users.AsNoTracking().SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
|
|
||||||
await Clients.Users(usersToSendDataTo).Client_UserSendOnline(new(self.ToUserData(), UserCharaIdent)).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return usersToSendDataTo;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<(bool IsValid, Group ReferredGroup)> TryValidateGroupModeratorOrOwner(string gid)
|
|
||||||
{
|
|
||||||
var isOwnerResult = await TryValidateOwner(gid).ConfigureAwait(false);
|
|
||||||
if (isOwnerResult.isValid) return (true, isOwnerResult.ReferredGroup);
|
|
||||||
|
|
||||||
if (isOwnerResult.ReferredGroup == null) return (false, null);
|
|
||||||
|
|
||||||
var groupPairSelf = await DbContext.GroupPairs.SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == UserUID).ConfigureAwait(false);
|
|
||||||
if (groupPairSelf == null || !groupPairSelf.IsModerator) return (false, null);
|
|
||||||
|
|
||||||
return (true, isOwnerResult.ReferredGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<(bool isValid, Group ReferredGroup)> TryValidateOwner(string gid)
|
|
||||||
{
|
|
||||||
var group = await DbContext.Groups.SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false);
|
|
||||||
if (group == null) return (false, null);
|
|
||||||
|
|
||||||
return (string.Equals(group.OwnerUID, UserUID, StringComparison.Ordinal), group);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<(bool IsValid, GroupPair ReferredPair)> TryValidateUserInGroup(string gid, string? uid = null)
|
|
||||||
{
|
|
||||||
uid ??= UserUID;
|
|
||||||
|
|
||||||
var groupPair = await DbContext.GroupPairs.Include(c => c.GroupUser)
|
|
||||||
.SingleOrDefaultAsync(g => g.GroupGID == gid && (g.GroupUserUID == uid || g.GroupUser.Alias == uid)).ConfigureAwait(false);
|
|
||||||
if (groupPair == null) return (false, null);
|
|
||||||
|
|
||||||
return (true, groupPair);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UpdateUserOnRedis()
|
|
||||||
{
|
|
||||||
await _redis.AddAsync("UID:" + UserUID, UserCharaIdent, TimeSpan.FromSeconds(60), StackExchange.Redis.When.Always, StackExchange.Redis.CommandFlags.FireAndForget).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UserGroupLeave(GroupPair groupUserPair, List<PausedEntry> allUserPairs, string userIdent, string? uid = null)
|
|
||||||
{
|
|
||||||
uid ??= UserUID;
|
|
||||||
var userPair = allUserPairs.SingleOrDefault(p => string.Equals(p.UID, groupUserPair.GroupUserUID, StringComparison.Ordinal));
|
|
||||||
if (userPair != null)
|
|
||||||
{
|
|
||||||
if (userPair.IsDirectlyPaused != PauseInfo.NoConnection) return;
|
|
||||||
if (userPair.IsPausedPerGroup is PauseInfo.Unpaused) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var groupUserIdent = await GetUserIdent(groupUserPair.GroupUserUID).ConfigureAwait(false);
|
|
||||||
if (!string.IsNullOrEmpty(groupUserIdent))
|
|
||||||
{
|
|
||||||
await Clients.User(uid).Client_UserSendOffline(new(new(groupUserPair.GroupUserUID))).ConfigureAwait(false);
|
|
||||||
await Clients.User(groupUserPair.GroupUserUID).Client_UserSendOffline(new(new(uid))).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UserLeaveGroup(GroupDto dto, string userUid)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
var (exists, groupPair) = await TryValidateUserInGroup(dto.Group.GID, userUid).ConfigureAwait(false);
|
|
||||||
if (!exists) return;
|
|
||||||
|
|
||||||
var group = await DbContext.Groups.SingleOrDefaultAsync(g => g.GID == dto.Group.GID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var groupPairs = await DbContext.GroupPairs.Where(p => p.GroupGID == group.GID).ToListAsync().ConfigureAwait(false);
|
|
||||||
var groupPairsWithoutSelf = groupPairs.Where(p => !string.Equals(p.GroupUserUID, userUid, StringComparison.Ordinal)).ToList();
|
|
||||||
|
|
||||||
DbContext.GroupPairs.Remove(groupPair);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
await Clients.User(userUid).Client_GroupDelete(new GroupDto(group.ToGroupData())).ConfigureAwait(false);
|
|
||||||
|
|
||||||
bool ownerHasLeft = string.Equals(group.OwnerUID, userUid, StringComparison.Ordinal);
|
|
||||||
if (ownerHasLeft)
|
|
||||||
{
|
|
||||||
if (!groupPairsWithoutSelf.Any())
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, "Deleted"));
|
|
||||||
|
|
||||||
DbContext.Groups.Remove(group);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var groupHasMigrated = await SharedDbFunctions.MigrateOrDeleteGroup(DbContext, group, groupPairsWithoutSelf, _maxExistingGroupsByUser).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (groupHasMigrated.Item1)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, "Migrated", groupHasMigrated.Item2));
|
|
||||||
|
|
||||||
var user = await DbContext.Users.SingleAsync(u => u.UID == groupHasMigrated.Item2).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await Clients.Users(groupPairsWithoutSelf.Select(p => p.GroupUserUID)).Client_GroupSendInfo(new GroupInfoDto(group.ToGroupData(),
|
|
||||||
user.ToUserData(), group.GetGroupPermissions())
|
|
||||||
{
|
|
||||||
IsTemporary = group.IsTemporary,
|
|
||||||
ExpiresAt = group.ExpiresAt,
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, "Deleted"));
|
|
||||||
|
|
||||||
await Clients.Users(groupPairsWithoutSelf.Select(p => p.GroupUserUID)).Client_GroupDelete(dto).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await SendGroupDeletedToAll(groupPairs).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var sharedData = await DbContext.CharaDataAllowances.Where(u => u.AllowedGroup != null && u.AllowedGroupGID == dto.GID && u.ParentUploaderUID == userUid).ToListAsync().ConfigureAwait(false);
|
|
||||||
DbContext.CharaDataAllowances.RemoveRange(sharedData);
|
|
||||||
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, "Success"));
|
|
||||||
|
|
||||||
await Clients.Users(groupPairsWithoutSelf.Select(p => p.GroupUserUID)).Client_GroupPairLeft(new GroupPairDto(dto.Group, groupPair.GroupUser.ToUserData())).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var allUserPairs = await GetAllPairedClientsWithPauseState().ConfigureAwait(false);
|
|
||||||
|
|
||||||
var ident = await GetUserIdent(userUid).ConfigureAwait(false);
|
|
||||||
|
|
||||||
foreach (var groupUserPair in groupPairsWithoutSelf)
|
|
||||||
{
|
|
||||||
await UserGroupLeave(groupUserPair, allUserPairs, ident, userUid).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
using MareSynchronos.API.Data;
|
|
||||||
using MareSynchronos.API.Dto.CharaData;
|
|
||||||
using MareSynchronosServer.Utils;
|
|
||||||
using MareSynchronosShared.Metrics;
|
|
||||||
using MareSynchronosShared.Utils;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Hubs;
|
|
||||||
|
|
||||||
public partial class MareHub
|
|
||||||
{
|
|
||||||
private async Task<string?> GetUserGposeLobby()
|
|
||||||
{
|
|
||||||
return await _redis.GetAsync<string>(GposeLobbyUser).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<List<string>> GetUsersInLobby(string lobbyId, bool includeSelf = false)
|
|
||||||
{
|
|
||||||
var users = await _redis.GetAsync<List<string>>($"GposeLobby:{lobbyId}").ConfigureAwait(false);
|
|
||||||
return users?.Where(u => includeSelf || !string.Equals(u, UserUID, StringComparison.Ordinal)).ToList() ?? [];
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task AddUserToLobby(string lobbyId, List<string> priorUsers)
|
|
||||||
{
|
|
||||||
_mareMetrics.IncGauge(MetricsAPI.GaugeGposeLobbyUsers);
|
|
||||||
if (priorUsers.Count == 0)
|
|
||||||
_mareMetrics.IncGauge(MetricsAPI.GaugeGposeLobbies);
|
|
||||||
|
|
||||||
await _redis.AddAsync(GposeLobbyUser, lobbyId).ConfigureAwait(false);
|
|
||||||
await _redis.AddAsync($"GposeLobby:{lobbyId}", priorUsers.Concat([UserUID])).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task RemoveUserFromLobby(string lobbyId, List<string> priorUsers)
|
|
||||||
{
|
|
||||||
await _redis.RemoveAsync(GposeLobbyUser).ConfigureAwait(false);
|
|
||||||
|
|
||||||
_mareMetrics.DecGauge(MetricsAPI.GaugeGposeLobbyUsers);
|
|
||||||
|
|
||||||
if (priorUsers.Count == 1)
|
|
||||||
{
|
|
||||||
await _redis.RemoveAsync($"GposeLobby:{lobbyId}").ConfigureAwait(false);
|
|
||||||
_mareMetrics.DecGauge(MetricsAPI.GaugeGposeLobbies);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
priorUsers.Remove(UserUID);
|
|
||||||
await _redis.AddAsync($"GposeLobby:{lobbyId}", priorUsers).ConfigureAwait(false);
|
|
||||||
await Clients.Users(priorUsers).Client_GposeLobbyLeave(new(UserUID)).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GposeLobbyUser => $"GposeLobbyUser:{UserUID}";
|
|
||||||
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<string> GposeLobbyCreate()
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo();
|
|
||||||
var alreadyInLobby = await GetUserGposeLobby().ConfigureAwait(false);
|
|
||||||
if (!string.IsNullOrEmpty(alreadyInLobby))
|
|
||||||
{
|
|
||||||
throw new HubException("Already in GPose Lobby, cannot join another");
|
|
||||||
}
|
|
||||||
|
|
||||||
string lobbyId = string.Empty;
|
|
||||||
while (string.IsNullOrEmpty(lobbyId))
|
|
||||||
{
|
|
||||||
lobbyId = StringUtils.GenerateRandomString(30, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
|
|
||||||
var result = await _redis.GetAsync<List<string>>($"GposeLobby:{lobbyId}").ConfigureAwait(false);
|
|
||||||
if (result != null)
|
|
||||||
lobbyId = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
await AddUserToLobby(lobbyId, []).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return lobbyId;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<List<UserData>> GposeLobbyJoin(string lobbyId)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo();
|
|
||||||
var existingLobbyId = await GetUserGposeLobby().ConfigureAwait(false);
|
|
||||||
if (!string.IsNullOrEmpty(existingLobbyId))
|
|
||||||
await GposeLobbyLeave().ConfigureAwait(false);
|
|
||||||
|
|
||||||
var lobbyUsers = await GetUsersInLobby(lobbyId).ConfigureAwait(false);
|
|
||||||
if (!lobbyUsers.Any())
|
|
||||||
return [];
|
|
||||||
|
|
||||||
await AddUserToLobby(lobbyId, lobbyUsers).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var user = await DbContext.Users.SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
|
|
||||||
await Clients.Users(lobbyUsers.Where(u => !string.Equals(u, UserUID, StringComparison.Ordinal)))
|
|
||||||
.Client_GposeLobbyJoin(user.ToUserData()).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var users = await DbContext.Users.Where(u => lobbyUsers.Contains(u.UID))
|
|
||||||
.Select(u => u.ToUserData())
|
|
||||||
.ToListAsync()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
return users;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<bool> GposeLobbyLeave()
|
|
||||||
{
|
|
||||||
var lobbyId = await GetUserGposeLobby().ConfigureAwait(false);
|
|
||||||
if (string.IsNullOrEmpty(lobbyId))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
_logger.LogCallInfo();
|
|
||||||
|
|
||||||
var lobbyUsers = await GetUsersInLobby(lobbyId, true).ConfigureAwait(false);
|
|
||||||
await RemoveUserFromLobby(lobbyId, lobbyUsers).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task GposeLobbyPushCharacterData(CharaDataDownloadDto charaDataDownloadDto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo();
|
|
||||||
var lobbyId = await GetUserGposeLobby().ConfigureAwait(false);
|
|
||||||
if (string.IsNullOrEmpty(lobbyId))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var lobbyUsers = await GetUsersInLobby(lobbyId).ConfigureAwait(false);
|
|
||||||
await Clients.Users(lobbyUsers).Client_GposeLobbyPushCharacterData(charaDataDownloadDto).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task GposeLobbyPushPoseData(PoseData poseData)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo();
|
|
||||||
var lobbyId = await GetUserGposeLobby().ConfigureAwait(false);
|
|
||||||
if (string.IsNullOrEmpty(lobbyId))
|
|
||||||
return;
|
|
||||||
|
|
||||||
await _gPoseLobbyDistributionService.PushPoseData(lobbyId, UserUID, poseData).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task GposeLobbyPushWorldData(WorldData worldData)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo();
|
|
||||||
var lobbyId = await GetUserGposeLobby().ConfigureAwait(false);
|
|
||||||
if (string.IsNullOrEmpty(lobbyId))
|
|
||||||
return;
|
|
||||||
|
|
||||||
await _gPoseLobbyDistributionService.PushWorldData(lobbyId, UserUID, worldData).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,681 +0,0 @@
|
|||||||
using MareSynchronos.API.Data;
|
|
||||||
using MareSynchronos.API.Data.Enum;
|
|
||||||
using MareSynchronos.API.Data.Extensions;
|
|
||||||
using MareSynchronos.API.Dto.Chat;
|
|
||||||
using MareSynchronos.API.Dto.Group;
|
|
||||||
using MareSynchronosServer.Utils;
|
|
||||||
using MareSynchronosShared.Models;
|
|
||||||
using MareSynchronosShared.Utils;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Hubs;
|
|
||||||
|
|
||||||
public partial class MareHub
|
|
||||||
{
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task GroupBanUser(GroupPairDto dto, string reason)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, reason));
|
|
||||||
|
|
||||||
var (userHasRights, group) = await TryValidateGroupModeratorOrOwner(dto.Group.GID).ConfigureAwait(false);
|
|
||||||
if (!userHasRights) return;
|
|
||||||
|
|
||||||
var (userExists, groupPair) = await TryValidateUserInGroup(dto.Group.GID, dto.User.UID).ConfigureAwait(false);
|
|
||||||
if (!userExists) return;
|
|
||||||
|
|
||||||
if (groupPair.IsModerator || string.Equals(group.OwnerUID, dto.User.UID, StringComparison.Ordinal)) return;
|
|
||||||
|
|
||||||
var alias = string.IsNullOrEmpty(groupPair.GroupUser.Alias) ? "-" : groupPair.GroupUser.Alias;
|
|
||||||
var ban = new GroupBan()
|
|
||||||
{
|
|
||||||
BannedByUID = UserUID,
|
|
||||||
BannedReason = $"{reason} (Alias at time of ban: {alias})",
|
|
||||||
BannedOn = DateTime.UtcNow,
|
|
||||||
BannedUserUID = dto.User.UID,
|
|
||||||
GroupGID = dto.Group.GID,
|
|
||||||
};
|
|
||||||
|
|
||||||
DbContext.Add(ban);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
await GroupRemoveUser(dto).ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, "Success"));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task GroupChangeGroupPermissionState(GroupPermissionDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
var (hasRights, group) = await TryValidateGroupModeratorOrOwner(dto.Group.GID).ConfigureAwait(false);
|
|
||||||
if (!hasRights) return;
|
|
||||||
|
|
||||||
group.InvitesEnabled = !dto.Permissions.HasFlag(GroupPermissions.DisableInvites);
|
|
||||||
group.DisableSounds = dto.Permissions.HasFlag(GroupPermissions.DisableSounds);
|
|
||||||
group.DisableAnimations = dto.Permissions.HasFlag(GroupPermissions.DisableAnimations);
|
|
||||||
group.DisableVFX = dto.Permissions.HasFlag(GroupPermissions.DisableVFX);
|
|
||||||
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
var groupPairs = DbContext.GroupPairs.Where(p => p.GroupGID == dto.Group.GID).Select(p => p.GroupUserUID).ToList();
|
|
||||||
await Clients.Users(groupPairs).Client_GroupChangePermissions(new GroupPermissionDto(dto.Group, dto.Permissions)).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task GroupChangeIndividualPermissionState(GroupPairUserPermissionDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
var (inGroup, groupPair) = await TryValidateUserInGroup(dto.Group.GID).ConfigureAwait(false);
|
|
||||||
if (!inGroup) return;
|
|
||||||
|
|
||||||
var wasPaused = groupPair.IsPaused;
|
|
||||||
groupPair.DisableSounds = dto.GroupPairPermissions.IsDisableSounds();
|
|
||||||
groupPair.DisableAnimations = dto.GroupPairPermissions.IsDisableAnimations();
|
|
||||||
groupPair.IsPaused = dto.GroupPairPermissions.IsPaused();
|
|
||||||
groupPair.DisableVFX = dto.GroupPairPermissions.IsDisableVFX();
|
|
||||||
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
var groupPairs = DbContext.GroupPairs.Include(p => p.GroupUser).Where(p => p.GroupGID == dto.Group.GID).ToList();
|
|
||||||
await Clients.Users(groupPairs.Select(p => p.GroupUserUID)).Client_GroupPairChangePermissions(dto).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var allUserPairs = await GetAllPairedClientsWithPauseState().ConfigureAwait(false);
|
|
||||||
var self = await DbContext.Users.SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (wasPaused == groupPair.IsPaused) return;
|
|
||||||
|
|
||||||
foreach (var groupUserPair in groupPairs.Where(u => !string.Equals(u.GroupUserUID, UserUID, StringComparison.Ordinal)).ToList())
|
|
||||||
{
|
|
||||||
var userPair = allUserPairs.SingleOrDefault(p => string.Equals(p.UID, groupUserPair.GroupUserUID, StringComparison.Ordinal));
|
|
||||||
if (userPair != null)
|
|
||||||
{
|
|
||||||
if (userPair.IsDirectlyPaused != PauseInfo.NoConnection) continue;
|
|
||||||
if (userPair.IsPausedExcludingGroup(dto.Group.GID) is PauseInfo.Unpaused) continue;
|
|
||||||
if (userPair.IsOtherPausedForSpecificGroup(dto.Group.GID) is PauseInfo.Paused) continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var groupUserIdent = await GetUserIdent(groupUserPair.GroupUserUID).ConfigureAwait(false);
|
|
||||||
if (!string.IsNullOrEmpty(groupUserIdent))
|
|
||||||
{
|
|
||||||
if (!groupPair.IsPaused)
|
|
||||||
{
|
|
||||||
await Clients.User(UserUID).Client_UserSendOnline(new(groupUserPair.ToUserData(), groupUserIdent)).ConfigureAwait(false);
|
|
||||||
await Clients.User(groupUserPair.GroupUserUID)
|
|
||||||
.Client_UserSendOnline(new(self.ToUserData(), UserCharaIdent)).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await Clients.User(UserUID).Client_UserSendOffline(new(groupUserPair.ToUserData())).ConfigureAwait(false);
|
|
||||||
await Clients.User(groupUserPair.GroupUserUID)
|
|
||||||
.Client_UserSendOffline(new(self.ToUserData())).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task GroupChangeOwnership(GroupPairDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
var (isOwner, group) = await TryValidateOwner(dto.Group.GID).ConfigureAwait(false);
|
|
||||||
if (!isOwner) return;
|
|
||||||
|
|
||||||
var (isInGroup, newOwnerPair) = await TryValidateUserInGroup(dto.Group.GID, dto.User.UID).ConfigureAwait(false);
|
|
||||||
if (!isInGroup) return;
|
|
||||||
|
|
||||||
var ownedShells = await DbContext.Groups.CountAsync(g => g.OwnerUID == dto.User.UID).ConfigureAwait(false);
|
|
||||||
if (ownedShells >= _maxExistingGroupsByUser) return;
|
|
||||||
|
|
||||||
var prevOwner = await DbContext.GroupPairs.SingleOrDefaultAsync(g => g.GroupGID == dto.Group.GID && g.GroupUserUID == UserUID).ConfigureAwait(false);
|
|
||||||
prevOwner.IsPinned = false;
|
|
||||||
group.Owner = newOwnerPair.GroupUser;
|
|
||||||
group.Alias = null;
|
|
||||||
newOwnerPair.IsPinned = true;
|
|
||||||
newOwnerPair.IsModerator = false;
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, "Success"));
|
|
||||||
|
|
||||||
var groupPairs = await DbContext.GroupPairs.Where(p => p.GroupGID == dto.Group.GID).Select(p => p.GroupUserUID).AsNoTracking().ToListAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
await Clients.Users(groupPairs).Client_GroupSendInfo(new GroupInfoDto(group.ToGroupData(), newOwnerPair.GroupUser.ToUserData(), group.GetGroupPermissions())
|
|
||||||
{
|
|
||||||
IsTemporary = group.IsTemporary,
|
|
||||||
ExpiresAt = group.ExpiresAt,
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<bool> GroupChangePassword(GroupPasswordDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
var (isOwner, group) = await TryValidateOwner(dto.Group.GID).ConfigureAwait(false);
|
|
||||||
if (!isOwner || dto.Password.Length < 10) return false;
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, "Success"));
|
|
||||||
|
|
||||||
group.HashedPassword = StringUtils.Sha256String(dto.Password);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task GroupClear(GroupDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
var (hasRights, group) = await TryValidateGroupModeratorOrOwner(dto.Group.GID).ConfigureAwait(false);
|
|
||||||
if (!hasRights) return;
|
|
||||||
|
|
||||||
var groupPairs = await DbContext.GroupPairs.Include(p => p.GroupUser).Where(p => p.GroupGID == dto.Group.GID).ToListAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
await Clients.Users(groupPairs.Where(p => !p.IsPinned && !p.IsModerator).Select(g => g.GroupUserUID)).Client_GroupDelete(new GroupDto(group.ToGroupData())).ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, "Success"));
|
|
||||||
|
|
||||||
var notPinned = groupPairs.Where(g => !g.IsPinned && !g.IsModerator).ToList();
|
|
||||||
|
|
||||||
DbContext.GroupPairs.RemoveRange(notPinned);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
foreach (var pair in notPinned)
|
|
||||||
{
|
|
||||||
await Clients.Users(groupPairs.Where(p => p.IsPinned).Select(g => g.GroupUserUID)).Client_GroupPairLeft(new GroupPairDto(dto.Group, pair.GroupUser.ToUserData())).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var pairIdent = await GetUserIdent(pair.GroupUserUID).ConfigureAwait(false);
|
|
||||||
if (string.IsNullOrEmpty(pairIdent)) continue;
|
|
||||||
|
|
||||||
var allUserPairs = await GetAllPairedClientsWithPauseState(pair.GroupUserUID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var sharedData = await DbContext.CharaDataAllowances.Where(u => u.AllowedGroup != null && u.AllowedGroupGID == dto.GID && u.ParentUploaderUID == pair.GroupUserUID).ToListAsync().ConfigureAwait(false);
|
|
||||||
DbContext.CharaDataAllowances.RemoveRange(sharedData);
|
|
||||||
|
|
||||||
foreach (var groupUserPair in groupPairs.Where(p => !string.Equals(p.GroupUserUID, pair.GroupUserUID, StringComparison.Ordinal)))
|
|
||||||
{
|
|
||||||
await UserGroupLeave(groupUserPair, allUserPairs, pairIdent).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<GroupPasswordDto> GroupCreate(string? alias)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo();
|
|
||||||
var existingGroupsByUser = await DbContext.Groups.CountAsync(u => u.OwnerUID == UserUID).ConfigureAwait(false);
|
|
||||||
var existingJoinedGroups = await DbContext.GroupPairs.CountAsync(u => u.GroupUserUID == UserUID).ConfigureAwait(false);
|
|
||||||
if (existingGroupsByUser >= _maxExistingGroupsByUser || existingJoinedGroups >= _maxJoinedGroupsByUser)
|
|
||||||
{
|
|
||||||
throw new System.Exception($"Max groups for user is {_maxExistingGroupsByUser}, max joined groups is {_maxJoinedGroupsByUser}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var gid = StringUtils.GenerateRandomString(9);
|
|
||||||
while (await DbContext.Groups.AnyAsync(g => g.GID == "UMB-" + gid).ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
gid = StringUtils.GenerateRandomString(9);
|
|
||||||
}
|
|
||||||
gid = "UMB-" + gid;
|
|
||||||
|
|
||||||
var passwd = StringUtils.GenerateRandomString(16);
|
|
||||||
var sha = SHA256.Create();
|
|
||||||
var hashedPw = StringUtils.Sha256String(passwd);
|
|
||||||
|
|
||||||
string? sanitizedAlias = null;
|
|
||||||
if (!string.IsNullOrWhiteSpace(alias))
|
|
||||||
{
|
|
||||||
sanitizedAlias = alias.Trim();
|
|
||||||
if (sanitizedAlias.Length > 50)
|
|
||||||
{
|
|
||||||
sanitizedAlias = sanitizedAlias[..50];
|
|
||||||
}
|
|
||||||
|
|
||||||
var aliasExists = await DbContext.Groups
|
|
||||||
.AnyAsync(g => g.Alias != null && EF.Functions.ILike(g.Alias!, sanitizedAlias))
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
if (aliasExists)
|
|
||||||
{
|
|
||||||
throw new System.Exception("Syncshell name is already in use.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Group newGroup = new()
|
|
||||||
{
|
|
||||||
GID = gid,
|
|
||||||
HashedPassword = hashedPw,
|
|
||||||
InvitesEnabled = true,
|
|
||||||
OwnerUID = UserUID,
|
|
||||||
Alias = sanitizedAlias,
|
|
||||||
IsTemporary = false,
|
|
||||||
ExpiresAt = null,
|
|
||||||
};
|
|
||||||
|
|
||||||
GroupPair initialPair = new()
|
|
||||||
{
|
|
||||||
GroupGID = newGroup.GID,
|
|
||||||
GroupUserUID = UserUID,
|
|
||||||
IsPaused = false,
|
|
||||||
IsPinned = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
await DbContext.Groups.AddAsync(newGroup).ConfigureAwait(false);
|
|
||||||
await DbContext.GroupPairs.AddAsync(initialPair).ConfigureAwait(false);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
var self = await DbContext.Users.SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await Clients.User(UserUID).Client_GroupSendFullInfo(new GroupFullInfoDto(newGroup.ToGroupData(), self.ToUserData(), GroupPermissions.NoneSet, GroupUserPermissions.NoneSet, GroupUserInfo.None)
|
|
||||||
{
|
|
||||||
IsTemporary = newGroup.IsTemporary,
|
|
||||||
ExpiresAt = newGroup.ExpiresAt,
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(gid));
|
|
||||||
|
|
||||||
return new GroupPasswordDto(newGroup.ToGroupData(), passwd)
|
|
||||||
{
|
|
||||||
IsTemporary = newGroup.IsTemporary,
|
|
||||||
ExpiresAt = newGroup.ExpiresAt,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<GroupPasswordDto> GroupCreateTemporary(DateTime expiresAtUtc)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo();
|
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
if (expiresAtUtc.Kind == DateTimeKind.Unspecified)
|
|
||||||
{
|
|
||||||
expiresAtUtc = DateTime.SpecifyKind(expiresAtUtc, DateTimeKind.Utc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expiresAtUtc <= now)
|
|
||||||
{
|
|
||||||
throw new System.Exception("Expiration must be in the future.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expiresAtUtc > now.AddDays(7))
|
|
||||||
{
|
|
||||||
throw new System.Exception("Temporary syncshells may not last longer than 7 days.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var existingGroupsByUser = await DbContext.Groups.CountAsync(u => u.OwnerUID == UserUID).ConfigureAwait(false);
|
|
||||||
var existingJoinedGroups = await DbContext.GroupPairs.CountAsync(u => u.GroupUserUID == UserUID).ConfigureAwait(false);
|
|
||||||
if (existingGroupsByUser >= _maxExistingGroupsByUser || existingJoinedGroups >= _maxJoinedGroupsByUser)
|
|
||||||
{
|
|
||||||
throw new System.Exception($"Max groups for user is {_maxExistingGroupsByUser}, max joined groups is {_maxJoinedGroupsByUser}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var gid = StringUtils.GenerateRandomString(9);
|
|
||||||
while (await DbContext.Groups.AnyAsync(g => g.GID == "UMB-" + gid).ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
gid = StringUtils.GenerateRandomString(9);
|
|
||||||
}
|
|
||||||
gid = "UMB-" + gid;
|
|
||||||
|
|
||||||
var passwd = StringUtils.GenerateRandomString(16);
|
|
||||||
var sha = SHA256.Create();
|
|
||||||
var hashedPw = StringUtils.Sha256String(passwd);
|
|
||||||
|
|
||||||
Group newGroup = new()
|
|
||||||
{
|
|
||||||
GID = gid,
|
|
||||||
HashedPassword = hashedPw,
|
|
||||||
InvitesEnabled = true,
|
|
||||||
OwnerUID = UserUID,
|
|
||||||
Alias = null,
|
|
||||||
IsTemporary = true,
|
|
||||||
ExpiresAt = expiresAtUtc,
|
|
||||||
};
|
|
||||||
|
|
||||||
GroupPair initialPair = new()
|
|
||||||
{
|
|
||||||
GroupGID = newGroup.GID,
|
|
||||||
GroupUserUID = UserUID,
|
|
||||||
IsPaused = false,
|
|
||||||
IsPinned = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
await DbContext.Groups.AddAsync(newGroup).ConfigureAwait(false);
|
|
||||||
await DbContext.GroupPairs.AddAsync(initialPair).ConfigureAwait(false);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
var self = await DbContext.Users.SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await Clients.User(UserUID).Client_GroupSendFullInfo(new GroupFullInfoDto(newGroup.ToGroupData(), self.ToUserData(), GroupPermissions.NoneSet, GroupUserPermissions.NoneSet, GroupUserInfo.None)
|
|
||||||
{
|
|
||||||
IsTemporary = newGroup.IsTemporary,
|
|
||||||
ExpiresAt = newGroup.ExpiresAt,
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(gid, "Temporary", expiresAtUtc));
|
|
||||||
|
|
||||||
return new GroupPasswordDto(newGroup.ToGroupData(), passwd)
|
|
||||||
{
|
|
||||||
IsTemporary = newGroup.IsTemporary,
|
|
||||||
ExpiresAt = newGroup.ExpiresAt,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<List<string>> GroupCreateTempInvite(GroupDto dto, int amount)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, amount));
|
|
||||||
List<string> inviteCodes = new();
|
|
||||||
List<GroupTempInvite> tempInvites = new();
|
|
||||||
var (hasRights, group) = await TryValidateGroupModeratorOrOwner(dto.Group.GID).ConfigureAwait(false);
|
|
||||||
if (!hasRights) return new();
|
|
||||||
|
|
||||||
var existingInvites = await DbContext.GroupTempInvites.Where(g => g.GroupGID == group.GID).ToListAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
for (int i = 0; i < amount; i++)
|
|
||||||
{
|
|
||||||
bool hasValidInvite = false;
|
|
||||||
string invite = string.Empty;
|
|
||||||
string hashedInvite = string.Empty;
|
|
||||||
while (!hasValidInvite)
|
|
||||||
{
|
|
||||||
invite = StringUtils.GenerateRandomString(10, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
|
|
||||||
hashedInvite = StringUtils.Sha256String(invite);
|
|
||||||
if (existingInvites.Any(i => string.Equals(i.Invite, hashedInvite, StringComparison.Ordinal))) continue;
|
|
||||||
hasValidInvite = true;
|
|
||||||
inviteCodes.Add(invite);
|
|
||||||
}
|
|
||||||
|
|
||||||
tempInvites.Add(new GroupTempInvite()
|
|
||||||
{
|
|
||||||
ExpirationDate = DateTime.UtcNow.AddDays(1),
|
|
||||||
GroupGID = group.GID,
|
|
||||||
Invite = hashedInvite,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
DbContext.GroupTempInvites.AddRange(tempInvites);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
return inviteCodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task GroupDelete(GroupDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
var (hasRights, group) = await TryValidateOwner(dto.Group.GID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, "Success"));
|
|
||||||
|
|
||||||
var groupPairs = await DbContext.GroupPairs.Where(p => p.GroupGID == dto.Group.GID).ToListAsync().ConfigureAwait(false);
|
|
||||||
DbContext.RemoveRange(groupPairs);
|
|
||||||
DbContext.Remove(group);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
await Clients.Users(groupPairs.Select(g => g.GroupUserUID)).Client_GroupDelete(new GroupDto(group.ToGroupData())).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await SendGroupDeletedToAll(groupPairs).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<List<BannedGroupUserDto>> GroupGetBannedUsers(GroupDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
var (userHasRights, group) = await TryValidateGroupModeratorOrOwner(dto.GID).ConfigureAwait(false);
|
|
||||||
if (!userHasRights) return new List<BannedGroupUserDto>();
|
|
||||||
|
|
||||||
var banEntries = await DbContext.GroupBans.Include(b => b.BannedUser).Where(g => g.GroupGID == dto.Group.GID).AsNoTracking().ToListAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
List<BannedGroupUserDto> bannedGroupUsers = banEntries.Select(b =>
|
|
||||||
new BannedGroupUserDto(group.ToGroupData(), b.BannedUser.ToUserData(), b.BannedReason, b.BannedOn,
|
|
||||||
b.BannedByUID)).ToList();
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, bannedGroupUsers.Count));
|
|
||||||
|
|
||||||
return bannedGroupUsers;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<bool> GroupJoin(GroupPasswordDto dto)
|
|
||||||
{
|
|
||||||
var aliasOrGid = dto.Group.GID.Trim();
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto.Group));
|
|
||||||
|
|
||||||
var group = await DbContext.Groups.Include(g => g.Owner).AsNoTracking().SingleOrDefaultAsync(g => g.GID == aliasOrGid || g.Alias == aliasOrGid).ConfigureAwait(false);
|
|
||||||
var groupGid = group?.GID ?? string.Empty;
|
|
||||||
var existingPair = await DbContext.GroupPairs.AsNoTracking().SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.GroupUserUID == UserUID).ConfigureAwait(false);
|
|
||||||
var hashedPw = StringUtils.Sha256String(dto.Password);
|
|
||||||
var existingUserCount = await DbContext.GroupPairs.AsNoTracking().CountAsync(g => g.GroupGID == groupGid).ConfigureAwait(false);
|
|
||||||
var joinedGroups = await DbContext.GroupPairs.CountAsync(g => g.GroupUserUID == UserUID).ConfigureAwait(false);
|
|
||||||
var isBanned = await DbContext.GroupBans.AnyAsync(g => g.GroupGID == groupGid && g.BannedUserUID == UserUID).ConfigureAwait(false);
|
|
||||||
var oneTimeInvite = await DbContext.GroupTempInvites.SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.Invite == hashedPw).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (group == null
|
|
||||||
|| (!string.Equals(group.HashedPassword, hashedPw, StringComparison.Ordinal) && oneTimeInvite == null)
|
|
||||||
|| existingPair != null
|
|
||||||
|| existingUserCount >= _maxGroupUserCount
|
|
||||||
|| !group.InvitesEnabled
|
|
||||||
|| joinedGroups >= _maxJoinedGroupsByUser
|
|
||||||
|| isBanned)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (oneTimeInvite != null)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(aliasOrGid, "TempInvite", oneTimeInvite.Invite));
|
|
||||||
DbContext.Remove(oneTimeInvite);
|
|
||||||
}
|
|
||||||
|
|
||||||
GroupPair newPair = new()
|
|
||||||
{
|
|
||||||
GroupGID = group.GID,
|
|
||||||
GroupUserUID = UserUID,
|
|
||||||
DisableAnimations = false,
|
|
||||||
DisableSounds = false,
|
|
||||||
DisableVFX = false
|
|
||||||
};
|
|
||||||
|
|
||||||
await DbContext.GroupPairs.AddAsync(newPair).ConfigureAwait(false);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(aliasOrGid, "Success"));
|
|
||||||
|
|
||||||
await Clients.User(UserUID).Client_GroupSendFullInfo(new GroupFullInfoDto(group.ToGroupData(), group.Owner.ToUserData(), group.GetGroupPermissions(), newPair.GetGroupPairPermissions(), newPair.GetGroupPairUserInfo())
|
|
||||||
{
|
|
||||||
IsTemporary = group.IsTemporary,
|
|
||||||
ExpiresAt = group.ExpiresAt,
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var self = DbContext.Users.Single(u => u.UID == UserUID);
|
|
||||||
|
|
||||||
var groupPairs = await DbContext.GroupPairs.Include(p => p.GroupUser).Where(p => p.GroupGID == group.GID && p.GroupUserUID != UserUID).ToListAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
await Clients.Users(groupPairs.Select(p => p.GroupUserUID))
|
|
||||||
.Client_GroupPairJoined(new GroupPairFullInfoDto(group.ToGroupData(), self.ToUserData(), newPair.GetGroupPairUserInfo(), newPair.GetGroupPairPermissions())).ConfigureAwait(false);
|
|
||||||
foreach (var pair in groupPairs)
|
|
||||||
{
|
|
||||||
await Clients.User(UserUID).Client_GroupPairJoined(new GroupPairFullInfoDto(group.ToGroupData(), pair.ToUserData(), pair.GetGroupPairUserInfo(), pair.GetGroupPairPermissions())).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
var allUserPairs = await GetAllPairedClientsWithPauseState().ConfigureAwait(false);
|
|
||||||
|
|
||||||
foreach (var groupUserPair in groupPairs)
|
|
||||||
{
|
|
||||||
var userPair = allUserPairs.Single(p => string.Equals(p.UID, groupUserPair.GroupUserUID, StringComparison.Ordinal));
|
|
||||||
if (userPair.IsDirectlyPaused != PauseInfo.NoConnection) continue;
|
|
||||||
if (userPair.IsPausedExcludingGroup(group.GID) is PauseInfo.Unpaused) continue;
|
|
||||||
if (userPair.IsPausedPerGroup is PauseInfo.Paused) continue;
|
|
||||||
|
|
||||||
var groupUserIdent = await GetUserIdent(groupUserPair.GroupUserUID).ConfigureAwait(false);
|
|
||||||
if (!string.IsNullOrEmpty(groupUserIdent))
|
|
||||||
{
|
|
||||||
await Clients.User(UserUID).Client_UserSendOnline(new(groupUserPair.ToUserData(), groupUserIdent)).ConfigureAwait(false);
|
|
||||||
await Clients.User(groupUserPair.GroupUserUID)
|
|
||||||
.Client_UserSendOnline(new(self.ToUserData(), UserCharaIdent)).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task GroupLeave(GroupDto dto)
|
|
||||||
{
|
|
||||||
await UserLeaveGroup(dto, UserUID).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<int> GroupPrune(GroupDto dto, int days, bool execute)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, days, execute));
|
|
||||||
|
|
||||||
var (hasRights, group) = await TryValidateGroupModeratorOrOwner(dto.Group.GID).ConfigureAwait(false);
|
|
||||||
if (!hasRights) return -1;
|
|
||||||
|
|
||||||
var allGroupUsers = await DbContext.GroupPairs.Include(p => p.GroupUser).Include(p => p.Group)
|
|
||||||
.Where(g => g.GroupGID == dto.Group.GID)
|
|
||||||
.ToListAsync().ConfigureAwait(false);
|
|
||||||
var usersToPrune = allGroupUsers.Where(p => !p.IsPinned && !p.IsModerator
|
|
||||||
&& p.GroupUserUID != UserUID
|
|
||||||
&& p.Group.OwnerUID != p.GroupUserUID
|
|
||||||
&& p.GroupUser.LastLoggedIn.AddDays(days) < DateTime.UtcNow);
|
|
||||||
|
|
||||||
if (!execute) return usersToPrune.Count();
|
|
||||||
|
|
||||||
DbContext.GroupPairs.RemoveRange(usersToPrune);
|
|
||||||
|
|
||||||
foreach (var pair in usersToPrune)
|
|
||||||
{
|
|
||||||
await Clients.Users(allGroupUsers.Where(p => !usersToPrune.Contains(p)).Select(g => g.GroupUserUID))
|
|
||||||
.Client_GroupPairLeft(new GroupPairDto(dto.Group, pair.GroupUser.ToUserData())).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
return usersToPrune.Count();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task GroupRemoveUser(GroupPairDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
var (hasRights, group) = await TryValidateGroupModeratorOrOwner(dto.Group.GID).ConfigureAwait(false);
|
|
||||||
if (!hasRights) return;
|
|
||||||
|
|
||||||
var (userExists, groupPair) = await TryValidateUserInGroup(dto.Group.GID, dto.User.UID).ConfigureAwait(false);
|
|
||||||
if (!userExists) return;
|
|
||||||
|
|
||||||
if (groupPair.IsModerator || string.Equals(group.OwnerUID, dto.User.UID, StringComparison.Ordinal)) return;
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, "Success"));
|
|
||||||
|
|
||||||
DbContext.GroupPairs.Remove(groupPair);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
var groupPairs = DbContext.GroupPairs.Where(p => p.GroupGID == group.GID).AsNoTracking().ToList();
|
|
||||||
await Clients.Users(groupPairs.Select(p => p.GroupUserUID)).Client_GroupPairLeft(dto).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var sharedData = await DbContext.CharaDataAllowances.Where(u => u.AllowedGroup != null && u.AllowedGroupGID == dto.GID && u.ParentUploaderUID == dto.UID).ToListAsync().ConfigureAwait(false);
|
|
||||||
DbContext.CharaDataAllowances.RemoveRange(sharedData);
|
|
||||||
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
var userIdent = await GetUserIdent(dto.User.UID).ConfigureAwait(false);
|
|
||||||
if (userIdent == null) return;
|
|
||||||
|
|
||||||
await Clients.User(dto.User.UID).Client_GroupDelete(new GroupDto(dto.Group)).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var allUserPairs = await GetAllPairedClientsWithPauseState(dto.User.UID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
foreach (var groupUserPair in groupPairs)
|
|
||||||
{
|
|
||||||
await UserGroupLeave(groupUserPair, allUserPairs, userIdent, dto.User.UID).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task GroupSetUserInfo(GroupPairUserInfoDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
var (userExists, userPair) = await TryValidateUserInGroup(dto.Group.GID, dto.User.UID).ConfigureAwait(false);
|
|
||||||
if (!userExists) return;
|
|
||||||
|
|
||||||
var (userIsOwner, _) = await TryValidateOwner(dto.Group.GID).ConfigureAwait(false);
|
|
||||||
var (userIsModerator, _) = await TryValidateGroupModeratorOrOwner(dto.Group.GID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (dto.GroupUserInfo.HasFlag(GroupUserInfo.IsPinned) && userIsModerator && !userPair.IsPinned)
|
|
||||||
{
|
|
||||||
userPair.IsPinned = true;
|
|
||||||
}
|
|
||||||
else if (userIsModerator && userPair.IsPinned)
|
|
||||||
{
|
|
||||||
userPair.IsPinned = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dto.GroupUserInfo.HasFlag(GroupUserInfo.IsModerator) && userIsOwner && !userPair.IsModerator)
|
|
||||||
{
|
|
||||||
userPair.IsModerator = true;
|
|
||||||
}
|
|
||||||
else if (userIsOwner && userPair.IsModerator)
|
|
||||||
{
|
|
||||||
userPair.IsModerator = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
var groupPairs = await DbContext.GroupPairs.AsNoTracking().Where(p => p.GroupGID == dto.Group.GID).Select(p => p.GroupUserUID).ToListAsync().ConfigureAwait(false);
|
|
||||||
await Clients.Users(groupPairs).Client_GroupPairChangeUserInfo(new GroupPairUserInfoDto(dto.Group, dto.User, userPair.GetGroupPairUserInfo())).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<List<GroupFullInfoDto>> GroupsGetAll()
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo();
|
|
||||||
|
|
||||||
var groups = await DbContext.GroupPairs.Include(g => g.Group).Include(g => g.Group.Owner).Where(g => g.GroupUserUID == UserUID).AsNoTracking().ToListAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
return groups.Select(g => new GroupFullInfoDto(g.Group.ToGroupData(), g.Group.Owner.ToUserData(),
|
|
||||||
g.Group.GetGroupPermissions(), g.GetGroupPairPermissions(), g.GetGroupPairUserInfo())
|
|
||||||
{
|
|
||||||
IsTemporary = g.Group.IsTemporary,
|
|
||||||
ExpiresAt = g.Group.ExpiresAt,
|
|
||||||
}).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<List<GroupPairFullInfoDto>> GroupsGetUsersInGroup(GroupDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
var (inGroup, _) = await TryValidateUserInGroup(dto.Group.GID).ConfigureAwait(false);
|
|
||||||
if (!inGroup) return new List<GroupPairFullInfoDto>();
|
|
||||||
|
|
||||||
var group = await DbContext.Groups.SingleAsync(g => g.GID == dto.Group.GID).ConfigureAwait(false);
|
|
||||||
var allPairs = await DbContext.GroupPairs.Include(g => g.GroupUser).Where(g => g.GroupGID == dto.Group.GID && g.GroupUserUID != UserUID).AsNoTracking().ToListAsync().ConfigureAwait(false);
|
|
||||||
return allPairs.Select(p => new GroupPairFullInfoDto(group.ToGroupData(), p.GroupUser.ToUserData(), p.GetGroupPairUserInfo(), p.GetGroupPairPermissions())).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task GroupUnbanUser(GroupPairDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
var (userHasRights, _) = await TryValidateGroupModeratorOrOwner(dto.Group.GID).ConfigureAwait(false);
|
|
||||||
if (!userHasRights) return;
|
|
||||||
|
|
||||||
var banEntry = await DbContext.GroupBans.SingleOrDefaultAsync(g => g.GroupGID == dto.Group.GID && g.BannedUserUID == dto.User.UID).ConfigureAwait(false);
|
|
||||||
if (banEntry == null) return;
|
|
||||||
|
|
||||||
DbContext.Remove(banEntry);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, "Success"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,514 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using MareSynchronos.API.Data;
|
|
||||||
using MareSynchronos.API.Data.Enum;
|
|
||||||
using MareSynchronos.API.Data.Extensions;
|
|
||||||
using MareSynchronos.API.Dto.User;
|
|
||||||
using MareSynchronosServer.Utils;
|
|
||||||
using MareSynchronosShared.Metrics;
|
|
||||||
using MareSynchronosShared.Models;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using SixLabors.ImageSharp;
|
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Hubs;
|
|
||||||
|
|
||||||
public partial class MareHub
|
|
||||||
{
|
|
||||||
private static readonly string[] AllowedExtensionsForGamePaths = { ".mdl", ".tex", ".mtrl", ".tmb", ".pap", ".avfx", ".atex", ".sklb", ".eid", ".phyb", ".pbd", ".scd", ".skp", ".shpk" };
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task UserAddPair(UserDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
// don't allow adding nothing
|
|
||||||
var uid = dto.User.UID.Trim();
|
|
||||||
if (string.Equals(dto.User.UID, UserUID, StringComparison.Ordinal) || string.IsNullOrWhiteSpace(dto.User.UID)) return;
|
|
||||||
|
|
||||||
// grab other user, check if it exists and if a pair already exists
|
|
||||||
var otherUser = await DbContext.Users.SingleOrDefaultAsync(u => u.UID == uid || u.Alias == uid).ConfigureAwait(false);
|
|
||||||
if (otherUser == null)
|
|
||||||
{
|
|
||||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, $"Cannot pair with {dto.User.UID}, UID does not exist").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.Equals(otherUser.UID, UserUID, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, $"My god you can't pair with yourself why would you do that please stop").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var existingEntry =
|
|
||||||
await DbContext.ClientPairs.AsNoTracking()
|
|
||||||
.FirstOrDefaultAsync(p =>
|
|
||||||
p.User.UID == UserUID && p.OtherUserUID == otherUser.UID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (existingEntry != null)
|
|
||||||
{
|
|
||||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, $"Cannot pair with {dto.User.UID}, already paired").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// grab self create new client pair and save
|
|
||||||
var user = await DbContext.Users.SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, "Success"));
|
|
||||||
|
|
||||||
ClientPair wl = new ClientPair()
|
|
||||||
{
|
|
||||||
IsPaused = false,
|
|
||||||
OtherUser = otherUser,
|
|
||||||
User = user,
|
|
||||||
};
|
|
||||||
await DbContext.ClientPairs.AddAsync(wl).ConfigureAwait(false);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
// get the opposite entry of the client pair
|
|
||||||
var otherEntry = OppositeEntry(otherUser.UID);
|
|
||||||
var otherIdent = await GetUserIdent(otherUser.UID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var ownPerm = UserPermissions.Paired;
|
|
||||||
var otherPerm = UserPermissions.NoneSet;
|
|
||||||
otherPerm.SetPaired(otherEntry != null);
|
|
||||||
otherPerm.SetPaused(otherEntry?.IsPaused ?? false);
|
|
||||||
var userPairResponse = new UserPairDto(otherUser.ToUserData(), ownPerm, otherPerm);
|
|
||||||
await Clients.User(user.UID).Client_UserAddClientPair(userPairResponse).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// check if other user is online
|
|
||||||
if (otherIdent == null || otherEntry == null) return;
|
|
||||||
|
|
||||||
// send push with update to other user if other user is online
|
|
||||||
await Clients.User(otherUser.UID).Client_UserAddClientPair(new UserPairDto(user.ToUserData(), otherPerm, ownPerm)).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!otherPerm.IsPaused())
|
|
||||||
{
|
|
||||||
await Clients.User(UserUID).Client_UserSendOnline(new(otherUser.ToUserData(), otherIdent)).ConfigureAwait(false);
|
|
||||||
await Clients.User(otherUser.UID).Client_UserSendOnline(new(user.ToUserData(), UserCharaIdent)).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task UserDelete()
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo();
|
|
||||||
|
|
||||||
var userEntry = await DbContext.Users.SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
|
|
||||||
var secondaryUsers = await DbContext.Auth.Include(u => u.User).Where(u => u.PrimaryUserUID == UserUID).Select(c => c.User).ToListAsync().ConfigureAwait(false);
|
|
||||||
foreach (var user in secondaryUsers)
|
|
||||||
{
|
|
||||||
await DeleteUser(user).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
await DeleteUser(userEntry).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<List<OnlineUserIdentDto>> UserGetOnlinePairs()
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo();
|
|
||||||
|
|
||||||
var allPairedUsers = await GetAllPairedUnpausedUsers().ConfigureAwait(false);
|
|
||||||
var pairs = await GetOnlineUsers(allPairedUsers).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await SendOnlineToAllPairedUsers().ConfigureAwait(false);
|
|
||||||
|
|
||||||
return pairs.Select(p => new OnlineUserIdentDto(new UserData(p.Key), p.Value)).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<List<UserPairDto>> UserGetPairedClients()
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo();
|
|
||||||
|
|
||||||
var query =
|
|
||||||
from userToOther in DbContext.ClientPairs
|
|
||||||
join otherToUser in DbContext.ClientPairs
|
|
||||||
on new
|
|
||||||
{
|
|
||||||
user = userToOther.UserUID,
|
|
||||||
other = userToOther.OtherUserUID,
|
|
||||||
} equals new
|
|
||||||
{
|
|
||||||
user = otherToUser.OtherUserUID,
|
|
||||||
other = otherToUser.UserUID,
|
|
||||||
} into leftJoin
|
|
||||||
from otherEntry in leftJoin.DefaultIfEmpty()
|
|
||||||
where
|
|
||||||
userToOther.UserUID == UserUID
|
|
||||||
select new
|
|
||||||
{
|
|
||||||
userToOther.OtherUser.Alias,
|
|
||||||
userToOther.IsPaused,
|
|
||||||
OtherIsPaused = otherEntry != null && otherEntry.IsPaused,
|
|
||||||
userToOther.OtherUserUID,
|
|
||||||
IsSynced = otherEntry != null,
|
|
||||||
DisableOwnAnimations = userToOther.DisableAnimations,
|
|
||||||
DisableOwnSounds = userToOther.DisableSounds,
|
|
||||||
DisableOwnVFX = userToOther.DisableVFX,
|
|
||||||
DisableOtherAnimations = otherEntry == null ? false : otherEntry.DisableAnimations,
|
|
||||||
DisableOtherSounds = otherEntry == null ? false : otherEntry.DisableSounds,
|
|
||||||
DisableOtherVFX = otherEntry == null ? false : otherEntry.DisableVFX
|
|
||||||
};
|
|
||||||
|
|
||||||
var results = await query.AsNoTracking().ToListAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
return results.Select(c =>
|
|
||||||
{
|
|
||||||
var ownPerm = UserPermissions.Paired;
|
|
||||||
ownPerm.SetPaused(c.IsPaused);
|
|
||||||
ownPerm.SetDisableAnimations(c.DisableOwnAnimations);
|
|
||||||
ownPerm.SetDisableSounds(c.DisableOwnSounds);
|
|
||||||
ownPerm.SetDisableVFX(c.DisableOwnVFX);
|
|
||||||
var otherPerm = UserPermissions.NoneSet;
|
|
||||||
otherPerm.SetPaired(c.IsSynced);
|
|
||||||
otherPerm.SetPaused(c.OtherIsPaused);
|
|
||||||
otherPerm.SetDisableAnimations(c.DisableOtherAnimations);
|
|
||||||
otherPerm.SetDisableSounds(c.DisableOtherSounds);
|
|
||||||
otherPerm.SetDisableVFX(c.DisableOtherVFX);
|
|
||||||
return new UserPairDto(new(c.OtherUserUID, c.Alias), ownPerm, otherPerm);
|
|
||||||
}).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<UserProfileDto> UserGetProfile(UserDto user)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(user));
|
|
||||||
|
|
||||||
var allUserPairs = await GetAllPairedUnpausedUsers().ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!allUserPairs.Contains(user.User.UID, StringComparer.Ordinal) && !string.Equals(user.User.UID, UserUID, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
return new UserProfileDto(user.User, false, null, null, "Due to the pause status you cannot access this users profile.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = await DbContext.UserProfileData.SingleOrDefaultAsync(u => u.UserUID == user.User.UID).ConfigureAwait(false);
|
|
||||||
if (data == null) return new UserProfileDto(user.User, false, null, null, null);
|
|
||||||
|
|
||||||
if (data.FlaggedForReport) return new UserProfileDto(user.User, true, null, null, "This profile is flagged for report and pending evaluation");
|
|
||||||
if (data.ProfileDisabled) return new UserProfileDto(user.User, true, null, null, "This profile was permanently disabled");
|
|
||||||
|
|
||||||
return new UserProfileDto(user.User, false, data.IsNSFW, data.Base64ProfileImage, data.UserDescription);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task UserPushData(UserCharaDataMessageDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto.CharaData.FileReplacements.Count));
|
|
||||||
|
|
||||||
// check for honorific containing . and /
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var honorificJson = Encoding.Default.GetString(Convert.FromBase64String(dto.CharaData.HonorificData));
|
|
||||||
var deserialized = JsonSerializer.Deserialize<JsonElement>(honorificJson);
|
|
||||||
if (deserialized.TryGetProperty("Title", out var honorificTitle))
|
|
||||||
{
|
|
||||||
var title = honorificTitle.GetString().Normalize(NormalizationForm.FormKD);
|
|
||||||
if (UrlRegex().IsMatch(title))
|
|
||||||
{
|
|
||||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "Your data was not pushed: The usage of URLs the Honorific titles is prohibited. Remove them to be able to continue to push data.").ConfigureAwait(false);
|
|
||||||
throw new HubException("Invalid data provided, Honorific title invalid: " + title);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (HubException)
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
// swallow
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hadInvalidData = false;
|
|
||||||
List<string> invalidGamePaths = new();
|
|
||||||
List<string> invalidFileSwapPaths = new();
|
|
||||||
foreach (var replacement in dto.CharaData.FileReplacements.SelectMany(p => p.Value))
|
|
||||||
{
|
|
||||||
var invalidPaths = replacement.GamePaths.Where(p => !GamePathRegex().IsMatch(p)).ToList();
|
|
||||||
invalidPaths.AddRange(replacement.GamePaths.Where(p => !AllowedExtensionsForGamePaths.Any(e => p.EndsWith(e, StringComparison.OrdinalIgnoreCase))));
|
|
||||||
replacement.GamePaths = replacement.GamePaths.Where(p => !invalidPaths.Contains(p, StringComparer.OrdinalIgnoreCase)).ToArray();
|
|
||||||
bool validGamePaths = replacement.GamePaths.Any();
|
|
||||||
bool validHash = string.IsNullOrEmpty(replacement.Hash) || HashRegex().IsMatch(replacement.Hash);
|
|
||||||
bool validFileSwapPath = string.IsNullOrEmpty(replacement.FileSwapPath) || GamePathRegex().IsMatch(replacement.FileSwapPath);
|
|
||||||
if (!validGamePaths || !validHash || !validFileSwapPath)
|
|
||||||
{
|
|
||||||
_logger.LogCallWarning(MareHubLogger.Args("Invalid Data", "GamePaths", validGamePaths, string.Join(",", invalidPaths), "Hash", validHash, replacement.Hash, "FileSwap", validFileSwapPath, replacement.FileSwapPath));
|
|
||||||
hadInvalidData = true;
|
|
||||||
if (!validFileSwapPath) invalidFileSwapPaths.Add(replacement.FileSwapPath);
|
|
||||||
if (!validGamePaths) invalidGamePaths.AddRange(replacement.GamePaths);
|
|
||||||
if (!validHash) invalidFileSwapPaths.Add(replacement.Hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hadInvalidData)
|
|
||||||
{
|
|
||||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "One or more of your supplied mods were rejected from the server. Consult /xllog for more information.").ConfigureAwait(false);
|
|
||||||
throw new HubException("Invalid data provided, contact the appropriate mod creator to resolve those issues"
|
|
||||||
+ Environment.NewLine
|
|
||||||
+ string.Join(Environment.NewLine, invalidGamePaths.Select(p => "Invalid Game Path: " + p))
|
|
||||||
+ Environment.NewLine
|
|
||||||
+ string.Join(Environment.NewLine, invalidFileSwapPaths.Select(p => "Invalid FileSwap Path: " + p)));
|
|
||||||
}
|
|
||||||
|
|
||||||
var allPairedUsers = await GetAllPairedUnpausedUsers().ConfigureAwait(false);
|
|
||||||
var idents = await GetOnlineUsers(allPairedUsers).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var recipients = allPairedUsers.Where(f => dto.Recipients.Select(r => r.UID).Contains(f, StringComparer.Ordinal)).ToList();
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(idents.Count, recipients.Count()));
|
|
||||||
|
|
||||||
await Clients.Users(recipients).Client_UserReceiveCharacterData(new OnlineUserCharaDataDto(new UserData(UserUID), dto.CharaData)).ConfigureAwait(false);
|
|
||||||
|
|
||||||
_mareMetrics.IncCounter(MetricsAPI.CounterUserPushData);
|
|
||||||
_mareMetrics.IncCounter(MetricsAPI.CounterUserPushDataTo, recipients.Count());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task UserRemovePair(UserDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
if (string.Equals(dto.User.UID, UserUID, StringComparison.Ordinal)) return;
|
|
||||||
|
|
||||||
// check if client pair even exists
|
|
||||||
ClientPair callerPair =
|
|
||||||
await DbContext.ClientPairs.SingleOrDefaultAsync(w => w.UserUID == UserUID && w.OtherUserUID == dto.User.UID).ConfigureAwait(false);
|
|
||||||
if (callerPair == null) return;
|
|
||||||
|
|
||||||
bool callerHadPaused = callerPair.IsPaused;
|
|
||||||
|
|
||||||
// delete from database, send update info to users pair list
|
|
||||||
DbContext.ClientPairs.Remove(callerPair);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, "Success"));
|
|
||||||
|
|
||||||
await Clients.User(UserUID).Client_UserRemoveClientPair(dto).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// check if opposite entry exists
|
|
||||||
var oppositeClientPair = OppositeEntry(dto.User.UID);
|
|
||||||
if (oppositeClientPair == null) return;
|
|
||||||
|
|
||||||
// check if other user is online, if no then there is no need to do anything further
|
|
||||||
var otherIdent = await GetUserIdent(dto.User.UID).ConfigureAwait(false);
|
|
||||||
if (otherIdent == null) return;
|
|
||||||
|
|
||||||
// get own ident and
|
|
||||||
await Clients.User(dto.User.UID)
|
|
||||||
.Client_UserUpdateOtherPairPermissions(new UserPermissionsDto(new UserData(UserUID),
|
|
||||||
UserPermissions.NoneSet)).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// if the other user had paused the user the state will be offline for either, do nothing
|
|
||||||
bool otherHadPaused = oppositeClientPair.IsPaused;
|
|
||||||
if (!callerHadPaused && otherHadPaused) return;
|
|
||||||
|
|
||||||
var allUsers = await GetAllPairedClientsWithPauseState().ConfigureAwait(false);
|
|
||||||
var pauseEntry = allUsers.SingleOrDefault(f => string.Equals(f.UID, dto.User.UID, StringComparison.Ordinal));
|
|
||||||
var isPausedInGroup = pauseEntry == null || pauseEntry.IsPausedPerGroup is PauseInfo.Paused or PauseInfo.NoConnection;
|
|
||||||
|
|
||||||
// if neither user had paused each other and both are in unpaused groups, state will be online for both, do nothing
|
|
||||||
if (!callerHadPaused && !otherHadPaused && !isPausedInGroup) return;
|
|
||||||
|
|
||||||
// if neither user had paused each other and either is not in an unpaused group with each other, change state to offline
|
|
||||||
if (!callerHadPaused && !otherHadPaused && isPausedInGroup)
|
|
||||||
{
|
|
||||||
await Clients.User(UserUID).Client_UserSendOffline(dto).ConfigureAwait(false);
|
|
||||||
await Clients.User(dto.User.UID).Client_UserSendOffline(new(new(UserUID))).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the caller had paused other but not the other has paused the caller and they are in an unpaused group together, change state to online
|
|
||||||
if (callerHadPaused && !otherHadPaused && !isPausedInGroup)
|
|
||||||
{
|
|
||||||
await Clients.User(UserUID).Client_UserSendOnline(new(dto.User, otherIdent)).ConfigureAwait(false);
|
|
||||||
await Clients.User(dto.User.UID).Client_UserSendOnline(new(new(UserUID), UserCharaIdent)).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task UserReportProfile(UserProfileReportDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
UserProfileDataReport report = await DbContext.UserProfileReports.SingleOrDefaultAsync(u => u.ReportedUserUID == dto.User.UID && u.ReportingUserUID == UserUID).ConfigureAwait(false);
|
|
||||||
if (report != null)
|
|
||||||
{
|
|
||||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "You already reported this profile and it's pending validation").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UserProfileData profile = await DbContext.UserProfileData.SingleOrDefaultAsync(u => u.UserUID == dto.User.UID).ConfigureAwait(false);
|
|
||||||
if (profile == null)
|
|
||||||
{
|
|
||||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "This user has no profile").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UserProfileDataReport reportToAdd = new()
|
|
||||||
{
|
|
||||||
ReportDate = DateTime.UtcNow,
|
|
||||||
ReportingUserUID = UserUID,
|
|
||||||
ReportReason = dto.ProfileReport,
|
|
||||||
ReportedUserUID = dto.User.UID,
|
|
||||||
};
|
|
||||||
|
|
||||||
profile.FlaggedForReport = true;
|
|
||||||
|
|
||||||
await DbContext.UserProfileReports.AddAsync(reportToAdd).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
var allPairedUsers = await GetAllPairedUnpausedUsers(dto.User.UID).ConfigureAwait(false);
|
|
||||||
var pairs = await GetOnlineUsers(allPairedUsers).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await Clients.Users(pairs.Select(p => p.Key)).Client_UserUpdateProfile(new(dto.User)).ConfigureAwait(false);
|
|
||||||
await Clients.Users(dto.User.UID).Client_UserUpdateProfile(new(dto.User)).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task UserSetPairPermissions(UserPermissionsDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
if (string.Equals(dto.User.UID, UserUID, StringComparison.Ordinal)) return;
|
|
||||||
ClientPair pair = await DbContext.ClientPairs.SingleOrDefaultAsync(w => w.UserUID == UserUID && w.OtherUserUID == dto.User.UID).ConfigureAwait(false);
|
|
||||||
if (pair == null) return;
|
|
||||||
|
|
||||||
var pauseChange = pair.IsPaused != dto.Permissions.IsPaused();
|
|
||||||
|
|
||||||
pair.IsPaused = dto.Permissions.IsPaused();
|
|
||||||
pair.DisableAnimations = dto.Permissions.IsDisableAnimations();
|
|
||||||
pair.DisableSounds = dto.Permissions.IsDisableSounds();
|
|
||||||
pair.DisableVFX = dto.Permissions.IsDisableVFX();
|
|
||||||
DbContext.Update(pair);
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto, "Success"));
|
|
||||||
|
|
||||||
var otherEntry = OppositeEntry(dto.User.UID);
|
|
||||||
|
|
||||||
await Clients.User(UserUID).Client_UserUpdateSelfPairPermissions(dto).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (otherEntry != null)
|
|
||||||
{
|
|
||||||
await Clients.User(dto.User.UID).Client_UserUpdateOtherPairPermissions(new UserPermissionsDto(new UserData(UserUID), dto.Permissions)).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (pauseChange)
|
|
||||||
{
|
|
||||||
var otherCharaIdent = await GetUserIdent(pair.OtherUserUID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (UserCharaIdent == null || otherCharaIdent == null || otherEntry.IsPaused) return;
|
|
||||||
|
|
||||||
if (dto.Permissions.IsPaused())
|
|
||||||
{
|
|
||||||
await Clients.User(UserUID).Client_UserSendOffline(dto).ConfigureAwait(false);
|
|
||||||
await Clients.User(dto.User.UID).Client_UserSendOffline(new(new(UserUID))).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await Clients.User(UserUID).Client_UserSendOnline(new(dto.User, otherCharaIdent)).ConfigureAwait(false);
|
|
||||||
await Clients.User(dto.User.UID).Client_UserSendOnline(new(new(UserUID), UserCharaIdent)).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task UserSetProfile(UserProfileDto dto)
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
|
||||||
|
|
||||||
if (!string.Equals(dto.User.UID, UserUID, StringComparison.Ordinal)) throw new HubException("Cannot modify profile data for anyone but yourself");
|
|
||||||
|
|
||||||
var existingData = await DbContext.UserProfileData.SingleOrDefaultAsync(u => u.UserUID == dto.User.UID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (existingData?.FlaggedForReport ?? false)
|
|
||||||
{
|
|
||||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "Your profile is currently flagged for report and cannot be edited").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existingData?.ProfileDisabled ?? false)
|
|
||||||
{
|
|
||||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "Your profile was permanently disabled and cannot be edited").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(dto.ProfilePictureBase64))
|
|
||||||
{
|
|
||||||
byte[] imageData = Convert.FromBase64String(dto.ProfilePictureBase64);
|
|
||||||
using MemoryStream ms = new(imageData);
|
|
||||||
var format = await Image.DetectFormatAsync(ms).ConfigureAwait(false);
|
|
||||||
if (!format.FileExtensions.Contains("png", StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "Your provided image file is not in PNG format").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
using var image = Image.Load<Rgba32>(imageData);
|
|
||||||
|
|
||||||
if (image.Width > 256 || image.Height > 256 || (imageData.Length > 250 * 1024))
|
|
||||||
{
|
|
||||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "Your provided image file is larger than 256x256 or more than 250KiB.").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existingData != null)
|
|
||||||
{
|
|
||||||
if (string.Equals("", dto.ProfilePictureBase64, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
existingData.Base64ProfileImage = null;
|
|
||||||
}
|
|
||||||
else if (dto.ProfilePictureBase64 != null)
|
|
||||||
{
|
|
||||||
existingData.Base64ProfileImage = dto.ProfilePictureBase64;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dto.IsNSFW != null)
|
|
||||||
{
|
|
||||||
existingData.IsNSFW = dto.IsNSFW.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dto.Description != null)
|
|
||||||
{
|
|
||||||
existingData.UserDescription = dto.Description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UserProfileData userProfileData = new()
|
|
||||||
{
|
|
||||||
UserUID = dto.User.UID,
|
|
||||||
Base64ProfileImage = dto.ProfilePictureBase64 ?? null,
|
|
||||||
UserDescription = dto.Description ?? null,
|
|
||||||
IsNSFW = dto.IsNSFW ?? false
|
|
||||||
};
|
|
||||||
|
|
||||||
await DbContext.UserProfileData.AddAsync(userProfileData).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
var allPairedUsers = await GetAllPairedUnpausedUsers().ConfigureAwait(false);
|
|
||||||
var pairs = await GetOnlineUsers(allPairedUsers).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await Clients.Users(pairs.Select(p => p.Key)).Client_UserUpdateProfile(new(dto.User)).ConfigureAwait(false);
|
|
||||||
await Clients.Caller.Client_UserUpdateProfile(new(dto.User)).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[GeneratedRegex(@"^([a-z0-9_ '+&,\.\-\{\}]+\/)+([a-z0-9_ '+&,\.\-\{\}]+\.[a-z]{3,4})$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.ECMAScript)]
|
|
||||||
private static partial Regex GamePathRegex();
|
|
||||||
|
|
||||||
[GeneratedRegex(@"^[A-Z0-9]{40}$", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.ECMAScript)]
|
|
||||||
private static partial Regex HashRegex();
|
|
||||||
|
|
||||||
[GeneratedRegex("^[-a-zA-Z0-9@:%._\\+~#=]{1,256}[\\.,][a-zA-Z0-9()]{1,6}\\b(?:[-a-zA-Z0-9()@:%_\\+.~#?&\\/=]*)$")]
|
|
||||||
private static partial Regex UrlRegex();
|
|
||||||
|
|
||||||
private ClientPair OppositeEntry(string otherUID) =>
|
|
||||||
DbContext.ClientPairs.AsNoTracking().SingleOrDefault(w => w.User.UID == otherUID && w.OtherUser.UID == UserUID);
|
|
||||||
}
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
using MareSynchronos.API.Data;
|
|
||||||
using MareSynchronos.API.Data.Enum;
|
|
||||||
using MareSynchronos.API.Dto;
|
|
||||||
using MareSynchronos.API.SignalR;
|
|
||||||
using MareSynchronosServer.Services;
|
|
||||||
using MareSynchronosServer.Utils;
|
|
||||||
using MareSynchronosShared;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using MareSynchronosShared.Metrics;
|
|
||||||
using MareSynchronosShared.Services;
|
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using StackExchange.Redis.Extensions.Core.Abstractions;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Hubs;
|
|
||||||
|
|
||||||
[Authorize(Policy = "Authenticated")]
|
|
||||||
public partial class MareHub : Hub<IMareHub>, IMareHub
|
|
||||||
{
|
|
||||||
private readonly MareMetrics _mareMetrics;
|
|
||||||
private readonly SystemInfoService _systemInfoService;
|
|
||||||
private readonly IHttpContextAccessor _contextAccessor;
|
|
||||||
private readonly MareHubLogger _logger;
|
|
||||||
private readonly string _shardName;
|
|
||||||
private readonly int _maxExistingGroupsByUser;
|
|
||||||
private readonly int _maxJoinedGroupsByUser;
|
|
||||||
private readonly int _maxGroupUserCount;
|
|
||||||
private readonly IRedisDatabase _redis;
|
|
||||||
private readonly GPoseLobbyDistributionService _gPoseLobbyDistributionService;
|
|
||||||
private readonly Uri _fileServerAddress;
|
|
||||||
private readonly Version _expectedClientVersion;
|
|
||||||
private readonly int _maxCharaDataByUser;
|
|
||||||
|
|
||||||
private readonly Lazy<MareDbContext> _dbContextLazy;
|
|
||||||
private MareDbContext DbContext => _dbContextLazy.Value;
|
|
||||||
|
|
||||||
public MareHub(MareMetrics mareMetrics,
|
|
||||||
IDbContextFactory<MareDbContext> mareDbContextFactory, ILogger<MareHub> logger, SystemInfoService systemInfoService,
|
|
||||||
IConfigurationService<ServerConfiguration> configuration, IHttpContextAccessor contextAccessor,
|
|
||||||
IRedisDatabase redisDb, GPoseLobbyDistributionService gPoseLobbyDistributionService)
|
|
||||||
{
|
|
||||||
_mareMetrics = mareMetrics;
|
|
||||||
_systemInfoService = systemInfoService;
|
|
||||||
_shardName = configuration.GetValue<string>(nameof(ServerConfiguration.ShardName));
|
|
||||||
_maxExistingGroupsByUser = configuration.GetValueOrDefault(nameof(ServerConfiguration.MaxExistingGroupsByUser), 3);
|
|
||||||
_maxJoinedGroupsByUser = configuration.GetValueOrDefault(nameof(ServerConfiguration.MaxJoinedGroupsByUser), 6);
|
|
||||||
_maxGroupUserCount = configuration.GetValueOrDefault(nameof(ServerConfiguration.MaxGroupUserCount), 100);
|
|
||||||
_fileServerAddress = configuration.GetValue<Uri>(nameof(ServerConfiguration.CdnFullUrl));
|
|
||||||
_expectedClientVersion = configuration.GetValueOrDefault(nameof(ServerConfiguration.ExpectedClientVersion), new Version(0, 0, 0));
|
|
||||||
_maxCharaDataByUser = configuration.GetValueOrDefault(nameof(ServerConfiguration.MaxCharaDataByUser), 10);
|
|
||||||
_contextAccessor = contextAccessor;
|
|
||||||
_redis = redisDb;
|
|
||||||
_gPoseLobbyDistributionService = gPoseLobbyDistributionService;
|
|
||||||
_logger = new MareHubLogger(this, logger);
|
|
||||||
_dbContextLazy = new Lazy<MareDbContext>(() => mareDbContextFactory.CreateDbContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
DbContext.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
|
||||||
public async Task<ConnectionDto> GetConnectionDto()
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo();
|
|
||||||
|
|
||||||
_mareMetrics.IncCounter(MetricsAPI.CounterInitializedConnections);
|
|
||||||
|
|
||||||
await Clients.Caller.Client_UpdateSystemInfo(_systemInfoService.SystemInfoDto).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var dbUser = DbContext.Users.SingleOrDefault(f => f.UID == UserUID);
|
|
||||||
dbUser.LastLoggedIn = DateTime.UtcNow;
|
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Information, "Bienvenue sur UmbraSync ! Utilisateurs en ligne : " + _systemInfoService.SystemInfoDto.OnlineUsers).ConfigureAwait(false);
|
|
||||||
|
|
||||||
return new ConnectionDto(new UserData(dbUser.UID, string.IsNullOrWhiteSpace(dbUser.Alias) ? null : dbUser.Alias))
|
|
||||||
{
|
|
||||||
CurrentClientVersion = _expectedClientVersion,
|
|
||||||
ServerVersion = IMareHub.ApiVersion,
|
|
||||||
IsAdmin = dbUser.IsAdmin,
|
|
||||||
IsModerator = dbUser.IsModerator,
|
|
||||||
ServerInfo = new ServerInfo()
|
|
||||||
{
|
|
||||||
MaxGroupsCreatedByUser = _maxExistingGroupsByUser,
|
|
||||||
ShardName = _shardName,
|
|
||||||
MaxGroupsJoinedByUser = _maxJoinedGroupsByUser,
|
|
||||||
MaxGroupUserCount = _maxGroupUserCount,
|
|
||||||
FileServerAddress = _fileServerAddress,
|
|
||||||
MaxCharaData = _maxCharaDataByUser
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Authenticated")]
|
|
||||||
public async Task<bool> CheckClientHealth()
|
|
||||||
{
|
|
||||||
await UpdateUserOnRedis().ConfigureAwait(false);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Authenticated")]
|
|
||||||
public override async Task OnConnectedAsync()
|
|
||||||
{
|
|
||||||
_mareMetrics.IncGaugeWithLabels(MetricsAPI.GaugeConnections, labels: Continent);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(_contextAccessor.GetIpAddress(), UserCharaIdent));
|
|
||||||
|
|
||||||
await UpdateUserOnRedis().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
|
|
||||||
await base.OnConnectedAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Authorize(Policy = "Authenticated")]
|
|
||||||
public override async Task OnDisconnectedAsync(Exception exception)
|
|
||||||
{
|
|
||||||
_mareMetrics.DecGaugeWithLabels(MetricsAPI.GaugeConnections, labels: Continent);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(_contextAccessor.GetIpAddress(), UserCharaIdent));
|
|
||||||
if (exception != null)
|
|
||||||
_logger.LogCallWarning(MareHubLogger.Args(_contextAccessor.GetIpAddress(), exception.Message, exception.StackTrace));
|
|
||||||
|
|
||||||
await GposeLobbyLeave().ConfigureAwait(false);
|
|
||||||
await RemoveUserFromRedis().ConfigureAwait(false);
|
|
||||||
|
|
||||||
await SendOfflineToAllPairedUsers().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
|
|
||||||
await base.OnDisconnectedAsync(exception).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
using AspNetCoreRateLimit;
|
|
||||||
using MareSynchronosShared;
|
|
||||||
using MareSynchronosShared.Utils;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Hubs;
|
|
||||||
public class SignalRLimitFilter : IHubFilter
|
|
||||||
{
|
|
||||||
private readonly IRateLimitProcessor _processor;
|
|
||||||
private readonly IHttpContextAccessor accessor;
|
|
||||||
private readonly ILogger<SignalRLimitFilter> logger;
|
|
||||||
private static readonly SemaphoreSlim ConnectionLimiterSemaphore = new(20, 20);
|
|
||||||
private static readonly SemaphoreSlim DisconnectLimiterSemaphore = new(20, 20);
|
|
||||||
|
|
||||||
public SignalRLimitFilter(
|
|
||||||
IOptions<IpRateLimitOptions> options, IProcessingStrategy processing, IIpPolicyStore policyStore, IHttpContextAccessor accessor, ILogger<SignalRLimitFilter> logger)
|
|
||||||
{
|
|
||||||
_processor = new IpRateLimitProcessor(options?.Value, policyStore, processing);
|
|
||||||
this.accessor = accessor;
|
|
||||||
this.logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ValueTask<object> InvokeMethodAsync(
|
|
||||||
HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object>> next)
|
|
||||||
{
|
|
||||||
var ip = accessor.GetIpAddress();
|
|
||||||
var client = new ClientRequestIdentity
|
|
||||||
{
|
|
||||||
ClientIp = ip,
|
|
||||||
Path = invocationContext.HubMethodName,
|
|
||||||
HttpVerb = "ws",
|
|
||||||
ClientId = invocationContext.Context.UserIdentifier,
|
|
||||||
};
|
|
||||||
foreach (var rule in await _processor.GetMatchingRulesAsync(client).ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
var counter = await _processor.ProcessRequestAsync(client, rule).ConfigureAwait(false);
|
|
||||||
if (counter.Count > rule.Limit)
|
|
||||||
{
|
|
||||||
var authUserId = invocationContext.Context.User.Claims?.SingleOrDefault(c => string.Equals(c.Type, MareClaimTypes.Uid, StringComparison.Ordinal))?.Value ?? "Unknown";
|
|
||||||
var retry = counter.Timestamp.RetryAfterFrom(rule);
|
|
||||||
logger.LogWarning("Method rate limit triggered from {ip}/{authUserId}: {method}", ip, authUserId, invocationContext.HubMethodName);
|
|
||||||
throw new HubException($"call limit {retry}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return await next(invocationContext).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optional method
|
|
||||||
public async Task OnConnectedAsync(HubLifetimeContext context, Func<HubLifetimeContext, Task> next)
|
|
||||||
{
|
|
||||||
await ConnectionLimiterSemaphore.WaitAsync().ConfigureAwait(false);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var ip = accessor.GetIpAddress();
|
|
||||||
var client = new ClientRequestIdentity
|
|
||||||
{
|
|
||||||
ClientIp = ip,
|
|
||||||
Path = "Connect",
|
|
||||||
HttpVerb = "ws",
|
|
||||||
};
|
|
||||||
foreach (var rule in await _processor.GetMatchingRulesAsync(client).ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
var counter = await _processor.ProcessRequestAsync(client, rule).ConfigureAwait(false);
|
|
||||||
if (counter.Count > rule.Limit)
|
|
||||||
{
|
|
||||||
var retry = counter.Timestamp.RetryAfterFrom(rule);
|
|
||||||
logger.LogWarning("Connection rate limit triggered from {ip}", ip);
|
|
||||||
ConnectionLimiterSemaphore.Release();
|
|
||||||
throw new HubException($"Connection rate limit {retry}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
await Task.Delay(25).ConfigureAwait(false);
|
|
||||||
await next(context).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
logger.LogWarning(ex, "Error on OnConnectedAsync");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ConnectionLimiterSemaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task OnDisconnectedAsync(
|
|
||||||
HubLifetimeContext context, Exception exception, Func<HubLifetimeContext, Exception, Task> next)
|
|
||||||
{
|
|
||||||
await DisconnectLimiterSemaphore.WaitAsync().ConfigureAwait(false);
|
|
||||||
if (exception != null)
|
|
||||||
{
|
|
||||||
logger.LogWarning(exception, "InitialException on OnDisconnectedAsync");
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await next(context, exception).ConfigureAwait(false);
|
|
||||||
await Task.Delay(25).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
logger.LogWarning(e, "ThrownException on OnDisconnectedAsync");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
DisconnectLimiterSemaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
|
||||||
<UserSecretsId>aspnet-MareSynchronosServer-BA82A12A-0B30-463C-801D-B7E81318CD50</UserSecretsId>
|
|
||||||
<AssemblyVersion>1.1.0.0</AssemblyVersion>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Remove="appsettings.Development.json" />
|
|
||||||
<Content Remove="appsettings.json" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="appsettings.Development.json" />
|
|
||||||
<None Include="appsettings.json">
|
|
||||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
|
||||||
<PackageReference Include="IDisposableAnalyzers" Version="4.0.8">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.212">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.19">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.1" />
|
|
||||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="7.7.1" />
|
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\MareAPI\MareSynchronosAPI\MareSynchronos.API.csproj" />
|
|
||||||
<ProjectReference Include="..\MareSynchronosShared\MareSynchronosShared.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using MareSynchronosShared.Metrics;
|
|
||||||
using MareSynchronosShared.Services;
|
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer;
|
|
||||||
|
|
||||||
public class Program
|
|
||||||
{
|
|
||||||
public static void Main(string[] args)
|
|
||||||
{
|
|
||||||
var hostBuilder = CreateHostBuilder(args);
|
|
||||||
var host = hostBuilder.Build();
|
|
||||||
using (var scope = host.Services.CreateScope())
|
|
||||||
{
|
|
||||||
var services = scope.ServiceProvider;
|
|
||||||
using var context = services.GetRequiredService<MareDbContext>();
|
|
||||||
var options = services.GetRequiredService<IConfigurationService<ServerConfiguration>>();
|
|
||||||
var logger = host.Services.GetRequiredService<ILogger<Program>>();
|
|
||||||
|
|
||||||
if (options.IsMain)
|
|
||||||
{
|
|
||||||
context.Database.Migrate();
|
|
||||||
context.SaveChanges();
|
|
||||||
|
|
||||||
// clean up residuals
|
|
||||||
var unfinishedRegistrations = context.LodeStoneAuth.Where(c => c.StartedAt != null);
|
|
||||||
context.RemoveRange(unfinishedRegistrations);
|
|
||||||
context.SaveChanges();
|
|
||||||
|
|
||||||
logger.LogInformation(options.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
var metrics = services.GetRequiredService<MareMetrics>();
|
|
||||||
|
|
||||||
metrics.SetGaugeTo(MetricsAPI.GaugeUsersRegistered, context.Users.AsNoTracking().Count());
|
|
||||||
metrics.SetGaugeTo(MetricsAPI.GaugePairs, context.ClientPairs.AsNoTracking().Count());
|
|
||||||
metrics.SetGaugeTo(MetricsAPI.GaugePairsPaused, context.ClientPairs.AsNoTracking().Count(p => p.IsPaused));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.Length == 0 || !string.Equals(args[0], "dry", StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
host.Run();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IHostBuilder CreateHostBuilder(string[] args)
|
|
||||||
{
|
|
||||||
var loggerFactory = LoggerFactory.Create(builder =>
|
|
||||||
{
|
|
||||||
builder.ClearProviders();
|
|
||||||
builder.AddConsole();
|
|
||||||
});
|
|
||||||
var logger = loggerFactory.CreateLogger<Startup>();
|
|
||||||
return Host.CreateDefaultBuilder(args)
|
|
||||||
.UseSystemd()
|
|
||||||
.ConfigureWebHostDefaults(webBuilder =>
|
|
||||||
{
|
|
||||||
webBuilder.UseContentRoot(AppContext.BaseDirectory);
|
|
||||||
webBuilder.ConfigureLogging((ctx, builder) =>
|
|
||||||
{
|
|
||||||
builder.AddConfiguration(ctx.Configuration.GetSection("Logging"));
|
|
||||||
builder.AddFile(o => o.RootPath = AppContext.BaseDirectory);
|
|
||||||
});
|
|
||||||
webBuilder.UseStartup(ctx => new Startup(ctx.Configuration, logger));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"profiles": {
|
|
||||||
"MareSynchronosServer": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"dotnetRunMessages": "true",
|
|
||||||
"launchBrowser": false,
|
|
||||||
//"applicationUrl": "https://localhost:5001;http://localhost:5000;https://192.168.1.124:5001;http://192.168.1.124:5000",
|
|
||||||
"applicationUrl": "http://localhost:5000;https://localhost:5001;https://darkarchon.internet-box.ch:5001",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"dependencies": {}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"dependencies": {}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Services;
|
|
||||||
|
|
||||||
public class CharaDataCleanupService : IHostedService
|
|
||||||
{
|
|
||||||
private readonly ILogger<CharaDataCleanupService> _logger;
|
|
||||||
private readonly IDbContextFactory<MareDbContext> _dbContextFactory;
|
|
||||||
private readonly CancellationTokenSource _cleanupCts = new();
|
|
||||||
|
|
||||||
public CharaDataCleanupService(ILogger<CharaDataCleanupService> logger, IDbContextFactory<MareDbContext> dbContextFactory)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_dbContextFactory = dbContextFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
_ = Cleanup(cancellationToken);
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Cleanup(CancellationToken ct)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("CharaData Cleanup Service started");
|
|
||||||
while (!ct.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
using (var db = await _dbContextFactory.CreateDbContextAsync(ct).ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
var dateTime = DateTime.UtcNow;
|
|
||||||
var expiredData = await db.CharaData.Where(c => c.ExpiryDate <= DateTime.UtcNow).ToListAsync(cancellationToken: ct).ConfigureAwait(false);
|
|
||||||
|
|
||||||
_logger.LogInformation("Removing {count} expired Chara Data entries", expiredData.Count);
|
|
||||||
|
|
||||||
db.RemoveRange(expiredData);
|
|
||||||
await db.SaveChangesAsync(ct).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(TimeSpan.FromHours(12), ct).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
_cleanupCts?.Cancel();
|
|
||||||
_cleanupCts?.Dispose();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,226 +0,0 @@
|
|||||||
using MareSynchronos.API.Dto.CharaData;
|
|
||||||
using MareSynchronos.API.SignalR;
|
|
||||||
using MareSynchronosServer.Hubs;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using StackExchange.Redis.Extensions.Core.Abstractions;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Services;
|
|
||||||
|
|
||||||
public sealed class GPoseLobbyDistributionService : IHostedService, IDisposable
|
|
||||||
{
|
|
||||||
private CancellationTokenSource _runtimeCts = new();
|
|
||||||
private readonly Dictionary<string, Dictionary<string, WorldData>> _lobbyWorldData = [];
|
|
||||||
private readonly Dictionary<string, Dictionary<string, PoseData>> _lobbyPoseData = [];
|
|
||||||
private readonly SemaphoreSlim _lobbyPoseDataModificationSemaphore = new(1, 1);
|
|
||||||
private readonly SemaphoreSlim _lobbyWorldDataModificationSemaphore = new(1, 1);
|
|
||||||
|
|
||||||
public GPoseLobbyDistributionService(ILogger<GPoseLobbyDistributionService> logger, IRedisDatabase redisDb,
|
|
||||||
IHubContext<MareHub, IMareHub> hubContext)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_redisDb = redisDb;
|
|
||||||
_hubContext = hubContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool _disposed;
|
|
||||||
private readonly ILogger<GPoseLobbyDistributionService> _logger;
|
|
||||||
private readonly IRedisDatabase _redisDb;
|
|
||||||
private readonly IHubContext<MareHub, IMareHub> _hubContext;
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (_disposed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_runtimeCts.Cancel();
|
|
||||||
_runtimeCts.Dispose();
|
|
||||||
_lobbyPoseDataModificationSemaphore.Dispose();
|
|
||||||
_lobbyWorldDataModificationSemaphore.Dispose();
|
|
||||||
|
|
||||||
_disposed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task PushWorldData(string lobby, string user, WorldData worldData)
|
|
||||||
{
|
|
||||||
await _lobbyWorldDataModificationSemaphore.WaitAsync().ConfigureAwait(false);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!_lobbyWorldData.TryGetValue(lobby, out var worldDataDict))
|
|
||||||
{
|
|
||||||
_lobbyWorldData[lobby] = worldDataDict = new(StringComparer.Ordinal);
|
|
||||||
}
|
|
||||||
worldDataDict[user] = worldData;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error during Pushing World Data for Lobby {lobby} by User {user}", lobby, user);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_lobbyWorldDataModificationSemaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task PushPoseData(string lobby, string user, PoseData poseData)
|
|
||||||
{
|
|
||||||
await _lobbyPoseDataModificationSemaphore.WaitAsync().ConfigureAwait(false);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!_lobbyPoseData.TryGetValue(lobby, out var poseDataDict))
|
|
||||||
{
|
|
||||||
_lobbyPoseData[lobby] = poseDataDict = new(StringComparer.Ordinal);
|
|
||||||
}
|
|
||||||
poseDataDict[user] = poseData;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error during Pushing World Data for Lobby {lobby} by User {user}", lobby, user);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_lobbyPoseDataModificationSemaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
_ = WorldDataDistribution(_runtimeCts.Token);
|
|
||||||
_ = PoseDataDistribution(_runtimeCts.Token);
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task WorldDataDistribution(CancellationToken token)
|
|
||||||
{
|
|
||||||
while (!token.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await DistributeWorldData(token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error during World Data Distribution");
|
|
||||||
}
|
|
||||||
await Task.Delay(TimeSpan.FromSeconds(1), token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task PoseDataDistribution(CancellationToken token)
|
|
||||||
{
|
|
||||||
while (!token.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await DistributePoseData(token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error during Pose Data Distribution");
|
|
||||||
}
|
|
||||||
await Task.Delay(TimeSpan.FromSeconds(2), token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task DistributeWorldData(CancellationToken token)
|
|
||||||
{
|
|
||||||
await _lobbyWorldDataModificationSemaphore.WaitAsync(token).ConfigureAwait(false);
|
|
||||||
Dictionary<string, Dictionary<string, WorldData>> clone = [];
|
|
||||||
try
|
|
||||||
{
|
|
||||||
clone = _lobbyWorldData.ToDictionary(k => k.Key, k => k.Value, StringComparer.Ordinal);
|
|
||||||
_lobbyWorldData.Clear();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error during Distributing World Data Clone generation");
|
|
||||||
_lobbyWorldData.Clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_lobbyWorldDataModificationSemaphore.Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var lobbyId in clone)
|
|
||||||
{
|
|
||||||
token.ThrowIfCancellationRequested();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!lobbyId.Value.Values.Any())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var gposeLobbyUsers = await _redisDb.GetAsync<List<string>>($"GposeLobby:{lobbyId.Key}").ConfigureAwait(false);
|
|
||||||
if (gposeLobbyUsers == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var data in lobbyId.Value)
|
|
||||||
{
|
|
||||||
await _hubContext.Clients.Users(gposeLobbyUsers.Where(k => !string.Equals(k, data.Key, StringComparison.Ordinal)))
|
|
||||||
.Client_GposeLobbyPushWorldData(new(data.Key), data.Value).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error during World Data Distribution for Lobby {lobby}", lobbyId.Key);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task DistributePoseData(CancellationToken token)
|
|
||||||
{
|
|
||||||
await _lobbyPoseDataModificationSemaphore.WaitAsync(token).ConfigureAwait(false);
|
|
||||||
Dictionary<string, Dictionary<string, PoseData>> clone = [];
|
|
||||||
try
|
|
||||||
{
|
|
||||||
clone = _lobbyPoseData.ToDictionary(k => k.Key, k => k.Value, StringComparer.Ordinal);
|
|
||||||
_lobbyPoseData.Clear();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error during Distributing Pose Data Clone generation");
|
|
||||||
_lobbyPoseData.Clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_lobbyPoseDataModificationSemaphore.Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var lobbyId in clone)
|
|
||||||
{
|
|
||||||
token.ThrowIfCancellationRequested();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!lobbyId.Value.Values.Any())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var gposeLobbyUsers = await _redisDb.GetAsync<List<string>>($"GposeLobby:{lobbyId.Key}").ConfigureAwait(false);
|
|
||||||
if (gposeLobbyUsers == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var data in lobbyId.Value)
|
|
||||||
{
|
|
||||||
await _hubContext.Clients.Users(gposeLobbyUsers.Where(k => !string.Equals(k, data.Key, StringComparison.Ordinal)))
|
|
||||||
.Client_GposeLobbyPushPoseData(new(data.Key), data.Value).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error during Pose Data Distribution for Lobby {lobby}", lobbyId.Key);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
_runtimeCts.Cancel();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
using MareSynchronos.API.Dto;
|
|
||||||
using MareSynchronos.API.SignalR;
|
|
||||||
using MareSynchronosServer.Hubs;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using MareSynchronosShared.Metrics;
|
|
||||||
using MareSynchronosShared.Services;
|
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using StackExchange.Redis.Extensions.Core.Abstractions;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Services;
|
|
||||||
|
|
||||||
public class SystemInfoService : IHostedService, IDisposable
|
|
||||||
{
|
|
||||||
private readonly MareMetrics _mareMetrics;
|
|
||||||
private readonly IConfigurationService<ServerConfiguration> _config;
|
|
||||||
private readonly IServiceProvider _services;
|
|
||||||
private readonly ILogger<SystemInfoService> _logger;
|
|
||||||
private readonly IHubContext<MareHub, IMareHub> _hubContext;
|
|
||||||
private readonly IRedisDatabase _redis;
|
|
||||||
private Timer _timer;
|
|
||||||
public SystemInfoDto SystemInfoDto { get; private set; } = new();
|
|
||||||
|
|
||||||
public SystemInfoService(MareMetrics mareMetrics, IConfigurationService<ServerConfiguration> configurationService, IServiceProvider services,
|
|
||||||
ILogger<SystemInfoService> logger, IHubContext<MareHub, IMareHub> hubContext, IRedisDatabase redisDb)
|
|
||||||
{
|
|
||||||
_mareMetrics = mareMetrics;
|
|
||||||
_config = configurationService;
|
|
||||||
_services = services;
|
|
||||||
_logger = logger;
|
|
||||||
_hubContext = hubContext;
|
|
||||||
_redis = redisDb;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("System Info Service started");
|
|
||||||
|
|
||||||
var timeOut = _config.IsMain ? 5 : 15;
|
|
||||||
|
|
||||||
_timer = new Timer(PushSystemInfo, null, TimeSpan.Zero, TimeSpan.FromSeconds(timeOut));
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PushSystemInfo(object state)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ThreadPool.GetAvailableThreads(out int workerThreads, out int ioThreads);
|
|
||||||
|
|
||||||
_mareMetrics.SetGaugeTo(MetricsAPI.GaugeAvailableWorkerThreads, workerThreads);
|
|
||||||
_mareMetrics.SetGaugeTo(MetricsAPI.GaugeAvailableIOWorkerThreads, ioThreads);
|
|
||||||
|
|
||||||
var onlineUsers = (_redis.SearchKeysAsync("UID:*").GetAwaiter().GetResult()).Count();
|
|
||||||
SystemInfoDto = new SystemInfoDto()
|
|
||||||
{
|
|
||||||
OnlineUsers = onlineUsers,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (_config.IsMain)
|
|
||||||
{
|
|
||||||
_logger.LogTrace("Sending System Info, Online Users: {onlineUsers}", onlineUsers);
|
|
||||||
|
|
||||||
_hubContext.Clients.All.Client_UpdateSystemInfo(SystemInfoDto);
|
|
||||||
|
|
||||||
using var scope = _services.CreateScope();
|
|
||||||
using var db = scope.ServiceProvider.GetService<MareDbContext>()!;
|
|
||||||
|
|
||||||
_mareMetrics.SetGaugeTo(MetricsAPI.GaugeAuthorizedConnections, onlineUsers);
|
|
||||||
_mareMetrics.SetGaugeTo(MetricsAPI.GaugePairs, db.ClientPairs.AsNoTracking().Count());
|
|
||||||
_mareMetrics.SetGaugeTo(MetricsAPI.GaugePairsPaused, db.ClientPairs.AsNoTracking().Count(p => p.IsPaused));
|
|
||||||
_mareMetrics.SetGaugeTo(MetricsAPI.GaugeGroups, db.Groups.AsNoTracking().Count());
|
|
||||||
_mareMetrics.SetGaugeTo(MetricsAPI.GaugeGroupPairs, db.GroupPairs.AsNoTracking().Count());
|
|
||||||
_mareMetrics.SetGaugeTo(MetricsAPI.GaugeGroupPairsPaused, db.GroupPairs.AsNoTracking().Count(p => p.IsPaused));
|
|
||||||
_mareMetrics.SetGaugeTo(MetricsAPI.GaugeUsersRegistered, db.Users.AsNoTracking().Count());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogWarning(ex, "Failed to push system info");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
_timer?.Change(Timeout.Infinite, 0);
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_timer?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
using MareSynchronosShared.Data;
|
|
||||||
using MareSynchronosShared.Metrics;
|
|
||||||
using MareSynchronosShared.Models;
|
|
||||||
using MareSynchronosShared.Services;
|
|
||||||
using MareSynchronosShared.Utils;
|
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Services;
|
|
||||||
|
|
||||||
public class UserCleanupService : IHostedService
|
|
||||||
{
|
|
||||||
private readonly MareMetrics metrics;
|
|
||||||
private readonly ILogger<UserCleanupService> _logger;
|
|
||||||
private readonly IDbContextFactory<MareDbContext> _mareDbContextFactory;
|
|
||||||
private readonly IConfigurationService<ServerConfiguration> _configuration;
|
|
||||||
private CancellationTokenSource _cleanupCts;
|
|
||||||
|
|
||||||
public UserCleanupService(MareMetrics metrics, ILogger<UserCleanupService> logger, IDbContextFactory<MareDbContext> mareDbContextFactory, IConfigurationService<ServerConfiguration> configuration)
|
|
||||||
{
|
|
||||||
this.metrics = metrics;
|
|
||||||
_logger = logger;
|
|
||||||
_mareDbContextFactory = mareDbContextFactory;
|
|
||||||
_configuration = configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Cleanup Service started");
|
|
||||||
_cleanupCts = new();
|
|
||||||
|
|
||||||
_ = CleanUp(_cleanupCts.Token);
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task CleanUp(CancellationToken ct)
|
|
||||||
{
|
|
||||||
while (!ct.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
using (var dbContext = await _mareDbContextFactory.CreateDbContextAsync(ct).ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
|
|
||||||
CleanUpOutdatedLodestoneAuths(dbContext);
|
|
||||||
|
|
||||||
await PurgeUnusedAccounts(dbContext).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await PurgeTempInvites(dbContext).ConfigureAwait(false);
|
|
||||||
await PurgeExpiredTemporaryGroups(dbContext).ConfigureAwait(false);
|
|
||||||
|
|
||||||
dbContext.SaveChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
var span = TimeSpan.FromMinutes(1);
|
|
||||||
var nextRun = DateTime.Now.Add(span);
|
|
||||||
|
|
||||||
_logger.LogInformation("User Cleanup Complete, next run at {date}", nextRun);
|
|
||||||
await Task.Delay(span, ct).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task PurgeExpiredTemporaryGroups(MareDbContext dbContext)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
var expiredGroups = await dbContext.Groups
|
|
||||||
.Where(g => g.IsTemporary && g.ExpiresAt != null && g.ExpiresAt <= now)
|
|
||||||
.ToListAsync()
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (expiredGroups.Count == 0) return;
|
|
||||||
|
|
||||||
_logger.LogInformation("Cleaning up {count} expired temporary syncshells", expiredGroups.Count);
|
|
||||||
|
|
||||||
dbContext.Groups.RemoveRange(expiredGroups);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogWarning(ex, "Error during temporary syncshell purge");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task PurgeTempInvites(MareDbContext dbContext)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var tempInvites = await dbContext.GroupTempInvites.ToListAsync().ConfigureAwait(false);
|
|
||||||
dbContext.RemoveRange(tempInvites.Where(i => i.ExpirationDate < DateTime.UtcNow));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogWarning(ex, "Error during Temp Invite purge");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task PurgeUnusedAccounts(MareDbContext dbContext)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_configuration.GetValueOrDefault(nameof(ServerConfiguration.PurgeUnusedAccounts), false))
|
|
||||||
{
|
|
||||||
var usersOlderThanDays = _configuration.GetValueOrDefault(nameof(ServerConfiguration.PurgeUnusedAccountsPeriodInDays), 14);
|
|
||||||
var maxGroupsByUser = _configuration.GetValueOrDefault(nameof(ServerConfiguration.MaxGroupUserCount), 3);
|
|
||||||
|
|
||||||
_logger.LogInformation("Cleaning up users older than {usersOlderThanDays} days", usersOlderThanDays);
|
|
||||||
|
|
||||||
var allUsers = dbContext.Users.Where(u => string.IsNullOrEmpty(u.Alias)).ToList();
|
|
||||||
List<User> usersToRemove = new();
|
|
||||||
foreach (var user in allUsers)
|
|
||||||
{
|
|
||||||
if (user.LastLoggedIn < DateTime.UtcNow - TimeSpan.FromDays(usersOlderThanDays))
|
|
||||||
{
|
|
||||||
_logger.LogInformation("User outdated: {userUID}", user.UID);
|
|
||||||
usersToRemove.Add(user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var user in usersToRemove)
|
|
||||||
{
|
|
||||||
await SharedDbFunctions.PurgeUser(_logger, user, dbContext, maxGroupsByUser).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation("Cleaning up unauthorized users");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogWarning(ex, "Error during user purge");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CleanUpOutdatedLodestoneAuths(MareDbContext dbContext)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"Cleaning up expired lodestone authentications");
|
|
||||||
var lodestoneAuths = dbContext.LodeStoneAuth.Include(u => u.User).Where(a => a.StartedAt != null).ToList();
|
|
||||||
List<LodeStoneAuth> expiredAuths = new List<LodeStoneAuth>();
|
|
||||||
foreach (var auth in lodestoneAuths)
|
|
||||||
{
|
|
||||||
if (auth.StartedAt < DateTime.UtcNow - TimeSpan.FromMinutes(15))
|
|
||||||
{
|
|
||||||
expiredAuths.Add(auth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dbContext.Users.RemoveRange(expiredAuths.Where(u => u.User != null).Select(a => a.User));
|
|
||||||
dbContext.RemoveRange(expiredAuths);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogWarning(ex, "Error during expired auths cleanup");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task PurgeUser(User user, MareDbContext dbContext)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Purging user: {uid}", user.UID);
|
|
||||||
|
|
||||||
var lodestone = dbContext.LodeStoneAuth.SingleOrDefault(a => a.User.UID == user.UID);
|
|
||||||
|
|
||||||
if (lodestone != null)
|
|
||||||
{
|
|
||||||
dbContext.Remove(lodestone);
|
|
||||||
}
|
|
||||||
|
|
||||||
var auth = dbContext.Auth.Single(a => a.UserUID == user.UID);
|
|
||||||
|
|
||||||
var ownPairData = dbContext.ClientPairs.Where(u => u.User.UID == user.UID).ToList();
|
|
||||||
dbContext.ClientPairs.RemoveRange(ownPairData);
|
|
||||||
var otherPairData = dbContext.ClientPairs.Include(u => u.User)
|
|
||||||
.Where(u => u.OtherUser.UID == user.UID).ToList();
|
|
||||||
dbContext.ClientPairs.RemoveRange(otherPairData);
|
|
||||||
|
|
||||||
var userJoinedGroups = await dbContext.GroupPairs.Include(g => g.Group).Where(u => u.GroupUserUID == user.UID).ToListAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
foreach (var userGroupPair in userJoinedGroups)
|
|
||||||
{
|
|
||||||
bool ownerHasLeft = string.Equals(userGroupPair.Group.OwnerUID, user.UID, StringComparison.Ordinal);
|
|
||||||
|
|
||||||
if (ownerHasLeft)
|
|
||||||
{
|
|
||||||
var groupPairs = await dbContext.GroupPairs.Where(g => g.GroupGID == userGroupPair.GroupGID && g.GroupUserUID != user.UID).ToListAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (!groupPairs.Any())
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Group {gid} has no new owner, deleting", userGroupPair.GroupGID);
|
|
||||||
dbContext.Groups.Remove(userGroupPair.Group);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_ = await SharedDbFunctions.MigrateOrDeleteGroup(dbContext, userGroupPair.Group, groupPairs, _configuration.GetValueOrDefault(nameof(ServerConfiguration.MaxExistingGroupsByUser), 3)).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dbContext.GroupPairs.Remove(userGroupPair);
|
|
||||||
|
|
||||||
await dbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation("User purged: {uid}", user.UID);
|
|
||||||
|
|
||||||
dbContext.Auth.Remove(auth);
|
|
||||||
dbContext.Users.Remove(user);
|
|
||||||
|
|
||||||
await dbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
_cleanupCts.Cancel();
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,365 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using MareSynchronosServer.Hubs;
|
|
||||||
using Microsoft.AspNetCore.Http.Connections;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using AspNetCoreRateLimit;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using MareSynchronosShared.Metrics;
|
|
||||||
using MareSynchronosServer.Services;
|
|
||||||
using MareSynchronosShared.Utils;
|
|
||||||
using MareSynchronosShared.Services;
|
|
||||||
using Prometheus;
|
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
||||||
using Microsoft.IdentityModel.Tokens;
|
|
||||||
using System.Text;
|
|
||||||
using Microsoft.AspNetCore.HttpOverrides;
|
|
||||||
using StackExchange.Redis;
|
|
||||||
using StackExchange.Redis.Extensions.Core.Configuration;
|
|
||||||
using System.Net;
|
|
||||||
using StackExchange.Redis.Extensions.System.Text.Json;
|
|
||||||
using MareSynchronos.API.SignalR;
|
|
||||||
using MessagePack;
|
|
||||||
using MessagePack.Resolvers;
|
|
||||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
|
||||||
using MareSynchronosServer.Controllers;
|
|
||||||
using MareSynchronosShared.RequirementHandlers;
|
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer;
|
|
||||||
|
|
||||||
public class Startup
|
|
||||||
{
|
|
||||||
private readonly ILogger<Startup> _logger;
|
|
||||||
|
|
||||||
public Startup(IConfiguration configuration, ILogger<Startup> logger)
|
|
||||||
{
|
|
||||||
Configuration = configuration;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IConfiguration Configuration { get; }
|
|
||||||
|
|
||||||
public void ConfigureServices(IServiceCollection services)
|
|
||||||
{
|
|
||||||
services.AddHttpContextAccessor();
|
|
||||||
|
|
||||||
services.AddTransient(_ => Configuration);
|
|
||||||
|
|
||||||
var mareConfig = Configuration.GetRequiredSection("MareSynchronos");
|
|
||||||
|
|
||||||
// configure metrics
|
|
||||||
ConfigureMetrics(services);
|
|
||||||
|
|
||||||
// configure database
|
|
||||||
ConfigureDatabase(services, mareConfig);
|
|
||||||
|
|
||||||
// configure authentication and authorization
|
|
||||||
ConfigureAuthorization(services);
|
|
||||||
|
|
||||||
// configure rate limiting
|
|
||||||
ConfigureIpRateLimiting(services);
|
|
||||||
|
|
||||||
// configure SignalR
|
|
||||||
ConfigureSignalR(services, mareConfig);
|
|
||||||
|
|
||||||
// configure mare specific services
|
|
||||||
ConfigureMareServices(services, mareConfig);
|
|
||||||
|
|
||||||
services.AddHealthChecks();
|
|
||||||
services.AddControllers().ConfigureApplicationPartManager(a =>
|
|
||||||
{
|
|
||||||
a.FeatureProviders.Remove(a.FeatureProviders.OfType<ControllerFeatureProvider>().First());
|
|
||||||
if (mareConfig.GetValue<Uri>(nameof(ServerConfiguration.MainServerAddress), defaultValue: null) == null)
|
|
||||||
{
|
|
||||||
a.FeatureProviders.Add(new AllowedControllersFeatureProvider(typeof(MareServerConfigurationController), typeof(MareBaseConfigurationController), typeof(ClientMessageController), typeof(MainController), typeof(DiscoveryNotifyController)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
a.FeatureProviders.Add(new AllowedControllersFeatureProvider());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ConfigureMareServices(IServiceCollection services, IConfigurationSection mareConfig)
|
|
||||||
{
|
|
||||||
bool isMainServer = mareConfig.GetValue<Uri>(nameof(ServerConfiguration.MainServerAddress), defaultValue: null) == null;
|
|
||||||
|
|
||||||
services.Configure<ServerConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
|
|
||||||
services.Configure<MareConfigurationBase>(Configuration.GetRequiredSection("MareSynchronos"));
|
|
||||||
|
|
||||||
services.AddSingleton<ServerTokenGenerator>();
|
|
||||||
services.AddSingleton<SystemInfoService>();
|
|
||||||
services.AddHostedService(provider => provider.GetService<SystemInfoService>());
|
|
||||||
// configure services based on main server status
|
|
||||||
ConfigureServicesBasedOnShardType(services, mareConfig, isMainServer);
|
|
||||||
|
|
||||||
if (isMainServer)
|
|
||||||
{
|
|
||||||
services.AddSingleton<UserCleanupService>();
|
|
||||||
services.AddHostedService(provider => provider.GetService<UserCleanupService>());
|
|
||||||
services.AddSingleton<CharaDataCleanupService>();
|
|
||||||
services.AddHostedService(provider => provider.GetService<CharaDataCleanupService>());
|
|
||||||
}
|
|
||||||
|
|
||||||
services.AddSingleton<GPoseLobbyDistributionService>();
|
|
||||||
services.AddHostedService(provider => provider.GetService<GPoseLobbyDistributionService>());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ConfigureSignalR(IServiceCollection services, IConfigurationSection mareConfig)
|
|
||||||
{
|
|
||||||
services.AddSingleton<IUserIdProvider, IdBasedUserIdProvider>();
|
|
||||||
|
|
||||||
var signalRServiceBuilder = services.AddSignalR(hubOptions =>
|
|
||||||
{
|
|
||||||
hubOptions.MaximumReceiveMessageSize = long.MaxValue;
|
|
||||||
hubOptions.EnableDetailedErrors = true;
|
|
||||||
hubOptions.MaximumParallelInvocationsPerClient = 10;
|
|
||||||
hubOptions.StreamBufferCapacity = 200;
|
|
||||||
|
|
||||||
hubOptions.AddFilter<SignalRLimitFilter>();
|
|
||||||
}).AddMessagePackProtocol(opt =>
|
|
||||||
{
|
|
||||||
var resolver = CompositeResolver.Create(StandardResolverAllowPrivate.Instance,
|
|
||||||
BuiltinResolver.Instance,
|
|
||||||
AttributeFormatterResolver.Instance,
|
|
||||||
// replace enum resolver
|
|
||||||
DynamicEnumAsStringResolver.Instance,
|
|
||||||
DynamicGenericResolver.Instance,
|
|
||||||
DynamicUnionResolver.Instance,
|
|
||||||
DynamicObjectResolver.Instance,
|
|
||||||
PrimitiveObjectResolver.Instance,
|
|
||||||
// final fallback(last priority)
|
|
||||||
StandardResolver.Instance);
|
|
||||||
|
|
||||||
opt.SerializerOptions = MessagePackSerializerOptions.Standard
|
|
||||||
.WithCompression(MessagePackCompression.Lz4Block)
|
|
||||||
.WithResolver(resolver);
|
|
||||||
});
|
|
||||||
|
|
||||||
// configure redis for SignalR
|
|
||||||
var redisConnection = mareConfig.GetValue(nameof(ServerConfiguration.RedisConnectionString), string.Empty);
|
|
||||||
signalRServiceBuilder.AddStackExchangeRedis(redisConnection, options => { });
|
|
||||||
|
|
||||||
var options = ConfigurationOptions.Parse(redisConnection);
|
|
||||||
|
|
||||||
var endpoint = options.EndPoints[0];
|
|
||||||
string address = "";
|
|
||||||
int port = 0;
|
|
||||||
if (endpoint is DnsEndPoint dnsEndPoint) { address = dnsEndPoint.Host; port = dnsEndPoint.Port; }
|
|
||||||
if (endpoint is IPEndPoint ipEndPoint) { address = ipEndPoint.Address.ToString(); port = ipEndPoint.Port; }
|
|
||||||
var redisConfiguration = new RedisConfiguration()
|
|
||||||
{
|
|
||||||
AbortOnConnectFail = true,
|
|
||||||
KeyPrefix = "",
|
|
||||||
Hosts = new RedisHost[]
|
|
||||||
{
|
|
||||||
new RedisHost(){ Host = address, Port = port },
|
|
||||||
},
|
|
||||||
AllowAdmin = true,
|
|
||||||
ConnectTimeout = options.ConnectTimeout,
|
|
||||||
Database = 0,
|
|
||||||
Ssl = false,
|
|
||||||
Password = options.Password,
|
|
||||||
ServerEnumerationStrategy = new ServerEnumerationStrategy()
|
|
||||||
{
|
|
||||||
Mode = ServerEnumerationStrategy.ModeOptions.All,
|
|
||||||
TargetRole = ServerEnumerationStrategy.TargetRoleOptions.Any,
|
|
||||||
UnreachableServerAction = ServerEnumerationStrategy.UnreachableServerActionOptions.Throw,
|
|
||||||
},
|
|
||||||
MaxValueLength = 1024,
|
|
||||||
PoolSize = mareConfig.GetValue(nameof(ServerConfiguration.RedisPool), 50),
|
|
||||||
SyncTimeout = options.SyncTimeout,
|
|
||||||
};
|
|
||||||
|
|
||||||
services.AddStackExchangeRedisExtensions<SystemTextJsonSerializer>(redisConfiguration);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ConfigureIpRateLimiting(IServiceCollection services)
|
|
||||||
{
|
|
||||||
services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
|
|
||||||
services.Configure<IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies"));
|
|
||||||
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
|
|
||||||
services.AddMemoryCache();
|
|
||||||
services.AddInMemoryRateLimiting();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ConfigureAuthorization(IServiceCollection services)
|
|
||||||
{
|
|
||||||
services.AddTransient<IAuthorizationHandler, UserRequirementHandler>();
|
|
||||||
|
|
||||||
services.AddOptions<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme)
|
|
||||||
.Configure<IConfigurationService<MareConfigurationBase>>((options, config) =>
|
|
||||||
{
|
|
||||||
options.TokenValidationParameters = new()
|
|
||||||
{
|
|
||||||
ValidateIssuer = false,
|
|
||||||
ValidateLifetime = false,
|
|
||||||
ValidateAudience = false,
|
|
||||||
ValidateIssuerSigningKey = true,
|
|
||||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(config.GetValue<string>(nameof(MareConfigurationBase.Jwt)))),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Allow SignalR WebSocket connections to authenticate via access_token query on the hub path
|
|
||||||
options.Events = new JwtBearerEvents
|
|
||||||
{
|
|
||||||
OnMessageReceived = context =>
|
|
||||||
{
|
|
||||||
var accessToken = context.Request.Query["access_token"].ToString();
|
|
||||||
var path = context.HttpContext.Request.Path;
|
|
||||||
if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments(IMareHub.Path))
|
|
||||||
{
|
|
||||||
context.Token = accessToken;
|
|
||||||
}
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
services.AddAuthentication(o =>
|
|
||||||
{
|
|
||||||
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
}).AddJwtBearer();
|
|
||||||
|
|
||||||
services.AddAuthorization(options =>
|
|
||||||
{
|
|
||||||
options.DefaultPolicy = new AuthorizationPolicyBuilder()
|
|
||||||
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
|
|
||||||
.RequireAuthenticatedUser().Build();
|
|
||||||
options.AddPolicy("Authenticated", policy =>
|
|
||||||
{
|
|
||||||
policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
|
|
||||||
policy.RequireAuthenticatedUser();
|
|
||||||
});
|
|
||||||
options.AddPolicy("Identified", policy =>
|
|
||||||
{
|
|
||||||
policy.AddRequirements(new UserRequirement(UserRequirements.Identified));
|
|
||||||
});
|
|
||||||
options.AddPolicy("Admin", policy =>
|
|
||||||
{
|
|
||||||
policy.AddRequirements(new UserRequirement(UserRequirements.Identified | UserRequirements.Administrator));
|
|
||||||
});
|
|
||||||
options.AddPolicy("Moderator", policy =>
|
|
||||||
{
|
|
||||||
policy.AddRequirements(new UserRequirement(UserRequirements.Identified | UserRequirements.Moderator | UserRequirements.Administrator));
|
|
||||||
});
|
|
||||||
options.AddPolicy("Internal", new AuthorizationPolicyBuilder().RequireClaim(MareClaimTypes.Internal, "true").Build());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ConfigureDatabase(IServiceCollection services, IConfigurationSection mareConfig)
|
|
||||||
{
|
|
||||||
services.AddDbContextPool<MareDbContext>(options =>
|
|
||||||
{
|
|
||||||
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"), builder =>
|
|
||||||
{
|
|
||||||
builder.MigrationsHistoryTable("_efmigrationshistory", "public");
|
|
||||||
builder.MigrationsAssembly("MareSynchronosShared");
|
|
||||||
}).UseSnakeCaseNamingConvention();
|
|
||||||
options.EnableThreadSafetyChecks(false);
|
|
||||||
}, mareConfig.GetValue(nameof(MareConfigurationBase.DbContextPoolSize), 1024));
|
|
||||||
services.AddDbContextFactory<MareDbContext>(options =>
|
|
||||||
{
|
|
||||||
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"), builder =>
|
|
||||||
{
|
|
||||||
builder.MigrationsHistoryTable("_efmigrationshistory", "public");
|
|
||||||
builder.MigrationsAssembly("MareSynchronosShared");
|
|
||||||
}).UseSnakeCaseNamingConvention();
|
|
||||||
options.EnableThreadSafetyChecks(false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ConfigureMetrics(IServiceCollection services)
|
|
||||||
{
|
|
||||||
services.AddSingleton<MareMetrics>(m => new MareMetrics(m.GetService<ILogger<MareMetrics>>(), new List<string>
|
|
||||||
{
|
|
||||||
MetricsAPI.CounterInitializedConnections,
|
|
||||||
MetricsAPI.CounterUserPushData,
|
|
||||||
MetricsAPI.CounterUserPushDataTo,
|
|
||||||
MetricsAPI.CounterUsersRegisteredDeleted,
|
|
||||||
MetricsAPI.CounterAuthenticationCacheHits,
|
|
||||||
MetricsAPI.CounterAuthenticationFailures,
|
|
||||||
MetricsAPI.CounterAuthenticationRequests,
|
|
||||||
MetricsAPI.CounterAuthenticationSuccesses,
|
|
||||||
}, new List<string>
|
|
||||||
{
|
|
||||||
MetricsAPI.GaugeAuthorizedConnections,
|
|
||||||
MetricsAPI.GaugeConnections,
|
|
||||||
MetricsAPI.GaugePairs,
|
|
||||||
MetricsAPI.GaugePairsPaused,
|
|
||||||
MetricsAPI.GaugeAvailableIOWorkerThreads,
|
|
||||||
MetricsAPI.GaugeAvailableWorkerThreads,
|
|
||||||
MetricsAPI.GaugeGroups,
|
|
||||||
MetricsAPI.GaugeGroupPairs,
|
|
||||||
MetricsAPI.GaugeGroupPairsPaused,
|
|
||||||
MetricsAPI.GaugeUsersRegistered,
|
|
||||||
MetricsAPI.GaugeGposeLobbies,
|
|
||||||
MetricsAPI.GaugeGposeLobbyUsers
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ConfigureServicesBasedOnShardType(IServiceCollection services, IConfigurationSection mareConfig, bool isMainServer)
|
|
||||||
{
|
|
||||||
if (!isMainServer)
|
|
||||||
{
|
|
||||||
services.AddSingleton<IConfigurationService<ServerConfiguration>, MareConfigurationServiceClient<ServerConfiguration>>();
|
|
||||||
services.AddSingleton<IConfigurationService<MareConfigurationBase>, MareConfigurationServiceClient<MareConfigurationBase>>();
|
|
||||||
|
|
||||||
services.AddHostedService(p => (MareConfigurationServiceClient<ServerConfiguration>)p.GetService<IConfigurationService<ServerConfiguration>>());
|
|
||||||
services.AddHostedService(p => (MareConfigurationServiceClient<MareConfigurationBase>)p.GetService<IConfigurationService<MareConfigurationBase>>());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
services.AddSingleton<IConfigurationService<ServerConfiguration>, MareConfigurationServiceServer<ServerConfiguration>>();
|
|
||||||
services.AddSingleton<IConfigurationService<MareConfigurationBase>, MareConfigurationServiceServer<MareConfigurationBase>>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
|
|
||||||
{
|
|
||||||
logger.LogInformation("Running Configure");
|
|
||||||
|
|
||||||
var config = app.ApplicationServices.GetRequiredService<IConfigurationService<MareConfigurationBase>>();
|
|
||||||
|
|
||||||
// Respect X-Forwarded-* headers from reverse proxies (required for correct scheme/host)
|
|
||||||
app.UseForwardedHeaders(new ForwardedHeadersOptions
|
|
||||||
{
|
|
||||||
ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedHost | ForwardedHeaders.XForwardedFor
|
|
||||||
});
|
|
||||||
|
|
||||||
app.UseIpRateLimiting();
|
|
||||||
|
|
||||||
app.UseRouting();
|
|
||||||
|
|
||||||
app.UseWebSockets();
|
|
||||||
app.UseHttpMetrics();
|
|
||||||
|
|
||||||
var metricServer = new KestrelMetricServer(config.GetValueOrDefault<int>(nameof(MareConfigurationBase.MetricsPort), 4980));
|
|
||||||
metricServer.Start();
|
|
||||||
|
|
||||||
app.UseAuthentication();
|
|
||||||
app.UseAuthorization();
|
|
||||||
|
|
||||||
app.UseEndpoints(endpoints =>
|
|
||||||
{
|
|
||||||
endpoints.MapHub<MareHub>(IMareHub.Path, options =>
|
|
||||||
{
|
|
||||||
options.ApplicationMaxBufferSize = 5242880;
|
|
||||||
options.TransportMaxBufferSize = 5242880;
|
|
||||||
options.Transports = HttpTransportType.WebSockets | HttpTransportType.ServerSentEvents | HttpTransportType.LongPolling;
|
|
||||||
});
|
|
||||||
|
|
||||||
endpoints.MapHealthChecks("/health").AllowAnonymous();
|
|
||||||
endpoints.MapControllers();
|
|
||||||
|
|
||||||
foreach (var source in endpoints.DataSources.SelectMany(e => e.Endpoints).Cast<RouteEndpoint>())
|
|
||||||
{
|
|
||||||
if (source == null) continue;
|
|
||||||
_logger.LogInformation("Endpoint: {url} ", source.RoutePattern.RawText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
using MareSynchronos.API.Data;
|
|
||||||
using MareSynchronos.API.Data.Enum;
|
|
||||||
using MareSynchronos.API.Data.Extensions;
|
|
||||||
using MareSynchronosShared.Models;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Utils
|
|
||||||
{
|
|
||||||
public static class Extensions
|
|
||||||
{
|
|
||||||
public static GroupData ToGroupData(this Group group)
|
|
||||||
{
|
|
||||||
return new GroupData(group.GID, group.Alias);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UserData ToUserData(this GroupPair pair)
|
|
||||||
{
|
|
||||||
return new UserData(pair.GroupUser.UID, pair.GroupUser.Alias);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UserData ToUserData(this User user)
|
|
||||||
{
|
|
||||||
return new UserData(user.UID, user.Alias);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GroupPermissions GetGroupPermissions(this Group group)
|
|
||||||
{
|
|
||||||
var permissions = GroupPermissions.NoneSet;
|
|
||||||
permissions.SetDisableAnimations(group.DisableAnimations);
|
|
||||||
permissions.SetDisableSounds(group.DisableSounds);
|
|
||||||
permissions.SetDisableInvites(!group.InvitesEnabled);
|
|
||||||
permissions.SetDisableVFX(group.DisableVFX);
|
|
||||||
return permissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GroupUserPermissions GetGroupPairPermissions(this GroupPair groupPair)
|
|
||||||
{
|
|
||||||
var permissions = GroupUserPermissions.NoneSet;
|
|
||||||
permissions.SetDisableAnimations(groupPair.DisableAnimations);
|
|
||||||
permissions.SetDisableSounds(groupPair.DisableSounds);
|
|
||||||
permissions.SetPaused(groupPair.IsPaused);
|
|
||||||
permissions.SetDisableVFX(groupPair.DisableVFX);
|
|
||||||
return permissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GroupUserInfo GetGroupPairUserInfo(this GroupPair groupPair)
|
|
||||||
{
|
|
||||||
var groupUserInfo = GroupUserInfo.None;
|
|
||||||
groupUserInfo.SetPinned(groupPair.IsPinned);
|
|
||||||
groupUserInfo.SetModerator(groupPair.IsModerator);
|
|
||||||
return groupUserInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
using MareSynchronosServer.Hubs;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Utils;
|
|
||||||
|
|
||||||
public class MareHubLogger
|
|
||||||
{
|
|
||||||
private readonly MareHub _hub;
|
|
||||||
private readonly ILogger<MareHub> _logger;
|
|
||||||
|
|
||||||
public MareHubLogger(MareHub hub, ILogger<MareHub> logger)
|
|
||||||
{
|
|
||||||
_hub = hub;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static object[] Args(params object[] args)
|
|
||||||
{
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LogCallInfo(object[] args = null, [CallerMemberName] string methodName = "")
|
|
||||||
{
|
|
||||||
string formattedArgs = args != null && args.Length != 0 ? "|" + string.Join(":", args) : string.Empty;
|
|
||||||
_logger.LogInformation("{uid}:{method}{args}", _hub.UserUID, methodName, formattedArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LogCallWarning(object[] args = null, [CallerMemberName] string methodName = "")
|
|
||||||
{
|
|
||||||
string formattedArgs = args != null && args.Length != 0 ? "|" + string.Join(":", args) : string.Empty;
|
|
||||||
_logger.LogWarning("{uid}:{method}{args}", _hub.UserUID, methodName, formattedArgs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
namespace MareSynchronosServer.Utils;
|
|
||||||
|
|
||||||
public enum PauseInfo
|
|
||||||
{
|
|
||||||
NoConnection,
|
|
||||||
Paused,
|
|
||||||
Unpaused,
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace MareSynchronosServer.Utils;
|
|
||||||
|
|
||||||
public record PauseState
|
|
||||||
{
|
|
||||||
public string GID { get; set; }
|
|
||||||
public bool IsPaused => IsSelfPaused || IsOtherPaused;
|
|
||||||
public bool IsSelfPaused { get; set; }
|
|
||||||
public bool IsOtherPaused { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
namespace MareSynchronosServer.Utils;
|
|
||||||
|
|
||||||
public record PausedEntry
|
|
||||||
{
|
|
||||||
public string UID { get; set; }
|
|
||||||
public List<PauseState> PauseStates { get; set; } = new();
|
|
||||||
|
|
||||||
public PauseInfo IsDirectlyPaused => PauseStateWithoutGroups == null ? PauseInfo.NoConnection
|
|
||||||
: PauseStates.First(g => g.GID == null).IsPaused ? PauseInfo.Paused : PauseInfo.Unpaused;
|
|
||||||
|
|
||||||
public PauseInfo IsPausedPerGroup => !PauseStatesWithoutDirect.Any() ? PauseInfo.NoConnection
|
|
||||||
: PauseStatesWithoutDirect.All(p => p.IsPaused) ? PauseInfo.Paused : PauseInfo.Unpaused;
|
|
||||||
|
|
||||||
private IEnumerable<PauseState> PauseStatesWithoutDirect => PauseStates.Where(f => f.GID != null);
|
|
||||||
private PauseState PauseStateWithoutGroups => PauseStates.SingleOrDefault(p => p.GID == null);
|
|
||||||
|
|
||||||
public bool IsPaused
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var isDirectlyPaused = IsDirectlyPaused;
|
|
||||||
bool result;
|
|
||||||
if (isDirectlyPaused != PauseInfo.NoConnection)
|
|
||||||
{
|
|
||||||
result = isDirectlyPaused == PauseInfo.Paused;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = IsPausedPerGroup == PauseInfo.Paused;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public PauseInfo IsOtherPausedForSpecificGroup(string gid)
|
|
||||||
{
|
|
||||||
var state = PauseStatesWithoutDirect.SingleOrDefault(g => string.Equals(g.GID, gid, StringComparison.Ordinal));
|
|
||||||
if (state == null) return PauseInfo.NoConnection;
|
|
||||||
return state.IsOtherPaused ? PauseInfo.Paused : PauseInfo.Unpaused;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PauseInfo IsPausedForSpecificGroup(string gid)
|
|
||||||
{
|
|
||||||
var state = PauseStatesWithoutDirect.SingleOrDefault(g => string.Equals(g.GID, gid, StringComparison.Ordinal));
|
|
||||||
if (state == null) return PauseInfo.NoConnection;
|
|
||||||
return state.IsPaused ? PauseInfo.Paused : PauseInfo.NoConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PauseInfo IsPausedExcludingGroup(string gid)
|
|
||||||
{
|
|
||||||
var states = PauseStatesWithoutDirect.Where(f => !string.Equals(f.GID, gid, StringComparison.Ordinal)).ToList();
|
|
||||||
if (!states.Any()) return PauseInfo.NoConnection;
|
|
||||||
var result = states.All(p => p.IsPaused);
|
|
||||||
if (result) return PauseInfo.Paused;
|
|
||||||
return PauseInfo.Unpaused;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
namespace MareSynchronosServer.Hubs;
|
|
||||||
|
|
||||||
public partial class MareHub
|
|
||||||
{
|
|
||||||
private record UserPair
|
|
||||||
{
|
|
||||||
public string UserUID { get; set; }
|
|
||||||
public string OtherUserUID { get; set; }
|
|
||||||
public bool UserPausedOther { get; set; }
|
|
||||||
public bool OtherPausedUser { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
{
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"DefaultConnection": "Host=localhost;Port=5432;Database=mare;Username=postgres"
|
|
||||||
},
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft": "Warning",
|
|
||||||
"Microsoft.Hosting.Lifetime": "Information",
|
|
||||||
"MareSynchronosServer.Authentication": "Warning",
|
|
||||||
"System.IO.IOException": "Warning"
|
|
||||||
},
|
|
||||||
"File": {
|
|
||||||
"BasePath": "logs",
|
|
||||||
"FileAccessMode": "KeepOpenAndAutoFlush",
|
|
||||||
"FileEncodingName": "utf-8",
|
|
||||||
"DateFormat": "yyyMMdd",
|
|
||||||
"MaxFileSize": 10485760,
|
|
||||||
"Files": [
|
|
||||||
{
|
|
||||||
"Path": "mare-<counter>.log"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"MareSynchronos": {
|
|
||||||
"DbContextPoolSize": 2000,
|
|
||||||
"CdnFullUrl": "https://<url or ip to your server>/cache/",
|
|
||||||
"ServiceAddress": "http://localhost:5002",
|
|
||||||
"StaticFileServiceAddress": "http://localhost:5003"
|
|
||||||
},
|
|
||||||
"AllowedHosts": "*",
|
|
||||||
"Kestrel": {
|
|
||||||
"Endpoints": {
|
|
||||||
"Https": {
|
|
||||||
"Url": "https://+:5000",
|
|
||||||
"Certificate": {
|
|
||||||
"Subject": "darkarchon.internet-box.ch",
|
|
||||||
"Store": "My",
|
|
||||||
"Location": "LocalMachine"
|
|
||||||
//"AllowInvalid": false
|
|
||||||
// "Path": "", //use path, keypath and password to provide a valid certificate if not using windows key store
|
|
||||||
// "KeyPath": ""
|
|
||||||
// "Password": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"IpRateLimiting": {
|
|
||||||
"EnableEndpointRateLimiting": false,
|
|
||||||
"StackBlockedRequests": false,
|
|
||||||
"RealIpHeader": "X-Real-IP",
|
|
||||||
"ClientIdHeader": "X-ClientId",
|
|
||||||
"HttpStatusCode": 429,
|
|
||||||
"IpWhitelist": [ ],
|
|
||||||
"GeneralRules": [ ]
|
|
||||||
},
|
|
||||||
"IPRateLimitPolicies": {
|
|
||||||
"IpRules": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"isRoot": true,
|
|
||||||
"tools": {
|
|
||||||
"dotnet-ef": {
|
|
||||||
"version": "6.0.8",
|
|
||||||
"commands": [
|
|
||||||
"dotnet-ef"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,421 +0,0 @@
|
|||||||
using Discord;
|
|
||||||
using Discord.Interactions;
|
|
||||||
using Discord.Rest;
|
|
||||||
using Discord.WebSocket;
|
|
||||||
using MareSynchronos.API.Data.Enum;
|
|
||||||
using MareSynchronos.API.Dto.User;
|
|
||||||
using MareSynchronos.API.SignalR;
|
|
||||||
using MareSynchronosServer.Hubs;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using MareSynchronosShared.Services;
|
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using StackExchange.Redis;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace MareSynchronosServices.Discord;
|
|
||||||
|
|
||||||
internal class DiscordBot : IHostedService
|
|
||||||
{
|
|
||||||
private readonly DiscordBotServices _botServices;
|
|
||||||
private readonly IConfigurationService<ServicesConfiguration> _configurationService;
|
|
||||||
private readonly IConnectionMultiplexer _connectionMultiplexer;
|
|
||||||
private readonly DiscordSocketClient _discordClient;
|
|
||||||
private readonly ILogger<DiscordBot> _logger;
|
|
||||||
private readonly IHubContext<MareHub> _mareHubContext;
|
|
||||||
private readonly IServiceProvider _services;
|
|
||||||
private InteractionService _interactionModule;
|
|
||||||
private CancellationTokenSource? _processReportQueueCts;
|
|
||||||
private CancellationTokenSource? _updateStatusCts;
|
|
||||||
private CancellationTokenSource? _vanityUpdateCts;
|
|
||||||
|
|
||||||
public DiscordBot(DiscordBotServices botServices, IServiceProvider services, IConfigurationService<ServicesConfiguration> configuration,
|
|
||||||
IHubContext<MareHub> mareHubContext,
|
|
||||||
ILogger<DiscordBot> logger, IConnectionMultiplexer connectionMultiplexer)
|
|
||||||
{
|
|
||||||
_botServices = botServices;
|
|
||||||
_services = services;
|
|
||||||
_configurationService = configuration;
|
|
||||||
_mareHubContext = mareHubContext;
|
|
||||||
_logger = logger;
|
|
||||||
_connectionMultiplexer = connectionMultiplexer;
|
|
||||||
_discordClient = new(new DiscordSocketConfig()
|
|
||||||
{
|
|
||||||
DefaultRetryMode = RetryMode.AlwaysRetry
|
|
||||||
});
|
|
||||||
|
|
||||||
_discordClient.Log += Log;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task StartAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var token = _configurationService.GetValueOrDefault(nameof(ServicesConfiguration.DiscordBotToken), string.Empty);
|
|
||||||
if (!string.IsNullOrEmpty(token))
|
|
||||||
{
|
|
||||||
_interactionModule = new InteractionService(_discordClient);
|
|
||||||
await _interactionModule.AddModuleAsync(typeof(MareModule), _services).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await _discordClient.LoginAsync(TokenType.Bot, token).ConfigureAwait(false);
|
|
||||||
await _discordClient.StartAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
_discordClient.Ready += DiscordClient_Ready;
|
|
||||||
_discordClient.ButtonExecuted += ButtonExecutedHandler;
|
|
||||||
_discordClient.InteractionCreated += async (x) =>
|
|
||||||
{
|
|
||||||
var ctx = new SocketInteractionContext(_discordClient, x);
|
|
||||||
await _interactionModule.ExecuteCommandAsync(ctx, _services);
|
|
||||||
};
|
|
||||||
|
|
||||||
await _botServices.Start();
|
|
||||||
_ = UpdateStatusAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(_configurationService.GetValueOrDefault(nameof(ServicesConfiguration.DiscordBotToken), string.Empty)))
|
|
||||||
{
|
|
||||||
_discordClient.ButtonExecuted -= ButtonExecutedHandler;
|
|
||||||
|
|
||||||
await _botServices.Stop();
|
|
||||||
_processReportQueueCts?.Cancel();
|
|
||||||
_updateStatusCts?.Cancel();
|
|
||||||
_vanityUpdateCts?.Cancel();
|
|
||||||
|
|
||||||
await _discordClient.LogoutAsync().ConfigureAwait(false);
|
|
||||||
await _discordClient.StopAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ButtonExecutedHandler(SocketMessageComponent arg)
|
|
||||||
{
|
|
||||||
var id = arg.Data.CustomId;
|
|
||||||
if (!id.StartsWith("mare-report-button", StringComparison.Ordinal)) return;
|
|
||||||
|
|
||||||
var userId = arg.User.Id;
|
|
||||||
using var scope = _services.CreateScope();
|
|
||||||
using var dbContext = scope.ServiceProvider.GetRequiredService<MareDbContext>();
|
|
||||||
var user = await dbContext.LodeStoneAuth.Include(u => u.User).SingleOrDefaultAsync(u => u.DiscordId == userId).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (user == null || (!user.User.IsModerator && !user.User.IsAdmin))
|
|
||||||
{
|
|
||||||
EmbedBuilder eb = new();
|
|
||||||
eb.WithTitle($"Cannot resolve report");
|
|
||||||
eb.WithDescription($"<@{userId}>: You have no rights to resolve this report");
|
|
||||||
await arg.RespondAsync(embed: eb.Build()).ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
id = id.Remove(0, "mare-report-button-".Length);
|
|
||||||
var split = id.Split('-', StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
|
|
||||||
var profile = await dbContext.UserProfileData.SingleAsync(u => u.UserUID == split[1]).ConfigureAwait(false);
|
|
||||||
|
|
||||||
var embed = arg.Message.Embeds.First();
|
|
||||||
|
|
||||||
var builder = embed.ToEmbedBuilder();
|
|
||||||
var otherPairs = await dbContext.ClientPairs.Where(p => p.UserUID == split[1]).Select(p => p.OtherUserUID).ToListAsync().ConfigureAwait(false);
|
|
||||||
switch (split[0])
|
|
||||||
{
|
|
||||||
case "dismiss":
|
|
||||||
builder.AddField("Resolution", $"Dismissed by <@{userId}>");
|
|
||||||
builder.WithColor(Color.Green);
|
|
||||||
profile.FlaggedForReport = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "banreporting":
|
|
||||||
builder.AddField("Resolution", $"Dismissed by <@{userId}>, Reporting user banned");
|
|
||||||
builder.WithColor(Color.DarkGreen);
|
|
||||||
profile.FlaggedForReport = false;
|
|
||||||
var reportingUser = await dbContext.Auth.SingleAsync(u => u.UserUID == split[2]).ConfigureAwait(false);
|
|
||||||
reportingUser.IsBanned = true;
|
|
||||||
var regReporting = await dbContext.LodeStoneAuth.SingleAsync(u => u.User.UID == reportingUser.UserUID).ConfigureAwait(false);
|
|
||||||
dbContext.BannedRegistrations.Add(new MareSynchronosShared.Models.BannedRegistrations()
|
|
||||||
{
|
|
||||||
DiscordIdOrLodestoneAuth = regReporting.HashedLodestoneId
|
|
||||||
});
|
|
||||||
dbContext.BannedRegistrations.Add(new MareSynchronosShared.Models.BannedRegistrations()
|
|
||||||
{
|
|
||||||
DiscordIdOrLodestoneAuth = regReporting.DiscordId.ToString()
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "banprofile":
|
|
||||||
builder.AddField("Resolution", $"Profile has been banned by <@{userId}>");
|
|
||||||
builder.WithColor(Color.Red);
|
|
||||||
profile.Base64ProfileImage = null;
|
|
||||||
profile.UserDescription = null;
|
|
||||||
profile.ProfileDisabled = true;
|
|
||||||
profile.FlaggedForReport = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "banuser":
|
|
||||||
builder.AddField("Resolution", $"User has been banned by <@{userId}>");
|
|
||||||
builder.WithColor(Color.DarkRed);
|
|
||||||
var offendingUser = await dbContext.Auth.SingleAsync(u => u.UserUID == split[1]).ConfigureAwait(false);
|
|
||||||
offendingUser.IsBanned = true;
|
|
||||||
profile.Base64ProfileImage = null;
|
|
||||||
profile.UserDescription = null;
|
|
||||||
profile.ProfileDisabled = true;
|
|
||||||
var reg = await dbContext.LodeStoneAuth.SingleAsync(u => u.User.UID == offendingUser.UserUID).ConfigureAwait(false);
|
|
||||||
dbContext.BannedRegistrations.Add(new MareSynchronosShared.Models.BannedRegistrations()
|
|
||||||
{
|
|
||||||
DiscordIdOrLodestoneAuth = reg.HashedLodestoneId
|
|
||||||
});
|
|
||||||
dbContext.BannedRegistrations.Add(new MareSynchronosShared.Models.BannedRegistrations()
|
|
||||||
{
|
|
||||||
DiscordIdOrLodestoneAuth = reg.DiscordId.ToString()
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
await dbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
await _mareHubContext.Clients.Users(otherPairs).SendAsync(nameof(IMareHub.Client_UserUpdateProfile), new UserDto(new(split[1]))).ConfigureAwait(false);
|
|
||||||
await _mareHubContext.Clients.User(split[1]).SendAsync(nameof(IMareHub.Client_UserUpdateProfile), new UserDto(new(split[1]))).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await arg.Message.ModifyAsync(msg =>
|
|
||||||
{
|
|
||||||
msg.Content = arg.Message.Content;
|
|
||||||
msg.Components = null;
|
|
||||||
msg.Embed = new Optional<Embed>(builder.Build());
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task DiscordClient_Ready()
|
|
||||||
{
|
|
||||||
var guild = (await _discordClient.Rest.GetGuildsAsync()).First();
|
|
||||||
await _interactionModule.RegisterCommandsToGuildAsync(guild.Id, true).ConfigureAwait(false);
|
|
||||||
|
|
||||||
//_ = RemoveUsersNotInVanityRole();
|
|
||||||
_ = ProcessReportsQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task Log(LogMessage msg)
|
|
||||||
{
|
|
||||||
_logger.LogInformation("{msg}", msg);
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ProcessReportsQueue()
|
|
||||||
{
|
|
||||||
var guild = (await _discordClient.Rest.GetGuildsAsync()).First();
|
|
||||||
|
|
||||||
_processReportQueueCts?.Cancel();
|
|
||||||
_processReportQueueCts?.Dispose();
|
|
||||||
_processReportQueueCts = new();
|
|
||||||
var token = _processReportQueueCts.Token;
|
|
||||||
while (!token.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
await Task.Delay(TimeSpan.FromSeconds(30)).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (_discordClient.ConnectionState != ConnectionState.Connected) continue;
|
|
||||||
var reportChannelId = _configurationService.GetValue<ulong?>(nameof(ServicesConfiguration.DiscordChannelForReports));
|
|
||||||
if (reportChannelId == null) continue;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var scope = _services.CreateScope())
|
|
||||||
{
|
|
||||||
_logger.LogTrace("Checking for Profile Reports");
|
|
||||||
var dbContext = scope.ServiceProvider.GetRequiredService<MareDbContext>();
|
|
||||||
if (!dbContext.UserProfileReports.Any())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var reports = await dbContext.UserProfileReports.ToListAsync().ConfigureAwait(false);
|
|
||||||
var restChannel = await guild.GetTextChannelAsync(reportChannelId.Value).ConfigureAwait(false);
|
|
||||||
|
|
||||||
foreach (var report in reports)
|
|
||||||
{
|
|
||||||
var reportedUser = await dbContext.Users.SingleAsync(u => u.UID == report.ReportedUserUID).ConfigureAwait(false);
|
|
||||||
var reportedUserLodestone = await dbContext.LodeStoneAuth.SingleOrDefaultAsync(u => u.User.UID == report.ReportedUserUID).ConfigureAwait(false);
|
|
||||||
var reportingUser = await dbContext.Users.SingleAsync(u => u.UID == report.ReportingUserUID).ConfigureAwait(false);
|
|
||||||
var reportingUserLodestone = await dbContext.LodeStoneAuth.SingleOrDefaultAsync(u => u.User.UID == report.ReportingUserUID).ConfigureAwait(false);
|
|
||||||
var reportedUserProfile = await dbContext.UserProfileData.SingleAsync(u => u.UserUID == report.ReportedUserUID).ConfigureAwait(false);
|
|
||||||
EmbedBuilder eb = new();
|
|
||||||
eb.WithTitle("Mare Synchronos Profile Report");
|
|
||||||
|
|
||||||
StringBuilder reportedUserSb = new();
|
|
||||||
StringBuilder reportingUserSb = new();
|
|
||||||
reportedUserSb.Append(reportedUser.UID);
|
|
||||||
reportingUserSb.Append(reportingUser.UID);
|
|
||||||
if (reportedUserLodestone != null)
|
|
||||||
{
|
|
||||||
reportedUserSb.AppendLine($" (<@{reportedUserLodestone.DiscordId}>)");
|
|
||||||
}
|
|
||||||
if (reportingUserLodestone != null)
|
|
||||||
{
|
|
||||||
reportingUserSb.AppendLine($" (<@{reportingUserLodestone.DiscordId}>)");
|
|
||||||
}
|
|
||||||
eb.AddField("Reported User", reportedUserSb.ToString());
|
|
||||||
eb.AddField("Reporting User", reportingUserSb.ToString());
|
|
||||||
eb.AddField("Report Date (UTC)", report.ReportDate);
|
|
||||||
eb.AddField("Report Reason", string.IsNullOrWhiteSpace(report.ReportReason) ? "-" : report.ReportReason);
|
|
||||||
eb.AddField("Reported User Profile Description", string.IsNullOrWhiteSpace(reportedUserProfile.UserDescription) ? "-" : reportedUserProfile.UserDescription);
|
|
||||||
eb.AddField("Reported User Profile Is NSFW", reportedUserProfile.IsNSFW);
|
|
||||||
|
|
||||||
var cb = new ComponentBuilder();
|
|
||||||
cb.WithButton("Dismiss Report", customId: $"mare-report-button-dismiss-{reportedUser.UID}", style: ButtonStyle.Primary);
|
|
||||||
cb.WithButton("Ban profile", customId: $"mare-report-button-banprofile-{reportedUser.UID}", style: ButtonStyle.Secondary);
|
|
||||||
cb.WithButton("Ban user", customId: $"mare-report-button-banuser-{reportedUser.UID}", style: ButtonStyle.Danger);
|
|
||||||
cb.WithButton("Dismiss and Ban Reporting user", customId: $"mare-report-button-banreporting-{reportedUser.UID}-{reportingUser.UID}", style: ButtonStyle.Danger);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(reportedUserProfile.Base64ProfileImage))
|
|
||||||
{
|
|
||||||
var fileName = reportedUser.UID + "_profile_" + Guid.NewGuid().ToString("N") + ".png";
|
|
||||||
eb.WithImageUrl($"attachment://{fileName}");
|
|
||||||
using MemoryStream ms = new(Convert.FromBase64String(reportedUserProfile.Base64ProfileImage));
|
|
||||||
await restChannel.SendFileAsync(ms, fileName, "User Report", embed: eb.Build(), components: cb.Build(), isSpoiler: true).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var msg = await restChannel.SendMessageAsync(embed: eb.Build(), components: cb.Build()).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
dbContext.Remove(report);
|
|
||||||
}
|
|
||||||
|
|
||||||
await dbContext.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogWarning(ex, "Failed to process reports");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task RemoveUsersNotInVanityRole()
|
|
||||||
{
|
|
||||||
_vanityUpdateCts?.Cancel();
|
|
||||||
_vanityUpdateCts?.Dispose();
|
|
||||||
_vanityUpdateCts = new();
|
|
||||||
var token = _vanityUpdateCts.Token;
|
|
||||||
var guild = (await _discordClient.Rest.GetGuildsAsync()).First();
|
|
||||||
var commands = await guild.GetApplicationCommandsAsync();
|
|
||||||
var appId = await _discordClient.GetApplicationInfoAsync().ConfigureAwait(false);
|
|
||||||
var vanityCommandId = commands.First(c => c.ApplicationId == appId.Id && c.Name == "setvanityuid").Id;
|
|
||||||
|
|
||||||
while (!token.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"Cleaning up Vanity UIDs");
|
|
||||||
_logger.LogInformation("Getting application commands from guild {guildName}", guild.Name);
|
|
||||||
var restGuild = await _discordClient.Rest.GetGuildAsync(guild.Id);
|
|
||||||
var vanityCommand = await restGuild.GetSlashCommandAsync(vanityCommandId).ConfigureAwait(false);
|
|
||||||
GuildApplicationCommandPermission commandPermissions = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"Getting command permissions");
|
|
||||||
commandPermissions = await vanityCommand.GetCommandPermission().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error getting command permissions");
|
|
||||||
throw new Exception("Can't get command permissions");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation($"Getting allowed role ids from permissions");
|
|
||||||
List<ulong> allowedRoleIds = new();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
allowedRoleIds = (from perm in commandPermissions.Permissions where perm.TargetType == ApplicationCommandPermissionTarget.Role where perm.Permission select perm.TargetId).ToList();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Error resolving permissions to roles");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation($"Found allowed role ids: {string.Join(", ", allowedRoleIds)}");
|
|
||||||
|
|
||||||
if (allowedRoleIds.Any())
|
|
||||||
{
|
|
||||||
await using var scope = _services.CreateAsyncScope();
|
|
||||||
await using (var db = scope.ServiceProvider.GetRequiredService<MareDbContext>())
|
|
||||||
{
|
|
||||||
var aliasedUsers = await db.LodeStoneAuth.Include("User")
|
|
||||||
.Where(c => c.User != null && !string.IsNullOrEmpty(c.User.Alias)).ToListAsync().ConfigureAwait(false);
|
|
||||||
var aliasedGroups = await db.Groups.Include(u => u.Owner)
|
|
||||||
.Where(c => !string.IsNullOrEmpty(c.Alias)).ToListAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
foreach (var lodestoneAuth in aliasedUsers)
|
|
||||||
{
|
|
||||||
var discordUser = await restGuild.GetUserAsync(lodestoneAuth.DiscordId).ConfigureAwait(false);
|
|
||||||
_logger.LogInformation($"Checking User: {lodestoneAuth.DiscordId}, {lodestoneAuth.User.UID} ({lodestoneAuth.User.Alias}), User in Roles: {string.Join(", ", discordUser?.RoleIds ?? new List<ulong>())}");
|
|
||||||
|
|
||||||
if (discordUser == null || !discordUser.RoleIds.Any(u => allowedRoleIds.Contains(u)))
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"User {lodestoneAuth.User.UID} not in allowed roles, deleting alias");
|
|
||||||
lodestoneAuth.User.Alias = null;
|
|
||||||
var secondaryUsers = await db.Auth.Include(u => u.User).Where(u => u.PrimaryUserUID == lodestoneAuth.User.UID).ToListAsync().ConfigureAwait(false);
|
|
||||||
foreach (var secondaryUser in secondaryUsers)
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"Secondary User {secondaryUser.User.UID} not in allowed roles, deleting alias");
|
|
||||||
|
|
||||||
secondaryUser.User.Alias = null;
|
|
||||||
db.Update(secondaryUser.User);
|
|
||||||
}
|
|
||||||
db.Update(lodestoneAuth.User);
|
|
||||||
}
|
|
||||||
|
|
||||||
await db.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
await Task.Delay(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var group in aliasedGroups)
|
|
||||||
{
|
|
||||||
var lodestoneUser = await db.LodeStoneAuth.Include(u => u.User).SingleOrDefaultAsync(f => f.User.UID == group.OwnerUID).ConfigureAwait(false);
|
|
||||||
RestGuildUser discordUser = null;
|
|
||||||
if (lodestoneUser != null)
|
|
||||||
{
|
|
||||||
discordUser = await restGuild.GetUserAsync(lodestoneUser.DiscordId).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation($"Checking Group: {group.GID}, owned by {lodestoneUser?.User?.UID ?? string.Empty} ({lodestoneUser?.User?.Alias ?? string.Empty}), User in Roles: {string.Join(", ", discordUser?.RoleIds ?? new List<ulong>())}");
|
|
||||||
|
|
||||||
if (lodestoneUser == null || discordUser == null || !discordUser.RoleIds.Any(u => allowedRoleIds.Contains(u)))
|
|
||||||
{
|
|
||||||
_logger.LogInformation($"User {lodestoneUser.User.UID} not in allowed roles, deleting group alias");
|
|
||||||
group.Alias = null;
|
|
||||||
db.Update(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
await db.SaveChangesAsync().ConfigureAwait(false);
|
|
||||||
await Task.Delay(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogInformation("No roles for command defined, no cleanup performed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.LogError(ex, "Something failed during checking vanity user uids");
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogInformation("Vanity UID cleanup complete");
|
|
||||||
await Task.Delay(TimeSpan.FromHours(12), _vanityUpdateCts.Token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UpdateStatusAsync()
|
|
||||||
{
|
|
||||||
_updateStatusCts = new();
|
|
||||||
while (!_updateStatusCts.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
var endPoint = _connectionMultiplexer.GetEndPoints().First();
|
|
||||||
var onlineUsers = await _connectionMultiplexer.GetServer(endPoint).KeysAsync(pattern: "UID:*").CountAsync();
|
|
||||||
|
|
||||||
//_logger.LogInformation("Users online: " + onlineUsers);
|
|
||||||
await _discordClient.SetActivityAsync(new Game("with " + onlineUsers + " Users")).ConfigureAwait(false);
|
|
||||||
await Task.Delay(TimeSpan.FromSeconds(15)).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
using System.Collections.Concurrent;
|
|
||||||
using MareSynchronosShared.Metrics;
|
|
||||||
|
|
||||||
namespace MareSynchronosServices.Discord;
|
|
||||||
|
|
||||||
public class DiscordBotServices
|
|
||||||
{
|
|
||||||
public readonly string[] LodestoneServers = new[] { "eu", "na", "jp", "fr", "de" };
|
|
||||||
public ConcurrentDictionary<ulong, string> DiscordLodestoneMapping = new();
|
|
||||||
public ConcurrentDictionary<ulong, string> DiscordRelinkLodestoneMapping = new();
|
|
||||||
public ConcurrentDictionary<ulong, DateTime> LastVanityChange = new();
|
|
||||||
public ConcurrentDictionary<string, DateTime> LastVanityGidChange = new();
|
|
||||||
private readonly IServiceProvider _serviceProvider;
|
|
||||||
private CancellationTokenSource? verificationTaskCts;
|
|
||||||
|
|
||||||
public DiscordBotServices(IServiceProvider serviceProvider, ILogger<DiscordBotServices> logger, MareMetrics metrics)
|
|
||||||
{
|
|
||||||
_serviceProvider = serviceProvider;
|
|
||||||
Logger = logger;
|
|
||||||
Metrics = metrics;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ILogger<DiscordBotServices> Logger { get; init; }
|
|
||||||
public MareMetrics Metrics { get; init; }
|
|
||||||
public ConcurrentQueue<KeyValuePair<ulong, Action<IServiceProvider>>> VerificationQueue { get; } = new();
|
|
||||||
|
|
||||||
public Task Start()
|
|
||||||
{
|
|
||||||
_ = ProcessVerificationQueue();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task Stop()
|
|
||||||
{
|
|
||||||
verificationTaskCts?.Cancel();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ProcessVerificationQueue()
|
|
||||||
{
|
|
||||||
verificationTaskCts = new CancellationTokenSource();
|
|
||||||
while (!verificationTaskCts.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
if (VerificationQueue.TryDequeue(out var queueitem))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
queueitem.Value.Invoke(_serviceProvider);
|
|
||||||
|
|
||||||
Logger.LogInformation("Sent login information to user");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.LogError(e, "Error during queue work");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(TimeSpan.FromSeconds(2), verificationTaskCts.Token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.SignalR;
|
|
||||||
|
|
||||||
// this is a very hacky way to attach this file server to the main mare hub signalr instance via redis
|
|
||||||
// signalr publishes the namespace and hubname into the redis backend so this needs to be equal to the original
|
|
||||||
// but I don't need to reimplement the hub completely as I only exclusively use it for internal connection calling
|
|
||||||
// from the queue service so I keep the namespace and name of the class the same so it can connect to the same channel
|
|
||||||
// if anyone finds a better way to do this let me know
|
|
||||||
|
|
||||||
#pragma warning disable IDE0130 // Namespace does not match folder structure
|
|
||||||
#pragma warning disable MA0048 // File name must match type name
|
|
||||||
namespace MareSynchronosServer.Hubs;
|
|
||||||
public class MareHub : Hub
|
|
||||||
{
|
|
||||||
public override Task OnConnectedAsync()
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Task OnDisconnectedAsync(Exception exception)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma warning restore IDE0130 // Namespace does not match folder structure
|
|
||||||
#pragma warning restore MA0048 // File name must match type name
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Remove="appsettings.Development.json" />
|
|
||||||
<Content Remove="appsettings.json" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="appsettings.Development.json" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="appsettings.json">
|
|
||||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Discord.Net" Version="3.18.0" />
|
|
||||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.212">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.2" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\MareAPI\MareSynchronosAPI\MareSynchronos.API.csproj" />
|
|
||||||
<ProjectReference Include="..\MareSynchronosShared\MareSynchronosShared.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
using MareSynchronosServices;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using MareSynchronosShared.Services;
|
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
|
||||||
|
|
||||||
public class Program
|
|
||||||
{
|
|
||||||
public static void Main(string[] args)
|
|
||||||
{
|
|
||||||
var hostBuilder = CreateHostBuilder(args);
|
|
||||||
var host = hostBuilder.Build();
|
|
||||||
|
|
||||||
using (var scope = host.Services.CreateScope())
|
|
||||||
{
|
|
||||||
var services = scope.ServiceProvider;
|
|
||||||
using var dbContext = services.GetRequiredService<MareDbContext>();
|
|
||||||
|
|
||||||
var options = host.Services.GetService<IConfigurationService<ServicesConfiguration>>();
|
|
||||||
var optionsServer = host.Services.GetService<IConfigurationService<ServerConfiguration>>();
|
|
||||||
var logger = host.Services.GetService<ILogger<Program>>();
|
|
||||||
logger.LogInformation("Loaded MareSynchronos Services Configuration (IsMain: {isMain})", options.IsMain);
|
|
||||||
logger.LogInformation(options.ToString());
|
|
||||||
logger.LogInformation("Loaded MareSynchronos Server Configuration (IsMain: {isMain})", optionsServer.IsMain);
|
|
||||||
logger.LogInformation(optionsServer.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
host.Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
|
||||||
Host.CreateDefaultBuilder(args)
|
|
||||||
.UseSystemd()
|
|
||||||
.ConfigureWebHostDefaults(webBuilder =>
|
|
||||||
{
|
|
||||||
webBuilder.UseContentRoot(AppContext.BaseDirectory);
|
|
||||||
webBuilder.ConfigureLogging((ctx, builder) =>
|
|
||||||
{
|
|
||||||
builder.AddConfiguration(ctx.Configuration.GetSection("Logging"));
|
|
||||||
builder.AddFile(o => o.RootPath = AppContext.BaseDirectory);
|
|
||||||
});
|
|
||||||
webBuilder.UseStartup<Startup>();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"profiles": {
|
|
||||||
"MareSynchronosServices": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"dotnetRunMessages": true,
|
|
||||||
"launchBrowser": false,
|
|
||||||
"applicationUrl": "http://localhost:5294;https://localhost:7294",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
using MareSynchronosServices.Discord;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using MareSynchronosShared.Metrics;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Prometheus;
|
|
||||||
using MareSynchronosShared.Utils;
|
|
||||||
using MareSynchronosShared.Services;
|
|
||||||
using StackExchange.Redis;
|
|
||||||
using MessagePack.Resolvers;
|
|
||||||
using MessagePack;
|
|
||||||
using MareSynchronosShared.Utils.Configuration;
|
|
||||||
|
|
||||||
namespace MareSynchronosServices;
|
|
||||||
|
|
||||||
public class Startup
|
|
||||||
{
|
|
||||||
public Startup(IConfiguration configuration)
|
|
||||||
{
|
|
||||||
Configuration = configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IConfiguration Configuration { get; }
|
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
|
||||||
{
|
|
||||||
var config = app.ApplicationServices.GetRequiredService<IConfigurationService<MareConfigurationBase>>();
|
|
||||||
|
|
||||||
var metricServer = new KestrelMetricServer(config.GetValueOrDefault<int>(nameof(MareConfigurationBase.MetricsPort), 4982));
|
|
||||||
metricServer.Start();
|
|
||||||
|
|
||||||
app.UseRouting();
|
|
||||||
app.UseEndpoints(e =>
|
|
||||||
{
|
|
||||||
e.MapHub<MareSynchronosServer.Hubs.MareHub>("/dummyhub");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ConfigureServices(IServiceCollection services)
|
|
||||||
{
|
|
||||||
var mareConfig = Configuration.GetSection("MareSynchronos");
|
|
||||||
|
|
||||||
services.AddDbContextPool<MareDbContext>(options =>
|
|
||||||
{
|
|
||||||
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"), builder =>
|
|
||||||
{
|
|
||||||
builder.MigrationsHistoryTable("_efmigrationshistory", "public");
|
|
||||||
}).UseSnakeCaseNamingConvention();
|
|
||||||
options.EnableThreadSafetyChecks(false);
|
|
||||||
}, Configuration.GetValue(nameof(MareConfigurationBase.DbContextPoolSize), 1024));
|
|
||||||
|
|
||||||
services.AddSingleton(m => new MareMetrics(m.GetService<ILogger<MareMetrics>>(), new List<string> { },
|
|
||||||
new List<string> { }));
|
|
||||||
|
|
||||||
var redis = mareConfig.GetValue(nameof(ServerConfiguration.RedisConnectionString), string.Empty);
|
|
||||||
var options = ConfigurationOptions.Parse(redis);
|
|
||||||
options.ClientName = "Mare";
|
|
||||||
options.ChannelPrefix = "UserData";
|
|
||||||
ConnectionMultiplexer connectionMultiplexer = ConnectionMultiplexer.Connect(options);
|
|
||||||
services.AddSingleton<IConnectionMultiplexer>(connectionMultiplexer);
|
|
||||||
|
|
||||||
var signalRServiceBuilder = services.AddSignalR(hubOptions =>
|
|
||||||
{
|
|
||||||
hubOptions.MaximumReceiveMessageSize = long.MaxValue;
|
|
||||||
hubOptions.EnableDetailedErrors = true;
|
|
||||||
hubOptions.MaximumParallelInvocationsPerClient = 10;
|
|
||||||
hubOptions.StreamBufferCapacity = 200;
|
|
||||||
}).AddMessagePackProtocol(opt =>
|
|
||||||
{
|
|
||||||
var resolver = CompositeResolver.Create(StandardResolverAllowPrivate.Instance,
|
|
||||||
BuiltinResolver.Instance,
|
|
||||||
AttributeFormatterResolver.Instance,
|
|
||||||
// replace enum resolver
|
|
||||||
DynamicEnumAsStringResolver.Instance,
|
|
||||||
DynamicGenericResolver.Instance,
|
|
||||||
DynamicUnionResolver.Instance,
|
|
||||||
DynamicObjectResolver.Instance,
|
|
||||||
PrimitiveObjectResolver.Instance,
|
|
||||||
// final fallback(last priority)
|
|
||||||
StandardResolver.Instance);
|
|
||||||
|
|
||||||
opt.SerializerOptions = MessagePackSerializerOptions.Standard
|
|
||||||
.WithCompression(MessagePackCompression.Lz4Block)
|
|
||||||
.WithResolver(resolver);
|
|
||||||
});
|
|
||||||
|
|
||||||
// configure redis for SignalR
|
|
||||||
var redisConnection = mareConfig.GetValue(nameof(MareConfigurationBase.RedisConnectionString), string.Empty);
|
|
||||||
signalRServiceBuilder.AddStackExchangeRedis(redisConnection, options => { });
|
|
||||||
|
|
||||||
services.Configure<ServicesConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
|
|
||||||
services.Configure<ServerConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
|
|
||||||
services.Configure<MareConfigurationBase>(Configuration.GetRequiredSection("MareSynchronos"));
|
|
||||||
services.AddSingleton(Configuration);
|
|
||||||
services.AddSingleton<ServerTokenGenerator>();
|
|
||||||
services.AddSingleton<DiscordBotServices>();
|
|
||||||
services.AddHostedService<DiscordBot>();
|
|
||||||
services.AddSingleton<IConfigurationService<ServicesConfiguration>, MareConfigurationServiceServer<ServicesConfiguration>>();
|
|
||||||
services.AddSingleton<IConfigurationService<ServerConfiguration>, MareConfigurationServiceClient<ServerConfiguration>>();
|
|
||||||
services.AddSingleton<IConfigurationService<MareConfigurationBase>, MareConfigurationServiceClient<MareConfigurationBase>>();
|
|
||||||
|
|
||||||
services.AddHostedService(p => (MareConfigurationServiceClient<MareConfigurationBase>)p.GetService<IConfigurationService<MareConfigurationBase>>());
|
|
||||||
services.AddHostedService(p => (MareConfigurationServiceClient<ServerConfiguration>)p.GetService<IConfigurationService<ServerConfiguration>>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"ConnectionStrings": {
|
|
||||||
"DefaultConnection": "Host=localhost;Port=5432;Database=mare;Username=postgres"
|
|
||||||
},
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Kestrel": {
|
|
||||||
"Endpoints": {
|
|
||||||
"Http": {
|
|
||||||
"Protocols": "Http2",
|
|
||||||
"Url": "http://+:5002"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"MareSynchronos": {
|
|
||||||
"DbContextPoolSize": 1024,
|
|
||||||
"DiscordBotToken": "",
|
|
||||||
"DiscordChannelForMessages": "",
|
|
||||||
"PurgeUnusedAccounts": true,
|
|
||||||
"PurgeUnusedAccountsPeriodInDays": 14,
|
|
||||||
"FailedAuthForTempBan": 5,
|
|
||||||
"TempBanDurationInMinutes": 30,
|
|
||||||
},
|
|
||||||
"AllowedHosts": "*"
|
|
||||||
}
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
using MareSynchronosShared.Models;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace MareSynchronosShared.Data;
|
|
||||||
|
|
||||||
public class MareDbContext : DbContext
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
public MareDbContext() { }
|
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
|
||||||
{
|
|
||||||
if (optionsBuilder.IsConfigured)
|
|
||||||
{
|
|
||||||
base.OnConfiguring(optionsBuilder);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
optionsBuilder.UseNpgsql("Host=localhost;Port=5432;Database=mare;Username=postgres", builder =>
|
|
||||||
{
|
|
||||||
builder.MigrationsHistoryTable("_efmigrationshistory", "public");
|
|
||||||
builder.MigrationsAssembly("MareSynchronosShared");
|
|
||||||
}).UseSnakeCaseNamingConvention();
|
|
||||||
optionsBuilder.EnableThreadSafetyChecks(false);
|
|
||||||
|
|
||||||
base.OnConfiguring(optionsBuilder);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public MareDbContext(DbContextOptions<MareDbContext> options) : base(options)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public DbSet<Auth> Auth { get; set; }
|
|
||||||
public DbSet<BannedRegistrations> BannedRegistrations { get; set; }
|
|
||||||
public DbSet<Banned> BannedUsers { get; set; }
|
|
||||||
public DbSet<ClientPair> ClientPairs { get; set; }
|
|
||||||
public DbSet<FileCache> Files { get; set; }
|
|
||||||
public DbSet<ForbiddenUploadEntry> ForbiddenUploadEntries { get; set; }
|
|
||||||
public DbSet<GroupBan> GroupBans { get; set; }
|
|
||||||
public DbSet<GroupPair> GroupPairs { get; set; }
|
|
||||||
public DbSet<Group> Groups { get; set; }
|
|
||||||
public DbSet<GroupTempInvite> GroupTempInvites { get; set; }
|
|
||||||
public DbSet<LodeStoneAuth> LodeStoneAuth { get; set; }
|
|
||||||
public DbSet<UserProfileData> UserProfileData { get; set; }
|
|
||||||
public DbSet<UserProfileDataReport> UserProfileReports { get; set; }
|
|
||||||
public DbSet<User> Users { get; set; }
|
|
||||||
public DbSet<CharaData> CharaData { get; set; }
|
|
||||||
public DbSet<CharaDataFile> CharaDataFiles { get; set; }
|
|
||||||
public DbSet<CharaDataFileSwap> CharaDataFileSwaps { get; set; }
|
|
||||||
public DbSet<CharaDataOriginalFile> CharaDataOriginalFiles { get; set; }
|
|
||||||
public DbSet<CharaDataPose> CharaDataPoses { get; set; }
|
|
||||||
public DbSet<CharaDataAllowance> CharaDataAllowances { get; set; }
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder mb)
|
|
||||||
{
|
|
||||||
mb.Entity<Auth>().ToTable("auth");
|
|
||||||
mb.Entity<User>().ToTable("users");
|
|
||||||
mb.Entity<FileCache>().ToTable("file_caches");
|
|
||||||
mb.Entity<FileCache>().HasIndex(c => c.UploaderUID);
|
|
||||||
mb.Entity<ClientPair>().ToTable("client_pairs");
|
|
||||||
mb.Entity<ClientPair>().HasKey(u => new { u.UserUID, u.OtherUserUID });
|
|
||||||
mb.Entity<ClientPair>().HasIndex(c => c.UserUID);
|
|
||||||
mb.Entity<ClientPair>().HasIndex(c => c.OtherUserUID);
|
|
||||||
mb.Entity<ForbiddenUploadEntry>().ToTable("forbidden_upload_entries");
|
|
||||||
mb.Entity<Banned>().ToTable("banned_users");
|
|
||||||
mb.Entity<LodeStoneAuth>().ToTable("lodestone_auth");
|
|
||||||
mb.Entity<BannedRegistrations>().ToTable("banned_registrations");
|
|
||||||
mb.Entity<Group>().ToTable("groups");
|
|
||||||
mb.Entity<Group>().HasIndex(c => c.OwnerUID);
|
|
||||||
mb.Entity<GroupPair>().ToTable("group_pairs");
|
|
||||||
mb.Entity<GroupPair>().HasKey(u => new { u.GroupGID, u.GroupUserUID });
|
|
||||||
mb.Entity<GroupPair>().HasIndex(c => c.GroupUserUID);
|
|
||||||
mb.Entity<GroupPair>().HasIndex(c => c.GroupGID);
|
|
||||||
mb.Entity<GroupBan>().ToTable("group_bans");
|
|
||||||
mb.Entity<GroupBan>().HasKey(u => new { u.GroupGID, u.BannedUserUID });
|
|
||||||
mb.Entity<GroupBan>().HasIndex(c => c.BannedUserUID);
|
|
||||||
mb.Entity<GroupBan>().HasIndex(c => c.GroupGID);
|
|
||||||
mb.Entity<GroupTempInvite>().ToTable("group_temp_invites");
|
|
||||||
mb.Entity<GroupTempInvite>().HasKey(u => new { u.GroupGID, u.Invite });
|
|
||||||
mb.Entity<GroupTempInvite>().HasIndex(c => c.GroupGID);
|
|
||||||
mb.Entity<GroupTempInvite>().HasIndex(c => c.Invite);
|
|
||||||
mb.Entity<UserProfileData>().ToTable("user_profile_data");
|
|
||||||
mb.Entity<UserProfileData>().HasKey(c => c.UserUID);
|
|
||||||
mb.Entity<UserProfileDataReport>().ToTable("user_profile_data_reports");
|
|
||||||
mb.Entity<CharaData>().ToTable("chara_data");
|
|
||||||
mb.Entity<CharaData>()
|
|
||||||
.HasMany(p => p.Poses)
|
|
||||||
.WithOne(c => c.Parent)
|
|
||||||
.HasForeignKey(c => new { c.ParentId, c.ParentUploaderUID });
|
|
||||||
mb.Entity<CharaData>()
|
|
||||||
.HasMany(p => p.Files)
|
|
||||||
.WithOne(c => c.Parent)
|
|
||||||
.HasForeignKey(c => new { c.ParentId, c.ParentUploaderUID });
|
|
||||||
mb.Entity<CharaData>()
|
|
||||||
.HasMany(p => p.OriginalFiles)
|
|
||||||
.WithOne(p => p.Parent)
|
|
||||||
.HasForeignKey(p => new { p.ParentId, p.ParentUploaderUID });
|
|
||||||
mb.Entity<CharaData>()
|
|
||||||
.HasMany(p => p.AllowedIndividiuals)
|
|
||||||
.WithOne(p => p.Parent)
|
|
||||||
.HasForeignKey(p => new { p.ParentId, p.ParentUploaderUID });
|
|
||||||
mb.Entity<CharaData>()
|
|
||||||
.HasMany(p => p.FileSwaps)
|
|
||||||
.WithOne(p => p.Parent)
|
|
||||||
.HasForeignKey(p => new { p.ParentId, p.ParentUploaderUID });
|
|
||||||
mb.Entity<CharaData>().HasKey(p => new { p.Id, p.UploaderUID });
|
|
||||||
mb.Entity<CharaData>().HasIndex(p => p.UploaderUID);
|
|
||||||
mb.Entity<CharaData>().HasIndex(p => p.Id);
|
|
||||||
mb.Entity<CharaDataFile>().ToTable("chara_data_files");
|
|
||||||
mb.Entity<CharaDataFile>().HasKey(c => new { c.ParentId, c.ParentUploaderUID, c.GamePath });
|
|
||||||
mb.Entity<CharaDataFile>().HasIndex(c => c.ParentId);
|
|
||||||
mb.Entity<CharaDataFile>().HasOne(f => f.FileCache).WithMany().HasForeignKey(f => f.FileCacheHash).OnDelete(DeleteBehavior.Cascade);
|
|
||||||
mb.Entity<CharaDataFileSwap>().ToTable("chara_data_file_swaps");
|
|
||||||
mb.Entity<CharaDataFileSwap>().HasKey(c => new { c.ParentId, c.ParentUploaderUID, c.GamePath });
|
|
||||||
mb.Entity<CharaDataFileSwap>().HasIndex(c => c.ParentId);
|
|
||||||
mb.Entity<CharaDataPose>().ToTable("chara_data_poses");
|
|
||||||
mb.Entity<CharaDataPose>().Property(p => p.Id).ValueGeneratedOnAdd();
|
|
||||||
mb.Entity<CharaDataPose>().HasKey(c => new { c.ParentId, c.ParentUploaderUID, c.Id });
|
|
||||||
mb.Entity<CharaDataPose>().HasIndex(c => c.ParentId);
|
|
||||||
mb.Entity<CharaDataOriginalFile>().ToTable("chara_data_orig_files");
|
|
||||||
mb.Entity<CharaDataOriginalFile>().HasKey(c => new { c.ParentId, c.ParentUploaderUID, c.GamePath });
|
|
||||||
mb.Entity<CharaDataOriginalFile>().HasIndex(c => c.ParentId);
|
|
||||||
mb.Entity<CharaDataAllowance>().ToTable("chara_data_allowance");
|
|
||||||
mb.Entity<CharaDataAllowance>().HasKey(c => new { c.ParentId, c.ParentUploaderUID, c.Id });
|
|
||||||
mb.Entity<CharaDataAllowance>().Property(p => p.Id).ValueGeneratedOnAdd();
|
|
||||||
mb.Entity<CharaDataAllowance>().HasIndex(c => c.ParentId);
|
|
||||||
mb.Entity<CharaDataAllowance>().HasOne(u => u.AllowedGroup).WithMany().HasForeignKey(u => u.AllowedGroupGID).OnDelete(DeleteBehavior.Cascade);
|
|
||||||
mb.Entity<CharaDataAllowance>().HasOne(u => u.AllowedUser).WithMany().HasForeignKey(u => u.AllowedUserUID).OnDelete(DeleteBehavior.Cascade);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
|
|
||||||
namespace MareSynchronosShared;
|
|
||||||
|
|
||||||
public static class Extensions
|
|
||||||
{
|
|
||||||
private static long _noIpCntr = 0;
|
|
||||||
public static string GetIpAddress(this IHttpContextAccessor accessor)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(accessor.HttpContext.Request.Headers["CF-CONNECTING-IP"]))
|
|
||||||
return accessor.HttpContext.Request.Headers["CF-CONNECTING-IP"];
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(accessor.HttpContext.Request.Headers["X-Forwarded-For"]))
|
|
||||||
{
|
|
||||||
return accessor.HttpContext.Request.Headers["X-Forwarded-For"];
|
|
||||||
}
|
|
||||||
|
|
||||||
var ipAddress = accessor.HttpContext.GetServerVariable("HTTP_X_FORWARDED_FOR");
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(ipAddress))
|
|
||||||
{
|
|
||||||
var addresses = ipAddress.Split(',', StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
var lastEntry = addresses.LastOrDefault();
|
|
||||||
if (lastEntry != null)
|
|
||||||
{
|
|
||||||
return lastEntry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return accessor.HttpContext.Connection.RemoteIpAddress?.ToString() ?? "NoIp";
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return "NoIp" + _noIpCntr++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="ByteSize" Version="2.1.2" />
|
|
||||||
<PackageReference Include="EFCore.NamingConventions" Version="8.0.3" />
|
|
||||||
<PackageReference Include="IDisposableAnalyzers" Version="4.0.8">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Karambolo.Extensions.Logging.File" Version="3.6.3" />
|
|
||||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.212">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.3.0" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Core" Version="2.3.0" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.19" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="8.0.19" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="8.0.19" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.19" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.19" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.19">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.19" />
|
|
||||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="7.7.1" />
|
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.11" />
|
|
||||||
<PackageReference Include="prometheus-net" Version="8.2.1" />
|
|
||||||
<PackageReference Include="prometheus-net.AspNetCore" Version="8.2.1" />
|
|
||||||
<PackageReference Include="StackExchange.Redis" Version="2.9.11" />
|
|
||||||
<PackageReference Include="StackExchange.Redis.Extensions.AspNetCore" Version="10.2.0" />
|
|
||||||
<PackageReference Include="StackExchange.Redis.Extensions.Core" Version="10.2.0" />
|
|
||||||
<PackageReference Include="StackExchange.Redis.Extensions.System.Text.Json" Version="10.2.0" />
|
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.7.1" />
|
|
||||||
<PackageReference Include="System.Linq.Async" Version="6.0.3" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\MareAPI\MareSynchronosAPI\MareSynchronos.API.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Prometheus;
|
|
||||||
|
|
||||||
namespace MareSynchronosShared.Metrics;
|
|
||||||
|
|
||||||
public class MareMetrics
|
|
||||||
{
|
|
||||||
public MareMetrics(ILogger<MareMetrics> logger, List<string> countersToServe, List<string> gaugesToServe)
|
|
||||||
{
|
|
||||||
logger.LogInformation("Initializing MareMetrics");
|
|
||||||
foreach (var counter in countersToServe)
|
|
||||||
{
|
|
||||||
logger.LogInformation($"Creating Metric for Counter {counter}");
|
|
||||||
counters.Add(counter, Prometheus.Metrics.CreateCounter(counter, counter));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var gauge in gaugesToServe)
|
|
||||||
{
|
|
||||||
logger.LogInformation($"Creating Metric for Counter {gauge}");
|
|
||||||
if (!string.Equals(gauge, MetricsAPI.GaugeConnections, StringComparison.OrdinalIgnoreCase))
|
|
||||||
gauges.Add(gauge, Prometheus.Metrics.CreateGauge(gauge, gauge));
|
|
||||||
else
|
|
||||||
gauges.Add(gauge, Prometheus.Metrics.CreateGauge(gauge, gauge, new[] { "continent" }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Dictionary<string, Counter> counters = new(StringComparer.Ordinal);
|
|
||||||
|
|
||||||
private readonly Dictionary<string, Gauge> gauges = new(StringComparer.Ordinal);
|
|
||||||
|
|
||||||
public void IncGaugeWithLabels(string gaugeName, double value = 1.0, params string[] labels)
|
|
||||||
{
|
|
||||||
if (gauges.TryGetValue(gaugeName, out Gauge gauge))
|
|
||||||
{
|
|
||||||
lock (gauge)
|
|
||||||
gauge.WithLabels(labels).Inc(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DecGaugeWithLabels(string gaugeName, double value = 1.0, params string[] labels)
|
|
||||||
{
|
|
||||||
if (gauges.TryGetValue(gaugeName, out Gauge gauge))
|
|
||||||
{
|
|
||||||
lock (gauge)
|
|
||||||
gauge.WithLabels(labels).Dec(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetGaugeTo(string gaugeName, double value)
|
|
||||||
{
|
|
||||||
if (gauges.TryGetValue(gaugeName, out Gauge gauge))
|
|
||||||
{
|
|
||||||
lock (gauge)
|
|
||||||
gauge.Set(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void IncGauge(string gaugeName, double value = 1.0)
|
|
||||||
{
|
|
||||||
if (gauges.TryGetValue(gaugeName, out Gauge gauge))
|
|
||||||
{
|
|
||||||
lock (gauge)
|
|
||||||
gauge.Inc(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DecGauge(string gaugeName, double value = 1.0)
|
|
||||||
{
|
|
||||||
if (gauges.TryGetValue(gaugeName, out Gauge gauge))
|
|
||||||
{
|
|
||||||
lock (gauge)
|
|
||||||
gauge.Dec(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void IncCounter(string counterName, double value = 1.0)
|
|
||||||
{
|
|
||||||
if (counters.TryGetValue(counterName, out Counter counter))
|
|
||||||
{
|
|
||||||
lock (counter)
|
|
||||||
counter.Inc(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
namespace MareSynchronosShared.Metrics;
|
|
||||||
|
|
||||||
public class MetricsAPI
|
|
||||||
{
|
|
||||||
public const string CounterInitializedConnections = "mare_initialized_connections";
|
|
||||||
public const string GaugeConnections = "mare_connections";
|
|
||||||
public const string GaugeAuthorizedConnections = "mare_authorized_connections";
|
|
||||||
public const string GaugeAvailableWorkerThreads = "mare_available_threadpool";
|
|
||||||
public const string GaugeAvailableIOWorkerThreads = "mare_available_threadpool_io";
|
|
||||||
public const string GaugeUsersRegistered = "mare_users_registered";
|
|
||||||
public const string CounterUsersRegisteredDeleted = "mare_users_registered_deleted";
|
|
||||||
public const string GaugePairs = "mare_pairs";
|
|
||||||
public const string GaugePairsPaused = "mare_pairs_paused";
|
|
||||||
public const string GaugeFilesTotal = "mare_files";
|
|
||||||
public const string GaugeFilesTotalColdStorage = "mare_files_cold";
|
|
||||||
public const string GaugeFilesTotalSize = "mare_files_size";
|
|
||||||
public const string GaugeFilesTotalSizeColdStorage = "mare_files_size_cold";
|
|
||||||
public const string GaugeFilesDownloadingFromCache = "mare_files_downloading_from_cache";
|
|
||||||
public const string GaugeFilesTasksWaitingForDownloadFromCache = "mare_files_waiting_for_dl";
|
|
||||||
public const string CounterUserPushData = "mare_user_push";
|
|
||||||
public const string CounterUserPushDataTo = "mare_user_push_to";
|
|
||||||
public const string CounterAuthenticationRequests = "mare_auth_requests";
|
|
||||||
public const string CounterAuthenticationCacheHits = "mare_auth_requests_cachehit";
|
|
||||||
public const string CounterAuthenticationFailures = "mare_auth_requests_fail";
|
|
||||||
public const string CounterAuthenticationSuccesses = "mare_auth_requests_success";
|
|
||||||
public const string GaugeGroups = "mare_groups";
|
|
||||||
public const string GaugeGroupPairs = "mare_groups_pairs";
|
|
||||||
public const string GaugeGroupPairsPaused = "mare_groups_pairs_paused";
|
|
||||||
public const string GaugeFilesUniquePastHour = "mare_files_unique_past_hour";
|
|
||||||
public const string GaugeFilesUniquePastHourSize = "mare_files_unique_past_hour_size";
|
|
||||||
public const string GaugeFilesUniquePastDay = "mare_files_unique_past_day";
|
|
||||||
public const string GaugeFilesUniquePastDaySize = "mare_files_unique_past_day_size";
|
|
||||||
public const string GaugeCurrentDownloads = "mare_current_downloads";
|
|
||||||
public const string GaugeQueueFree = "mare_download_queue_free";
|
|
||||||
public const string GaugeQueueActive = "mare_download_queue_active";
|
|
||||||
public const string GaugeQueueInactive = "mare_download_queue_inactive";
|
|
||||||
public const string GaugeDownloadQueue = "mare_download_queue";
|
|
||||||
public const string GaugeDownloadQueueCancelled = "mare_download_queue_cancelled";
|
|
||||||
public const string GaugeDownloadPriorityQueue = "mare_download_priority_queue";
|
|
||||||
public const string GaugeDownloadPriorityQueueCancelled = "mare_download_priority_queue_cancelled";
|
|
||||||
public const string CounterFileRequests = "mare_files_requests";
|
|
||||||
public const string CounterFileRequestSize = "mare_files_request_size";
|
|
||||||
public const string CounterAccountsCreated = "mare_accounts_created";
|
|
||||||
public const string GaugeGposeLobbies = "mare_gpose_lobbies";
|
|
||||||
public const string GaugeGposeLobbyUsers = "mare_gpose_lobby_users";
|
|
||||||
}
|
|
||||||
@@ -1,241 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(MareDbContext))]
|
|
||||||
[Migration("20220731210149_InitialCreate")]
|
|
||||||
partial class InitialCreate
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "6.0.6")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("HashedKey")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("hashed_key");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("HashedKey")
|
|
||||||
.HasName("pk_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("Auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Banned", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<string>("Reason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("reason");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("CharacterIdentification")
|
|
||||||
.HasName("pk_banned_users");
|
|
||||||
|
|
||||||
b.ToTable("BannedUsers", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("AllowReceivingMessages")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("allow_receiving_messages");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_client_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("ClientPairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<bool>("Uploaded")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("uploaded");
|
|
||||||
|
|
||||||
b.Property<string>("UploaderUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uploader_uid");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_file_caches");
|
|
||||||
|
|
||||||
b.HasIndex("UploaderUID")
|
|
||||||
.HasDatabaseName("ix_file_caches_uploader_uid");
|
|
||||||
|
|
||||||
b.ToTable("FileCaches", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ForbiddenUploadEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("ForbiddenBy")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("forbidden_by");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_forbidden_upload_entries");
|
|
||||||
|
|
||||||
b.ToTable("ForbiddenUploadEntries", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uid");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<bool>("IsAdmin")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_admin");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<DateTime>("LastLoggedIn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_logged_in");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UID")
|
|
||||||
.HasName("pk_users");
|
|
||||||
|
|
||||||
b.HasIndex("CharacterIdentification")
|
|
||||||
.HasDatabaseName("ix_users_character_identification");
|
|
||||||
|
|
||||||
b.ToTable("Users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_auth_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_other_user_uid");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "Uploader")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UploaderUID")
|
|
||||||
.HasConstraintName("fk_file_caches_users_uploader_uid");
|
|
||||||
|
|
||||||
b.Navigation("Uploader");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
public partial class InitialCreate : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "BannedUsers",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
character_identification = table.Column<string>(type: "text", nullable: false),
|
|
||||||
reason = table.Column<string>(type: "text", nullable: true),
|
|
||||||
timestamp = table.Column<byte[]>(type: "bytea", rowVersion: true, nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_banned_users", x => x.character_identification);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "ForbiddenUploadEntries",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
hash = table.Column<string>(type: "character varying(40)", maxLength: 40, nullable: false),
|
|
||||||
forbidden_by = table.Column<string>(type: "text", nullable: true),
|
|
||||||
timestamp = table.Column<byte[]>(type: "bytea", rowVersion: true, nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_forbidden_upload_entries", x => x.hash);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Users",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
uid = table.Column<string>(type: "character varying(10)", maxLength: 10, nullable: false),
|
|
||||||
character_identification = table.Column<string>(type: "text", nullable: true),
|
|
||||||
timestamp = table.Column<byte[]>(type: "bytea", rowVersion: true, nullable: true),
|
|
||||||
is_moderator = table.Column<bool>(type: "boolean", nullable: false),
|
|
||||||
is_admin = table.Column<bool>(type: "boolean", nullable: false),
|
|
||||||
last_logged_in = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_users", x => x.uid);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Auth",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
hashed_key = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
|
|
||||||
user_uid = table.Column<string>(type: "character varying(10)", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_auth", x => x.hashed_key);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "fk_auth_users_user_uid",
|
|
||||||
column: x => x.user_uid,
|
|
||||||
principalTable: "Users",
|
|
||||||
principalColumn: "uid");
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "ClientPairs",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
user_uid = table.Column<string>(type: "character varying(10)", maxLength: 10, nullable: false),
|
|
||||||
other_user_uid = table.Column<string>(type: "character varying(10)", maxLength: 10, nullable: false),
|
|
||||||
is_paused = table.Column<bool>(type: "boolean", nullable: false),
|
|
||||||
allow_receiving_messages = table.Column<bool>(type: "boolean", nullable: false),
|
|
||||||
timestamp = table.Column<byte[]>(type: "bytea", rowVersion: true, nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_client_pairs", x => new { x.user_uid, x.other_user_uid });
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "fk_client_pairs_users_other_user_uid",
|
|
||||||
column: x => x.other_user_uid,
|
|
||||||
principalTable: "Users",
|
|
||||||
principalColumn: "uid",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "fk_client_pairs_users_user_uid",
|
|
||||||
column: x => x.user_uid,
|
|
||||||
principalTable: "Users",
|
|
||||||
principalColumn: "uid",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "FileCaches",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
hash = table.Column<string>(type: "character varying(40)", maxLength: 40, nullable: false),
|
|
||||||
uploader_uid = table.Column<string>(type: "character varying(10)", nullable: true),
|
|
||||||
uploaded = table.Column<bool>(type: "boolean", nullable: false),
|
|
||||||
timestamp = table.Column<byte[]>(type: "bytea", rowVersion: true, nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_file_caches", x => x.hash);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "fk_file_caches_users_uploader_uid",
|
|
||||||
column: x => x.uploader_uid,
|
|
||||||
principalTable: "Users",
|
|
||||||
principalColumn: "uid");
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_auth_user_uid",
|
|
||||||
table: "Auth",
|
|
||||||
column: "user_uid");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_client_pairs_other_user_uid",
|
|
||||||
table: "ClientPairs",
|
|
||||||
column: "other_user_uid");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_client_pairs_user_uid",
|
|
||||||
table: "ClientPairs",
|
|
||||||
column: "user_uid");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_file_caches_uploader_uid",
|
|
||||||
table: "FileCaches",
|
|
||||||
column: "uploader_uid");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_users_character_identification",
|
|
||||||
table: "Users",
|
|
||||||
column: "character_identification");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Auth");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "BannedUsers");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "ClientPairs");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "FileCaches");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "ForbiddenUploadEntries");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Users");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,241 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(MareDbContext))]
|
|
||||||
[Migration("20220731211419_RenameLowerSnakeCase")]
|
|
||||||
partial class RenameLowerSnakeCase
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "6.0.6")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("HashedKey")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("hashed_key");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("HashedKey")
|
|
||||||
.HasName("pk_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Banned", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<string>("Reason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("reason");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("CharacterIdentification")
|
|
||||||
.HasName("pk_banned_users");
|
|
||||||
|
|
||||||
b.ToTable("banned_users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("AllowReceivingMessages")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("allow_receiving_messages");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_client_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("client_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<bool>("Uploaded")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("uploaded");
|
|
||||||
|
|
||||||
b.Property<string>("UploaderUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uploader_uid");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_file_caches");
|
|
||||||
|
|
||||||
b.HasIndex("UploaderUID")
|
|
||||||
.HasDatabaseName("ix_file_caches_uploader_uid");
|
|
||||||
|
|
||||||
b.ToTable("file_caches", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ForbiddenUploadEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("ForbiddenBy")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("forbidden_by");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_forbidden_upload_entries");
|
|
||||||
|
|
||||||
b.ToTable("forbidden_upload_entries", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uid");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<bool>("IsAdmin")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_admin");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<DateTime>("LastLoggedIn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_logged_in");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UID")
|
|
||||||
.HasName("pk_users");
|
|
||||||
|
|
||||||
b.HasIndex("CharacterIdentification")
|
|
||||||
.HasDatabaseName("ix_users_character_identification");
|
|
||||||
|
|
||||||
b.ToTable("users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_auth_users_user_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_other_user_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_user_temp_id2");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "Uploader")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UploaderUID")
|
|
||||||
.HasConstraintName("fk_file_caches_users_uploader_uid");
|
|
||||||
|
|
||||||
b.Navigation("Uploader");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
public partial class RenameLowerSnakeCase : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "fk_auth_users_user_uid",
|
|
||||||
table: "Auth");
|
|
||||||
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "fk_client_pairs_users_other_user_uid",
|
|
||||||
table: "ClientPairs");
|
|
||||||
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "fk_client_pairs_users_user_uid",
|
|
||||||
table: "ClientPairs");
|
|
||||||
|
|
||||||
migrationBuilder.RenameTable(
|
|
||||||
name: "Users",
|
|
||||||
newName: "users");
|
|
||||||
|
|
||||||
migrationBuilder.RenameTable(
|
|
||||||
name: "Auth",
|
|
||||||
newName: "auth");
|
|
||||||
|
|
||||||
migrationBuilder.RenameTable(
|
|
||||||
name: "ForbiddenUploadEntries",
|
|
||||||
newName: "forbidden_upload_entries");
|
|
||||||
|
|
||||||
migrationBuilder.RenameTable(
|
|
||||||
name: "FileCaches",
|
|
||||||
newName: "file_caches");
|
|
||||||
|
|
||||||
migrationBuilder.RenameTable(
|
|
||||||
name: "ClientPairs",
|
|
||||||
newName: "client_pairs");
|
|
||||||
|
|
||||||
migrationBuilder.RenameTable(
|
|
||||||
name: "BannedUsers",
|
|
||||||
newName: "banned_users");
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "fk_auth_users_user_temp_id",
|
|
||||||
table: "auth",
|
|
||||||
column: "user_uid",
|
|
||||||
principalTable: "users",
|
|
||||||
principalColumn: "uid");
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "fk_client_pairs_users_other_user_temp_id1",
|
|
||||||
table: "client_pairs",
|
|
||||||
column: "other_user_uid",
|
|
||||||
principalTable: "users",
|
|
||||||
principalColumn: "uid",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "fk_client_pairs_users_user_temp_id2",
|
|
||||||
table: "client_pairs",
|
|
||||||
column: "user_uid",
|
|
||||||
principalTable: "users",
|
|
||||||
principalColumn: "uid",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "fk_auth_users_user_temp_id",
|
|
||||||
table: "auth");
|
|
||||||
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "fk_client_pairs_users_other_user_temp_id1",
|
|
||||||
table: "client_pairs");
|
|
||||||
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "fk_client_pairs_users_user_temp_id2",
|
|
||||||
table: "client_pairs");
|
|
||||||
|
|
||||||
migrationBuilder.RenameTable(
|
|
||||||
name: "users",
|
|
||||||
newName: "Users");
|
|
||||||
|
|
||||||
migrationBuilder.RenameTable(
|
|
||||||
name: "auth",
|
|
||||||
newName: "Auth");
|
|
||||||
|
|
||||||
migrationBuilder.RenameTable(
|
|
||||||
name: "forbidden_upload_entries",
|
|
||||||
newName: "ForbiddenUploadEntries");
|
|
||||||
|
|
||||||
migrationBuilder.RenameTable(
|
|
||||||
name: "file_caches",
|
|
||||||
newName: "FileCaches");
|
|
||||||
|
|
||||||
migrationBuilder.RenameTable(
|
|
||||||
name: "client_pairs",
|
|
||||||
newName: "ClientPairs");
|
|
||||||
|
|
||||||
migrationBuilder.RenameTable(
|
|
||||||
name: "banned_users",
|
|
||||||
newName: "BannedUsers");
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "fk_auth_users_user_uid",
|
|
||||||
table: "Auth",
|
|
||||||
column: "user_uid",
|
|
||||||
principalTable: "Users",
|
|
||||||
principalColumn: "uid");
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "fk_client_pairs_users_other_user_uid",
|
|
||||||
table: "ClientPairs",
|
|
||||||
column: "other_user_uid",
|
|
||||||
principalTable: "Users",
|
|
||||||
principalColumn: "uid",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "fk_client_pairs_users_user_uid",
|
|
||||||
table: "ClientPairs",
|
|
||||||
column: "user_uid",
|
|
||||||
principalTable: "Users",
|
|
||||||
principalColumn: "uid",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,283 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(MareDbContext))]
|
|
||||||
[Migration("20220801121419_AddLodestoneAuth")]
|
|
||||||
partial class AddLodestoneAuth
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "6.0.6")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("HashedKey")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("hashed_key");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("HashedKey")
|
|
||||||
.HasName("pk_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Banned", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<string>("Reason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("reason");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("CharacterIdentification")
|
|
||||||
.HasName("pk_banned_users");
|
|
||||||
|
|
||||||
b.ToTable("banned_users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("AllowReceivingMessages")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("allow_receiving_messages");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_client_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("client_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<bool>("Uploaded")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("uploaded");
|
|
||||||
|
|
||||||
b.Property<string>("UploaderUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uploader_uid");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_file_caches");
|
|
||||||
|
|
||||||
b.HasIndex("UploaderUID")
|
|
||||||
.HasDatabaseName("ix_file_caches_uploader_uid");
|
|
||||||
|
|
||||||
b.ToTable("file_caches", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ForbiddenUploadEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("ForbiddenBy")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("forbidden_by");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_forbidden_upload_entries");
|
|
||||||
|
|
||||||
b.ToTable("forbidden_upload_entries", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.Property<decimal>("DiscordId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("discord_id");
|
|
||||||
|
|
||||||
b.Property<string>("HashedLodestoneId")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("hashed_lodestone_id");
|
|
||||||
|
|
||||||
b.Property<string>("LodestoneAuthString")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("lodestone_auth_string");
|
|
||||||
|
|
||||||
b.Property<DateTime>("StartedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("started_at");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("DiscordId")
|
|
||||||
.HasName("pk_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_lodestone_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("lodestone_auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uid");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<bool>("IsAdmin")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_admin");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<DateTime>("LastLoggedIn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_logged_in");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UID")
|
|
||||||
.HasName("pk_users");
|
|
||||||
|
|
||||||
b.HasIndex("CharacterIdentification")
|
|
||||||
.HasDatabaseName("ix_users_character_identification");
|
|
||||||
|
|
||||||
b.ToTable("users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_auth_users_user_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_other_user_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_user_temp_id2");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "Uploader")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UploaderUID")
|
|
||||||
.HasConstraintName("fk_file_caches_users_uploader_uid");
|
|
||||||
|
|
||||||
b.Navigation("Uploader");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_lodestone_auth_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
public partial class AddLodestoneAuth : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "lodestone_auth",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
discord_id = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
|
||||||
hashed_lodestone_id = table.Column<string>(type: "text", nullable: true),
|
|
||||||
lodestone_auth_string = table.Column<string>(type: "text", nullable: true),
|
|
||||||
user_uid = table.Column<string>(type: "character varying(10)", nullable: true),
|
|
||||||
started_at = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_lodestone_auth", x => x.discord_id);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "fk_lodestone_auth_users_user_uid",
|
|
||||||
column: x => x.user_uid,
|
|
||||||
principalTable: "users",
|
|
||||||
principalColumn: "uid");
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_lodestone_auth_user_uid",
|
|
||||||
table: "lodestone_auth",
|
|
||||||
column: "user_uid");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "lodestone_auth");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,283 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(MareDbContext))]
|
|
||||||
[Migration("20220801122103_AddNullableLodestoneAuthProperties")]
|
|
||||||
partial class AddNullableLodestoneAuthProperties
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "6.0.6")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("HashedKey")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("hashed_key");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("HashedKey")
|
|
||||||
.HasName("pk_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Banned", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<string>("Reason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("reason");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("CharacterIdentification")
|
|
||||||
.HasName("pk_banned_users");
|
|
||||||
|
|
||||||
b.ToTable("banned_users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("AllowReceivingMessages")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("allow_receiving_messages");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_client_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("client_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<bool>("Uploaded")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("uploaded");
|
|
||||||
|
|
||||||
b.Property<string>("UploaderUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uploader_uid");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_file_caches");
|
|
||||||
|
|
||||||
b.HasIndex("UploaderUID")
|
|
||||||
.HasDatabaseName("ix_file_caches_uploader_uid");
|
|
||||||
|
|
||||||
b.ToTable("file_caches", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ForbiddenUploadEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("ForbiddenBy")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("forbidden_by");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_forbidden_upload_entries");
|
|
||||||
|
|
||||||
b.ToTable("forbidden_upload_entries", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.Property<decimal>("DiscordId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("discord_id");
|
|
||||||
|
|
||||||
b.Property<string>("HashedLodestoneId")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("hashed_lodestone_id");
|
|
||||||
|
|
||||||
b.Property<string>("LodestoneAuthString")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("lodestone_auth_string");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("StartedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("started_at");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("DiscordId")
|
|
||||||
.HasName("pk_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_lodestone_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("lodestone_auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uid");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<bool>("IsAdmin")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_admin");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<DateTime>("LastLoggedIn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_logged_in");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UID")
|
|
||||||
.HasName("pk_users");
|
|
||||||
|
|
||||||
b.HasIndex("CharacterIdentification")
|
|
||||||
.HasDatabaseName("ix_users_character_identification");
|
|
||||||
|
|
||||||
b.ToTable("users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_auth_users_user_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_other_user_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_user_temp_id2");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "Uploader")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UploaderUID")
|
|
||||||
.HasConstraintName("fk_file_caches_users_uploader_uid");
|
|
||||||
|
|
||||||
b.Navigation("Uploader");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_lodestone_auth_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
public partial class AddNullableLodestoneAuthProperties : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AlterColumn<DateTime>(
|
|
||||||
name: "started_at",
|
|
||||||
table: "lodestone_auth",
|
|
||||||
type: "timestamp with time zone",
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(DateTime),
|
|
||||||
oldType: "timestamp with time zone");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AlterColumn<DateTime>(
|
|
||||||
name: "started_at",
|
|
||||||
table: "lodestone_auth",
|
|
||||||
type: "timestamp with time zone",
|
|
||||||
nullable: false,
|
|
||||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
|
|
||||||
oldClrType: typeof(DateTime),
|
|
||||||
oldType: "timestamp with time zone",
|
|
||||||
oldNullable: true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,295 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(MareDbContext))]
|
|
||||||
[Migration("20220806103053_AddBannedRegistrations")]
|
|
||||||
partial class AddBannedRegistrations
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "6.0.6")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("HashedKey")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("hashed_key");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("HashedKey")
|
|
||||||
.HasName("pk_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Banned", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<string>("Reason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("reason");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("CharacterIdentification")
|
|
||||||
.HasName("pk_banned_users");
|
|
||||||
|
|
||||||
b.ToTable("banned_users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.BannedRegistrations", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("discord_id_or_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasKey("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasName("pk_banned_registrations");
|
|
||||||
|
|
||||||
b.ToTable("banned_registrations", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("AllowReceivingMessages")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("allow_receiving_messages");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_client_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("client_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<bool>("Uploaded")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("uploaded");
|
|
||||||
|
|
||||||
b.Property<string>("UploaderUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uploader_uid");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_file_caches");
|
|
||||||
|
|
||||||
b.HasIndex("UploaderUID")
|
|
||||||
.HasDatabaseName("ix_file_caches_uploader_uid");
|
|
||||||
|
|
||||||
b.ToTable("file_caches", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ForbiddenUploadEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("ForbiddenBy")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("forbidden_by");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_forbidden_upload_entries");
|
|
||||||
|
|
||||||
b.ToTable("forbidden_upload_entries", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.Property<decimal>("DiscordId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("discord_id");
|
|
||||||
|
|
||||||
b.Property<string>("HashedLodestoneId")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("hashed_lodestone_id");
|
|
||||||
|
|
||||||
b.Property<string>("LodestoneAuthString")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("lodestone_auth_string");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("StartedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("started_at");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("DiscordId")
|
|
||||||
.HasName("pk_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_lodestone_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("lodestone_auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uid");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<bool>("IsAdmin")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_admin");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<DateTime>("LastLoggedIn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_logged_in");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UID")
|
|
||||||
.HasName("pk_users");
|
|
||||||
|
|
||||||
b.HasIndex("CharacterIdentification")
|
|
||||||
.HasDatabaseName("ix_users_character_identification");
|
|
||||||
|
|
||||||
b.ToTable("users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_auth_users_user_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_other_user_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_user_temp_id2");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "Uploader")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UploaderUID")
|
|
||||||
.HasConstraintName("fk_file_caches_users_uploader_uid");
|
|
||||||
|
|
||||||
b.Navigation("Uploader");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_lodestone_auth_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
public partial class AddBannedRegistrations : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "banned_registrations",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
discord_id_or_lodestone_auth = table.Column<string>(type: "text", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_banned_registrations", x => x.discord_id_or_lodestone_auth);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "banned_registrations");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,302 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(MareDbContext))]
|
|
||||||
[Migration("20220816170426_SetMaxLimitForStrings")]
|
|
||||||
partial class SetMaxLimitForStrings
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "6.0.8")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("HashedKey")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("hashed_key");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("HashedKey")
|
|
||||||
.HasName("pk_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Banned", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<string>("Reason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("reason");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("CharacterIdentification")
|
|
||||||
.HasName("pk_banned_users");
|
|
||||||
|
|
||||||
b.ToTable("banned_users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.BannedRegistrations", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("discord_id_or_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasKey("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasName("pk_banned_registrations");
|
|
||||||
|
|
||||||
b.ToTable("banned_registrations", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("AllowReceivingMessages")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("allow_receiving_messages");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_client_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("client_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<bool>("Uploaded")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("uploaded");
|
|
||||||
|
|
||||||
b.Property<string>("UploaderUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uploader_uid");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_file_caches");
|
|
||||||
|
|
||||||
b.HasIndex("UploaderUID")
|
|
||||||
.HasDatabaseName("ix_file_caches_uploader_uid");
|
|
||||||
|
|
||||||
b.ToTable("file_caches", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ForbiddenUploadEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("ForbiddenBy")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("forbidden_by");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_forbidden_upload_entries");
|
|
||||||
|
|
||||||
b.ToTable("forbidden_upload_entries", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.Property<decimal>("DiscordId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("discord_id");
|
|
||||||
|
|
||||||
b.Property<string>("HashedLodestoneId")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("hashed_lodestone_id");
|
|
||||||
|
|
||||||
b.Property<string>("LodestoneAuthString")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("lodestone_auth_string");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("StartedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("started_at");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("DiscordId")
|
|
||||||
.HasName("pk_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_lodestone_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("lodestone_auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uid");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<bool>("IsAdmin")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_admin");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<DateTime>("LastLoggedIn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_logged_in");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UID")
|
|
||||||
.HasName("pk_users");
|
|
||||||
|
|
||||||
b.HasIndex("CharacterIdentification")
|
|
||||||
.HasDatabaseName("ix_users_character_identification");
|
|
||||||
|
|
||||||
b.ToTable("users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_auth_users_user_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_other_user_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_user_temp_id2");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "Uploader")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UploaderUID")
|
|
||||||
.HasConstraintName("fk_file_caches_users_uploader_uid");
|
|
||||||
|
|
||||||
b.Navigation("Uploader");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosServer.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosServer.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_lodestone_auth_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
public partial class SetMaxLimitForStrings : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "character_identification",
|
|
||||||
table: "users",
|
|
||||||
type: "character varying(100)",
|
|
||||||
maxLength: 100,
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "text",
|
|
||||||
oldNullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "lodestone_auth_string",
|
|
||||||
table: "lodestone_auth",
|
|
||||||
type: "character varying(100)",
|
|
||||||
maxLength: 100,
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "text",
|
|
||||||
oldNullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "hashed_lodestone_id",
|
|
||||||
table: "lodestone_auth",
|
|
||||||
type: "character varying(100)",
|
|
||||||
maxLength: 100,
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "text",
|
|
||||||
oldNullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "forbidden_by",
|
|
||||||
table: "forbidden_upload_entries",
|
|
||||||
type: "character varying(100)",
|
|
||||||
maxLength: 100,
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "text",
|
|
||||||
oldNullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "character_identification",
|
|
||||||
table: "banned_users",
|
|
||||||
type: "character varying(100)",
|
|
||||||
maxLength: 100,
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "text");
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "discord_id_or_lodestone_auth",
|
|
||||||
table: "banned_registrations",
|
|
||||||
type: "character varying(100)",
|
|
||||||
maxLength: 100,
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "text");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "character_identification",
|
|
||||||
table: "users",
|
|
||||||
type: "text",
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(100)",
|
|
||||||
oldMaxLength: 100,
|
|
||||||
oldNullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "lodestone_auth_string",
|
|
||||||
table: "lodestone_auth",
|
|
||||||
type: "text",
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(100)",
|
|
||||||
oldMaxLength: 100,
|
|
||||||
oldNullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "hashed_lodestone_id",
|
|
||||||
table: "lodestone_auth",
|
|
||||||
type: "text",
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(100)",
|
|
||||||
oldMaxLength: 100,
|
|
||||||
oldNullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "forbidden_by",
|
|
||||||
table: "forbidden_upload_entries",
|
|
||||||
type: "text",
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(100)",
|
|
||||||
oldMaxLength: 100,
|
|
||||||
oldNullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "character_identification",
|
|
||||||
table: "banned_users",
|
|
||||||
type: "text",
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(100)",
|
|
||||||
oldMaxLength: 100);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "discord_id_or_lodestone_auth",
|
|
||||||
table: "banned_registrations",
|
|
||||||
type: "text",
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(100)",
|
|
||||||
oldMaxLength: 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,307 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(MareDbContext))]
|
|
||||||
[Migration("20220824225157_AddAlias")]
|
|
||||||
partial class AddAlias
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "6.0.8")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("HashedKey")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("hashed_key");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("HashedKey")
|
|
||||||
.HasName("pk_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Banned", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<string>("Reason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("reason");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("CharacterIdentification")
|
|
||||||
.HasName("pk_banned_users");
|
|
||||||
|
|
||||||
b.ToTable("banned_users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.BannedRegistrations", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("discord_id_or_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasKey("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasName("pk_banned_registrations");
|
|
||||||
|
|
||||||
b.ToTable("banned_registrations", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("AllowReceivingMessages")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("allow_receiving_messages");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_client_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("client_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<bool>("Uploaded")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("uploaded");
|
|
||||||
|
|
||||||
b.Property<string>("UploaderUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uploader_uid");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_file_caches");
|
|
||||||
|
|
||||||
b.HasIndex("UploaderUID")
|
|
||||||
.HasDatabaseName("ix_file_caches_uploader_uid");
|
|
||||||
|
|
||||||
b.ToTable("file_caches", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ForbiddenUploadEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("ForbiddenBy")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("forbidden_by");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_forbidden_upload_entries");
|
|
||||||
|
|
||||||
b.ToTable("forbidden_upload_entries", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.Property<decimal>("DiscordId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("discord_id");
|
|
||||||
|
|
||||||
b.Property<string>("HashedLodestoneId")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("hashed_lodestone_id");
|
|
||||||
|
|
||||||
b.Property<string>("LodestoneAuthString")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("lodestone_auth_string");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("StartedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("started_at");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("DiscordId")
|
|
||||||
.HasName("pk_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_lodestone_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("lodestone_auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<bool>("IsAdmin")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_admin");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<DateTime>("LastLoggedIn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_logged_in");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UID")
|
|
||||||
.HasName("pk_users");
|
|
||||||
|
|
||||||
b.HasIndex("CharacterIdentification")
|
|
||||||
.HasDatabaseName("ix_users_character_identification");
|
|
||||||
|
|
||||||
b.ToTable("users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_auth_users_user_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_other_user_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_user_temp_id2");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Uploader")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UploaderUID")
|
|
||||||
.HasConstraintName("fk_file_caches_users_uploader_uid");
|
|
||||||
|
|
||||||
b.Navigation("Uploader");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_lodestone_auth_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
public partial class AddAlias : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<string>(
|
|
||||||
name: "alias",
|
|
||||||
table: "users",
|
|
||||||
type: "character varying(10)",
|
|
||||||
maxLength: 10,
|
|
||||||
nullable: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "alias",
|
|
||||||
table: "users");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,389 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(MareDbContext))]
|
|
||||||
[Migration("20220917115233_Groups")]
|
|
||||||
partial class Groups
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "6.0.8")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("HashedKey")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("hashed_key");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("HashedKey")
|
|
||||||
.HasName("pk_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Banned", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<string>("Reason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("reason");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("CharacterIdentification")
|
|
||||||
.HasName("pk_banned_users");
|
|
||||||
|
|
||||||
b.ToTable("banned_users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.BannedRegistrations", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("discord_id_or_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasKey("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasName("pk_banned_registrations");
|
|
||||||
|
|
||||||
b.ToTable("banned_registrations", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("AllowReceivingMessages")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("allow_receiving_messages");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_client_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("client_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<bool>("Uploaded")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("uploaded");
|
|
||||||
|
|
||||||
b.Property<string>("UploaderUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uploader_uid");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_file_caches");
|
|
||||||
|
|
||||||
b.HasIndex("UploaderUID")
|
|
||||||
.HasDatabaseName("ix_file_caches_uploader_uid");
|
|
||||||
|
|
||||||
b.ToTable("file_caches", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ForbiddenUploadEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("ForbiddenBy")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("forbidden_by");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_forbidden_upload_entries");
|
|
||||||
|
|
||||||
b.ToTable("forbidden_upload_entries", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GID")
|
|
||||||
.HasMaxLength(14)
|
|
||||||
.HasColumnType("character varying(14)")
|
|
||||||
.HasColumnName("gid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<string>("HashedPassword")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("hashed_password");
|
|
||||||
|
|
||||||
b.Property<bool>("InvitesEnabled")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("invites_enabled");
|
|
||||||
|
|
||||||
b.Property<string>("OwnerUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("owner_uid");
|
|
||||||
|
|
||||||
b.HasKey("GID")
|
|
||||||
.HasName("pk_groups");
|
|
||||||
|
|
||||||
b.HasIndex("OwnerUID")
|
|
||||||
.HasDatabaseName("ix_groups_owner_uid");
|
|
||||||
|
|
||||||
b.ToTable("groups", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(14)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<string>("GroupUserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("group_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.HasKey("GroupGID", "GroupUserUID")
|
|
||||||
.HasName("pk_group_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_gid");
|
|
||||||
|
|
||||||
b.HasIndex("GroupUserUID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("group_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.Property<decimal>("DiscordId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("discord_id");
|
|
||||||
|
|
||||||
b.Property<string>("HashedLodestoneId")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("hashed_lodestone_id");
|
|
||||||
|
|
||||||
b.Property<string>("LodestoneAuthString")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("lodestone_auth_string");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("StartedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("started_at");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("DiscordId")
|
|
||||||
.HasName("pk_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_lodestone_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("lodestone_auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<bool>("IsAdmin")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_admin");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<DateTime>("LastLoggedIn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_logged_in");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UID")
|
|
||||||
.HasName("pk_users");
|
|
||||||
|
|
||||||
b.ToTable("users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_auth_users_user_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_other_user_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_user_temp_id2");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Uploader")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UploaderUID")
|
|
||||||
.HasConstraintName("fk_file_caches_users_uploader_uid");
|
|
||||||
|
|
||||||
b.Navigation("Uploader");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Owner")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OwnerUID")
|
|
||||||
.HasConstraintName("fk_groups_users_owner_temp_id5");
|
|
||||||
|
|
||||||
b.Navigation("Owner");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_groups_group_temp_id");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "GroupUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_users_group_user_temp_id4");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
|
|
||||||
b.Navigation("GroupUser");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_lodestone_auth_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
public partial class Groups : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropIndex(
|
|
||||||
name: "ix_users_character_identification",
|
|
||||||
table: "users");
|
|
||||||
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "character_identification",
|
|
||||||
table: "users");
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "alias",
|
|
||||||
table: "users",
|
|
||||||
type: "character varying(10)",
|
|
||||||
maxLength: 10,
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(100)",
|
|
||||||
oldMaxLength: 100,
|
|
||||||
oldNullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "groups",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
gid = table.Column<string>(type: "character varying(14)", maxLength: 14, nullable: false),
|
|
||||||
owner_uid = table.Column<string>(type: "character varying(10)", nullable: true),
|
|
||||||
alias = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
|
|
||||||
invites_enabled = table.Column<bool>(type: "boolean", nullable: false),
|
|
||||||
hashed_password = table.Column<string>(type: "text", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_groups", x => x.gid);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "fk_groups_users_owner_temp_id5",
|
|
||||||
column: x => x.owner_uid,
|
|
||||||
principalTable: "users",
|
|
||||||
principalColumn: "uid");
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "group_pairs",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
group_gid = table.Column<string>(type: "character varying(14)", nullable: false),
|
|
||||||
group_user_uid = table.Column<string>(type: "character varying(10)", nullable: false),
|
|
||||||
is_paused = table.Column<bool>(type: "boolean", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_group_pairs", x => new { x.group_gid, x.group_user_uid });
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "fk_group_pairs_groups_group_temp_id",
|
|
||||||
column: x => x.group_gid,
|
|
||||||
principalTable: "groups",
|
|
||||||
principalColumn: "gid",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "fk_group_pairs_users_group_user_temp_id4",
|
|
||||||
column: x => x.group_user_uid,
|
|
||||||
principalTable: "users",
|
|
||||||
principalColumn: "uid",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_group_pairs_group_gid",
|
|
||||||
table: "group_pairs",
|
|
||||||
column: "group_gid");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_group_pairs_group_user_uid",
|
|
||||||
table: "group_pairs",
|
|
||||||
column: "group_user_uid");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_groups_owner_uid",
|
|
||||||
table: "groups",
|
|
||||||
column: "owner_uid");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "group_pairs");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "groups");
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "alias",
|
|
||||||
table: "users",
|
|
||||||
type: "character varying(100)",
|
|
||||||
maxLength: 100,
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(10)",
|
|
||||||
oldMaxLength: 10,
|
|
||||||
oldNullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.AddColumn<string>(
|
|
||||||
name: "character_identification",
|
|
||||||
table: "users",
|
|
||||||
type: "character varying(100)",
|
|
||||||
maxLength: 100,
|
|
||||||
nullable: true);
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_users_character_identification",
|
|
||||||
table: "users",
|
|
||||||
column: "character_identification");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,389 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(MareDbContext))]
|
|
||||||
[Migration("20220929150304_ChangeGidLength")]
|
|
||||||
partial class ChangeGidLength
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "6.0.8")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("HashedKey")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("hashed_key");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("HashedKey")
|
|
||||||
.HasName("pk_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Banned", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<string>("Reason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("reason");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("CharacterIdentification")
|
|
||||||
.HasName("pk_banned_users");
|
|
||||||
|
|
||||||
b.ToTable("banned_users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.BannedRegistrations", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("discord_id_or_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasKey("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasName("pk_banned_registrations");
|
|
||||||
|
|
||||||
b.ToTable("banned_registrations", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("AllowReceivingMessages")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("allow_receiving_messages");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_client_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("client_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<bool>("Uploaded")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("uploaded");
|
|
||||||
|
|
||||||
b.Property<string>("UploaderUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uploader_uid");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_file_caches");
|
|
||||||
|
|
||||||
b.HasIndex("UploaderUID")
|
|
||||||
.HasDatabaseName("ix_file_caches_uploader_uid");
|
|
||||||
|
|
||||||
b.ToTable("file_caches", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ForbiddenUploadEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("ForbiddenBy")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("forbidden_by");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_forbidden_upload_entries");
|
|
||||||
|
|
||||||
b.ToTable("forbidden_upload_entries", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GID")
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("gid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<string>("HashedPassword")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("hashed_password");
|
|
||||||
|
|
||||||
b.Property<bool>("InvitesEnabled")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("invites_enabled");
|
|
||||||
|
|
||||||
b.Property<string>("OwnerUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("owner_uid");
|
|
||||||
|
|
||||||
b.HasKey("GID")
|
|
||||||
.HasName("pk_groups");
|
|
||||||
|
|
||||||
b.HasIndex("OwnerUID")
|
|
||||||
.HasDatabaseName("ix_groups_owner_uid");
|
|
||||||
|
|
||||||
b.ToTable("groups", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<string>("GroupUserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("group_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.HasKey("GroupGID", "GroupUserUID")
|
|
||||||
.HasName("pk_group_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_gid");
|
|
||||||
|
|
||||||
b.HasIndex("GroupUserUID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("group_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.Property<decimal>("DiscordId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("discord_id");
|
|
||||||
|
|
||||||
b.Property<string>("HashedLodestoneId")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("hashed_lodestone_id");
|
|
||||||
|
|
||||||
b.Property<string>("LodestoneAuthString")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("lodestone_auth_string");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("StartedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("started_at");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("DiscordId")
|
|
||||||
.HasName("pk_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_lodestone_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("lodestone_auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<bool>("IsAdmin")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_admin");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<DateTime>("LastLoggedIn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_logged_in");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UID")
|
|
||||||
.HasName("pk_users");
|
|
||||||
|
|
||||||
b.ToTable("users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_auth_users_user_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_other_user_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_user_temp_id2");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Uploader")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UploaderUID")
|
|
||||||
.HasConstraintName("fk_file_caches_users_uploader_uid");
|
|
||||||
|
|
||||||
b.Navigation("Uploader");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Owner")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OwnerUID")
|
|
||||||
.HasConstraintName("fk_groups_users_owner_temp_id5");
|
|
||||||
|
|
||||||
b.Navigation("Owner");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_groups_group_temp_id");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "GroupUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_users_group_user_temp_id4");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
|
|
||||||
b.Navigation("GroupUser");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_lodestone_auth_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
public partial class ChangeGidLength : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "gid",
|
|
||||||
table: "groups",
|
|
||||||
type: "character varying(20)",
|
|
||||||
maxLength: 20,
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(14)",
|
|
||||||
oldMaxLength: 14);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "group_gid",
|
|
||||||
table: "group_pairs",
|
|
||||||
type: "character varying(20)",
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(14)");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "gid",
|
|
||||||
table: "groups",
|
|
||||||
type: "character varying(14)",
|
|
||||||
maxLength: 14,
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(20)",
|
|
||||||
oldMaxLength: 20);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "group_gid",
|
|
||||||
table: "group_pairs",
|
|
||||||
type: "character varying(14)",
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(20)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,393 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(MareDbContext))]
|
|
||||||
[Migration("20221002105428_IsPinned")]
|
|
||||||
partial class IsPinned
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "6.0.8")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("HashedKey")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("hashed_key");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("HashedKey")
|
|
||||||
.HasName("pk_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Banned", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<string>("Reason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("reason");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("CharacterIdentification")
|
|
||||||
.HasName("pk_banned_users");
|
|
||||||
|
|
||||||
b.ToTable("banned_users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.BannedRegistrations", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("discord_id_or_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasKey("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasName("pk_banned_registrations");
|
|
||||||
|
|
||||||
b.ToTable("banned_registrations", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("AllowReceivingMessages")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("allow_receiving_messages");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_client_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("client_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<bool>("Uploaded")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("uploaded");
|
|
||||||
|
|
||||||
b.Property<string>("UploaderUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uploader_uid");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_file_caches");
|
|
||||||
|
|
||||||
b.HasIndex("UploaderUID")
|
|
||||||
.HasDatabaseName("ix_file_caches_uploader_uid");
|
|
||||||
|
|
||||||
b.ToTable("file_caches", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ForbiddenUploadEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("ForbiddenBy")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("forbidden_by");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_forbidden_upload_entries");
|
|
||||||
|
|
||||||
b.ToTable("forbidden_upload_entries", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GID")
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("gid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<string>("HashedPassword")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("hashed_password");
|
|
||||||
|
|
||||||
b.Property<bool>("InvitesEnabled")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("invites_enabled");
|
|
||||||
|
|
||||||
b.Property<string>("OwnerUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("owner_uid");
|
|
||||||
|
|
||||||
b.HasKey("GID")
|
|
||||||
.HasName("pk_groups");
|
|
||||||
|
|
||||||
b.HasIndex("OwnerUID")
|
|
||||||
.HasDatabaseName("ix_groups_owner_uid");
|
|
||||||
|
|
||||||
b.ToTable("groups", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<string>("GroupUserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("group_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPinned")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_pinned");
|
|
||||||
|
|
||||||
b.HasKey("GroupGID", "GroupUserUID")
|
|
||||||
.HasName("pk_group_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_gid");
|
|
||||||
|
|
||||||
b.HasIndex("GroupUserUID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("group_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.Property<decimal>("DiscordId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("discord_id");
|
|
||||||
|
|
||||||
b.Property<string>("HashedLodestoneId")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("hashed_lodestone_id");
|
|
||||||
|
|
||||||
b.Property<string>("LodestoneAuthString")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("lodestone_auth_string");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("StartedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("started_at");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("DiscordId")
|
|
||||||
.HasName("pk_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_lodestone_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("lodestone_auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<bool>("IsAdmin")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_admin");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<DateTime>("LastLoggedIn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_logged_in");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UID")
|
|
||||||
.HasName("pk_users");
|
|
||||||
|
|
||||||
b.ToTable("users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_auth_users_user_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_other_user_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_user_temp_id2");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Uploader")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UploaderUID")
|
|
||||||
.HasConstraintName("fk_file_caches_users_uploader_uid");
|
|
||||||
|
|
||||||
b.Navigation("Uploader");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Owner")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OwnerUID")
|
|
||||||
.HasConstraintName("fk_groups_users_owner_temp_id5");
|
|
||||||
|
|
||||||
b.Navigation("Owner");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_groups_group_temp_id");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "GroupUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_users_group_user_temp_id4");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
|
|
||||||
b.Navigation("GroupUser");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_lodestone_auth_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
public partial class IsPinned : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<bool>(
|
|
||||||
name: "is_pinned",
|
|
||||||
table: "group_pairs",
|
|
||||||
type: "boolean",
|
|
||||||
nullable: false,
|
|
||||||
defaultValue: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "is_pinned",
|
|
||||||
table: "group_pairs");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,393 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(MareDbContext))]
|
|
||||||
[Migration("20221004125939_AdjustAliasLength")]
|
|
||||||
partial class AdjustAliasLength
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "6.0.8")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("HashedKey")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("hashed_key");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("HashedKey")
|
|
||||||
.HasName("pk_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Banned", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<string>("Reason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("reason");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("CharacterIdentification")
|
|
||||||
.HasName("pk_banned_users");
|
|
||||||
|
|
||||||
b.ToTable("banned_users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.BannedRegistrations", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("discord_id_or_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasKey("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasName("pk_banned_registrations");
|
|
||||||
|
|
||||||
b.ToTable("banned_registrations", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("AllowReceivingMessages")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("allow_receiving_messages");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_client_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("client_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<bool>("Uploaded")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("uploaded");
|
|
||||||
|
|
||||||
b.Property<string>("UploaderUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uploader_uid");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_file_caches");
|
|
||||||
|
|
||||||
b.HasIndex("UploaderUID")
|
|
||||||
.HasDatabaseName("ix_file_caches_uploader_uid");
|
|
||||||
|
|
||||||
b.ToTable("file_caches", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ForbiddenUploadEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("ForbiddenBy")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("forbidden_by");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_forbidden_upload_entries");
|
|
||||||
|
|
||||||
b.ToTable("forbidden_upload_entries", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GID")
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("gid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<string>("HashedPassword")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("hashed_password");
|
|
||||||
|
|
||||||
b.Property<bool>("InvitesEnabled")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("invites_enabled");
|
|
||||||
|
|
||||||
b.Property<string>("OwnerUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("owner_uid");
|
|
||||||
|
|
||||||
b.HasKey("GID")
|
|
||||||
.HasName("pk_groups");
|
|
||||||
|
|
||||||
b.HasIndex("OwnerUID")
|
|
||||||
.HasDatabaseName("ix_groups_owner_uid");
|
|
||||||
|
|
||||||
b.ToTable("groups", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<string>("GroupUserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("group_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPinned")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_pinned");
|
|
||||||
|
|
||||||
b.HasKey("GroupGID", "GroupUserUID")
|
|
||||||
.HasName("pk_group_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_gid");
|
|
||||||
|
|
||||||
b.HasIndex("GroupUserUID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("group_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.Property<decimal>("DiscordId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("discord_id");
|
|
||||||
|
|
||||||
b.Property<string>("HashedLodestoneId")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("hashed_lodestone_id");
|
|
||||||
|
|
||||||
b.Property<string>("LodestoneAuthString")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("lodestone_auth_string");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("StartedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("started_at");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("DiscordId")
|
|
||||||
.HasName("pk_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_lodestone_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("lodestone_auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(15)
|
|
||||||
.HasColumnType("character varying(15)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<bool>("IsAdmin")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_admin");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<DateTime>("LastLoggedIn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_logged_in");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UID")
|
|
||||||
.HasName("pk_users");
|
|
||||||
|
|
||||||
b.ToTable("users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_auth_users_user_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_other_user_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_user_temp_id2");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Uploader")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UploaderUID")
|
|
||||||
.HasConstraintName("fk_file_caches_users_uploader_uid");
|
|
||||||
|
|
||||||
b.Navigation("Uploader");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Owner")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OwnerUID")
|
|
||||||
.HasConstraintName("fk_groups_users_owner_temp_id5");
|
|
||||||
|
|
||||||
b.Navigation("Owner");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_groups_group_temp_id");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "GroupUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_users_group_user_temp_id4");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
|
|
||||||
b.Navigation("GroupUser");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_lodestone_auth_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
public partial class AdjustAliasLength : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "alias",
|
|
||||||
table: "users",
|
|
||||||
type: "character varying(15)",
|
|
||||||
maxLength: 15,
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(10)",
|
|
||||||
oldMaxLength: 10,
|
|
||||||
oldNullable: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "alias",
|
|
||||||
table: "users",
|
|
||||||
type: "character varying(10)",
|
|
||||||
maxLength: 10,
|
|
||||||
nullable: true,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(15)",
|
|
||||||
oldMaxLength: 15,
|
|
||||||
oldNullable: true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,397 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(MareDbContext))]
|
|
||||||
[Migration("20221006115929_GroupModerator")]
|
|
||||||
partial class GroupModerator
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "6.0.8")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("HashedKey")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("hashed_key");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("HashedKey")
|
|
||||||
.HasName("pk_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Banned", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<string>("Reason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("reason");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("CharacterIdentification")
|
|
||||||
.HasName("pk_banned_users");
|
|
||||||
|
|
||||||
b.ToTable("banned_users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.BannedRegistrations", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("discord_id_or_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasKey("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasName("pk_banned_registrations");
|
|
||||||
|
|
||||||
b.ToTable("banned_registrations", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("AllowReceivingMessages")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("allow_receiving_messages");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_client_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("client_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<bool>("Uploaded")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("uploaded");
|
|
||||||
|
|
||||||
b.Property<string>("UploaderUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uploader_uid");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_file_caches");
|
|
||||||
|
|
||||||
b.HasIndex("UploaderUID")
|
|
||||||
.HasDatabaseName("ix_file_caches_uploader_uid");
|
|
||||||
|
|
||||||
b.ToTable("file_caches", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ForbiddenUploadEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("ForbiddenBy")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("forbidden_by");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_forbidden_upload_entries");
|
|
||||||
|
|
||||||
b.ToTable("forbidden_upload_entries", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GID")
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("gid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<string>("HashedPassword")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("hashed_password");
|
|
||||||
|
|
||||||
b.Property<bool>("InvitesEnabled")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("invites_enabled");
|
|
||||||
|
|
||||||
b.Property<string>("OwnerUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("owner_uid");
|
|
||||||
|
|
||||||
b.HasKey("GID")
|
|
||||||
.HasName("pk_groups");
|
|
||||||
|
|
||||||
b.HasIndex("OwnerUID")
|
|
||||||
.HasDatabaseName("ix_groups_owner_uid");
|
|
||||||
|
|
||||||
b.ToTable("groups", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<string>("GroupUserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("group_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPinned")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_pinned");
|
|
||||||
|
|
||||||
b.HasKey("GroupGID", "GroupUserUID")
|
|
||||||
.HasName("pk_group_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_gid");
|
|
||||||
|
|
||||||
b.HasIndex("GroupUserUID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("group_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.Property<decimal>("DiscordId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("discord_id");
|
|
||||||
|
|
||||||
b.Property<string>("HashedLodestoneId")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("hashed_lodestone_id");
|
|
||||||
|
|
||||||
b.Property<string>("LodestoneAuthString")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("lodestone_auth_string");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("StartedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("started_at");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("DiscordId")
|
|
||||||
.HasName("pk_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_lodestone_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("lodestone_auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(15)
|
|
||||||
.HasColumnType("character varying(15)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<bool>("IsAdmin")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_admin");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<DateTime>("LastLoggedIn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_logged_in");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UID")
|
|
||||||
.HasName("pk_users");
|
|
||||||
|
|
||||||
b.ToTable("users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_auth_users_user_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_other_user_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_user_temp_id2");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Uploader")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UploaderUID")
|
|
||||||
.HasConstraintName("fk_file_caches_users_uploader_uid");
|
|
||||||
|
|
||||||
b.Navigation("Uploader");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Owner")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OwnerUID")
|
|
||||||
.HasConstraintName("fk_groups_users_owner_temp_id5");
|
|
||||||
|
|
||||||
b.Navigation("Owner");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_groups_group_temp_id");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "GroupUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_users_group_user_temp_id4");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
|
|
||||||
b.Navigation("GroupUser");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_lodestone_auth_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
public partial class GroupModerator : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<bool>(
|
|
||||||
name: "is_moderator",
|
|
||||||
table: "group_pairs",
|
|
||||||
type: "boolean",
|
|
||||||
nullable: false,
|
|
||||||
defaultValue: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "is_moderator",
|
|
||||||
table: "group_pairs");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,462 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(MareDbContext))]
|
|
||||||
[Migration("20221006122618_groupbans")]
|
|
||||||
partial class groupbans
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "6.0.8")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("HashedKey")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("hashed_key");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("HashedKey")
|
|
||||||
.HasName("pk_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Banned", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<string>("Reason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("reason");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("CharacterIdentification")
|
|
||||||
.HasName("pk_banned_users");
|
|
||||||
|
|
||||||
b.ToTable("banned_users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.BannedRegistrations", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("discord_id_or_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasKey("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasName("pk_banned_registrations");
|
|
||||||
|
|
||||||
b.ToTable("banned_registrations", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("AllowReceivingMessages")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("allow_receiving_messages");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_client_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("client_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<bool>("Uploaded")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("uploaded");
|
|
||||||
|
|
||||||
b.Property<string>("UploaderUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uploader_uid");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_file_caches");
|
|
||||||
|
|
||||||
b.HasIndex("UploaderUID")
|
|
||||||
.HasDatabaseName("ix_file_caches_uploader_uid");
|
|
||||||
|
|
||||||
b.ToTable("file_caches", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ForbiddenUploadEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("ForbiddenBy")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("forbidden_by");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_forbidden_upload_entries");
|
|
||||||
|
|
||||||
b.ToTable("forbidden_upload_entries", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GID")
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("gid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<string>("HashedPassword")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("hashed_password");
|
|
||||||
|
|
||||||
b.Property<bool>("InvitesEnabled")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("invites_enabled");
|
|
||||||
|
|
||||||
b.Property<string>("OwnerUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("owner_uid");
|
|
||||||
|
|
||||||
b.HasKey("GID")
|
|
||||||
.HasName("pk_groups");
|
|
||||||
|
|
||||||
b.HasIndex("OwnerUID")
|
|
||||||
.HasDatabaseName("ix_groups_owner_uid");
|
|
||||||
|
|
||||||
b.ToTable("groups", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupBan", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<string>("BannedUserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("banned_user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("BannedByUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("banned_by_uid");
|
|
||||||
|
|
||||||
b.Property<DateTime>("BannedOn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("banned_on");
|
|
||||||
|
|
||||||
b.Property<string>("BannedReason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("banned_reason");
|
|
||||||
|
|
||||||
b.HasKey("GroupGID", "BannedUserUID")
|
|
||||||
.HasName("pk_group_bans");
|
|
||||||
|
|
||||||
b.HasIndex("BannedByUID")
|
|
||||||
.HasDatabaseName("ix_group_bans_banned_by_uid");
|
|
||||||
|
|
||||||
b.HasIndex("BannedUserUID")
|
|
||||||
.HasDatabaseName("ix_group_bans_banned_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_bans_group_gid");
|
|
||||||
|
|
||||||
b.ToTable("group_bans", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<string>("GroupUserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("group_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPinned")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_pinned");
|
|
||||||
|
|
||||||
b.HasKey("GroupGID", "GroupUserUID")
|
|
||||||
.HasName("pk_group_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_gid");
|
|
||||||
|
|
||||||
b.HasIndex("GroupUserUID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("group_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.Property<decimal>("DiscordId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("discord_id");
|
|
||||||
|
|
||||||
b.Property<string>("HashedLodestoneId")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("hashed_lodestone_id");
|
|
||||||
|
|
||||||
b.Property<string>("LodestoneAuthString")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("lodestone_auth_string");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("StartedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("started_at");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("DiscordId")
|
|
||||||
.HasName("pk_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_lodestone_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("lodestone_auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(15)
|
|
||||||
.HasColumnType("character varying(15)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<bool>("IsAdmin")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_admin");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<DateTime>("LastLoggedIn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_logged_in");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UID")
|
|
||||||
.HasName("pk_users");
|
|
||||||
|
|
||||||
b.ToTable("users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_auth_users_user_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_other_user_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_user_temp_id2");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Uploader")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UploaderUID")
|
|
||||||
.HasConstraintName("fk_file_caches_users_uploader_uid");
|
|
||||||
|
|
||||||
b.Navigation("Uploader");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Owner")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OwnerUID")
|
|
||||||
.HasConstraintName("fk_groups_users_owner_temp_id7");
|
|
||||||
|
|
||||||
b.Navigation("Owner");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupBan", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "BannedBy")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("BannedByUID")
|
|
||||||
.HasConstraintName("fk_group_bans_users_banned_by_temp_id4");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "BannedUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("BannedUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_bans_users_banned_user_temp_id5");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_bans_groups_group_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("BannedBy");
|
|
||||||
|
|
||||||
b.Navigation("BannedUser");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_groups_group_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "GroupUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_users_group_user_temp_id6");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
|
|
||||||
b.Navigation("GroupUser");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_lodestone_auth_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
public partial class groupbans : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "fk_group_pairs_groups_group_temp_id",
|
|
||||||
table: "group_pairs");
|
|
||||||
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "fk_group_pairs_users_group_user_temp_id4",
|
|
||||||
table: "group_pairs");
|
|
||||||
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "fk_groups_users_owner_temp_id5",
|
|
||||||
table: "groups");
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "group_bans",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
group_gid = table.Column<string>(type: "character varying(20)", nullable: false),
|
|
||||||
banned_user_uid = table.Column<string>(type: "character varying(10)", nullable: false),
|
|
||||||
banned_by_uid = table.Column<string>(type: "character varying(10)", nullable: true),
|
|
||||||
banned_on = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
|
||||||
banned_reason = table.Column<string>(type: "text", nullable: true)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_group_bans", x => new { x.group_gid, x.banned_user_uid });
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "fk_group_bans_groups_group_temp_id",
|
|
||||||
column: x => x.group_gid,
|
|
||||||
principalTable: "groups",
|
|
||||||
principalColumn: "gid",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "fk_group_bans_users_banned_by_temp_id4",
|
|
||||||
column: x => x.banned_by_uid,
|
|
||||||
principalTable: "users",
|
|
||||||
principalColumn: "uid");
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "fk_group_bans_users_banned_user_temp_id5",
|
|
||||||
column: x => x.banned_user_uid,
|
|
||||||
principalTable: "users",
|
|
||||||
principalColumn: "uid",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_group_bans_banned_by_uid",
|
|
||||||
table: "group_bans",
|
|
||||||
column: "banned_by_uid");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_group_bans_banned_user_uid",
|
|
||||||
table: "group_bans",
|
|
||||||
column: "banned_user_uid");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_group_bans_group_gid",
|
|
||||||
table: "group_bans",
|
|
||||||
column: "group_gid");
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "fk_group_pairs_groups_group_temp_id1",
|
|
||||||
table: "group_pairs",
|
|
||||||
column: "group_gid",
|
|
||||||
principalTable: "groups",
|
|
||||||
principalColumn: "gid",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "fk_group_pairs_users_group_user_temp_id6",
|
|
||||||
table: "group_pairs",
|
|
||||||
column: "group_user_uid",
|
|
||||||
principalTable: "users",
|
|
||||||
principalColumn: "uid",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "fk_groups_users_owner_temp_id7",
|
|
||||||
table: "groups",
|
|
||||||
column: "owner_uid",
|
|
||||||
principalTable: "users",
|
|
||||||
principalColumn: "uid");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "fk_group_pairs_groups_group_temp_id1",
|
|
||||||
table: "group_pairs");
|
|
||||||
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "fk_group_pairs_users_group_user_temp_id6",
|
|
||||||
table: "group_pairs");
|
|
||||||
|
|
||||||
migrationBuilder.DropForeignKey(
|
|
||||||
name: "fk_groups_users_owner_temp_id7",
|
|
||||||
table: "groups");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "group_bans");
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "fk_group_pairs_groups_group_temp_id",
|
|
||||||
table: "group_pairs",
|
|
||||||
column: "group_gid",
|
|
||||||
principalTable: "groups",
|
|
||||||
principalColumn: "gid",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "fk_group_pairs_users_group_user_temp_id4",
|
|
||||||
table: "group_pairs",
|
|
||||||
column: "group_user_uid",
|
|
||||||
principalTable: "users",
|
|
||||||
principalColumn: "uid",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
|
|
||||||
migrationBuilder.AddForeignKey(
|
|
||||||
name: "fk_groups_users_owner_temp_id5",
|
|
||||||
table: "groups",
|
|
||||||
column: "owner_uid",
|
|
||||||
principalTable: "users",
|
|
||||||
principalColumn: "uid");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,501 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(MareDbContext))]
|
|
||||||
[Migration("20221024141548_GroupTempInvite")]
|
|
||||||
partial class GroupTempInvite
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "6.0.8")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("HashedKey")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("hashed_key");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("HashedKey")
|
|
||||||
.HasName("pk_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Banned", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<string>("Reason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("reason");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("CharacterIdentification")
|
|
||||||
.HasName("pk_banned_users");
|
|
||||||
|
|
||||||
b.ToTable("banned_users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.BannedRegistrations", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("discord_id_or_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasKey("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasName("pk_banned_registrations");
|
|
||||||
|
|
||||||
b.ToTable("banned_registrations", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("AllowReceivingMessages")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("allow_receiving_messages");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_client_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("client_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<bool>("Uploaded")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("uploaded");
|
|
||||||
|
|
||||||
b.Property<string>("UploaderUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uploader_uid");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_file_caches");
|
|
||||||
|
|
||||||
b.HasIndex("UploaderUID")
|
|
||||||
.HasDatabaseName("ix_file_caches_uploader_uid");
|
|
||||||
|
|
||||||
b.ToTable("file_caches", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ForbiddenUploadEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("ForbiddenBy")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("forbidden_by");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_forbidden_upload_entries");
|
|
||||||
|
|
||||||
b.ToTable("forbidden_upload_entries", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GID")
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("gid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<string>("HashedPassword")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("hashed_password");
|
|
||||||
|
|
||||||
b.Property<bool>("InvitesEnabled")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("invites_enabled");
|
|
||||||
|
|
||||||
b.Property<string>("OwnerUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("owner_uid");
|
|
||||||
|
|
||||||
b.HasKey("GID")
|
|
||||||
.HasName("pk_groups");
|
|
||||||
|
|
||||||
b.HasIndex("OwnerUID")
|
|
||||||
.HasDatabaseName("ix_groups_owner_uid");
|
|
||||||
|
|
||||||
b.ToTable("groups", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupBan", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<string>("BannedUserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("banned_user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("BannedByUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("banned_by_uid");
|
|
||||||
|
|
||||||
b.Property<DateTime>("BannedOn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("banned_on");
|
|
||||||
|
|
||||||
b.Property<string>("BannedReason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("banned_reason");
|
|
||||||
|
|
||||||
b.HasKey("GroupGID", "BannedUserUID")
|
|
||||||
.HasName("pk_group_bans");
|
|
||||||
|
|
||||||
b.HasIndex("BannedByUID")
|
|
||||||
.HasDatabaseName("ix_group_bans_banned_by_uid");
|
|
||||||
|
|
||||||
b.HasIndex("BannedUserUID")
|
|
||||||
.HasDatabaseName("ix_group_bans_banned_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_bans_group_gid");
|
|
||||||
|
|
||||||
b.ToTable("group_bans", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<string>("GroupUserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("group_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPinned")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_pinned");
|
|
||||||
|
|
||||||
b.HasKey("GroupGID", "GroupUserUID")
|
|
||||||
.HasName("pk_group_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_gid");
|
|
||||||
|
|
||||||
b.HasIndex("GroupUserUID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("group_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupTempInvite", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<string>("Invite")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("invite");
|
|
||||||
|
|
||||||
b.Property<DateTime>("ExpirationDate")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("expiration_date");
|
|
||||||
|
|
||||||
b.HasKey("GroupGID", "Invite")
|
|
||||||
.HasName("pk_group_temp_invites");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_temp_invites_group_gid");
|
|
||||||
|
|
||||||
b.HasIndex("Invite")
|
|
||||||
.HasDatabaseName("ix_group_temp_invites_invite");
|
|
||||||
|
|
||||||
b.ToTable("group_temp_invites", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.Property<decimal>("DiscordId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("discord_id");
|
|
||||||
|
|
||||||
b.Property<string>("HashedLodestoneId")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("hashed_lodestone_id");
|
|
||||||
|
|
||||||
b.Property<string>("LodestoneAuthString")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("lodestone_auth_string");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("StartedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("started_at");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("DiscordId")
|
|
||||||
.HasName("pk_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_lodestone_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("lodestone_auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(15)
|
|
||||||
.HasColumnType("character varying(15)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<bool>("IsAdmin")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_admin");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<DateTime>("LastLoggedIn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_logged_in");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UID")
|
|
||||||
.HasName("pk_users");
|
|
||||||
|
|
||||||
b.ToTable("users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_auth_users_user_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_other_user_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_user_temp_id2");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Uploader")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UploaderUID")
|
|
||||||
.HasConstraintName("fk_file_caches_users_uploader_uid");
|
|
||||||
|
|
||||||
b.Navigation("Uploader");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Owner")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OwnerUID")
|
|
||||||
.HasConstraintName("fk_groups_users_owner_temp_id7");
|
|
||||||
|
|
||||||
b.Navigation("Owner");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupBan", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "BannedBy")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("BannedByUID")
|
|
||||||
.HasConstraintName("fk_group_bans_users_banned_by_temp_id4");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "BannedUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("BannedUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_bans_users_banned_user_temp_id5");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_bans_groups_group_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("BannedBy");
|
|
||||||
|
|
||||||
b.Navigation("BannedUser");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_groups_group_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "GroupUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_users_group_user_temp_id6");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
|
|
||||||
b.Navigation("GroupUser");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupTempInvite", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_temp_invites_groups_group_gid");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_lodestone_auth_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
public partial class GroupTempInvite : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "group_temp_invites",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
group_gid = table.Column<string>(type: "character varying(20)", nullable: false),
|
|
||||||
invite = table.Column<string>(type: "character varying(10)", maxLength: 10, nullable: false),
|
|
||||||
expiration_date = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("pk_group_temp_invites", x => new { x.group_gid, x.invite });
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "fk_group_temp_invites_groups_group_gid",
|
|
||||||
column: x => x.group_gid,
|
|
||||||
principalTable: "groups",
|
|
||||||
principalColumn: "gid",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_group_temp_invites_group_gid",
|
|
||||||
table: "group_temp_invites",
|
|
||||||
column: "group_gid");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "ix_group_temp_invites_invite",
|
|
||||||
table: "group_temp_invites",
|
|
||||||
column: "invite");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "group_temp_invites");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,501 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(MareDbContext))]
|
|
||||||
[Migration("20221024181912_AdjustInviteLength")]
|
|
||||||
partial class AdjustInviteLength
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "6.0.8")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("HashedKey")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("hashed_key");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("HashedKey")
|
|
||||||
.HasName("pk_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Banned", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<string>("Reason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("reason");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("CharacterIdentification")
|
|
||||||
.HasName("pk_banned_users");
|
|
||||||
|
|
||||||
b.ToTable("banned_users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.BannedRegistrations", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("discord_id_or_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasKey("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasName("pk_banned_registrations");
|
|
||||||
|
|
||||||
b.ToTable("banned_registrations", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("AllowReceivingMessages")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("allow_receiving_messages");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_client_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("client_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<bool>("Uploaded")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("uploaded");
|
|
||||||
|
|
||||||
b.Property<string>("UploaderUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uploader_uid");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_file_caches");
|
|
||||||
|
|
||||||
b.HasIndex("UploaderUID")
|
|
||||||
.HasDatabaseName("ix_file_caches_uploader_uid");
|
|
||||||
|
|
||||||
b.ToTable("file_caches", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ForbiddenUploadEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("ForbiddenBy")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("forbidden_by");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_forbidden_upload_entries");
|
|
||||||
|
|
||||||
b.ToTable("forbidden_upload_entries", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GID")
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("gid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<string>("HashedPassword")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("hashed_password");
|
|
||||||
|
|
||||||
b.Property<bool>("InvitesEnabled")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("invites_enabled");
|
|
||||||
|
|
||||||
b.Property<string>("OwnerUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("owner_uid");
|
|
||||||
|
|
||||||
b.HasKey("GID")
|
|
||||||
.HasName("pk_groups");
|
|
||||||
|
|
||||||
b.HasIndex("OwnerUID")
|
|
||||||
.HasDatabaseName("ix_groups_owner_uid");
|
|
||||||
|
|
||||||
b.ToTable("groups", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupBan", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<string>("BannedUserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("banned_user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("BannedByUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("banned_by_uid");
|
|
||||||
|
|
||||||
b.Property<DateTime>("BannedOn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("banned_on");
|
|
||||||
|
|
||||||
b.Property<string>("BannedReason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("banned_reason");
|
|
||||||
|
|
||||||
b.HasKey("GroupGID", "BannedUserUID")
|
|
||||||
.HasName("pk_group_bans");
|
|
||||||
|
|
||||||
b.HasIndex("BannedByUID")
|
|
||||||
.HasDatabaseName("ix_group_bans_banned_by_uid");
|
|
||||||
|
|
||||||
b.HasIndex("BannedUserUID")
|
|
||||||
.HasDatabaseName("ix_group_bans_banned_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_bans_group_gid");
|
|
||||||
|
|
||||||
b.ToTable("group_bans", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<string>("GroupUserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("group_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPinned")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_pinned");
|
|
||||||
|
|
||||||
b.HasKey("GroupGID", "GroupUserUID")
|
|
||||||
.HasName("pk_group_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_gid");
|
|
||||||
|
|
||||||
b.HasIndex("GroupUserUID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("group_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupTempInvite", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<string>("Invite")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("invite");
|
|
||||||
|
|
||||||
b.Property<DateTime>("ExpirationDate")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("expiration_date");
|
|
||||||
|
|
||||||
b.HasKey("GroupGID", "Invite")
|
|
||||||
.HasName("pk_group_temp_invites");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_temp_invites_group_gid");
|
|
||||||
|
|
||||||
b.HasIndex("Invite")
|
|
||||||
.HasDatabaseName("ix_group_temp_invites_invite");
|
|
||||||
|
|
||||||
b.ToTable("group_temp_invites", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.Property<decimal>("DiscordId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("discord_id");
|
|
||||||
|
|
||||||
b.Property<string>("HashedLodestoneId")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("hashed_lodestone_id");
|
|
||||||
|
|
||||||
b.Property<string>("LodestoneAuthString")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("lodestone_auth_string");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("StartedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("started_at");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("DiscordId")
|
|
||||||
.HasName("pk_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_lodestone_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("lodestone_auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(15)
|
|
||||||
.HasColumnType("character varying(15)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<bool>("IsAdmin")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_admin");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<DateTime>("LastLoggedIn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_logged_in");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UID")
|
|
||||||
.HasName("pk_users");
|
|
||||||
|
|
||||||
b.ToTable("users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_auth_users_user_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_other_user_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_user_temp_id2");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Uploader")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UploaderUID")
|
|
||||||
.HasConstraintName("fk_file_caches_users_uploader_uid");
|
|
||||||
|
|
||||||
b.Navigation("Uploader");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Owner")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OwnerUID")
|
|
||||||
.HasConstraintName("fk_groups_users_owner_temp_id7");
|
|
||||||
|
|
||||||
b.Navigation("Owner");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupBan", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "BannedBy")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("BannedByUID")
|
|
||||||
.HasConstraintName("fk_group_bans_users_banned_by_temp_id4");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "BannedUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("BannedUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_bans_users_banned_user_temp_id5");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_bans_groups_group_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("BannedBy");
|
|
||||||
|
|
||||||
b.Navigation("BannedUser");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_groups_group_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "GroupUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_users_group_user_temp_id6");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
|
|
||||||
b.Navigation("GroupUser");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupTempInvite", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_temp_invites_groups_group_gid");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_lodestone_auth_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
public partial class AdjustInviteLength : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "invite",
|
|
||||||
table: "group_temp_invites",
|
|
||||||
type: "character varying(64)",
|
|
||||||
maxLength: 64,
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(10)",
|
|
||||||
oldMaxLength: 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AlterColumn<string>(
|
|
||||||
name: "invite",
|
|
||||||
table: "group_temp_invites",
|
|
||||||
type: "character varying(10)",
|
|
||||||
maxLength: 10,
|
|
||||||
nullable: false,
|
|
||||||
oldClrType: typeof(string),
|
|
||||||
oldType: "character varying(64)",
|
|
||||||
oldMaxLength: 64);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,506 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using System;
|
|
||||||
using MareSynchronosShared.Data;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
[DbContext(typeof(MareDbContext))]
|
|
||||||
[Migration("20221228033214_FileCacheSize")]
|
|
||||||
partial class FileCacheSize
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "7.0.0")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("HashedKey")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("hashed_key");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("HashedKey")
|
|
||||||
.HasName("pk_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Banned", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("CharacterIdentification")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("character_identification");
|
|
||||||
|
|
||||||
b.Property<string>("Reason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("reason");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("CharacterIdentification")
|
|
||||||
.HasName("pk_banned_users");
|
|
||||||
|
|
||||||
b.ToTable("banned_users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.BannedRegistrations", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("discord_id_or_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasKey("DiscordIdOrLodestoneAuth")
|
|
||||||
.HasName("pk_banned_registrations");
|
|
||||||
|
|
||||||
b.ToTable("banned_registrations", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("OtherUserUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("other_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("AllowReceivingMessages")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("allow_receiving_messages");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UserUID", "OtherUserUID")
|
|
||||||
.HasName("pk_client_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("OtherUserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_other_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_client_pairs_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("client_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<long>("Size")
|
|
||||||
.HasColumnType("bigint")
|
|
||||||
.HasColumnName("size");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.Property<bool>("Uploaded")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("uploaded");
|
|
||||||
|
|
||||||
b.Property<string>("UploaderUID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uploader_uid");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_file_caches");
|
|
||||||
|
|
||||||
b.HasIndex("UploaderUID")
|
|
||||||
.HasDatabaseName("ix_file_caches_uploader_uid");
|
|
||||||
|
|
||||||
b.ToTable("file_caches", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ForbiddenUploadEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("Hash")
|
|
||||||
.HasMaxLength(40)
|
|
||||||
.HasColumnType("character varying(40)")
|
|
||||||
.HasColumnName("hash");
|
|
||||||
|
|
||||||
b.Property<string>("ForbiddenBy")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("forbidden_by");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("Hash")
|
|
||||||
.HasName("pk_forbidden_upload_entries");
|
|
||||||
|
|
||||||
b.ToTable("forbidden_upload_entries", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GID")
|
|
||||||
.HasMaxLength(20)
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("gid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(50)
|
|
||||||
.HasColumnType("character varying(50)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<string>("HashedPassword")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("hashed_password");
|
|
||||||
|
|
||||||
b.Property<bool>("InvitesEnabled")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("invites_enabled");
|
|
||||||
|
|
||||||
b.Property<string>("OwnerUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("owner_uid");
|
|
||||||
|
|
||||||
b.HasKey("GID")
|
|
||||||
.HasName("pk_groups");
|
|
||||||
|
|
||||||
b.HasIndex("OwnerUID")
|
|
||||||
.HasDatabaseName("ix_groups_owner_uid");
|
|
||||||
|
|
||||||
b.ToTable("groups", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupBan", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<string>("BannedUserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("banned_user_uid");
|
|
||||||
|
|
||||||
b.Property<string>("BannedByUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("banned_by_uid");
|
|
||||||
|
|
||||||
b.Property<DateTime>("BannedOn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("banned_on");
|
|
||||||
|
|
||||||
b.Property<string>("BannedReason")
|
|
||||||
.HasColumnType("text")
|
|
||||||
.HasColumnName("banned_reason");
|
|
||||||
|
|
||||||
b.HasKey("GroupGID", "BannedUserUID")
|
|
||||||
.HasName("pk_group_bans");
|
|
||||||
|
|
||||||
b.HasIndex("BannedByUID")
|
|
||||||
.HasDatabaseName("ix_group_bans_banned_by_uid");
|
|
||||||
|
|
||||||
b.HasIndex("BannedUserUID")
|
|
||||||
.HasDatabaseName("ix_group_bans_banned_user_uid");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_bans_group_gid");
|
|
||||||
|
|
||||||
b.ToTable("group_bans", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<string>("GroupUserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("group_user_uid");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPaused")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_paused");
|
|
||||||
|
|
||||||
b.Property<bool>("IsPinned")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_pinned");
|
|
||||||
|
|
||||||
b.HasKey("GroupGID", "GroupUserUID")
|
|
||||||
.HasName("pk_group_pairs");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_gid");
|
|
||||||
|
|
||||||
b.HasIndex("GroupUserUID")
|
|
||||||
.HasDatabaseName("ix_group_pairs_group_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("group_pairs", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupTempInvite", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("GroupGID")
|
|
||||||
.HasColumnType("character varying(20)")
|
|
||||||
.HasColumnName("group_gid");
|
|
||||||
|
|
||||||
b.Property<string>("Invite")
|
|
||||||
.HasMaxLength(64)
|
|
||||||
.HasColumnType("character varying(64)")
|
|
||||||
.HasColumnName("invite");
|
|
||||||
|
|
||||||
b.Property<DateTime>("ExpirationDate")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("expiration_date");
|
|
||||||
|
|
||||||
b.HasKey("GroupGID", "Invite")
|
|
||||||
.HasName("pk_group_temp_invites");
|
|
||||||
|
|
||||||
b.HasIndex("GroupGID")
|
|
||||||
.HasDatabaseName("ix_group_temp_invites_group_gid");
|
|
||||||
|
|
||||||
b.HasIndex("Invite")
|
|
||||||
.HasDatabaseName("ix_group_temp_invites_invite");
|
|
||||||
|
|
||||||
b.ToTable("group_temp_invites", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.Property<decimal>("DiscordId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("numeric(20,0)")
|
|
||||||
.HasColumnName("discord_id");
|
|
||||||
|
|
||||||
b.Property<string>("HashedLodestoneId")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("hashed_lodestone_id");
|
|
||||||
|
|
||||||
b.Property<string>("LodestoneAuthString")
|
|
||||||
.HasMaxLength(100)
|
|
||||||
.HasColumnType("character varying(100)")
|
|
||||||
.HasColumnName("lodestone_auth_string");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("StartedAt")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("started_at");
|
|
||||||
|
|
||||||
b.Property<string>("UserUID")
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("user_uid");
|
|
||||||
|
|
||||||
b.HasKey("DiscordId")
|
|
||||||
.HasName("pk_lodestone_auth");
|
|
||||||
|
|
||||||
b.HasIndex("UserUID")
|
|
||||||
.HasDatabaseName("ix_lodestone_auth_user_uid");
|
|
||||||
|
|
||||||
b.ToTable("lodestone_auth", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.User", b =>
|
|
||||||
{
|
|
||||||
b.Property<string>("UID")
|
|
||||||
.HasMaxLength(10)
|
|
||||||
.HasColumnType("character varying(10)")
|
|
||||||
.HasColumnName("uid");
|
|
||||||
|
|
||||||
b.Property<string>("Alias")
|
|
||||||
.HasMaxLength(15)
|
|
||||||
.HasColumnType("character varying(15)")
|
|
||||||
.HasColumnName("alias");
|
|
||||||
|
|
||||||
b.Property<bool>("IsAdmin")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_admin");
|
|
||||||
|
|
||||||
b.Property<bool>("IsModerator")
|
|
||||||
.HasColumnType("boolean")
|
|
||||||
.HasColumnName("is_moderator");
|
|
||||||
|
|
||||||
b.Property<DateTime>("LastLoggedIn")
|
|
||||||
.HasColumnType("timestamp with time zone")
|
|
||||||
.HasColumnName("last_logged_in");
|
|
||||||
|
|
||||||
b.Property<byte[]>("Timestamp")
|
|
||||||
.IsConcurrencyToken()
|
|
||||||
.ValueGeneratedOnAddOrUpdate()
|
|
||||||
.HasColumnType("bytea")
|
|
||||||
.HasColumnName("timestamp");
|
|
||||||
|
|
||||||
b.HasKey("UID")
|
|
||||||
.HasName("pk_users");
|
|
||||||
|
|
||||||
b.ToTable("users", (string)null);
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Auth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_auth_users_user_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.ClientPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "OtherUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OtherUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_other_user_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_client_pairs_users_user_temp_id2");
|
|
||||||
|
|
||||||
b.Navigation("OtherUser");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.FileCache", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Uploader")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UploaderUID")
|
|
||||||
.HasConstraintName("fk_file_caches_users_uploader_uid");
|
|
||||||
|
|
||||||
b.Navigation("Uploader");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.Group", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Owner")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("OwnerUID")
|
|
||||||
.HasConstraintName("fk_groups_users_owner_temp_id7");
|
|
||||||
|
|
||||||
b.Navigation("Owner");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupBan", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "BannedBy")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("BannedByUID")
|
|
||||||
.HasConstraintName("fk_group_bans_users_banned_by_temp_id4");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "BannedUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("BannedUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_bans_users_banned_user_temp_id5");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_bans_groups_group_temp_id");
|
|
||||||
|
|
||||||
b.Navigation("BannedBy");
|
|
||||||
|
|
||||||
b.Navigation("BannedUser");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupPair", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_groups_group_temp_id1");
|
|
||||||
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "GroupUser")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupUserUID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_pairs_users_group_user_temp_id6");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
|
|
||||||
b.Navigation("GroupUser");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupTempInvite", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.Group", "Group")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("GroupGID")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired()
|
|
||||||
.HasConstraintName("fk_group_temp_invites_groups_group_gid");
|
|
||||||
|
|
||||||
b.Navigation("Group");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
|
||||||
.WithMany()
|
|
||||||
.HasForeignKey("UserUID")
|
|
||||||
.HasConstraintName("fk_lodestone_auth_users_user_uid");
|
|
||||||
|
|
||||||
b.Navigation("User");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Migrations
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public partial class FileCacheSize : Migration
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<long>(
|
|
||||||
name: "size",
|
|
||||||
table: "file_caches",
|
|
||||||
type: "bigint",
|
|
||||||
nullable: false,
|
|
||||||
defaultValue: 0L);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "size",
|
|
||||||
table: "file_caches");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user