add redis for character identification

This commit is contained in:
rootdarkarchon
2022-09-13 11:45:09 +02:00
parent ea48fb3947
commit 1f66b2c980
16 changed files with 356 additions and 175 deletions

View File

@@ -16,8 +16,8 @@ namespace MareSynchronosServer.Hubs
private bool IsModerator => _dbContext.Users.Single(b => b.UID == AuthenticatedUserId).IsModerator || IsAdmin;
private List<string> OnlineAdmins => _dbContext.Users.Where(u => !string.IsNullOrEmpty(u.CharacterIdentification) && (u.IsModerator || u.IsAdmin))
.Select(u => u.UID).ToList();
private List<string> OnlineAdmins => _dbContext.Users.Where(u => (u.IsModerator || u.IsAdmin)).Select(u => u.UID).ToList();
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
[HubMethodName(Api.SendAdminChangeModeratorStatus)]
public async Task ChangeModeratorStatus(string uid, bool isModerator)
@@ -101,13 +101,14 @@ namespace MareSynchronosServer.Hubs
{
if (!IsModerator) return null;
return await _dbContext.Users.AsNoTracking().Where(b => !string.IsNullOrEmpty(b.CharacterIdentification)).Select(b => new OnlineUserDto
var users = await _dbContext.Users.AsNoTracking().ToListAsync().ConfigureAwait(false);
return users.Where(c => !string.IsNullOrEmpty(_clientIdentService.GetCharacterIdentForUid(c.UID))).Select(b => new OnlineUserDto
{
CharacterNameHash = b.CharacterIdentification,
CharacterNameHash = _clientIdentService.GetCharacterIdentForUid(b.UID),
UID = b.UID,
IsModerator = b.IsModerator,
IsAdmin = b.IsAdmin
}).ToListAsync().ConfigureAwait(false);
}).ToList();
}
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
@@ -134,11 +135,10 @@ namespace MareSynchronosServer.Hubs
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
await Clients.Users(OnlineAdmins).SendAsync(Api.OnAdminUpdateOrAddBannedUser, dto).ConfigureAwait(false);
var bannedUser =
await _dbContext.Users.SingleOrDefaultAsync(u => u.CharacterIdentification == dto.CharacterHash).ConfigureAwait(false);
if (bannedUser != null)
var bannedUser = _clientIdentService.GetUidForCharacterIdent(dto.CharacterHash);
if (!string.IsNullOrEmpty(bannedUser))
{
await Clients.User(bannedUser.UID).SendAsync(Api.OnAdminForcedReconnect).ConfigureAwait(false);
await Clients.User(bannedUser).SendAsync(Api.OnAdminForcedReconnect).ConfigureAwait(false);
}
}

View File

@@ -76,7 +76,7 @@ namespace MareSynchronosServer.Hubs
IsForbidden = forbiddenFile != null,
Hash = hash.Key,
Size = hash.Value,
Url = new Uri(cdnFullUri, hash.Key.ToUpperInvariant()).ToString()
Url = new Uri(_cdnFullUri, hash.Key.ToUpperInvariant()).ToString()
});
}

View File

@@ -21,9 +21,9 @@ namespace MareSynchronosServer.Hubs
{
_logger.LogInformation("User {AuthenticatedUserId} deleted their account", AuthenticatedUserId);
string userid = AuthenticatedUserId;
var userEntry = await _dbContext.Users.SingleAsync(u => u.UID == userid).ConfigureAwait(false);
var charaIdent = _clientIdentService.GetCharacterIdentForUid(userid);
var ownPairData = await _dbContext.ClientPairs.Where(u => u.User.UID == userid).ToListAsync().ConfigureAwait(false);
var auth = await _dbContext.Auth.SingleAsync(u => u.UserUID == userid).ConfigureAwait(false);
var lodestone = await _dbContext.LodeStoneAuth.SingleOrDefaultAsync(a => a.User.UID == userid).ConfigureAwait(false);
@@ -52,7 +52,7 @@ namespace MareSynchronosServer.Hubs
{
OtherUID = userid,
IsRemoved = true
}, userEntry.CharacterIdentification).ConfigureAwait(false);
}, charaIdent).ConfigureAwait(false);
}
_mareMetrics.DecGauge(MetricsAPI.GaugePairs, ownPairData.Count + otherPairData.Count);
@@ -77,14 +77,18 @@ namespace MareSynchronosServer.Hubs
.Include(u => u.User)
.Include(u => u.OtherUser)
.Where(w => w.User.UID == ownUser.UID && !w.IsPaused)
.Where(w => !string.IsNullOrEmpty(w.OtherUser.CharacterIdentification))
//.Where(w => !string.IsNullOrEmpty(w.OtherUser.CharacterIdentification))
.Select(e => e.OtherUser).ToListAsync().ConfigureAwait(false);
var otherOnlineUsers =
otherUsers.Where(u => !string.IsNullOrEmpty(_clientIdentService.GetCharacterIdentForUid(u.UID)));
var otherEntries = await _dbContext.ClientPairs.AsNoTracking()
.Include(u => u.User)
.Where(u => otherUsers.Any(e => e == u.User) && u.OtherUser == ownUser && !u.IsPaused).ToListAsync().ConfigureAwait(false);
.Where(u => otherOnlineUsers.Any(e => e == u.User) && u.OtherUser == ownUser && !u.IsPaused)
.ToListAsync().ConfigureAwait(false);
var ownIdent = _clientIdentService.GetCharacterIdentForUid(ownUser.UID);
await Clients.Users(otherEntries.Select(e => e.User.UID)).SendAsync(Api.OnUserAddOnlinePairedPlayer, ownUser.CharacterIdentification).ConfigureAwait(false);
return otherEntries.Select(e => e.User.CharacterIdentification).Distinct().ToList();
await Clients.Users(otherEntries.Select(e => e.User.UID)).SendAsync(Api.OnUserAddOnlinePairedPlayer, ownIdent).ConfigureAwait(false);
return otherEntries.Select(e => _clientIdentService.GetCharacterIdentForUid(e.User.UID)).Distinct().ToList();
}
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
@@ -152,12 +156,14 @@ namespace MareSynchronosServer.Hubs
userToOther.UserUID == user.UID
&& !userToOther.IsPaused
&& !otherToUser.IsPaused
&& visibleCharacterIds.Contains(userToOther.OtherUser.CharacterIdentification)
select otherToUser.UserUID;
var otherEntries = await query.ToListAsync().ConfigureAwait(false);
otherEntries =
otherEntries.Where(c => !string.IsNullOrEmpty(_clientIdentService.GetCharacterIdentForUid(c))).ToList();
var ownIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
await Clients.Users(otherEntries).SendAsync(Api.OnUserReceiveCharacterData, characterCache, user.CharacterIdentification).ConfigureAwait(false);
await Clients.Users(otherEntries).SendAsync(Api.OnUserReceiveCharacterData, characterCache, ownIdent).ConfigureAwait(false);
_mareMetrics.IncCounter(MetricsAPI.CounterUserPushData);
_mareMetrics.IncCounter(MetricsAPI.CounterUserPushDataTo, otherEntries.Count);
@@ -199,6 +205,7 @@ namespace MareSynchronosServer.Hubs
}, string.Empty).ConfigureAwait(false);
if (otherEntry != null)
{
var userIdent = _clientIdentService.GetCharacterIdentForUid(user.UID);
await Clients.User(otherUser.UID).SendAsync(Api.OnUserUpdateClientPairs,
new ClientPairDto()
{
@@ -207,14 +214,15 @@ namespace MareSynchronosServer.Hubs
IsPaused = otherEntry.IsPaused,
IsPausedFromOthers = false,
IsSynced = true
}, user.CharacterIdentification).ConfigureAwait(false);
}, userIdent).ConfigureAwait(false);
if (!string.IsNullOrEmpty(otherUser.CharacterIdentification))
var otherIdent = _clientIdentService.GetCharacterIdentForUid(otherUser.UID);
if (!string.IsNullOrEmpty(otherIdent))
{
await Clients.User(user.UID)
.SendAsync(Api.OnUserAddOnlinePairedPlayer, otherUser.CharacterIdentification).ConfigureAwait(false);
.SendAsync(Api.OnUserAddOnlinePairedPlayer, otherIdent).ConfigureAwait(false);
await Clients.User(otherUser.UID)
.SendAsync(Api.OnUserAddOnlinePairedPlayer, user.CharacterIdentification).ConfigureAwait(false);
.SendAsync(Api.OnUserAddOnlinePairedPlayer, userIdent).ConfigureAwait(false);
}
}
@@ -233,8 +241,8 @@ namespace MareSynchronosServer.Hubs
pair.IsPaused = isPaused;
_dbContext.Update(pair);
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
var selfCharaIdent = (await _dbContext.Users.SingleAsync(u => u.UID == AuthenticatedUserId).ConfigureAwait(false)).CharacterIdentification;
var otherCharaIdent = (await _dbContext.Users.SingleAsync(u => u.UID == otherUserUid).ConfigureAwait(false)).CharacterIdentification;
var selfCharaIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
var otherCharaIdent = _clientIdentService.GetCharacterIdentForUid(pair.OtherUserUID);
var otherEntry = OppositeEntry(otherUserUid);
await Clients.User(AuthenticatedUserId)
@@ -282,27 +290,29 @@ namespace MareSynchronosServer.Hubs
_dbContext.ClientPairs.Remove(wl);
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
var otherEntry = OppositeEntry(uid);
var otherIdent = _clientIdentService.GetCharacterIdentForUid(otherUser.UID);
await Clients.User(sender.UID)
.SendAsync(Api.OnUserUpdateClientPairs, new ClientPairDto()
{
OtherUID = otherUser.UID,
IsRemoved = true
}, otherUser.CharacterIdentification).ConfigureAwait(false);
}, otherIdent).ConfigureAwait(false);
if (otherEntry != null)
{
if (!string.IsNullOrEmpty(otherUser.CharacterIdentification))
if (!string.IsNullOrEmpty(otherIdent))
{
var ownIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
await Clients.User(sender.UID)
.SendAsync(Api.OnUserRemoveOnlinePairedPlayer, otherUser.CharacterIdentification).ConfigureAwait(false);
.SendAsync(Api.OnUserRemoveOnlinePairedPlayer, otherIdent).ConfigureAwait(false);
await Clients.User(otherUser.UID)
.SendAsync(Api.OnUserRemoveOnlinePairedPlayer, sender.CharacterIdentification).ConfigureAwait(false);
.SendAsync(Api.OnUserRemoveOnlinePairedPlayer, ownIdent).ConfigureAwait(false);
await Clients.User(otherUser.UID).SendAsync(Api.OnUserUpdateClientPairs, new ClientPairDto()
{
OtherUID = sender.UID,
IsPaused = otherEntry.IsPaused,
IsPausedFromOthers = false,
IsSynced = false
}, sender.CharacterIdentification).ConfigureAwait(false);
}, ownIdent).ConfigureAwait(false);
}
}

View File

@@ -3,11 +3,13 @@ using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using MareSynchronos.API;
using MareSynchronosServer.Services;
using MareSynchronosShared.Authentication;
using MareSynchronosShared.Data;
using MareSynchronosShared.Metrics;
using MareSynchronosShared.Models;
using MareSynchronosShared.Protos;
using MareSynchronosShared.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.SignalR;
@@ -15,133 +17,134 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace MareSynchronosServer.Hubs
namespace MareSynchronosServer.Hubs;
public partial class MareHub : Hub
{
public partial class MareHub : Hub
private readonly MareMetrics _mareMetrics;
private readonly AuthService.AuthServiceClient _authServiceClient;
private readonly FileService.FileServiceClient _fileServiceClient;
private readonly SystemInfoService _systemInfoService;
private readonly IHttpContextAccessor _contextAccessor;
private readonly IClientIdentificationService _clientIdentService;
private readonly ILogger<MareHub> _logger;
private readonly MareDbContext _dbContext;
private readonly Uri _cdnFullUri;
public MareHub(MareMetrics mareMetrics, AuthService.AuthServiceClient authServiceClient, FileService.FileServiceClient fileServiceClient,
MareDbContext mareDbContext, ILogger<MareHub> logger, SystemInfoService systemInfoService, IConfiguration configuration, IHttpContextAccessor contextAccessor,
IClientIdentificationService clientIdentService)
{
private readonly MareMetrics _mareMetrics;
private readonly AuthService.AuthServiceClient _authServiceClient;
private readonly FileService.FileServiceClient _fileServiceClient;
private readonly SystemInfoService _systemInfoService;
private readonly IHttpContextAccessor contextAccessor;
private readonly ILogger<MareHub> _logger;
private readonly MareDbContext _dbContext;
private readonly Uri cdnFullUri;
public MareHub(MareMetrics mareMetrics, AuthService.AuthServiceClient authServiceClient, FileService.FileServiceClient fileServiceClient,
MareDbContext mareDbContext, ILogger<MareHub> logger, SystemInfoService systemInfoService, IConfiguration configuration, IHttpContextAccessor contextAccessor)
_mareMetrics = mareMetrics;
_authServiceClient = authServiceClient;
_fileServiceClient = fileServiceClient;
_systemInfoService = systemInfoService;
_cdnFullUri = new Uri(configuration.GetRequiredSection("MareSynchronos").GetValue<string>("CdnFullUrl"));
_contextAccessor = contextAccessor;
_clientIdentService = clientIdentService;
_logger = logger;
_dbContext = mareDbContext;
}
[HubMethodName(Api.InvokeHeartbeat)]
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
public async Task<ConnectionDto> Heartbeat(string characterIdentification)
{
_mareMetrics.IncCounter(MetricsAPI.CounterInitializedConnections);
var userId = Context.User!.Claims.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value;
_logger.LogInformation("Connection from {userId}, CI: {characterIdentification}", userId, characterIdentification);
await Clients.Caller.SendAsync(Api.OnUpdateSystemInfo, _systemInfoService.SystemInfoDto).ConfigureAwait(false);
var isBanned = await _dbContext.BannedUsers.AsNoTracking().AnyAsync(u => u.CharacterIdentification == characterIdentification).ConfigureAwait(false);
if (!string.IsNullOrEmpty(userId) && !isBanned && !string.IsNullOrEmpty(characterIdentification))
{
_mareMetrics = mareMetrics;
_authServiceClient = authServiceClient;
_fileServiceClient = fileServiceClient;
_systemInfoService = systemInfoService;
cdnFullUri = new Uri(configuration.GetRequiredSection("MareSynchronos").GetValue<string>("CdnFullUrl"));
this.contextAccessor = contextAccessor;
_logger = logger;
_dbContext = mareDbContext;
}
[HubMethodName(Api.InvokeHeartbeat)]
[Authorize(AuthenticationSchemes = SecretKeyGrpcAuthenticationHandler.AuthScheme)]
public async Task<ConnectionDto> Heartbeat(string characterIdentification)
{
_mareMetrics.IncCounter(MetricsAPI.CounterInitializedConnections);
var userId = Context.User!.Claims.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value;
_logger.LogInformation("Connection from {userId}, CI: {characterIdentification}", userId, characterIdentification);
await Clients.Caller.SendAsync(Api.OnUpdateSystemInfo, _systemInfoService.SystemInfoDto).ConfigureAwait(false);
var isBanned = await _dbContext.BannedUsers.AsNoTracking().AnyAsync(u => u.CharacterIdentification == characterIdentification).ConfigureAwait(false);
if (!string.IsNullOrEmpty(userId) && !isBanned && !string.IsNullOrEmpty(characterIdentification))
var user = (await _dbContext.Users.SingleAsync(u => u.UID == userId).ConfigureAwait(false));
var existingIdent = _clientIdentService.GetCharacterIdentForUid(userId);
if (!string.IsNullOrEmpty(existingIdent) && characterIdentification != existingIdent)
{
var user = (await _dbContext.Users.SingleAsync(u => u.UID == userId).ConfigureAwait(false));
if (!string.IsNullOrEmpty(user.CharacterIdentification) && characterIdentification != user.CharacterIdentification)
return new ConnectionDto()
{
return new ConnectionDto()
{
ServerVersion = Api.Version
};
}
else if (string.IsNullOrEmpty(user.CharacterIdentification))
{
_mareMetrics.IncGauge(MetricsAPI.GaugeAuthorizedConnections);
}
user.LastLoggedIn = DateTime.UtcNow;
user.CharacterIdentification = characterIdentification;
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
return new ConnectionDto
{
ServerVersion = Api.Version,
UID = string.IsNullOrEmpty(user.Alias) ? user.UID : user.Alias,
IsModerator = user.IsModerator,
IsAdmin = user.IsAdmin
ServerVersion = Api.Version
};
}
return new ConnectionDto()
user.LastLoggedIn = DateTime.UtcNow;
_clientIdentService.MarkUserOnline(user.UID, characterIdentification);
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
return new ConnectionDto
{
ServerVersion = Api.Version
ServerVersion = Api.Version,
UID = string.IsNullOrEmpty(user.Alias) ? user.UID : user.Alias,
IsModerator = user.IsModerator,
IsAdmin = user.IsAdmin
};
}
public override async Task OnConnectedAsync()
return new ConnectionDto()
{
_logger.LogInformation("Connection from {ip}", contextAccessor.GetIpAddress());
_mareMetrics.IncGauge(MetricsAPI.GaugeConnections);
await base.OnConnectedAsync().ConfigureAwait(false);
}
public override async Task OnDisconnectedAsync(Exception exception)
{
_mareMetrics.DecGauge(MetricsAPI.GaugeConnections);
var user = await _dbContext.Users.SingleOrDefaultAsync(u => u.UID == AuthenticatedUserId).ConfigureAwait(false);
if (user != null && !string.IsNullOrEmpty(user.CharacterIdentification))
{
_mareMetrics.DecGauge(MetricsAPI.GaugeAuthorizedConnections);
_logger.LogInformation("Disconnect from {id}", AuthenticatedUserId);
var query =
from userToOther in _dbContext.ClientPairs
join otherToUser in _dbContext.ClientPairs
on new
{
user = userToOther.UserUID,
other = userToOther.OtherUserUID
} equals new
{
user = otherToUser.OtherUserUID,
other = otherToUser.UserUID
}
where
userToOther.UserUID == user.UID
&& !userToOther.IsPaused
&& !otherToUser.IsPaused
select otherToUser.UserUID;
var otherEntries = await query.ToListAsync().ConfigureAwait(false);
await Clients.Users(otherEntries).SendAsync(Api.OnUserRemoveOnlinePairedPlayer, user.CharacterIdentification).ConfigureAwait(false);
_dbContext.RemoveRange(_dbContext.Files.Where(f => !f.Uploaded && f.UploaderUID == user.UID));
user.CharacterIdentification = null;
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
}
await base.OnDisconnectedAsync(exception).ConfigureAwait(false);
}
protected string AuthenticatedUserId => Context.User?.Claims?.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value ?? "Unknown";
protected async Task<User> GetAuthenticatedUserUntrackedAsync()
{
return await _dbContext.Users.AsNoTrackingWithIdentityResolution().SingleAsync(u => u.UID == AuthenticatedUserId).ConfigureAwait(false);
}
ServerVersion = Api.Version
};
}
}
public override async Task OnConnectedAsync()
{
_logger.LogInformation("Connection from {ip}", _contextAccessor.GetIpAddress());
_mareMetrics.IncGauge(MetricsAPI.GaugeConnections);
await base.OnConnectedAsync().ConfigureAwait(false);
}
public override async Task OnDisconnectedAsync(Exception exception)
{
_mareMetrics.DecGauge(MetricsAPI.GaugeConnections);
var userCharaIdent = _clientIdentService.GetCharacterIdentForUid(AuthenticatedUserId);
if (!string.IsNullOrEmpty(userCharaIdent))
{
var user = await _dbContext.Users.SingleOrDefaultAsync(u => u.UID == AuthenticatedUserId)!.ConfigureAwait(false);
_mareMetrics.DecGauge(MetricsAPI.GaugeAuthorizedConnections);
_logger.LogInformation("Disconnect from {id}", AuthenticatedUserId);
var query =
from userToOther in _dbContext.ClientPairs
join otherToUser in _dbContext.ClientPairs
on new
{
user = userToOther.UserUID,
other = userToOther.OtherUserUID
} equals new
{
user = otherToUser.OtherUserUID,
other = otherToUser.UserUID
}
where
userToOther.UserUID == user.UID
&& !userToOther.IsPaused
&& !otherToUser.IsPaused
select otherToUser.UserUID;
var otherEntries = await query.ToListAsync().ConfigureAwait(false);
await Clients.Users(otherEntries).SendAsync(Api.OnUserRemoveOnlinePairedPlayer, userCharaIdent).ConfigureAwait(false);
_dbContext.RemoveRange(_dbContext.Files.Where(f => !f.Uploaded && f.UploaderUID == user.UID));
_clientIdentService.MarkUserOffline(user.UID);
await _dbContext.SaveChangesAsync().ConfigureAwait(false);
}
await base.OnDisconnectedAsync(exception).ConfigureAwait(false);
}
protected string AuthenticatedUserId => Context.User?.Claims?.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value ?? "Unknown";
protected async Task<User> GetAuthenticatedUserUntrackedAsync()
{
return await _dbContext.Users.AsNoTrackingWithIdentityResolution().SingleAsync(u => u.UID == AuthenticatedUserId).ConfigureAwait(false);
}
}