Refactoring using Claims more, add Server Side Messaging (#20)
* add some refactoring based on claims, handle chara ident inside claim, fix discord userid in log * improve authentication responses, add server side messaging * update server to mainline api Co-authored-by: rootdarkarchon <root.darkarchon@outlook.com>
This commit is contained in:
2
MareAPI
2
MareAPI
Submodule MareAPI updated: 6645eaf63f...d361cfa3b9
@@ -0,0 +1,3 @@
|
|||||||
|
namespace MareSynchronosServer.Authentication;
|
||||||
|
|
||||||
|
public record SecretKeyAuthReply(bool Success, string Uid, bool TempBan);
|
||||||
@@ -4,10 +4,8 @@ using MareSynchronosShared.Metrics;
|
|||||||
using MareSynchronosShared.Services;
|
using MareSynchronosShared.Services;
|
||||||
using MareSynchronosShared.Utils;
|
using MareSynchronosShared.Utils;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace MareSynchronosShared.Authentication;
|
namespace MareSynchronosServer.Authentication;
|
||||||
|
|
||||||
public class SecretKeyAuthenticatorService
|
public class SecretKeyAuthenticatorService
|
||||||
{
|
{
|
||||||
@@ -16,7 +14,7 @@ public class SecretKeyAuthenticatorService
|
|||||||
private readonly IConfigurationService<MareConfigurationAuthBase> _configurationService;
|
private readonly IConfigurationService<MareConfigurationAuthBase> _configurationService;
|
||||||
private readonly ILogger<SecretKeyAuthenticatorService> _logger;
|
private readonly ILogger<SecretKeyAuthenticatorService> _logger;
|
||||||
private readonly ConcurrentDictionary<string, SecretKeyAuthReply> _cachedPositiveResponses = new(StringComparer.Ordinal);
|
private readonly ConcurrentDictionary<string, SecretKeyAuthReply> _cachedPositiveResponses = new(StringComparer.Ordinal);
|
||||||
private readonly ConcurrentDictionary<string, SecretKeyFailedAuthorization?> _failedAuthorizations = new(StringComparer.Ordinal);
|
private readonly ConcurrentDictionary<string, SecretKeyFailedAuthorization> _failedAuthorizations = new(StringComparer.Ordinal);
|
||||||
|
|
||||||
public SecretKeyAuthenticatorService(MareMetrics metrics, IServiceScopeFactory serviceScopeFactory, IConfigurationService<MareConfigurationAuthBase> configuration, ILogger<SecretKeyAuthenticatorService> logger)
|
public SecretKeyAuthenticatorService(MareMetrics metrics, IServiceScopeFactory serviceScopeFactory, IConfigurationService<MareConfigurationAuthBase> configuration, ILogger<SecretKeyAuthenticatorService> logger)
|
||||||
{
|
{
|
||||||
@@ -52,14 +50,14 @@ public class SecretKeyAuthenticatorService
|
|||||||
_failedAuthorizations.Remove(ip, out _);
|
_failedAuthorizations.Remove(ip, out _);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return new(Success: false, Uid: null);
|
return new(Success: false, Uid: null, TempBan: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
using var scope = _serviceScopeFactory.CreateScope();
|
using var scope = _serviceScopeFactory.CreateScope();
|
||||||
using var context = scope.ServiceProvider.GetService<MareDbContext>();
|
using var context = scope.ServiceProvider.GetService<MareDbContext>();
|
||||||
var authReply = await context.Auth.AsNoTracking().SingleOrDefaultAsync(u => u.HashedKey == hashedSecretKey).ConfigureAwait(false);
|
var authReply = await context.Auth.AsNoTracking().SingleOrDefaultAsync(u => u.HashedKey == hashedSecretKey).ConfigureAwait(false);
|
||||||
|
|
||||||
SecretKeyAuthReply reply = new(authReply != null, authReply?.UserUID);
|
SecretKeyAuthReply reply = new(authReply != null, authReply?.UserUID, false);
|
||||||
|
|
||||||
if (reply.Success)
|
if (reply.Success)
|
||||||
{
|
{
|
||||||
@@ -99,6 +97,6 @@ public class SecretKeyAuthenticatorService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new(Success: false, Uid: null);
|
return new(Success: false, Uid: null, TempBan: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace MareSynchronosShared.Authentication;
|
namespace MareSynchronosServer.Authentication;
|
||||||
|
|
||||||
internal record SecretKeyFailedAuthorization
|
internal record SecretKeyFailedAuthorization
|
||||||
{
|
{
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
using MareSynchronos.API;
|
using MareSynchronos.API;
|
||||||
|
using MareSynchronosServer.Authentication;
|
||||||
|
using MareSynchronosServer.Hubs;
|
||||||
|
using MareSynchronosServer.Services;
|
||||||
using MareSynchronosShared;
|
using MareSynchronosShared;
|
||||||
using MareSynchronosShared.Authentication;
|
using MareSynchronosShared.Data;
|
||||||
using MareSynchronosShared.Services;
|
using MareSynchronosShared.Services;
|
||||||
using MareSynchronosShared.Utils;
|
using MareSynchronosShared.Utils;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using System.IdentityModel.Tokens.Jwt;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
@@ -17,14 +21,50 @@ namespace MareSynchronosServer.Controllers;
|
|||||||
public class JwtController : Controller
|
public class JwtController : Controller
|
||||||
{
|
{
|
||||||
private readonly IHttpContextAccessor _accessor;
|
private readonly IHttpContextAccessor _accessor;
|
||||||
|
private readonly MareDbContext _mareDbContext;
|
||||||
private readonly SecretKeyAuthenticatorService _secretKeyAuthenticatorService;
|
private readonly SecretKeyAuthenticatorService _secretKeyAuthenticatorService;
|
||||||
private readonly IConfigurationService<MareConfigurationAuthBase> _configuration;
|
private readonly IConfigurationService<MareConfigurationAuthBase> _configuration;
|
||||||
|
private readonly IClientIdentificationService _clientIdentService;
|
||||||
|
|
||||||
public JwtController(IHttpContextAccessor accessor, SecretKeyAuthenticatorService secretKeyAuthenticatorService, IConfigurationService<MareConfigurationAuthBase> configuration)
|
public JwtController(IHttpContextAccessor accessor, MareDbContext mareDbContext,
|
||||||
|
SecretKeyAuthenticatorService secretKeyAuthenticatorService,
|
||||||
|
IConfigurationService<MareConfigurationAuthBase> configuration,
|
||||||
|
IClientIdentificationService clientIdentService)
|
||||||
{
|
{
|
||||||
_accessor = accessor;
|
_accessor = accessor;
|
||||||
|
_mareDbContext = mareDbContext;
|
||||||
_secretKeyAuthenticatorService = secretKeyAuthenticatorService;
|
_secretKeyAuthenticatorService = secretKeyAuthenticatorService;
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
|
_clientIdentService = clientIdentService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[AllowAnonymous]
|
||||||
|
[HttpPost(MareAuth.AuthCreateIdent)]
|
||||||
|
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");
|
||||||
|
|
||||||
|
var isBanned = await _mareDbContext.BannedUsers.AsNoTracking().AnyAsync(u => u.CharacterIdentification == charaIdent).ConfigureAwait(false);
|
||||||
|
if (isBanned) return Unauthorized("Your character is banned from using the service.");
|
||||||
|
|
||||||
|
var ip = _accessor.GetIpAddress();
|
||||||
|
|
||||||
|
var authResult = await _secretKeyAuthenticatorService.AuthorizeAsync(ip, auth);
|
||||||
|
|
||||||
|
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("You are temporarily banned. Try connecting again later.");
|
||||||
|
|
||||||
|
var existingIdent = _clientIdentService.GetCharacterIdentForUid(authResult.Uid);
|
||||||
|
if (!string.IsNullOrEmpty(existingIdent)) return Unauthorized("Already logged in to this account.");
|
||||||
|
|
||||||
|
var token = CreateToken(new List<Claim>()
|
||||||
|
{
|
||||||
|
new Claim(MareClaimTypes.Uid, authResult.Uid),
|
||||||
|
new Claim(MareClaimTypes.CharaIdent, charaIdent)
|
||||||
|
});
|
||||||
|
|
||||||
|
return Content(token.RawData);
|
||||||
}
|
}
|
||||||
|
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
@@ -41,7 +81,7 @@ public class JwtController : Controller
|
|||||||
|
|
||||||
var token = CreateToken(new List<Claim>()
|
var token = CreateToken(new List<Claim>()
|
||||||
{
|
{
|
||||||
new Claim(ClaimTypes.NameIdentifier, authResult.Uid)
|
new Claim(MareClaimTypes.Uid, authResult.Uid)
|
||||||
});
|
});
|
||||||
|
|
||||||
return Content(token.RawData);
|
return Content(token.RawData);
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace MareSynchronosServer.Hubs;
|
||||||
|
|
||||||
|
public static class MareClaimTypes
|
||||||
|
{
|
||||||
|
public const string Uid = "uid";
|
||||||
|
public const string CharaIdent = "character_identification";
|
||||||
|
}
|
||||||
@@ -58,5 +58,10 @@ namespace MareSynchronosServer.Hubs
|
|||||||
{
|
{
|
||||||
throw new PlatformNotSupportedException("Calling clientside method on server not supported");
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ public partial class MareHub
|
|||||||
public async Task FilesAbortUpload()
|
public async Task FilesAbortUpload()
|
||||||
{
|
{
|
||||||
_logger.LogCallInfo();
|
_logger.LogCallInfo();
|
||||||
var userId = AuthenticatedUserId;
|
var notUploadedFiles = _dbContext.Files.Where(f => !f.Uploaded && f.Uploader.UID == UserUID).ToList();
|
||||||
var notUploadedFiles = _dbContext.Files.Where(f => !f.Uploaded && f.Uploader.UID == userId).ToList();
|
|
||||||
_dbContext.RemoveRange(notUploadedFiles);
|
_dbContext.RemoveRange(notUploadedFiles);
|
||||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@@ -32,7 +31,7 @@ public partial class MareHub
|
|||||||
{
|
{
|
||||||
_logger.LogCallInfo();
|
_logger.LogCallInfo();
|
||||||
|
|
||||||
var ownFiles = await _dbContext.Files.Where(f => f.Uploaded && f.Uploader.UID == AuthenticatedUserId).ToListAsync().ConfigureAwait(false);
|
var ownFiles = await _dbContext.Files.Where(f => f.Uploaded && f.Uploader.UID == UserUID).ToListAsync().ConfigureAwait(false);
|
||||||
var request = new DeleteFilesRequest();
|
var request = new DeleteFilesRequest();
|
||||||
request.Hash.AddRange(ownFiles.Select(f => f.Hash));
|
request.Hash.AddRange(ownFiles.Select(f => f.Hash));
|
||||||
Metadata headers = new Metadata()
|
Metadata headers = new Metadata()
|
||||||
@@ -81,9 +80,8 @@ public partial class MareHub
|
|||||||
public async Task<bool> FilesIsUploadFinished()
|
public async Task<bool> FilesIsUploadFinished()
|
||||||
{
|
{
|
||||||
_logger.LogCallInfo();
|
_logger.LogCallInfo();
|
||||||
var userUid = AuthenticatedUserId;
|
|
||||||
return await _dbContext.Files.AsNoTracking()
|
return await _dbContext.Files.AsNoTracking()
|
||||||
.AnyAsync(f => f.Uploader.UID == userUid && !f.Uploaded).ConfigureAwait(false);
|
.AnyAsync(f => f.Uploader.UID == UserUID && !f.Uploaded).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Authorize(Policy = "Identified")]
|
[Authorize(Policy = "Identified")]
|
||||||
@@ -94,7 +92,7 @@ public partial class MareHub
|
|||||||
var notCoveredFiles = new Dictionary<string, UploadFileDto>(StringComparer.Ordinal);
|
var notCoveredFiles = new Dictionary<string, UploadFileDto>(StringComparer.Ordinal);
|
||||||
var forbiddenFiles = await _dbContext.ForbiddenUploadEntries.AsNoTracking().Where(f => userSentHashes.Contains(f.Hash)).AsNoTracking().ToDictionaryAsync(f => f.Hash, f => f).ConfigureAwait(false);
|
var forbiddenFiles = await _dbContext.ForbiddenUploadEntries.AsNoTracking().Where(f => userSentHashes.Contains(f.Hash)).AsNoTracking().ToDictionaryAsync(f => f.Hash, f => f).ConfigureAwait(false);
|
||||||
var existingFiles = await _dbContext.Files.AsNoTracking().Where(f => userSentHashes.Contains(f.Hash)).AsNoTracking().ToDictionaryAsync(f => f.Hash, f => f).ConfigureAwait(false);
|
var existingFiles = await _dbContext.Files.AsNoTracking().Where(f => userSentHashes.Contains(f.Hash)).AsNoTracking().ToDictionaryAsync(f => f.Hash, f => f).ConfigureAwait(false);
|
||||||
var uploader = await _dbContext.Users.SingleAsync(u => u.UID == AuthenticatedUserId).ConfigureAwait(false);
|
var uploader = await _dbContext.Users.SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
|
||||||
|
|
||||||
List<FileCache> fileCachesToUpload = new();
|
List<FileCache> fileCachesToUpload = new();
|
||||||
foreach (var file in userSentHashes)
|
foreach (var file in userSentHashes)
|
||||||
@@ -117,7 +115,6 @@ public partial class MareHub
|
|||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(file, "Missing"));
|
_logger.LogCallInfo(MareHubLogger.Args(file, "Missing"));
|
||||||
|
|
||||||
var userId = AuthenticatedUserId;
|
|
||||||
fileCachesToUpload.Add(new FileCache()
|
fileCachesToUpload.Add(new FileCache()
|
||||||
{
|
{
|
||||||
Hash = file,
|
Hash = file,
|
||||||
@@ -143,7 +140,7 @@ public partial class MareHub
|
|||||||
|
|
||||||
await _uploadSemaphore.WaitAsync(Context.ConnectionAborted).ConfigureAwait(false);
|
await _uploadSemaphore.WaitAsync(Context.ConnectionAborted).ConfigureAwait(false);
|
||||||
|
|
||||||
var relatedFile = _dbContext.Files.SingleOrDefault(f => f.Hash == hash && f.Uploader.UID == AuthenticatedUserId && !f.Uploaded);
|
var relatedFile = _dbContext.Files.SingleOrDefault(f => f.Hash == hash && f.Uploader.UID == UserUID && !f.Uploaded);
|
||||||
if (relatedFile == null)
|
if (relatedFile == null)
|
||||||
{
|
{
|
||||||
_uploadSemaphore.Release();
|
_uploadSemaphore.Release();
|
||||||
@@ -226,7 +223,7 @@ public partial class MareHub
|
|||||||
{
|
{
|
||||||
FileData = ByteString.CopyFrom(data, 0, readBytes),
|
FileData = ByteString.CopyFrom(data, 0, readBytes),
|
||||||
Hash = computedHashString,
|
Hash = computedHashString,
|
||||||
Uploader = AuthenticatedUserId
|
Uploader = UserUID
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await streamingCall.RequestStream.CompleteAsync().ConfigureAwait(false);
|
await streamingCall.RequestStream.CompleteAsync().ConfigureAwait(false);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using MareSynchronosShared.Models;
|
using MareSynchronosShared.Models;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using MareSynchronosServer.Utils;
|
using MareSynchronosServer.Utils;
|
||||||
using System.Security.Claims;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Hubs;
|
namespace MareSynchronosServer.Hubs;
|
||||||
|
|
||||||
@@ -9,7 +8,7 @@ public partial class MareHub
|
|||||||
{
|
{
|
||||||
private async Task<List<PausedEntry>> GetAllPairedClientsWithPauseState(string? uid = null)
|
private async Task<List<PausedEntry>> GetAllPairedClientsWithPauseState(string? uid = null)
|
||||||
{
|
{
|
||||||
uid ??= AuthenticatedUserId;
|
uid ??= UserUID;
|
||||||
|
|
||||||
var query = await (from userPair in _dbContext.ClientPairs
|
var query = await (from userPair in _dbContext.ClientPairs
|
||||||
join otherUserPair in _dbContext.ClientPairs on userPair.OtherUserUID equals otherUserPair.UserUID
|
join otherUserPair in _dbContext.ClientPairs on userPair.OtherUserUID equals otherUserPair.UserUID
|
||||||
@@ -47,7 +46,7 @@ public partial class MareHub
|
|||||||
|
|
||||||
private async Task<List<string>> GetAllPairedUnpausedUsers(string? uid = null)
|
private async Task<List<string>> GetAllPairedUnpausedUsers(string? uid = null)
|
||||||
{
|
{
|
||||||
uid ??= AuthenticatedUserId;
|
uid ??= UserUID;
|
||||||
var ret = await GetAllPairedClientsWithPauseState(uid).ConfigureAwait(false);
|
var ret = await GetAllPairedClientsWithPauseState(uid).ConfigureAwait(false);
|
||||||
return ret.Where(k => !k.IsPaused).Select(k => k.UID).ToList();
|
return ret.Where(k => !k.IsPaused).Select(k => k.UID).ToList();
|
||||||
}
|
}
|
||||||
@@ -68,11 +67,12 @@ public partial class MareHub
|
|||||||
return usersToSendDataTo;
|
return usersToSendDataTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string AuthenticatedUserId => Context.User?.Claims?.SingleOrDefault(c => string.Equals(c.Type, ClaimTypes.NameIdentifier, StringComparison.Ordinal))?.Value ?? "Unknown";
|
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 UserCharaIdent => Context.User?.Claims?.SingleOrDefault(c => string.Equals(c.Type, MareClaimTypes.CharaIdent, StringComparison.Ordinal))?.Value ?? throw new Exception("No Chara Ident in Claims");
|
||||||
|
|
||||||
private async Task UserGroupLeave(GroupPair groupUserPair, List<PausedEntry> allUserPairs, string userIdent, string? uid = null)
|
private async Task UserGroupLeave(GroupPair groupUserPair, List<PausedEntry> allUserPairs, string userIdent, string? uid = null)
|
||||||
{
|
{
|
||||||
uid ??= AuthenticatedUserId;
|
uid ??= UserUID;
|
||||||
var userPair = allUserPairs.SingleOrDefault(p => string.Equals(p.UID, groupUserPair.GroupUserUID, StringComparison.Ordinal));
|
var userPair = allUserPairs.SingleOrDefault(p => string.Equals(p.UID, groupUserPair.GroupUserUID, StringComparison.Ordinal));
|
||||||
if (userPair != null)
|
if (userPair != null)
|
||||||
{
|
{
|
||||||
@@ -106,7 +106,7 @@ public partial class MareHub
|
|||||||
|
|
||||||
private async Task<(bool IsValid, GroupPair ReferredPair)> TryValidateUserInGroup(string gid, string? uid = null)
|
private async Task<(bool IsValid, GroupPair ReferredPair)> TryValidateUserInGroup(string gid, string? uid = null)
|
||||||
{
|
{
|
||||||
uid ??= AuthenticatedUserId;
|
uid ??= UserUID;
|
||||||
|
|
||||||
var groupPair = await _dbContext.GroupPairs.Include(c => c.GroupUser)
|
var groupPair = await _dbContext.GroupPairs.Include(c => c.GroupUser)
|
||||||
.SingleOrDefaultAsync(g => g.GroupGID == gid && (g.GroupUserUID == uid || g.GroupUser.Alias == uid)).ConfigureAwait(false);
|
.SingleOrDefaultAsync(g => g.GroupGID == gid && (g.GroupUserUID == uid || g.GroupUser.Alias == uid)).ConfigureAwait(false);
|
||||||
@@ -122,7 +122,7 @@ public partial class MareHub
|
|||||||
|
|
||||||
if (isOwnerResult.ReferredGroup == null) return (false, null);
|
if (isOwnerResult.ReferredGroup == null) return (false, null);
|
||||||
|
|
||||||
var groupPairSelf = await _dbContext.GroupPairs.SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == AuthenticatedUserId).ConfigureAwait(false);
|
var groupPairSelf = await _dbContext.GroupPairs.SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == UserUID).ConfigureAwait(false);
|
||||||
if (groupPairSelf == null || !groupPairSelf.IsModerator) return (false, null);
|
if (groupPairSelf == null || !groupPairSelf.IsModerator) return (false, null);
|
||||||
|
|
||||||
return (true, isOwnerResult.ReferredGroup);
|
return (true, isOwnerResult.ReferredGroup);
|
||||||
@@ -133,6 +133,6 @@ public partial class MareHub
|
|||||||
var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false);
|
var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false);
|
||||||
if (group == null) return (false, null);
|
if (group == null) return (false, null);
|
||||||
|
|
||||||
return (string.Equals(group.OwnerUID, AuthenticatedUserId, StringComparison.Ordinal), group);
|
return (string.Equals(group.OwnerUID, UserUID, StringComparison.Ordinal), group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ public partial class MareHub
|
|||||||
public async Task<GroupCreatedDto> GroupCreate()
|
public async Task<GroupCreatedDto> GroupCreate()
|
||||||
{
|
{
|
||||||
_logger.LogCallInfo();
|
_logger.LogCallInfo();
|
||||||
var existingGroupsByUser = await _dbContext.Groups.CountAsync(u => u.OwnerUID == AuthenticatedUserId).ConfigureAwait(false);
|
var existingGroupsByUser = await _dbContext.Groups.CountAsync(u => u.OwnerUID == UserUID).ConfigureAwait(false);
|
||||||
var existingJoinedGroups = await _dbContext.GroupPairs.CountAsync(u => u.GroupUserUID == AuthenticatedUserId).ConfigureAwait(false);
|
var existingJoinedGroups = await _dbContext.GroupPairs.CountAsync(u => u.GroupUserUID == UserUID).ConfigureAwait(false);
|
||||||
if (existingGroupsByUser >= _maxExistingGroupsByUser || existingJoinedGroups >= _maxJoinedGroupsByUser)
|
if (existingGroupsByUser >= _maxExistingGroupsByUser || existingJoinedGroups >= _maxJoinedGroupsByUser)
|
||||||
{
|
{
|
||||||
throw new System.Exception($"Max groups for user is {_maxExistingGroupsByUser}, max joined groups is {_maxJoinedGroupsByUser}.");
|
throw new System.Exception($"Max groups for user is {_maxExistingGroupsByUser}, max joined groups is {_maxJoinedGroupsByUser}.");
|
||||||
@@ -38,13 +38,13 @@ public partial class MareHub
|
|||||||
GID = gid,
|
GID = gid,
|
||||||
HashedPassword = hashedPw,
|
HashedPassword = hashedPw,
|
||||||
InvitesEnabled = true,
|
InvitesEnabled = true,
|
||||||
OwnerUID = AuthenticatedUserId
|
OwnerUID = UserUID
|
||||||
};
|
};
|
||||||
|
|
||||||
GroupPair initialPair = new()
|
GroupPair initialPair = new()
|
||||||
{
|
{
|
||||||
GroupGID = newGroup.GID,
|
GroupGID = newGroup.GID,
|
||||||
GroupUserUID = AuthenticatedUserId,
|
GroupUserUID = UserUID,
|
||||||
IsPaused = false,
|
IsPaused = false,
|
||||||
IsPinned = true
|
IsPinned = true
|
||||||
};
|
};
|
||||||
@@ -53,9 +53,9 @@ public partial class MareHub
|
|||||||
await _dbContext.GroupPairs.AddAsync(initialPair).ConfigureAwait(false);
|
await _dbContext.GroupPairs.AddAsync(initialPair).ConfigureAwait(false);
|
||||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
var self = await _dbContext.Users.SingleAsync(u => u.UID == AuthenticatedUserId).ConfigureAwait(false);
|
var self = await _dbContext.Users.SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
|
||||||
|
|
||||||
await Clients.User(AuthenticatedUserId).Client_GroupChange(new GroupDto()
|
await Clients.User(UserUID).Client_GroupChange(new GroupDto()
|
||||||
{
|
{
|
||||||
GID = newGroup.GID,
|
GID = newGroup.GID,
|
||||||
OwnedBy = string.IsNullOrEmpty(self.Alias) ? self.UID : self.Alias,
|
OwnedBy = string.IsNullOrEmpty(self.Alias) ? self.UID : self.Alias,
|
||||||
@@ -78,7 +78,7 @@ public partial class MareHub
|
|||||||
{
|
{
|
||||||
_logger.LogCallInfo();
|
_logger.LogCallInfo();
|
||||||
|
|
||||||
var groups = await _dbContext.GroupPairs.Include(g => g.Group).Include(g => g.Group.Owner).Where(g => g.GroupUserUID == AuthenticatedUserId).AsNoTracking().ToListAsync().ConfigureAwait(false);
|
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 GroupDto()
|
return groups.Select(g => new GroupDto()
|
||||||
{
|
{
|
||||||
@@ -99,7 +99,7 @@ public partial class MareHub
|
|||||||
var (inGroup, _) = await TryValidateUserInGroup(gid).ConfigureAwait(false);
|
var (inGroup, _) = await TryValidateUserInGroup(gid).ConfigureAwait(false);
|
||||||
if (!inGroup) return new List<GroupPairDto>();
|
if (!inGroup) return new List<GroupPairDto>();
|
||||||
|
|
||||||
var allPairs = await _dbContext.GroupPairs.Include(g => g.GroupUser).Where(g => g.GroupGID == gid && g.GroupUserUID != AuthenticatedUserId).AsNoTracking().ToListAsync().ConfigureAwait(false);
|
var allPairs = await _dbContext.GroupPairs.Include(g => g.GroupUser).Where(g => g.GroupGID == gid && g.GroupUserUID != UserUID).AsNoTracking().ToListAsync().ConfigureAwait(false);
|
||||||
return allPairs.Select(p => new GroupPairDto()
|
return allPairs.Select(p => new GroupPairDto()
|
||||||
{
|
{
|
||||||
GroupGID = gid,
|
GroupGID = gid,
|
||||||
@@ -160,14 +160,16 @@ public partial class MareHub
|
|||||||
[Authorize(Policy = "Identified")]
|
[Authorize(Policy = "Identified")]
|
||||||
public async Task<bool> GroupJoin(string gid, string password)
|
public async Task<bool> GroupJoin(string gid, string password)
|
||||||
{
|
{
|
||||||
|
gid = gid.Trim();
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(gid));
|
_logger.LogCallInfo(MareHubLogger.Args(gid));
|
||||||
|
|
||||||
var group = await _dbContext.Groups.Include(g => g.Owner).AsNoTracking().SingleOrDefaultAsync(g => g.GID == gid || g.Alias == gid).ConfigureAwait(false);
|
var group = await _dbContext.Groups.Include(g => g.Owner).AsNoTracking().SingleOrDefaultAsync(g => g.GID == gid || g.Alias == gid).ConfigureAwait(false);
|
||||||
var existingPair = await _dbContext.GroupPairs.AsNoTracking().SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == AuthenticatedUserId).ConfigureAwait(false);
|
var existingPair = await _dbContext.GroupPairs.AsNoTracking().SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == UserUID).ConfigureAwait(false);
|
||||||
var hashedPw = StringUtils.Sha256String(password);
|
var hashedPw = StringUtils.Sha256String(password);
|
||||||
var existingUserCount = await _dbContext.GroupPairs.AsNoTracking().CountAsync(g => g.GroupGID == gid).ConfigureAwait(false);
|
var existingUserCount = await _dbContext.GroupPairs.AsNoTracking().CountAsync(g => g.GroupGID == gid).ConfigureAwait(false);
|
||||||
var joinedGroups = await _dbContext.GroupPairs.CountAsync(g => g.GroupUserUID == AuthenticatedUserId).ConfigureAwait(false);
|
var joinedGroups = await _dbContext.GroupPairs.CountAsync(g => g.GroupUserUID == UserUID).ConfigureAwait(false);
|
||||||
var isBanned = await _dbContext.GroupBans.AnyAsync(g => g.GroupGID == gid && g.BannedUserUID == AuthenticatedUserId).ConfigureAwait(false);
|
var isBanned = await _dbContext.GroupBans.AnyAsync(g => g.GroupGID == gid && g.BannedUserUID == UserUID).ConfigureAwait(false);
|
||||||
var groupGid = group?.GID ?? string.Empty;
|
var groupGid = group?.GID ?? string.Empty;
|
||||||
var oneTimeInvite = await _dbContext.GroupTempInvites.SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.Invite == hashedPw).ConfigureAwait(false);
|
var oneTimeInvite = await _dbContext.GroupTempInvites.SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.Invite == hashedPw).ConfigureAwait(false);
|
||||||
|
|
||||||
@@ -189,7 +191,7 @@ public partial class MareHub
|
|||||||
GroupPair newPair = new()
|
GroupPair newPair = new()
|
||||||
{
|
{
|
||||||
GroupGID = group.GID,
|
GroupGID = group.GID,
|
||||||
GroupUserUID = AuthenticatedUserId
|
GroupUserUID = UserUID
|
||||||
};
|
};
|
||||||
|
|
||||||
await _dbContext.GroupPairs.AddAsync(newPair).ConfigureAwait(false);
|
await _dbContext.GroupPairs.AddAsync(newPair).ConfigureAwait(false);
|
||||||
@@ -197,7 +199,7 @@ public partial class MareHub
|
|||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(gid, "Success"));
|
_logger.LogCallInfo(MareHubLogger.Args(gid, "Success"));
|
||||||
|
|
||||||
await Clients.User(AuthenticatedUserId).Client_GroupChange(new GroupDto()
|
await Clients.User(UserUID).Client_GroupChange(new GroupDto()
|
||||||
{
|
{
|
||||||
GID = group.GID,
|
GID = group.GID,
|
||||||
OwnedBy = string.IsNullOrEmpty(group.Owner.Alias) ? group.Owner.UID : group.Owner.Alias,
|
OwnedBy = string.IsNullOrEmpty(group.Owner.Alias) ? group.Owner.UID : group.Owner.Alias,
|
||||||
@@ -207,15 +209,15 @@ public partial class MareHub
|
|||||||
InvitesEnabled = true
|
InvitesEnabled = true
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
var self = _dbContext.Users.Single(u => u.UID == AuthenticatedUserId);
|
var self = _dbContext.Users.Single(u => u.UID == UserUID);
|
||||||
|
|
||||||
var groupPairs = await _dbContext.GroupPairs.Where(p => p.GroupGID == group.GID && p.GroupUserUID != AuthenticatedUserId).ToListAsync().ConfigureAwait(false);
|
var groupPairs = await _dbContext.GroupPairs.Where(p => p.GroupGID == group.GID && p.GroupUserUID != UserUID).ToListAsync().ConfigureAwait(false);
|
||||||
await Clients.Users(groupPairs.Select(p => p.GroupUserUID)).Client_GroupUserChange(new GroupPairDto()
|
await Clients.Users(groupPairs.Select(p => p.GroupUserUID)).Client_GroupUserChange(new GroupPairDto()
|
||||||
{
|
{
|
||||||
GroupGID = group.GID,
|
GroupGID = group.GID,
|
||||||
IsPaused = false,
|
IsPaused = false,
|
||||||
IsRemoved = false,
|
IsRemoved = false,
|
||||||
UserUID = AuthenticatedUserId,
|
UserUID = UserUID,
|
||||||
UserAlias = self.Alias,
|
UserAlias = self.Alias,
|
||||||
IsPinned = false,
|
IsPinned = false,
|
||||||
IsModerator = false,
|
IsModerator = false,
|
||||||
@@ -223,7 +225,6 @@ public partial class MareHub
|
|||||||
|
|
||||||
var allUserPairs = await GetAllPairedClientsWithPauseState().ConfigureAwait(false);
|
var allUserPairs = await GetAllPairedClientsWithPauseState().ConfigureAwait(false);
|
||||||
|
|
||||||
var userIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
|
|
||||||
foreach (var groupUserPair in groupPairs)
|
foreach (var groupUserPair in groupPairs)
|
||||||
{
|
{
|
||||||
var userPair = allUserPairs.Single(p => string.Equals(p.UID, groupUserPair.GroupUserUID, StringComparison.Ordinal));
|
var userPair = allUserPairs.Single(p => string.Equals(p.UID, groupUserPair.GroupUserUID, StringComparison.Ordinal));
|
||||||
@@ -234,8 +235,8 @@ public partial class MareHub
|
|||||||
var groupUserIdent = _clientIdentService.GetCharacterIdentForUid(groupUserPair.GroupUserUID);
|
var groupUserIdent = _clientIdentService.GetCharacterIdentForUid(groupUserPair.GroupUserUID);
|
||||||
if (!string.IsNullOrEmpty(groupUserIdent))
|
if (!string.IsNullOrEmpty(groupUserIdent))
|
||||||
{
|
{
|
||||||
await Clients.User(AuthenticatedUserId).Client_UserChangePairedPlayer(groupUserIdent, true).ConfigureAwait(false);
|
await Clients.User(UserUID).Client_UserChangePairedPlayer(groupUserIdent, true).ConfigureAwait(false);
|
||||||
await Clients.User(groupUserPair.GroupUserUID).Client_UserChangePairedPlayer(userIdent, true).ConfigureAwait(false);
|
await Clients.User(groupUserPair.GroupUserUID).Client_UserChangePairedPlayer(UserCharaIdent, true).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,18 +293,18 @@ public partial class MareHub
|
|||||||
var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false);
|
var group = await _dbContext.Groups.SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false);
|
||||||
|
|
||||||
var groupPairs = await _dbContext.GroupPairs.Where(p => p.GroupGID == group.GID).ToListAsync().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, AuthenticatedUserId, StringComparison.Ordinal)).ToList();
|
var groupPairsWithoutSelf = groupPairs.Where(p => !string.Equals(p.GroupUserUID, UserUID, StringComparison.Ordinal)).ToList();
|
||||||
|
|
||||||
_dbContext.GroupPairs.Remove(groupPair);
|
_dbContext.GroupPairs.Remove(groupPair);
|
||||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
await Clients.User(AuthenticatedUserId).Client_GroupChange(new GroupDto()
|
await Clients.User(UserUID).Client_GroupChange(new GroupDto()
|
||||||
{
|
{
|
||||||
GID = group.GID,
|
GID = group.GID,
|
||||||
IsDeleted = true
|
IsDeleted = true
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
bool ownerHasLeft = string.Equals(group.OwnerUID, AuthenticatedUserId, StringComparison.Ordinal);
|
bool ownerHasLeft = string.Equals(group.OwnerUID, UserUID, StringComparison.Ordinal);
|
||||||
if (ownerHasLeft)
|
if (ownerHasLeft)
|
||||||
{
|
{
|
||||||
if (!groupPairsWithoutSelf.Any())
|
if (!groupPairsWithoutSelf.Any())
|
||||||
@@ -352,15 +353,14 @@ public partial class MareHub
|
|||||||
{
|
{
|
||||||
GroupGID = group.GID,
|
GroupGID = group.GID,
|
||||||
IsRemoved = true,
|
IsRemoved = true,
|
||||||
UserUID = AuthenticatedUserId,
|
UserUID = UserUID,
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
var allUserPairs = await GetAllPairedClientsWithPauseState().ConfigureAwait(false);
|
var allUserPairs = await GetAllPairedClientsWithPauseState().ConfigureAwait(false);
|
||||||
|
|
||||||
var userIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
|
|
||||||
foreach (var groupUserPair in groupPairsWithoutSelf)
|
foreach (var groupUserPair in groupPairsWithoutSelf)
|
||||||
{
|
{
|
||||||
await UserGroupLeave(groupUserPair, allUserPairs, userIdent).ConfigureAwait(false);
|
await UserGroupLeave(groupUserPair, allUserPairs, UserCharaIdent).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,15 +377,15 @@ public partial class MareHub
|
|||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(gid, isPaused, "Success"));
|
_logger.LogCallInfo(MareHubLogger.Args(gid, isPaused, "Success"));
|
||||||
|
|
||||||
var groupPairs = await _dbContext.GroupPairs.Where(p => p.GroupGID == gid && p.GroupUserUID != AuthenticatedUserId).AsNoTracking().ToListAsync().ConfigureAwait(false);
|
var groupPairs = await _dbContext.GroupPairs.Where(p => p.GroupGID == gid && p.GroupUserUID != UserUID).AsNoTracking().ToListAsync().ConfigureAwait(false);
|
||||||
await Clients.Users(groupPairs.Select(p => p.GroupUserUID)).Client_GroupUserChange(new GroupPairDto()
|
await Clients.Users(groupPairs.Select(p => p.GroupUserUID)).Client_GroupUserChange(new GroupPairDto()
|
||||||
{
|
{
|
||||||
GroupGID = gid,
|
GroupGID = gid,
|
||||||
IsPaused = isPaused,
|
IsPaused = isPaused,
|
||||||
UserUID = AuthenticatedUserId,
|
UserUID = UserUID,
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
await Clients.User(AuthenticatedUserId).Client_GroupChange(new GroupDto
|
await Clients.User(UserUID).Client_GroupChange(new GroupDto
|
||||||
{
|
{
|
||||||
GID = gid,
|
GID = gid,
|
||||||
IsPaused = isPaused
|
IsPaused = isPaused
|
||||||
@@ -393,7 +393,6 @@ public partial class MareHub
|
|||||||
|
|
||||||
var allUserPairs = await GetAllPairedClientsWithPauseState().ConfigureAwait(false);
|
var allUserPairs = await GetAllPairedClientsWithPauseState().ConfigureAwait(false);
|
||||||
|
|
||||||
var userIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
|
|
||||||
foreach (var groupUserPair in groupPairs)
|
foreach (var groupUserPair in groupPairs)
|
||||||
{
|
{
|
||||||
var userPair = allUserPairs.SingleOrDefault(p => string.Equals(p.UID, groupUserPair.GroupUserUID, StringComparison.Ordinal));
|
var userPair = allUserPairs.SingleOrDefault(p => string.Equals(p.UID, groupUserPair.GroupUserUID, StringComparison.Ordinal));
|
||||||
@@ -407,8 +406,8 @@ public partial class MareHub
|
|||||||
var groupUserIdent = _clientIdentService.GetCharacterIdentForUid(groupUserPair.GroupUserUID);
|
var groupUserIdent = _clientIdentService.GetCharacterIdentForUid(groupUserPair.GroupUserUID);
|
||||||
if (!string.IsNullOrEmpty(groupUserIdent))
|
if (!string.IsNullOrEmpty(groupUserIdent))
|
||||||
{
|
{
|
||||||
await Clients.User(AuthenticatedUserId).Client_UserChangePairedPlayer(groupUserIdent, !isPaused).ConfigureAwait(false);
|
await Clients.User(UserUID).Client_UserChangePairedPlayer(groupUserIdent, !isPaused).ConfigureAwait(false);
|
||||||
await Clients.User(groupUserPair.GroupUserUID).Client_UserChangePairedPlayer(userIdent, !isPaused).ConfigureAwait(false);
|
await Clients.User(groupUserPair.GroupUserUID).Client_UserChangePairedPlayer(UserCharaIdent, !isPaused).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -471,7 +470,7 @@ public partial class MareHub
|
|||||||
var alias = string.IsNullOrEmpty(groupPair.GroupUser.Alias) ? "-" : groupPair.GroupUser.Alias;
|
var alias = string.IsNullOrEmpty(groupPair.GroupUser.Alias) ? "-" : groupPair.GroupUser.Alias;
|
||||||
var ban = new GroupBan()
|
var ban = new GroupBan()
|
||||||
{
|
{
|
||||||
BannedByUID = AuthenticatedUserId,
|
BannedByUID = UserUID,
|
||||||
BannedReason = $"{reason} (Alias at time of ban: {alias})",
|
BannedReason = $"{reason} (Alias at time of ban: {alias})",
|
||||||
BannedOn = DateTime.UtcNow,
|
BannedOn = DateTime.UtcNow,
|
||||||
BannedUserUID = uid,
|
BannedUserUID = uid,
|
||||||
@@ -574,7 +573,7 @@ public partial class MareHub
|
|||||||
var ownedShells = await _dbContext.Groups.CountAsync(g => g.OwnerUID == uid).ConfigureAwait(false);
|
var ownedShells = await _dbContext.Groups.CountAsync(g => g.OwnerUID == uid).ConfigureAwait(false);
|
||||||
if (ownedShells >= _maxExistingGroupsByUser) return;
|
if (ownedShells >= _maxExistingGroupsByUser) return;
|
||||||
|
|
||||||
var prevOwner = await _dbContext.GroupPairs.SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == AuthenticatedUserId).ConfigureAwait(false);
|
var prevOwner = await _dbContext.GroupPairs.SingleOrDefaultAsync(g => g.GroupGID == gid && g.GroupUserUID == UserUID).ConfigureAwait(false);
|
||||||
prevOwner.IsPinned = false;
|
prevOwner.IsPinned = false;
|
||||||
group.Owner = newOwnerPair.GroupUser;
|
group.Owner = newOwnerPair.GroupUser;
|
||||||
group.Alias = null;
|
group.Alias = null;
|
||||||
|
|||||||
@@ -16,13 +16,11 @@ public partial class MareHub
|
|||||||
{
|
{
|
||||||
_logger.LogCallInfo();
|
_logger.LogCallInfo();
|
||||||
|
|
||||||
string userid = AuthenticatedUserId;
|
var userEntry = await _dbContext.Users.SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
|
||||||
var userEntry = await _dbContext.Users.SingleAsync(u => u.UID == userid).ConfigureAwait(false);
|
var ownPairData = await _dbContext.ClientPairs.Where(u => u.User.UID == UserUID).ToListAsync().ConfigureAwait(false);
|
||||||
var charaIdent = _clientIdentService.GetCharacterIdentForUid(userid);
|
var auth = await _dbContext.Auth.SingleAsync(u => u.UserUID == UserUID).ConfigureAwait(false);
|
||||||
var ownPairData = await _dbContext.ClientPairs.Where(u => u.User.UID == userid).ToListAsync().ConfigureAwait(false);
|
var lodestone = await _dbContext.LodeStoneAuth.SingleOrDefaultAsync(a => a.User.UID == UserUID).ConfigureAwait(false);
|
||||||
var auth = await _dbContext.Auth.SingleAsync(u => u.UserUID == userid).ConfigureAwait(false);
|
var groupPairs = await _dbContext.GroupPairs.Where(g => g.GroupUserUID == UserUID).ToListAsync().ConfigureAwait(false);
|
||||||
var lodestone = await _dbContext.LodeStoneAuth.SingleOrDefaultAsync(a => a.User.UID == userid).ConfigureAwait(false);
|
|
||||||
var groupPairs = await _dbContext.GroupPairs.Where(g => g.GroupUserUID == userid).ToListAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (lodestone != null)
|
if (lodestone != null)
|
||||||
{
|
{
|
||||||
@@ -37,12 +35,12 @@ public partial class MareHub
|
|||||||
_dbContext.ClientPairs.RemoveRange(ownPairData);
|
_dbContext.ClientPairs.RemoveRange(ownPairData);
|
||||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
var otherPairData = await _dbContext.ClientPairs.Include(u => u.User)
|
var otherPairData = await _dbContext.ClientPairs.Include(u => u.User)
|
||||||
.Where(u => u.OtherUser.UID == userid).AsNoTracking().ToListAsync().ConfigureAwait(false);
|
.Where(u => u.OtherUser.UID == UserUID).AsNoTracking().ToListAsync().ConfigureAwait(false);
|
||||||
foreach (var pair in otherPairData)
|
foreach (var pair in otherPairData)
|
||||||
{
|
{
|
||||||
await Clients.User(pair.User.UID).Client_UserUpdateClientPairs(new ClientPairDto()
|
await Clients.User(pair.User.UID).Client_UserUpdateClientPairs(new ClientPairDto()
|
||||||
{
|
{
|
||||||
OtherUID = userid,
|
OtherUID = UserUID,
|
||||||
IsRemoved = true
|
IsRemoved = true
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@@ -65,9 +63,7 @@ public partial class MareHub
|
|||||||
{
|
{
|
||||||
_logger.LogCallInfo();
|
_logger.LogCallInfo();
|
||||||
|
|
||||||
var ownIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
|
var usersToSendOnlineTo = await SendOnlineToAllPairedUsers(UserCharaIdent).ConfigureAwait(false);
|
||||||
|
|
||||||
var usersToSendOnlineTo = await SendOnlineToAllPairedUsers(ownIdent).ConfigureAwait(false);
|
|
||||||
return usersToSendOnlineTo.Select(e => _clientIdentService.GetCharacterIdentForUid(e)).Where(t => !string.IsNullOrEmpty(t)).Distinct(StringComparer.Ordinal).ToList();
|
return usersToSendOnlineTo.Select(e => _clientIdentService.GetCharacterIdentForUid(e)).Where(t => !string.IsNullOrEmpty(t)).Distinct(StringComparer.Ordinal).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +72,6 @@ public partial class MareHub
|
|||||||
{
|
{
|
||||||
_logger.LogCallInfo();
|
_logger.LogCallInfo();
|
||||||
|
|
||||||
string userid = AuthenticatedUserId;
|
|
||||||
var query =
|
var query =
|
||||||
from userToOther in _dbContext.ClientPairs
|
from userToOther in _dbContext.ClientPairs
|
||||||
join otherToUser in _dbContext.ClientPairs
|
join otherToUser in _dbContext.ClientPairs
|
||||||
@@ -92,7 +87,7 @@ public partial class MareHub
|
|||||||
} into leftJoin
|
} into leftJoin
|
||||||
from otherEntry in leftJoin.DefaultIfEmpty()
|
from otherEntry in leftJoin.DefaultIfEmpty()
|
||||||
where
|
where
|
||||||
userToOther.UserUID == userid
|
userToOther.UserUID == UserUID
|
||||||
select new
|
select new
|
||||||
{
|
{
|
||||||
userToOther.OtherUser.Alias,
|
userToOther.OtherUser.Alias,
|
||||||
@@ -140,22 +135,24 @@ public partial class MareHub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hadInvalidData) throw new HubException("Invalid data provided, contact the appropriate mod creator to resolve those issues"
|
if (hadInvalidData)
|
||||||
+ Environment.NewLine
|
{
|
||||||
|
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))
|
+ string.Join(Environment.NewLine, invalidGamePaths.Select(p => "Invalid Game Path: " + p))
|
||||||
+ Environment.NewLine
|
+ Environment.NewLine
|
||||||
+ string.Join(Environment.NewLine, invalidFileSwapPaths.Select(p => "Invalid FileSwap Path: " + p)));
|
+ string.Join(Environment.NewLine, invalidFileSwapPaths.Select(p => "Invalid FileSwap Path: " + p)));
|
||||||
|
}
|
||||||
|
|
||||||
var allPairedUsers = await GetAllPairedUnpausedUsers().ConfigureAwait(false);
|
var allPairedUsers = await GetAllPairedUnpausedUsers().ConfigureAwait(false);
|
||||||
|
|
||||||
var allPairedUsersDict = allPairedUsers.ToDictionary(f => f, f => _clientIdentService.GetCharacterIdentForUid(f), StringComparer.Ordinal)
|
var allPairedUsersDict = allPairedUsers.ToDictionary(f => f, f => _clientIdentService.GetCharacterIdentForUid(f), StringComparer.Ordinal)
|
||||||
.Where(f => visibleCharacterIds.Contains(f.Value, StringComparer.Ordinal));
|
.Where(f => visibleCharacterIds.Contains(f.Value, StringComparer.Ordinal));
|
||||||
|
|
||||||
var ownIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(visibleCharacterIds.Count, allPairedUsersDict.Count()));
|
_logger.LogCallInfo(MareHubLogger.Args(visibleCharacterIds.Count, allPairedUsersDict.Count()));
|
||||||
|
|
||||||
await Clients.Users(allPairedUsersDict.Select(f => f.Key)).Client_UserReceiveCharacterData(characterCache, ownIdent).ConfigureAwait(false);
|
await Clients.Users(allPairedUsersDict.Select(f => f.Key)).Client_UserReceiveCharacterData(characterCache, UserCharaIdent).ConfigureAwait(false);
|
||||||
|
|
||||||
_mareMetrics.IncCounter(MetricsAPI.CounterUserPushData);
|
_mareMetrics.IncCounter(MetricsAPI.CounterUserPushData);
|
||||||
_mareMetrics.IncCounter(MetricsAPI.CounterUserPushDataTo, allPairedUsersDict.Count());
|
_mareMetrics.IncCounter(MetricsAPI.CounterUserPushDataTo, allPairedUsersDict.Count());
|
||||||
@@ -168,18 +165,22 @@ public partial class MareHub
|
|||||||
|
|
||||||
// don't allow adding yourself or nothing
|
// don't allow adding yourself or nothing
|
||||||
uid = uid.Trim();
|
uid = uid.Trim();
|
||||||
if (string.Equals(uid, AuthenticatedUserId, StringComparison.Ordinal) || string.IsNullOrWhiteSpace(uid)) return;
|
if (string.Equals(uid, UserUID, StringComparison.Ordinal) || string.IsNullOrWhiteSpace(uid)) return;
|
||||||
|
|
||||||
// grab other user, check if it exists and if a pair already exists
|
// 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);
|
var otherUser = await _dbContext.Users.SingleOrDefaultAsync(u => u.UID == uid || u.Alias == uid).ConfigureAwait(false);
|
||||||
var existingEntry =
|
var existingEntry =
|
||||||
await _dbContext.ClientPairs.AsNoTracking()
|
await _dbContext.ClientPairs.AsNoTracking()
|
||||||
.FirstOrDefaultAsync(p =>
|
.FirstOrDefaultAsync(p =>
|
||||||
p.User.UID == AuthenticatedUserId && p.OtherUserUID == uid).ConfigureAwait(false);
|
p.User.UID == UserUID && p.OtherUserUID == uid).ConfigureAwait(false);
|
||||||
if (otherUser == null || existingEntry != null) return;
|
if (otherUser == null || existingEntry != null)
|
||||||
|
{
|
||||||
|
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, $"Cannot pair with {uid}, either already paired or UID does not exist").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// grab self create new client pair and save
|
// grab self create new client pair and save
|
||||||
var user = await _dbContext.Users.SingleAsync(u => u.UID == AuthenticatedUserId).ConfigureAwait(false);
|
var user = await _dbContext.Users.SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(uid, "Success"));
|
_logger.LogCallInfo(MareHubLogger.Args(uid, "Success"));
|
||||||
|
|
||||||
@@ -239,8 +240,8 @@ public partial class MareHub
|
|||||||
{
|
{
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(otherUserUid, isPaused));
|
_logger.LogCallInfo(MareHubLogger.Args(otherUserUid, isPaused));
|
||||||
|
|
||||||
if (string.Equals(otherUserUid, AuthenticatedUserId, StringComparison.Ordinal)) return;
|
if (string.Equals(otherUserUid, UserUID, StringComparison.Ordinal)) return;
|
||||||
ClientPair pair = await _dbContext.ClientPairs.SingleOrDefaultAsync(w => w.UserUID == AuthenticatedUserId && w.OtherUserUID == otherUserUid).ConfigureAwait(false);
|
ClientPair pair = await _dbContext.ClientPairs.SingleOrDefaultAsync(w => w.UserUID == UserUID && w.OtherUserUID == otherUserUid).ConfigureAwait(false);
|
||||||
if (pair == null) return;
|
if (pair == null) return;
|
||||||
|
|
||||||
pair.IsPaused = isPaused;
|
pair.IsPaused = isPaused;
|
||||||
@@ -251,7 +252,7 @@ public partial class MareHub
|
|||||||
|
|
||||||
var otherEntry = OppositeEntry(otherUserUid);
|
var otherEntry = OppositeEntry(otherUserUid);
|
||||||
|
|
||||||
await Clients.User(AuthenticatedUserId).Client_UserUpdateClientPairs(
|
await Clients.User(UserUID).Client_UserUpdateClientPairs(
|
||||||
new ClientPairDto()
|
new ClientPairDto()
|
||||||
{
|
{
|
||||||
OtherUID = otherUserUid,
|
OtherUID = otherUserUid,
|
||||||
@@ -263,19 +264,18 @@ public partial class MareHub
|
|||||||
{
|
{
|
||||||
await Clients.User(otherUserUid).Client_UserUpdateClientPairs(new ClientPairDto()
|
await Clients.User(otherUserUid).Client_UserUpdateClientPairs(new ClientPairDto()
|
||||||
{
|
{
|
||||||
OtherUID = AuthenticatedUserId,
|
OtherUID = UserUID,
|
||||||
IsPaused = otherEntry.IsPaused,
|
IsPaused = otherEntry.IsPaused,
|
||||||
IsPausedFromOthers = isPaused,
|
IsPausedFromOthers = isPaused,
|
||||||
IsSynced = true
|
IsSynced = true
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
var selfCharaIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
|
|
||||||
var otherCharaIdent = _clientIdentService.GetCharacterIdentForUid(pair.OtherUserUID);
|
var otherCharaIdent = _clientIdentService.GetCharacterIdentForUid(pair.OtherUserUID);
|
||||||
|
|
||||||
if (selfCharaIdent == null || otherCharaIdent == null || otherEntry.IsPaused) return;
|
if (UserCharaIdent == null || otherCharaIdent == null || otherEntry.IsPaused) return;
|
||||||
|
|
||||||
await Clients.User(AuthenticatedUserId).Client_UserChangePairedPlayer(otherCharaIdent, !isPaused).ConfigureAwait(false);
|
await Clients.User(UserUID).Client_UserChangePairedPlayer(otherCharaIdent, !isPaused).ConfigureAwait(false);
|
||||||
await Clients.User(otherUserUid).Client_UserChangePairedPlayer(selfCharaIdent, !isPaused).ConfigureAwait(false);
|
await Clients.User(otherUserUid).Client_UserChangePairedPlayer(UserCharaIdent, !isPaused).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,11 +284,11 @@ public partial class MareHub
|
|||||||
{
|
{
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(otherUserUid));
|
_logger.LogCallInfo(MareHubLogger.Args(otherUserUid));
|
||||||
|
|
||||||
if (string.Equals(otherUserUid, AuthenticatedUserId, StringComparison.Ordinal)) return;
|
if (string.Equals(otherUserUid, UserUID, StringComparison.Ordinal)) return;
|
||||||
|
|
||||||
// check if client pair even exists
|
// check if client pair even exists
|
||||||
ClientPair callerPair =
|
ClientPair callerPair =
|
||||||
await _dbContext.ClientPairs.SingleOrDefaultAsync(w => w.UserUID == AuthenticatedUserId && w.OtherUserUID == otherUserUid).ConfigureAwait(false);
|
await _dbContext.ClientPairs.SingleOrDefaultAsync(w => w.UserUID == UserUID && w.OtherUserUID == otherUserUid).ConfigureAwait(false);
|
||||||
bool callerHadPaused = callerPair.IsPaused;
|
bool callerHadPaused = callerPair.IsPaused;
|
||||||
if (callerPair == null) return;
|
if (callerPair == null) return;
|
||||||
|
|
||||||
@@ -298,7 +298,7 @@ public partial class MareHub
|
|||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(otherUserUid, "Success"));
|
_logger.LogCallInfo(MareHubLogger.Args(otherUserUid, "Success"));
|
||||||
|
|
||||||
await Clients.User(AuthenticatedUserId)
|
await Clients.User(UserUID)
|
||||||
.Client_UserUpdateClientPairs(new ClientPairDto()
|
.Client_UserUpdateClientPairs(new ClientPairDto()
|
||||||
{
|
{
|
||||||
OtherUID = otherUserUid,
|
OtherUID = otherUserUid,
|
||||||
@@ -317,7 +317,7 @@ public partial class MareHub
|
|||||||
await Clients.User(otherUserUid).Client_UserUpdateClientPairs(
|
await Clients.User(otherUserUid).Client_UserUpdateClientPairs(
|
||||||
new ClientPairDto()
|
new ClientPairDto()
|
||||||
{
|
{
|
||||||
OtherUID = AuthenticatedUserId,
|
OtherUID = UserUID,
|
||||||
IsPausedFromOthers = false,
|
IsPausedFromOthers = false,
|
||||||
IsSynced = false
|
IsSynced = false
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
@@ -336,20 +336,18 @@ public partial class MareHub
|
|||||||
// if neither user had paused each other and either is not in an unpaused group with each other, change state to offline
|
// 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)
|
if (!callerHadPaused && !otherHadPaused && isPausedInGroup)
|
||||||
{
|
{
|
||||||
var userIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
|
await Clients.User(UserUID).Client_UserChangePairedPlayer(otherIdent, false).ConfigureAwait(false);
|
||||||
await Clients.User(AuthenticatedUserId).Client_UserChangePairedPlayer(otherIdent, false).ConfigureAwait(false);
|
await Clients.User(otherUserUid).Client_UserChangePairedPlayer(UserCharaIdent, false).ConfigureAwait(false);
|
||||||
await Clients.User(otherUserUid).Client_UserChangePairedPlayer(userIdent, false).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 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)
|
if (callerHadPaused && !otherHadPaused && !isPausedInGroup)
|
||||||
{
|
{
|
||||||
var userIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
|
await Clients.User(UserUID).Client_UserChangePairedPlayer(otherIdent, true).ConfigureAwait(false);
|
||||||
await Clients.User(AuthenticatedUserId).Client_UserChangePairedPlayer(otherIdent, true).ConfigureAwait(false);
|
await Clients.User(otherUserUid).Client_UserChangePairedPlayer(UserCharaIdent, true).ConfigureAwait(false);
|
||||||
await Clients.User(otherUserUid).Client_UserChangePairedPlayer(userIdent, true).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClientPair OppositeEntry(string otherUID) =>
|
private ClientPair OppositeEntry(string otherUID) =>
|
||||||
_dbContext.ClientPairs.AsNoTracking().SingleOrDefault(w => w.User.UID == otherUID && w.OtherUser.UID == AuthenticatedUserId);
|
_dbContext.ClientPairs.AsNoTracking().SingleOrDefault(w => w.User.UID == otherUID && w.OtherUser.UID == UserUID);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Security.Claims;
|
using MareSynchronos.API;
|
||||||
using MareSynchronos.API;
|
|
||||||
using MareSynchronosServer.Services;
|
using MareSynchronosServer.Services;
|
||||||
using MareSynchronosServer.Utils;
|
using MareSynchronosServer.Utils;
|
||||||
using MareSynchronosShared;
|
using MareSynchronosShared;
|
||||||
@@ -10,7 +9,6 @@ using MareSynchronosShared.Services;
|
|||||||
using MareSynchronosShared.Utils;
|
using MareSynchronosShared.Utils;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace MareSynchronosServer.Hubs;
|
namespace MareSynchronosServer.Hubs;
|
||||||
|
|
||||||
@@ -51,57 +49,40 @@ public partial class MareHub : Hub<IMareHub>, IMareHub
|
|||||||
_dbContext = mareDbContext;
|
_dbContext = mareDbContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Authorize(Policy = "Authenticated")]
|
[Authorize(Policy = "Identified")]
|
||||||
public async Task<ConnectionDto> Heartbeat(string characterIdentification)
|
public async Task<ConnectionDto> GetConnectionDto()
|
||||||
{
|
{
|
||||||
|
_logger.LogCallInfo();
|
||||||
|
|
||||||
_mareMetrics.IncCounter(MetricsAPI.CounterInitializedConnections);
|
_mareMetrics.IncCounter(MetricsAPI.CounterInitializedConnections);
|
||||||
|
|
||||||
var userId = Context.User!.Claims.SingleOrDefault(c => string.Equals(c.Type, ClaimTypes.NameIdentifier, StringComparison.Ordinal))?.Value;
|
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(characterIdentification));
|
|
||||||
|
|
||||||
await Clients.Caller.Client_UpdateSystemInfo(_systemInfoService.SystemInfoDto).ConfigureAwait(false);
|
await Clients.Caller.Client_UpdateSystemInfo(_systemInfoService.SystemInfoDto).ConfigureAwait(false);
|
||||||
|
|
||||||
var isBanned = await _dbContext.BannedUsers.AsNoTracking().AnyAsync(u => u.CharacterIdentification == characterIdentification).ConfigureAwait(false);
|
var dbUser = _dbContext.Users.SingleOrDefault(f => f.UID == UserUID);
|
||||||
|
dbUser.LastLoggedIn = DateTime.UtcNow;
|
||||||
|
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(userId) && !isBanned && !string.IsNullOrEmpty(characterIdentification))
|
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Information, "Welcome to Mare Synchronos \"" + _shardName + "\", Current Online Users: " + _systemInfoService.SystemInfoDto.OnlineUsers).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return new ConnectionDto()
|
||||||
{
|
{
|
||||||
var user = (await _dbContext.Users.SingleAsync(u => u.UID == userId).ConfigureAwait(false));
|
ServerVersion = IMareHub.ApiVersion,
|
||||||
var existingIdent = _clientIdentService.GetCharacterIdentForUid(userId);
|
UID = string.IsNullOrEmpty(dbUser.Alias) ? dbUser.UID : dbUser.Alias,
|
||||||
if (!string.IsNullOrEmpty(existingIdent) && !string.Equals(characterIdentification, existingIdent, StringComparison.Ordinal))
|
IsAdmin = dbUser.IsAdmin,
|
||||||
|
IsModerator = dbUser.IsModerator,
|
||||||
|
ServerInfo = new ServerInfoDto()
|
||||||
{
|
{
|
||||||
_logger.LogCallWarning(MareHubLogger.Args(characterIdentification, "Failure", "LoggedIn"));
|
MaxGroupsCreatedByUser = _maxExistingGroupsByUser,
|
||||||
|
ShardName = _shardName,
|
||||||
return new ConnectionDto()
|
MaxGroupsJoinedByUser = _maxJoinedGroupsByUser,
|
||||||
{
|
MaxGroupUserCount = _maxGroupUserCount
|
||||||
ServerVersion = IMareHub.ApiVersion
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
user.LastLoggedIn = DateTime.UtcNow;
|
[Authorize(Policy = "Authenticated")]
|
||||||
_clientIdentService.MarkUserOnline(user.UID, characterIdentification);
|
public async Task<ConnectionDto> Heartbeat(string characterIdentification)
|
||||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
{
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(characterIdentification, "Success"));
|
|
||||||
|
|
||||||
return new ConnectionDto
|
|
||||||
{
|
|
||||||
ServerVersion = IMareHub.ApiVersion,
|
|
||||||
UID = string.IsNullOrEmpty(user.Alias) ? user.UID : user.Alias,
|
|
||||||
IsModerator = user.IsModerator,
|
|
||||||
IsAdmin = user.IsAdmin,
|
|
||||||
ServerInfo = new ServerInfoDto()
|
|
||||||
{
|
|
||||||
MaxGroupsCreatedByUser = _maxExistingGroupsByUser,
|
|
||||||
ShardName = _shardName,
|
|
||||||
MaxGroupsJoinedByUser = _maxJoinedGroupsByUser,
|
|
||||||
MaxGroupUserCount = _maxGroupUserCount
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogCallWarning(MareHubLogger.Args(characterIdentification, "Failure"));
|
|
||||||
|
|
||||||
return new ConnectionDto()
|
return new ConnectionDto()
|
||||||
{
|
{
|
||||||
ServerVersion = IMareHub.ApiVersion
|
ServerVersion = IMareHub.ApiVersion
|
||||||
@@ -109,21 +90,31 @@ public partial class MareHub : Hub<IMareHub>, IMareHub
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Authorize(Policy = "Authenticated")]
|
[Authorize(Policy = "Authenticated")]
|
||||||
public Task<bool> CheckClientHealth()
|
public async Task<bool> CheckClientHealth()
|
||||||
{
|
{
|
||||||
var needsReconnect = !_clientIdentService.IsOnCurrentServer(AuthenticatedUserId);
|
var needsReconnect = !_clientIdentService.IsOnCurrentServer(UserUID);
|
||||||
if (needsReconnect)
|
if (needsReconnect)
|
||||||
{
|
{
|
||||||
|
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, "Internal server state corruption detected, reconnecting you automatically to fix the issue.").ConfigureAwait(false);
|
||||||
_logger.LogCallWarning(MareHubLogger.Args(needsReconnect));
|
_logger.LogCallWarning(MareHubLogger.Args(needsReconnect));
|
||||||
}
|
}
|
||||||
return Task.FromResult(needsReconnect);
|
|
||||||
|
return needsReconnect;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Authorize(Policy = "Authenticated")]
|
[Authorize(Policy = "Authenticated")]
|
||||||
public override async Task OnConnectedAsync()
|
public override async Task OnConnectedAsync()
|
||||||
{
|
{
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(_contextAccessor.GetIpAddress()));
|
|
||||||
_mareMetrics.IncGauge(MetricsAPI.GaugeConnections);
|
_mareMetrics.IncGauge(MetricsAPI.GaugeConnections);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogCallInfo(MareHubLogger.Args(_contextAccessor.GetIpAddress(), UserCharaIdent));
|
||||||
|
|
||||||
|
_clientIdentService.MarkUserOnline(UserUID, UserCharaIdent);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
await base.OnConnectedAsync().ConfigureAwait(false);
|
await base.OnConnectedAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,19 +123,18 @@ public partial class MareHub : Hub<IMareHub>, IMareHub
|
|||||||
{
|
{
|
||||||
_mareMetrics.DecGauge(MetricsAPI.GaugeConnections);
|
_mareMetrics.DecGauge(MetricsAPI.GaugeConnections);
|
||||||
|
|
||||||
var userCharaIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
|
try
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(userCharaIdent))
|
|
||||||
{
|
{
|
||||||
_logger.LogCallInfo();
|
_logger.LogCallInfo(MareHubLogger.Args(_contextAccessor.GetIpAddress(), UserCharaIdent));
|
||||||
_clientIdentService.MarkUserOffline(AuthenticatedUserId);
|
|
||||||
|
|
||||||
await SendOfflineToAllPairedUsers(userCharaIdent).ConfigureAwait(false);
|
_clientIdentService.MarkUserOffline(UserUID);
|
||||||
|
|
||||||
_dbContext.RemoveRange(_dbContext.Files.Where(f => !f.Uploaded && f.UploaderUID == AuthenticatedUserId));
|
await SendOfflineToAllPairedUsers(UserCharaIdent).ConfigureAwait(false);
|
||||||
|
|
||||||
|
_dbContext.RemoveRange(_dbContext.Files.Where(f => !f.Uploaded && f.UploaderUID == UserUID));
|
||||||
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
await base.OnDisconnectedAsync(exception).ConfigureAwait(false);
|
await base.OnDisconnectedAsync(exception).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Security.Claims;
|
using AspNetCoreRateLimit;
|
||||||
using AspNetCoreRateLimit;
|
|
||||||
using MareSynchronosShared;
|
using MareSynchronosShared;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
@@ -37,7 +36,7 @@ public class SignalRLimitFilter : IHubFilter
|
|||||||
var counter = await _processor.ProcessRequestAsync(client, rule).ConfigureAwait(false);
|
var counter = await _processor.ProcessRequestAsync(client, rule).ConfigureAwait(false);
|
||||||
if (counter.Count > rule.Limit)
|
if (counter.Count > rule.Limit)
|
||||||
{
|
{
|
||||||
var authUserId = invocationContext.Context.User.Claims?.SingleOrDefault(c => string.Equals(c.Type, ClaimTypes.NameIdentifier, StringComparison.Ordinal))?.Value ?? "Unknown";
|
var authUserId = invocationContext.Context.User.Claims?.SingleOrDefault(c => string.Equals(c.Type, MareClaimTypes.Uid, StringComparison.Ordinal))?.Value ?? "Unknown";
|
||||||
var retry = counter.Timestamp.RetryAfterFrom(rule);
|
var retry = counter.Timestamp.RetryAfterFrom(rule);
|
||||||
logger.LogWarning("Method rate limit triggered from {ip}/{authUserId}: {method}", ip, authUserId, invocationContext.HubMethodName);
|
logger.LogWarning("Method rate limit triggered from {ip}/{authUserId}: {method}", ip, authUserId, invocationContext.HubMethodName);
|
||||||
throw new HubException($"call limit {retry}");
|
throw new HubException($"call limit {retry}");
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
using System.Security.Claims;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using MareSynchronosShared.Data;
|
using MareSynchronosShared.Data;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using MareSynchronosServer.Services;
|
using MareSynchronosServer.Services;
|
||||||
|
using MareSynchronosServer.Hubs;
|
||||||
|
|
||||||
namespace MareSynchronosServer.RequirementHandlers;
|
namespace MareSynchronosServer.RequirementHandlers;
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ public class UserRequirementHandler : AuthorizationHandler<UserRequirement, HubI
|
|||||||
|
|
||||||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, UserRequirement requirement, HubInvocationContext resource)
|
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, UserRequirement requirement, HubInvocationContext resource)
|
||||||
{
|
{
|
||||||
var uid = context.User.Claims.SingleOrDefault(g => string.Equals(g.Type, ClaimTypes.NameIdentifier, StringComparison.Ordinal))?.Value;
|
var uid = context.User.Claims.SingleOrDefault(g => string.Equals(g.Type, MareClaimTypes.Uid, StringComparison.Ordinal))?.Value;
|
||||||
|
|
||||||
if (uid == null) context.Fail();
|
if (uid == null) context.Fail();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
using Grpc.Core;
|
||||||
|
using MareSynchronos.API;
|
||||||
|
using MareSynchronosServer.Hubs;
|
||||||
|
using MareSynchronosShared.Protos;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using static MareSynchronosShared.Protos.ClientMessageService;
|
||||||
|
|
||||||
|
namespace MareSynchronosServer.Services;
|
||||||
|
|
||||||
|
public class GrpcClientMessageService : ClientMessageServiceBase
|
||||||
|
{
|
||||||
|
private readonly ILogger<GrpcClientMessageService> _logger;
|
||||||
|
private readonly IHubContext<MareHub, IMareHub> _hubContext;
|
||||||
|
|
||||||
|
public GrpcClientMessageService(ILogger<GrpcClientMessageService> logger, IHubContext<MareHub, IMareHub> hubContext)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_hubContext = hubContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<Empty> SendClientMessage(ClientMessage request, ServerCallContext context)
|
||||||
|
{
|
||||||
|
bool hasUid = !string.IsNullOrEmpty(request.Uid);
|
||||||
|
|
||||||
|
var severity = request.Type switch
|
||||||
|
{
|
||||||
|
MessageType.Info => MessageSeverity.Information,
|
||||||
|
MessageType.Warning => MessageSeverity.Warning,
|
||||||
|
MessageType.Error => MessageSeverity.Error,
|
||||||
|
_ => MessageSeverity.Information,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!hasUid)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Sending Message of severity {severity} to all online users: {message}", severity, request.Message);
|
||||||
|
await _hubContext.Clients.All.Client_ReceiveServerMessage(severity, request.Message).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Sending Message of severity {severity} to user {uid}: {message}", severity, request.Uid, request.Message);
|
||||||
|
await _hubContext.Clients.User(request.Uid).Client_ReceiveServerMessage(severity, request.Message).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -94,9 +94,10 @@ public class GrpcClientIdentificationService : GrpcBaseService, IClientIdentific
|
|||||||
|
|
||||||
public void MarkUserOffline(string uid)
|
public void MarkUserOffline(string uid)
|
||||||
{
|
{
|
||||||
|
_metrics.SetGaugeTo(MetricsAPI.GaugeAuthorizedConnections, OnlineClients.Count);
|
||||||
|
|
||||||
if (OnlineClients.TryRemove(uid, out var uidWithIdent))
|
if (OnlineClients.TryRemove(uid, out var uidWithIdent))
|
||||||
{
|
{
|
||||||
_metrics.SetGaugeTo(MetricsAPI.GaugeAuthorizedConnections, OnlineClients.Count);
|
|
||||||
_identChangeQueue.Enqueue(new IdentChange()
|
_identChangeQueue.Enqueue(new IdentChange()
|
||||||
{
|
{
|
||||||
IsOnline = false,
|
IsOnline = false,
|
||||||
@@ -172,6 +173,7 @@ public class GrpcClientIdentificationService : GrpcBaseService, IClientIdentific
|
|||||||
_logger.LogInformation("Starting Receive Online Client Data stream");
|
_logger.LogInformation("Starting Receive Online Client Data stream");
|
||||||
await foreach (var cur in stream.ResponseStream.ReadAllAsync(cts).ConfigureAwait(false))
|
await foreach (var cur in stream.ResponseStream.ReadAllAsync(cts).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
|
OnlineClients.Remove(cur.UidWithIdent.Uid.Uid, out _);
|
||||||
if (cur.IsOnline)
|
if (cur.IsOnline)
|
||||||
{
|
{
|
||||||
RemoteCachedIdents[cur.UidWithIdent.Uid.Uid] = cur.UidWithIdent;
|
RemoteCachedIdents[cur.UidWithIdent.Uid.Uid] = cur.UidWithIdent;
|
||||||
|
|||||||
@@ -47,14 +47,14 @@ public class SystemInfoService : IHostedService, IDisposable
|
|||||||
_mareMetrics.SetGaugeTo(MetricsAPI.GaugeAvailableWorkerThreads, workerThreads);
|
_mareMetrics.SetGaugeTo(MetricsAPI.GaugeAvailableWorkerThreads, workerThreads);
|
||||||
_mareMetrics.SetGaugeTo(MetricsAPI.GaugeAvailableIOWorkerThreads, ioThreads);
|
_mareMetrics.SetGaugeTo(MetricsAPI.GaugeAvailableIOWorkerThreads, ioThreads);
|
||||||
|
|
||||||
|
var onlineUsers = (int)_clientIdentService.GetOnlineUsers().Result;
|
||||||
|
SystemInfoDto = new SystemInfoDto()
|
||||||
|
{
|
||||||
|
OnlineUsers = onlineUsers,
|
||||||
|
};
|
||||||
|
|
||||||
if (_config.IsMain)
|
if (_config.IsMain)
|
||||||
{
|
{
|
||||||
var onlineUsers = (int)_clientIdentService.GetOnlineUsers().Result;
|
|
||||||
SystemInfoDto = new SystemInfoDto()
|
|
||||||
{
|
|
||||||
OnlineUsers = onlineUsers,
|
|
||||||
};
|
|
||||||
|
|
||||||
_logger.LogInformation("Sending System Info, Online Users: {onlineUsers}", onlineUsers);
|
_logger.LogInformation("Sending System Info, Online Users: {onlineUsers}", onlineUsers);
|
||||||
|
|
||||||
_hubContext.Clients.All.Client_UpdateSystemInfo(SystemInfoDto);
|
_hubContext.Clients.All.Client_UpdateSystemInfo(SystemInfoDto);
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Http.Connections;
|
|||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using AspNetCoreRateLimit;
|
using AspNetCoreRateLimit;
|
||||||
using MareSynchronosShared.Authentication;
|
|
||||||
using MareSynchronosShared.Data;
|
using MareSynchronosShared.Data;
|
||||||
using MareSynchronosShared.Protos;
|
using MareSynchronosShared.Protos;
|
||||||
using Grpc.Net.Client.Configuration;
|
using Grpc.Net.Client.Configuration;
|
||||||
@@ -22,6 +21,7 @@ using Grpc.Net.ClientFactory;
|
|||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using MareSynchronosServer.Authentication;
|
||||||
|
|
||||||
namespace MareSynchronosServer;
|
namespace MareSynchronosServer;
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ public class Startup
|
|||||||
services.AddSingleton<IUserIdProvider, IdBasedUserIdProvider>();
|
services.AddSingleton<IUserIdProvider, IdBasedUserIdProvider>();
|
||||||
services.AddHostedService(provider => provider.GetService<SystemInfoService>());
|
services.AddHostedService(provider => provider.GetService<SystemInfoService>());
|
||||||
// configure services based on main server status
|
// configure services based on main server status
|
||||||
ConfigureIdentityServices(services, mareConfig, isMainServer);
|
ConfigureServicesBasedOnShardType(services, mareConfig, isMainServer);
|
||||||
|
|
||||||
if (isMainServer)
|
if (isMainServer)
|
||||||
{
|
{
|
||||||
@@ -210,7 +210,7 @@ public class Startup
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ConfigureIdentityServices(IServiceCollection services, IConfigurationSection mareConfig, bool isMainServer)
|
private static void ConfigureServicesBasedOnShardType(IServiceCollection services, IConfigurationSection mareConfig, bool isMainServer)
|
||||||
{
|
{
|
||||||
if (!isMainServer)
|
if (!isMainServer)
|
||||||
{
|
{
|
||||||
@@ -325,6 +325,7 @@ public class Startup
|
|||||||
{
|
{
|
||||||
endpoints.MapGrpcService<GrpcIdentityService>().AllowAnonymous();
|
endpoints.MapGrpcService<GrpcIdentityService>().AllowAnonymous();
|
||||||
endpoints.MapGrpcService<GrpcConfigurationService<ServerConfiguration>>().AllowAnonymous();
|
endpoints.MapGrpcService<GrpcConfigurationService<ServerConfiguration>>().AllowAnonymous();
|
||||||
|
endpoints.MapGrpcService<GrpcClientMessageService>().AllowAnonymous();
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoints.MapHealthChecks("/health").AllowAnonymous();
|
endpoints.MapHealthChecks("/health").AllowAnonymous();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Security.Claims;
|
using MareSynchronosServer.Hubs;
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
namespace MareSynchronosServer.Utils;
|
namespace MareSynchronosServer.Utils;
|
||||||
@@ -7,6 +7,6 @@ public class IdBasedUserIdProvider : IUserIdProvider
|
|||||||
{
|
{
|
||||||
public string GetUserId(HubConnectionContext context)
|
public string GetUserId(HubConnectionContext context)
|
||||||
{
|
{
|
||||||
return context.User!.Claims.SingleOrDefault(c => string.Equals(c.Type, ClaimTypes.NameIdentifier, StringComparison.Ordinal))?.Value;
|
return context.User!.Claims.SingleOrDefault(c => string.Equals(c.Type, MareClaimTypes.Uid, StringComparison.Ordinal))?.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,12 +22,12 @@ public class MareHubLogger
|
|||||||
public void LogCallInfo(object[] args = null, [CallerMemberName] string methodName = "")
|
public void LogCallInfo(object[] args = null, [CallerMemberName] string methodName = "")
|
||||||
{
|
{
|
||||||
string formattedArgs = args != null && args.Length != 0 ? "|" + string.Join(":", args) : string.Empty;
|
string formattedArgs = args != null && args.Length != 0 ? "|" + string.Join(":", args) : string.Empty;
|
||||||
_logger.LogInformation("{uid}:{method}{args}", _hub.AuthenticatedUserId, methodName, formattedArgs);
|
_logger.LogInformation("{uid}:{method}{args}", _hub.UserUID, methodName, formattedArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LogCallWarning(object[] args = null, [CallerMemberName] string methodName = "")
|
public void LogCallWarning(object[] args = null, [CallerMemberName] string methodName = "")
|
||||||
{
|
{
|
||||||
string formattedArgs = args != null && args.Length != 0 ? "|" + string.Join(":", args) : string.Empty;
|
string formattedArgs = args != null && args.Length != 0 ? "|" + string.Join(":", args) : string.Empty;
|
||||||
_logger.LogWarning("{uid}:{method}{args}", _hub.AuthenticatedUserId, methodName, formattedArgs);
|
_logger.LogWarning("{uid}:{method}{args}", _hub.UserUID, methodName, formattedArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using Prometheus;
|
using Prometheus;
|
||||||
using MareSynchronosShared.Models;
|
using MareSynchronosShared.Models;
|
||||||
using MareSynchronosShared.Metrics;
|
|
||||||
using MareSynchronosShared.Utils;
|
using MareSynchronosShared.Utils;
|
||||||
using MareSynchronosShared.Services;
|
using MareSynchronosShared.Services;
|
||||||
using static MareSynchronosShared.Protos.IdentificationService;
|
using static MareSynchronosShared.Protos.IdentificationService;
|
||||||
using static System.Formats.Asn1.AsnWriter;
|
using Grpc.Net.ClientFactory;
|
||||||
|
using MareSynchronosShared.Protos;
|
||||||
|
|
||||||
namespace MareSynchronosServices.Discord;
|
namespace MareSynchronosServices.Discord;
|
||||||
|
|
||||||
@@ -30,23 +30,26 @@ public class MareModule : InteractionModuleBase
|
|||||||
private readonly DiscordBotServices _botServices;
|
private readonly DiscordBotServices _botServices;
|
||||||
private readonly IdentificationServiceClient _identificationServiceClient;
|
private readonly IdentificationServiceClient _identificationServiceClient;
|
||||||
private readonly IConfigurationService<ServerConfiguration> _mareClientConfigurationService;
|
private readonly IConfigurationService<ServerConfiguration> _mareClientConfigurationService;
|
||||||
|
private readonly GrpcClientFactory _grpcClientFactory;
|
||||||
private Random random = new();
|
private Random random = new();
|
||||||
|
|
||||||
public MareModule(ILogger<MareModule> logger, IServiceProvider services, DiscordBotServices botServices,
|
public MareModule(ILogger<MareModule> logger, IServiceProvider services, DiscordBotServices botServices,
|
||||||
IdentificationServiceClient identificationServiceClient, IConfigurationService<ServerConfiguration> mareClientConfigurationService)
|
IdentificationServiceClient identificationServiceClient, IConfigurationService<ServerConfiguration> mareClientConfigurationService,
|
||||||
|
GrpcClientFactory grpcClientFactory)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_services = services;
|
_services = services;
|
||||||
_botServices = botServices;
|
_botServices = botServices;
|
||||||
_identificationServiceClient = identificationServiceClient;
|
_identificationServiceClient = identificationServiceClient;
|
||||||
_mareClientConfigurationService = mareClientConfigurationService;
|
_mareClientConfigurationService = mareClientConfigurationService;
|
||||||
|
_grpcClientFactory = grpcClientFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
[SlashCommand("register", "Starts the registration process for the Mare Synchronos server of this Discord")]
|
[SlashCommand("register", "Starts the registration process for the Mare Synchronos server of this Discord")]
|
||||||
public async Task Register([Summary("overwrite", "Overwrites your old account")] bool overwrite = false)
|
public async Task Register([Summary("overwrite", "Overwrites your old account")] bool overwrite = false)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("SlashCommand:{userId}:{Method}:{params}",
|
_logger.LogInformation("SlashCommand:{userId}:{Method}:{params}",
|
||||||
Context.Client.CurrentUser.Id, nameof(Register),
|
Context.Interaction.User.Id, nameof(Register),
|
||||||
string.Join(",", new[] { $"{nameof(overwrite)}:{overwrite}" }));
|
string.Join(",", new[] { $"{nameof(overwrite)}:{overwrite}" }));
|
||||||
|
|
||||||
await TryRespondAsync(async () =>
|
await TryRespondAsync(async () =>
|
||||||
@@ -64,7 +67,7 @@ public class MareModule : InteractionModuleBase
|
|||||||
public async Task SetVanityUid([Summary("vanity_uid", "Desired Vanity UID")] string vanityUid)
|
public async Task SetVanityUid([Summary("vanity_uid", "Desired Vanity UID")] string vanityUid)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("SlashCommand:{userId}:{Method}:{params}",
|
_logger.LogInformation("SlashCommand:{userId}:{Method}:{params}",
|
||||||
Context.Client.CurrentUser.Id, nameof(SetVanityUid),
|
Context.Interaction.User.Id, nameof(SetVanityUid),
|
||||||
string.Join(",", new[] { $"{nameof(vanityUid)}:{vanityUid}" }));
|
string.Join(",", new[] { $"{nameof(vanityUid)}:{vanityUid}" }));
|
||||||
|
|
||||||
await TryRespondAsync(async () =>
|
await TryRespondAsync(async () =>
|
||||||
@@ -83,7 +86,7 @@ public class MareModule : InteractionModuleBase
|
|||||||
[Summary("vanity_syncshell_id", "Desired Vanity Syncshell ID")] string vanityId)
|
[Summary("vanity_syncshell_id", "Desired Vanity Syncshell ID")] string vanityId)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("SlashCommand:{userId}:{Method}:{params}",
|
_logger.LogInformation("SlashCommand:{userId}:{Method}:{params}",
|
||||||
Context.Client.CurrentUser.Id, nameof(SetSyncshellVanityId),
|
Context.Interaction.User.Id, nameof(SetSyncshellVanityId),
|
||||||
string.Join(",", new[] { $"{nameof(syncshellId)}:{syncshellId}", $"{nameof(vanityId)}:{vanityId}" }));
|
string.Join(",", new[] { $"{nameof(syncshellId)}:{syncshellId}", $"{nameof(vanityId)}:{vanityId}" }));
|
||||||
|
|
||||||
await TryRespondAsync(async () =>
|
await TryRespondAsync(async () =>
|
||||||
@@ -100,7 +103,7 @@ public class MareModule : InteractionModuleBase
|
|||||||
public async Task Verify()
|
public async Task Verify()
|
||||||
{
|
{
|
||||||
_logger.LogInformation("SlashCommand:{userId}:{Method}",
|
_logger.LogInformation("SlashCommand:{userId}:{Method}",
|
||||||
Context.Client.CurrentUser.Id, nameof(Verify));
|
Context.Interaction.User.Id, nameof(Verify));
|
||||||
await TryRespondAsync(async () =>
|
await TryRespondAsync(async () =>
|
||||||
{
|
{
|
||||||
EmbedBuilder eb = new();
|
EmbedBuilder eb = new();
|
||||||
@@ -128,7 +131,7 @@ public class MareModule : InteractionModuleBase
|
|||||||
public async Task VerifyRelink()
|
public async Task VerifyRelink()
|
||||||
{
|
{
|
||||||
_logger.LogInformation("SlashCommand:{userId}:{Method}",
|
_logger.LogInformation("SlashCommand:{userId}:{Method}",
|
||||||
Context.Client.CurrentUser.Id, nameof(VerifyRelink));
|
Context.Interaction.User.Id, nameof(VerifyRelink));
|
||||||
await TryRespondAsync(async () =>
|
await TryRespondAsync(async () =>
|
||||||
{
|
{
|
||||||
EmbedBuilder eb = new();
|
EmbedBuilder eb = new();
|
||||||
@@ -156,7 +159,7 @@ public class MareModule : InteractionModuleBase
|
|||||||
public async Task Recover()
|
public async Task Recover()
|
||||||
{
|
{
|
||||||
_logger.LogInformation("SlashCommand:{userId}:{Method}",
|
_logger.LogInformation("SlashCommand:{userId}:{Method}",
|
||||||
Context.Client.CurrentUser.Id, nameof(Recover));
|
Context.Interaction.User.Id, nameof(Recover));
|
||||||
await RespondWithModalAsync<LodestoneModal>("recover_modal").ConfigureAwait(false);
|
await RespondWithModalAsync<LodestoneModal>("recover_modal").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +169,7 @@ public class MareModule : InteractionModuleBase
|
|||||||
[Summary("uid", "ADMIN ONLY: UID to check for")] string? uid = null)
|
[Summary("uid", "ADMIN ONLY: UID to check for")] string? uid = null)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("SlashCommand:{userId}:{Method}",
|
_logger.LogInformation("SlashCommand:{userId}:{Method}",
|
||||||
Context.Client.CurrentUser.Id, nameof(UserInfo));
|
Context.Interaction.User.Id, nameof(UserInfo));
|
||||||
|
|
||||||
await TryRespondAsync(async () =>
|
await TryRespondAsync(async () =>
|
||||||
{
|
{
|
||||||
@@ -182,7 +185,7 @@ public class MareModule : InteractionModuleBase
|
|||||||
public async Task Relink()
|
public async Task Relink()
|
||||||
{
|
{
|
||||||
_logger.LogInformation("SlashCommand:{userId}:{Method}",
|
_logger.LogInformation("SlashCommand:{userId}:{Method}",
|
||||||
Context.Client.CurrentUser.Id, nameof(Relink));
|
Context.Interaction.User.Id, nameof(Relink));
|
||||||
await RespondWithModalAsync<LodestoneModal>("relink_modal").ConfigureAwait(false);
|
await RespondWithModalAsync<LodestoneModal>("relink_modal").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,7 +193,7 @@ public class MareModule : InteractionModuleBase
|
|||||||
public async Task UserAdd([Summary("desired_uid", "Desired UID")] string desiredUid)
|
public async Task UserAdd([Summary("desired_uid", "Desired UID")] string desiredUid)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("SlashCommand:{userId}:{Method}:{params}",
|
_logger.LogInformation("SlashCommand:{userId}:{Method}:{params}",
|
||||||
Context.Client.CurrentUser.Id, nameof(UserAdd),
|
Context.Interaction.User.Id, nameof(UserAdd),
|
||||||
string.Join(",", new[] { $"{nameof(desiredUid)}:{desiredUid}" }));
|
string.Join(",", new[] { $"{nameof(desiredUid)}:{desiredUid}" }));
|
||||||
|
|
||||||
await TryRespondAsync(async () =>
|
await TryRespondAsync(async () =>
|
||||||
@@ -201,11 +204,51 @@ public class MareModule : InteractionModuleBase
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SlashCommand("message", "ADMIN ONLY: sends a message to clients")]
|
||||||
|
public async Task SendMessageToClients([Summary("message", "Message to send")] string message,
|
||||||
|
[Summary("severity", "Severity of the message")] MareSynchronosShared.Protos.MessageType messageType = MareSynchronosShared.Protos.MessageType.Info,
|
||||||
|
[Summary("uid", "User ID to the person to send the message to")] string? uid = null)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("SlashCommand:{userId}:{Method}:{message}:{type}:{uid}", Context.Interaction.User.Id, nameof(SendMessageToClients), message, messageType, uid);
|
||||||
|
|
||||||
|
using var scope = _services.CreateScope();
|
||||||
|
using var db = scope.ServiceProvider.GetService<MareDbContext>();
|
||||||
|
|
||||||
|
if (!(await db.LodeStoneAuth.Include(u => u.User).SingleOrDefaultAsync(a => a.DiscordId == Context.Interaction.User.Id))?.User?.IsAdmin ?? true)
|
||||||
|
{
|
||||||
|
await RespondAsync("No permission", ephemeral: true).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(uid) && !await db.Users.AnyAsync(u => u.UID == uid))
|
||||||
|
{
|
||||||
|
await RespondAsync("Specified UID does not exist", ephemeral: true).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var client = _grpcClientFactory.CreateClient<ClientMessageService.ClientMessageServiceClient>("MessageClient");
|
||||||
|
await client.SendClientMessageAsync(new ClientMessage()
|
||||||
|
{
|
||||||
|
Message = message,
|
||||||
|
Type = messageType,
|
||||||
|
Uid = uid ?? string.Empty
|
||||||
|
});
|
||||||
|
|
||||||
|
await RespondAsync("Message sent", ephemeral: true).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await RespondAsync("Failed to send message: " + ex.ToString(), ephemeral: true).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[ModalInteraction("recover_modal")]
|
[ModalInteraction("recover_modal")]
|
||||||
public async Task RecoverModal(LodestoneModal modal)
|
public async Task RecoverModal(LodestoneModal modal)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Modal:{userId}:{Method}",
|
_logger.LogInformation("Modal:{userId}:{Method}",
|
||||||
Context.Client.CurrentUser.Id, nameof(RecoverModal));
|
Context.Interaction.User.Id, nameof(RecoverModal));
|
||||||
|
|
||||||
await TryRespondAsync(async () =>
|
await TryRespondAsync(async () =>
|
||||||
{
|
{
|
||||||
@@ -218,7 +261,7 @@ public class MareModule : InteractionModuleBase
|
|||||||
public async Task RegisterModal(LodestoneModal modal)
|
public async Task RegisterModal(LodestoneModal modal)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Modal:{userId}:{Method}",
|
_logger.LogInformation("Modal:{userId}:{Method}",
|
||||||
Context.Client.CurrentUser.Id, nameof(RegisterModal));
|
Context.Interaction.User.Id, nameof(RegisterModal));
|
||||||
|
|
||||||
await TryRespondAsync(async () =>
|
await TryRespondAsync(async () =>
|
||||||
{
|
{
|
||||||
@@ -231,7 +274,7 @@ public class MareModule : InteractionModuleBase
|
|||||||
public async Task RelinkModal(LodestoneModal modal)
|
public async Task RelinkModal(LodestoneModal modal)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Modal:{userId}:{Method}",
|
_logger.LogInformation("Modal:{userId}:{Method}",
|
||||||
Context.Client.CurrentUser.Id, nameof(RelinkModal));
|
Context.Interaction.User.Id, nameof(RelinkModal));
|
||||||
|
|
||||||
await TryRespondAsync(async () =>
|
await TryRespondAsync(async () =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -68,6 +68,18 @@ public class Startup
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
services.AddGrpcClient<ClientMessageService.ClientMessageServiceClient>("MessageClient", c =>
|
||||||
|
{
|
||||||
|
c.Address = new Uri(mareConfig.GetValue<string>(nameof(ServicesConfiguration.MainServerGrpcAddress)));
|
||||||
|
}).ConfigureChannel(c =>
|
||||||
|
{
|
||||||
|
c.ServiceConfig = new ServiceConfig { MethodConfigs = { noRetryConfig } };
|
||||||
|
c.HttpHandler = new SocketsHttpHandler()
|
||||||
|
{
|
||||||
|
EnableMultipleHttp2Connections = true
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
services.Configure<ServicesConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
|
services.Configure<ServicesConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
|
||||||
services.Configure<ServerConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
|
services.Configure<ServerConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
|
||||||
services.Configure<MareConfigurationAuthBase>(Configuration.GetRequiredSection("MareSynchronos"));
|
services.Configure<MareConfigurationAuthBase>(Configuration.GetRequiredSection("MareSynchronos"));
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
namespace MareSynchronosShared.Authentication;
|
|
||||||
|
|
||||||
public record SecretKeyAuthReply(bool Success, string? Uid);
|
|
||||||
@@ -23,6 +23,22 @@ service ConfigurationService {
|
|||||||
rpc GetConfigurationEntry (KeyMessage) returns (ValueMessage);
|
rpc GetConfigurationEntry (KeyMessage) returns (ValueMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
service ClientMessageService {
|
||||||
|
rpc SendClientMessage (ClientMessage) returns (Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
message ClientMessage {
|
||||||
|
MessageType type = 1;
|
||||||
|
string message = 2;
|
||||||
|
string uid = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MessageType {
|
||||||
|
INFO = 0;
|
||||||
|
WARNING = 1;
|
||||||
|
ERROR = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message KeyMessage {
|
message KeyMessage {
|
||||||
string key = 1;
|
string key = 1;
|
||||||
string default = 2;
|
string default = 2;
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
using Grpc.Net.Client.Configuration;
|
using Grpc.Net.Client.Configuration;
|
||||||
using Grpc.Net.ClientFactory;
|
using Grpc.Net.ClientFactory;
|
||||||
using MareSynchronosShared.Authentication;
|
|
||||||
using MareSynchronosShared.Data;
|
using MareSynchronosShared.Data;
|
||||||
using MareSynchronosShared.Metrics;
|
using MareSynchronosShared.Metrics;
|
||||||
using MareSynchronosShared.Protos;
|
using MareSynchronosShared.Protos;
|
||||||
using MareSynchronosShared.Services;
|
using MareSynchronosShared.Services;
|
||||||
using MareSynchronosShared.Utils;
|
using MareSynchronosShared.Utils;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@@ -45,10 +43,6 @@ public class Startup
|
|||||||
|
|
||||||
services.AddSingleton(m => new MareMetrics(m.GetService<ILogger<MareMetrics>>(), new List<string>
|
services.AddSingleton(m => new MareMetrics(m.GetService<ILogger<MareMetrics>>(), new List<string>
|
||||||
{
|
{
|
||||||
MetricsAPI.CounterAuthenticationCacheHits,
|
|
||||||
MetricsAPI.CounterAuthenticationFailures,
|
|
||||||
MetricsAPI.CounterAuthenticationRequests,
|
|
||||||
MetricsAPI.CounterAuthenticationSuccesses
|
|
||||||
}, new List<string>
|
}, new List<string>
|
||||||
{
|
{
|
||||||
MetricsAPI.GaugeFilesTotalSize,
|
MetricsAPI.GaugeFilesTotalSize,
|
||||||
@@ -64,7 +58,6 @@ public class Startup
|
|||||||
services.AddHostedService(m => m.GetService<FileStatisticsService>());
|
services.AddHostedService(m => m.GetService<FileStatisticsService>());
|
||||||
services.AddHostedService<FileCleanupService>();
|
services.AddHostedService<FileCleanupService>();
|
||||||
|
|
||||||
services.AddSingleton<SecretKeyAuthenticatorService>();
|
|
||||||
services.AddDbContextPool<MareDbContext>(options =>
|
services.AddDbContextPool<MareDbContext>(options =>
|
||||||
{
|
{
|
||||||
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"), builder =>
|
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"), builder =>
|
||||||
|
|||||||
Reference in New Issue
Block a user