lightfinder config, securing methods with stricter checking and added pair request notifications
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace LightlessSyncServer.Configuration;
|
||||
|
||||
public class BroadcastConfiguration : IBroadcastConfiguration
|
||||
{
|
||||
private static readonly TimeSpan DefaultEntryTtl = TimeSpan.FromMinutes(5);
|
||||
private const int DefaultMaxStatusBatchSize = 30;
|
||||
private const string DefaultNotificationTemplate = "{DisplayName} sent you a pair request. To accept, right-click them, open the context menu, and send a request back.";
|
||||
|
||||
private readonly IOptionsMonitor<BroadcastOptions> _optionsMonitor;
|
||||
|
||||
public BroadcastConfiguration(IOptionsMonitor<BroadcastOptions> optionsMonitor)
|
||||
{
|
||||
_optionsMonitor = optionsMonitor;
|
||||
}
|
||||
|
||||
private BroadcastOptions Options => _optionsMonitor.CurrentValue ?? new BroadcastOptions();
|
||||
|
||||
public string RedisKeyPrefix
|
||||
{
|
||||
get
|
||||
{
|
||||
var prefix = Options.RedisKeyPrefix;
|
||||
return string.IsNullOrWhiteSpace(prefix) ? "broadcast:" : prefix!;
|
||||
}
|
||||
}
|
||||
|
||||
public TimeSpan BroadcastEntryTtl
|
||||
{
|
||||
get
|
||||
{
|
||||
var seconds = Options.EntryTtlSeconds;
|
||||
return seconds > 0 ? TimeSpan.FromSeconds(seconds) : DefaultEntryTtl;
|
||||
}
|
||||
}
|
||||
|
||||
public int MaxStatusBatchSize
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = Options.MaxStatusBatchSize;
|
||||
return value > 0 ? value : DefaultMaxStatusBatchSize;
|
||||
}
|
||||
}
|
||||
|
||||
public bool NotifyOwnerOnPairRequest => Options.NotifyOwnerOnPairRequest;
|
||||
|
||||
public bool EnableBroadcasting => Options.EnableBroadcasting;
|
||||
|
||||
public bool EnableSyncshellBroadcastPayloads => Options.EnableSyncshellBroadcastPayloads;
|
||||
|
||||
public string BuildRedisKey(string hashedCid)
|
||||
{
|
||||
if (string.IsNullOrEmpty(hashedCid))
|
||||
return RedisKeyPrefix;
|
||||
|
||||
return string.Concat(RedisKeyPrefix, hashedCid);
|
||||
}
|
||||
|
||||
public string BuildPairRequestNotification(string displayName)
|
||||
{
|
||||
var template = Options.PairRequestNotificationTemplate;
|
||||
if (string.IsNullOrWhiteSpace(template))
|
||||
{
|
||||
template = DefaultNotificationTemplate;
|
||||
}
|
||||
|
||||
displayName = string.IsNullOrWhiteSpace(displayName) ? "Someone" : displayName;
|
||||
|
||||
return template.Replace("{DisplayName}", displayName, StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace LightlessSyncServer.Configuration;
|
||||
|
||||
public class BroadcastOptions
|
||||
{
|
||||
[Required]
|
||||
public string RedisKeyPrefix { get; set; } = "broadcast:";
|
||||
|
||||
[Range(1, int.MaxValue)]
|
||||
public int EntryTtlSeconds { get; set; } = 300;
|
||||
|
||||
[Range(1, int.MaxValue)]
|
||||
public int MaxStatusBatchSize { get; set; } = 30;
|
||||
|
||||
public bool NotifyOwnerOnPairRequest { get; set; } = true;
|
||||
|
||||
public bool EnableBroadcasting { get; set; } = true;
|
||||
|
||||
public bool EnableSyncshellBroadcastPayloads { get; set; } = true;
|
||||
|
||||
public string PairRequestNotificationTemplate { get; set; } = "{DisplayName} sent you a pair request. To accept, right-click them, open the context menu, and send a request back.";
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace LightlessSyncServer.Configuration;
|
||||
|
||||
public interface IBroadcastConfiguration
|
||||
{
|
||||
string RedisKeyPrefix { get; }
|
||||
TimeSpan BroadcastEntryTtl { get; }
|
||||
int MaxStatusBatchSize { get; }
|
||||
bool NotifyOwnerOnPairRequest { get; }
|
||||
bool EnableBroadcasting { get; }
|
||||
bool EnableSyncshellBroadcastPayloads { get; }
|
||||
|
||||
string BuildRedisKey(string hashedCid);
|
||||
string BuildPairRequestNotification(string displayName);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using LightlessSync.API.Data;
|
||||
using LightlessSync.API.Data;
|
||||
using LightlessSync.API.Data.Enum;
|
||||
using LightlessSync.API.Data.Extensions;
|
||||
using LightlessSync.API.Dto.Group;
|
||||
@@ -925,6 +925,13 @@ public partial class LightlessHub
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_broadcastConfiguration.EnableBroadcasting || !_broadcastConfiguration.EnableSyncshellBroadcastPayloads)
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("syncshell broadcast disabled", "User", UserUID, "GID", dto.GID));
|
||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "Syncshell broadcasting is currently disabled.").ConfigureAwait(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
var (isOwner, _) = await TryValidateOwner(dto.GID).ConfigureAwait(false);
|
||||
if (!isOwner)
|
||||
{
|
||||
@@ -941,6 +948,9 @@ public partial class LightlessHub
|
||||
{
|
||||
_logger.LogCallInfo(LightlessHubLogger.Args("Requested Syncshells", broadcastEntries.Select(b => b.GID)));
|
||||
|
||||
if (!_broadcastConfiguration.EnableBroadcasting || !_broadcastConfiguration.EnableSyncshellBroadcastPayloads)
|
||||
return new List<GroupJoinDto>();
|
||||
|
||||
var results = new List<GroupJoinDto>();
|
||||
var gidsToValidate = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
@@ -949,10 +959,19 @@ public partial class LightlessHub
|
||||
if (string.IsNullOrWhiteSpace(entry.HashedCID) || string.IsNullOrWhiteSpace(entry.GID))
|
||||
continue;
|
||||
|
||||
var redisKey = $"broadcast:{entry.HashedCID}";
|
||||
var redisKey = _broadcastConfiguration.BuildRedisKey(entry.HashedCID);
|
||||
var redisEntry = await _redis.GetAsync<BroadcastRedisEntry>(redisKey).ConfigureAwait(false);
|
||||
|
||||
if (redisEntry?.GID != null && string.Equals(redisEntry.GID, entry.GID, StringComparison.OrdinalIgnoreCase))
|
||||
if (redisEntry is null)
|
||||
continue;
|
||||
|
||||
if (!string.IsNullOrEmpty(redisEntry.HashedCID) && !string.Equals(redisEntry.HashedCID, entry.HashedCID, StringComparison.Ordinal))
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("mismatched broadcast cid for group lookup", "Requested", entry.HashedCID, "EntryCID", redisEntry.HashedCID));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (redisEntry.GID != null && string.Equals(redisEntry.GID, entry.GID, StringComparison.OrdinalIgnoreCase))
|
||||
gidsToValidate.Add(entry.GID);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,14 +4,17 @@ using LightlessSync.API.Data.Extensions;
|
||||
using LightlessSync.API.Dto.Group;
|
||||
using LightlessSync.API.Dto.User;
|
||||
using LightlessSyncServer.Utils;
|
||||
using LightlessSyncServer.Configuration;
|
||||
using LightlessSyncShared.Metrics;
|
||||
using LightlessSyncShared.Models;
|
||||
using LightlessSyncShared.Utils;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using StackExchange.Redis;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -252,9 +255,62 @@ public partial class LightlessHub
|
||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Information, $"Pair request sent. Waiting for the other player to confirm.").ConfigureAwait(false);
|
||||
|
||||
_logger.LogCallInfo(LightlessHubLogger.Args("stored pairing request", myCid, otherCid));
|
||||
await NotifyBroadcastOwnerOfPairRequest(otherCid).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async Task NotifyBroadcastOwnerOfPairRequest(string targetHashedCid)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(targetHashedCid))
|
||||
return;
|
||||
|
||||
if (!_broadcastConfiguration.EnableBroadcasting || !_broadcastConfiguration.NotifyOwnerOnPairRequest)
|
||||
return;
|
||||
|
||||
var db = _redis.Database;
|
||||
var broadcastKey = _broadcastConfiguration.BuildRedisKey(targetHashedCid);
|
||||
RedisValueWithExpiry broadcastValue;
|
||||
|
||||
try
|
||||
{
|
||||
broadcastValue = await db.StringGetWithExpiryAsync(broadcastKey).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("failed to fetch broadcast for pair notify", "CID", targetHashedCid, "Error", ex));
|
||||
return;
|
||||
}
|
||||
|
||||
if (broadcastValue.Value.IsNullOrEmpty || broadcastValue.Expiry is null || broadcastValue.Expiry <= TimeSpan.Zero)
|
||||
return;
|
||||
|
||||
BroadcastRedisEntry? entry;
|
||||
try
|
||||
{
|
||||
entry = JsonSerializer.Deserialize<BroadcastRedisEntry>(broadcastValue.Value!);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("failed to deserialize broadcast for pair notify", "CID", targetHashedCid, "Value", broadcastValue.Value, "Error", ex));
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry is null || !string.Equals(entry.HashedCID, targetHashedCid, StringComparison.Ordinal))
|
||||
return;
|
||||
|
||||
if (!entry.HasOwner())
|
||||
return;
|
||||
|
||||
if (string.Equals(entry.OwnerUID, UserUID, StringComparison.Ordinal))
|
||||
return;
|
||||
|
||||
var senderAlias = Context.User?.Claims?.SingleOrDefault(c => string.Equals(c.Type, LightlessClaimTypes.Alias, StringComparison.Ordinal))?.Value;
|
||||
var displayName = string.IsNullOrWhiteSpace(senderAlias) ? UserUID : senderAlias;
|
||||
var message = _broadcastConfiguration.BuildPairRequestNotification(displayName);
|
||||
|
||||
await Clients.User(entry.OwnerUID).Client_ReceiveServerMessage(MessageSeverity.Information, message).ConfigureAwait(false);
|
||||
}
|
||||
private class PairingPayload
|
||||
{
|
||||
public string UID { get; set; } = string.Empty;
|
||||
@@ -264,14 +320,26 @@ public partial class LightlessHub
|
||||
public class BroadcastRedisEntry
|
||||
{
|
||||
public string HashedCID { get; set; } = string.Empty;
|
||||
public string OwnerUID { get; set; } = string.Empty;
|
||||
public string? GID { get; set; }
|
||||
|
||||
public bool OwnedBy(string userUid) => !string.IsNullOrEmpty(userUid) && string.Equals(OwnerUID, userUid, StringComparison.Ordinal);
|
||||
|
||||
public bool HasOwner() => !string.IsNullOrEmpty(OwnerUID);
|
||||
}
|
||||
|
||||
[Authorize(Policy = "Identified")]
|
||||
public async Task SetBroadcastStatus(string hashedCid, bool enabled, GroupBroadcastRequestDto? groupDto = null)
|
||||
{
|
||||
if (enabled && !_broadcastConfiguration.EnableBroadcasting)
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("broadcast disabled", UserUID, "CID", hashedCid));
|
||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "Broadcasting is currently disabled.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var db = _redis.Database;
|
||||
var broadcastKey = $"broadcast:{hashedCid}";
|
||||
var broadcastKey = _broadcastConfiguration.BuildRedisKey(hashedCid);
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
@@ -279,6 +347,13 @@ public partial class LightlessHub
|
||||
|
||||
if (groupDto is not null)
|
||||
{
|
||||
if (!_broadcastConfiguration.EnableSyncshellBroadcastPayloads)
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("syncshell broadcast disabled", UserUID, "CID", hashedCid, "GID", groupDto.GID));
|
||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "Syncshell broadcasting is currently disabled.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
groupDto.HashedCID = hashedCid;
|
||||
|
||||
var valid = await SetGroupBroadcastStatus(groupDto).ConfigureAwait(false);
|
||||
@@ -288,14 +363,36 @@ public partial class LightlessHub
|
||||
gid = groupDto.GID;
|
||||
}
|
||||
|
||||
BroadcastRedisEntry? existingEntry = null;
|
||||
var existingValue = await db.StringGetAsync(broadcastKey).ConfigureAwait(false);
|
||||
if (!existingValue.IsNullOrEmpty)
|
||||
{
|
||||
try
|
||||
{
|
||||
existingEntry = JsonSerializer.Deserialize<BroadcastRedisEntry>(existingValue!);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("failed to deserialize broadcast entry during enable", "CID", hashedCid, "Value", existingValue, "Error", ex));
|
||||
}
|
||||
|
||||
if (existingEntry is not null && existingEntry.HasOwner() && !existingEntry.OwnedBy(UserUID))
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("unauthorized attempt to take broadcast ownership", UserUID, "CID", hashedCid, "ExistingOwner", existingEntry.OwnerUID));
|
||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "Another user is already broadcasting with that CID.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var entry = new BroadcastRedisEntry
|
||||
{
|
||||
HashedCID = hashedCid,
|
||||
OwnerUID = UserUID,
|
||||
GID = gid,
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(entry);
|
||||
await db.StringSetAsync(broadcastKey, json, TimeSpan.FromMinutes(5)).ConfigureAwait(false);
|
||||
await db.StringSetAsync(broadcastKey, json, _broadcastConfiguration.BroadcastEntryTtl).ConfigureAwait(false);
|
||||
_logger.LogCallInfo(LightlessHubLogger.Args("broadcast enabled", hashedCid, "GID", gid));
|
||||
}
|
||||
else
|
||||
@@ -315,13 +412,20 @@ public partial class LightlessHub
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry is null || entry.HashedCID != hashedCid)
|
||||
if (entry is null || !string.Equals(entry.HashedCID, hashedCid, StringComparison.Ordinal))
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("unauthorized attempt to remove broadcast", UserUID, "CID", hashedCid, "Stored", entry?.HashedCID));
|
||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "You can only disable your own broadcast. :3");
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry.HasOwner() && !entry.OwnedBy(UserUID))
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("unauthorized attempt to remove broadcast", UserUID, "CID", hashedCid, "Owner", entry.OwnerUID));
|
||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "You can only disable your own broadcast. :3");
|
||||
return;
|
||||
}
|
||||
|
||||
await db.KeyDeleteAsync(broadcastKey).ConfigureAwait(false);
|
||||
_logger.LogCallInfo(LightlessHubLogger.Args("broadcast disabled", hashedCid, "GID", entry.GID));
|
||||
}
|
||||
@@ -331,8 +435,11 @@ public partial class LightlessHub
|
||||
[Authorize(Policy = "Identified")]
|
||||
public async Task<BroadcastStatusInfoDto?> IsUserBroadcasting(string hashedCid)
|
||||
{
|
||||
if (!_broadcastConfiguration.EnableBroadcasting)
|
||||
return null;
|
||||
|
||||
var db = _redis.Database;
|
||||
var key = $"broadcast:{hashedCid}";
|
||||
var key = _broadcastConfiguration.BuildRedisKey(hashedCid);
|
||||
|
||||
var result = await db.StringGetWithExpiryAsync(key).ConfigureAwait(false);
|
||||
if (result.Expiry is null || result.Expiry <= TimeSpan.Zero || result.Value.IsNullOrEmpty)
|
||||
@@ -348,6 +455,12 @@ public partial class LightlessHub
|
||||
return null;
|
||||
}
|
||||
|
||||
if (entry is not null && !string.Equals(entry.HashedCID, hashedCid, StringComparison.Ordinal))
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("mismatched broadcast entry", "CID", hashedCid, "EntryCID", entry.HashedCID));
|
||||
return null;
|
||||
}
|
||||
|
||||
var dto = new BroadcastStatusInfoDto
|
||||
{
|
||||
HashedCID = entry?.HashedCID ?? hashedCid,
|
||||
@@ -363,8 +476,11 @@ public partial class LightlessHub
|
||||
[Authorize(Policy = "Identified")]
|
||||
public async Task<TimeSpan?> GetBroadcastTtl(string hashedCid)
|
||||
{
|
||||
if (!_broadcastConfiguration.EnableBroadcasting)
|
||||
return null;
|
||||
|
||||
var db = _redis.Database;
|
||||
var key = $"broadcast:{hashedCid}";
|
||||
var key = _broadcastConfiguration.BuildRedisKey(hashedCid);
|
||||
|
||||
var value = await db.StringGetAsync(key).ConfigureAwait(false);
|
||||
if (value.IsNullOrEmpty)
|
||||
@@ -381,9 +497,21 @@ public partial class LightlessHub
|
||||
return null;
|
||||
}
|
||||
|
||||
if (entry?.HashedCID != hashedCid)
|
||||
if (entry is null)
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("unauthorized ttl query", UserUID, "CID", hashedCid, "EntryCID", entry?.HashedCID));
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("missing broadcast entry during ttl query", "CID", hashedCid));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!string.Equals(entry.HashedCID, hashedCid, StringComparison.Ordinal))
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("unauthorized ttl query", UserUID, "CID", hashedCid, "EntryCID", entry.HashedCID));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (entry.HasOwner() && !entry.OwnedBy(UserUID))
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("unauthorized ttl query", UserUID, "CID", hashedCid, "Owner", entry.OwnerUID));
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -396,19 +524,25 @@ public partial class LightlessHub
|
||||
}
|
||||
|
||||
|
||||
private const int MaxBatchSize = 30;
|
||||
|
||||
[Authorize(Policy = "Identified")]
|
||||
public async Task<BroadcastStatusBatchDto> AreUsersBroadcasting(List<string> hashedCids)
|
||||
public async Task<BroadcastStatusBatchDto?> AreUsersBroadcasting(List<string> hashedCids)
|
||||
{
|
||||
if (!_broadcastConfiguration.EnableBroadcasting)
|
||||
{
|
||||
_logger.LogCallInfo(LightlessHubLogger.Args("batch broadcast disabled", "Count", hashedCids.Count));
|
||||
return null;
|
||||
}
|
||||
|
||||
var maxBatchSize = _broadcastConfiguration.MaxStatusBatchSize;
|
||||
if (hashedCids.Count > maxBatchSize)
|
||||
hashedCids = hashedCids.Take(maxBatchSize).ToList();
|
||||
|
||||
var db = _redis.Database;
|
||||
if (hashedCids.Count > MaxBatchSize)
|
||||
hashedCids = hashedCids.Take(MaxBatchSize).ToList();
|
||||
|
||||
var tasks = new Dictionary<string, Task<RedisValueWithExpiry>>(hashedCids.Count);
|
||||
foreach (var cid in hashedCids)
|
||||
{
|
||||
var key = $"broadcast:{cid}";
|
||||
var key = _broadcastConfiguration.BuildRedisKey(cid);
|
||||
tasks[cid] = db.StringGetWithExpiryAsync(key);
|
||||
}
|
||||
|
||||
@@ -433,7 +567,17 @@ public partial class LightlessHub
|
||||
try
|
||||
{
|
||||
entry = JsonSerializer.Deserialize<BroadcastRedisEntry>(raw!);
|
||||
gid = entry?.GID;
|
||||
if (entry is not null && !string.Equals(entry.HashedCID, cid, StringComparison.Ordinal))
|
||||
{
|
||||
_logger.LogCallWarning(LightlessHubLogger.Args("mismatched broadcast cid in batch", "Requested", cid, "EntryCID", entry.HashedCID));
|
||||
entry = null;
|
||||
gid = null;
|
||||
isBroadcasting = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
gid = entry?.GID;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using LightlessSync.API.Data;
|
||||
using LightlessSync.API.Data;
|
||||
using LightlessSync.API.Data.Enum;
|
||||
using LightlessSync.API.Dto;
|
||||
using LightlessSync.API.SignalR;
|
||||
using LightlessSyncServer.Services;
|
||||
using LightlessSyncServer.Configuration;
|
||||
using LightlessSyncServer.Utils;
|
||||
using LightlessSyncShared;
|
||||
using LightlessSyncShared.Data;
|
||||
@@ -29,6 +30,7 @@ public partial class LightlessHub : Hub<ILightlessHub>, ILightlessHub
|
||||
private readonly LightlessHubLogger _logger;
|
||||
private readonly string _shardName;
|
||||
private readonly int _maxExistingGroupsByUser;
|
||||
private readonly IBroadcastConfiguration _broadcastConfiguration;
|
||||
private readonly int _maxJoinedGroupsByUser;
|
||||
private readonly int _maxGroupUserCount;
|
||||
private readonly IRedisDatabase _redis;
|
||||
@@ -46,7 +48,7 @@ public partial class LightlessHub : Hub<ILightlessHub>, ILightlessHub
|
||||
IDbContextFactory<LightlessDbContext> lightlessDbContextFactory, ILogger<LightlessHub> logger, SystemInfoService systemInfoService,
|
||||
IConfigurationService<ServerConfiguration> configuration, IHttpContextAccessor contextAccessor,
|
||||
IRedisDatabase redisDb, OnlineSyncedPairCacheService onlineSyncedPairCacheService, LightlessCensus lightlessCensus,
|
||||
GPoseLobbyDistributionService gPoseLobbyDistributionService, PairService pairService)
|
||||
GPoseLobbyDistributionService gPoseLobbyDistributionService, IBroadcastConfiguration broadcastConfiguration, PairService pairService)
|
||||
{
|
||||
_lightlessMetrics = lightlessMetrics;
|
||||
_systemInfoService = systemInfoService;
|
||||
@@ -65,6 +67,7 @@ public partial class LightlessHub : Hub<ILightlessHub>, ILightlessHub
|
||||
_gPoseLobbyDistributionService = gPoseLobbyDistributionService;
|
||||
_logger = new LightlessHubLogger(this, logger);
|
||||
_dbContextLazy = new Lazy<LightlessDbContext>(() => lightlessDbContextFactory.CreateDbContext());
|
||||
_broadcastConfiguration = broadcastConfiguration;
|
||||
_pairService = pairService;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ using AspNetCoreRateLimit;
|
||||
using LightlessSync.API.SignalR;
|
||||
using LightlessSyncAuthService.Controllers;
|
||||
using LightlessSyncServer.Controllers;
|
||||
using LightlessSyncServer.Configuration;
|
||||
using LightlessSyncServer.Hubs;
|
||||
using LightlessSyncServer.Services;
|
||||
using LightlessSyncShared.Data;
|
||||
@@ -87,7 +88,9 @@ public class Startup
|
||||
|
||||
services.Configure<ServerConfiguration>(Configuration.GetRequiredSection("LightlessSync"));
|
||||
services.Configure<LightlessConfigurationBase>(Configuration.GetRequiredSection("LightlessSync"));
|
||||
services.Configure<BroadcastOptions>(Configuration.GetSection("Broadcast"));
|
||||
|
||||
services.AddSingleton<IBroadcastConfiguration, BroadcastConfiguration>();
|
||||
services.AddSingleton<ServerTokenGenerator>();
|
||||
services.AddSingleton<SystemInfoService>();
|
||||
services.AddSingleton<OnlineSyncedPairCacheService>();
|
||||
|
||||
@@ -29,6 +29,15 @@
|
||||
"ServiceAddress": "http://localhost:5002",
|
||||
"StaticFileServiceAddress": "http://localhost:5003"
|
||||
},
|
||||
"Broadcast": {
|
||||
"RedisKeyPrefix": "broadcast:",
|
||||
"EntryTtlSeconds": 10800,
|
||||
"MaxStatusBatchSize": 30,
|
||||
"NotifyOwnerOnPairRequest": true,
|
||||
"EnableBroadcasting": true,
|
||||
"EnableSyncshellBroadcastPayloads": true,
|
||||
"PairRequestNotificationTemplate": "{DisplayName} sent you a pair request. To accept, right-click them, open the context menu, and send a request back."
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Kestrel": {
|
||||
"Endpoints": {
|
||||
|
||||
Reference in New Issue
Block a user