validate incoming cid's

This commit is contained in:
azyges
2025-10-01 08:41:56 +09:00
parent ed13ee8921
commit d2dabddeb7
4 changed files with 54 additions and 8 deletions

View File

@@ -5,7 +5,7 @@ namespace LightlessSyncServer.Configuration;
public class BroadcastConfiguration : IBroadcastConfiguration public class BroadcastConfiguration : IBroadcastConfiguration
{ {
private static readonly TimeSpan DefaultEntryTtl = TimeSpan.FromMinutes(5); private static readonly TimeSpan DefaultEntryTtl = TimeSpan.FromMinutes(180);
private const int DefaultMaxStatusBatchSize = 30; 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 const string DefaultNotificationTemplate = "{DisplayName} sent you a pair request. To accept, right-click them, open the context menu, and send a request back.";

View File

@@ -8,7 +8,7 @@ public class BroadcastOptions
public string RedisKeyPrefix { get; set; } = "broadcast:"; public string RedisKeyPrefix { get; set; } = "broadcast:";
[Range(1, int.MaxValue)] [Range(1, int.MaxValue)]
public int EntryTtlSeconds { get; set; } = 300; public int EntryTtlSeconds { get; set; } = 10800;
[Range(1, int.MaxValue)] [Range(1, int.MaxValue)]
public int MaxStatusBatchSize { get; set; } = 30; public int MaxStatusBatchSize { get; set; } = 30;

View File

@@ -371,11 +371,6 @@ public partial class LightlessHub
return new GroupJoinInfoDto(group.ToGroupData(), group.Owner.ToUserData(), group.ToEnum(), true); return new GroupJoinInfoDto(group.ToGroupData(), group.Owner.ToUserData(), group.ToEnum(), true);
} }
private static bool IsHex(char c) =>
(c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F');
[Authorize(Policy = "Identified")] [Authorize(Policy = "Identified")]
public async Task<bool> GroupJoinFinalize(GroupJoinDto dto) public async Task<bool> GroupJoinFinalize(GroupJoinDto dto)
{ {
@@ -386,7 +381,7 @@ public partial class LightlessHub
var group = await DbContext.Groups.Include(g => g.Owner).AsNoTracking().SingleOrDefaultAsync(g => g.GID == aliasOrGid || g.Alias == aliasOrGid, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false); var group = await DbContext.Groups.Include(g => g.Owner).AsNoTracking().SingleOrDefaultAsync(g => g.GID == aliasOrGid || g.Alias == aliasOrGid, cancellationToken: _contextAccessor.HttpContext.RequestAborted).ConfigureAwait(false);
var groupGid = group?.GID ?? string.Empty; var groupGid = group?.GID ?? string.Empty;
var existingPair = await DbContext.GroupPairs.AsNoTracking().SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.GroupUserUID == UserUID).ConfigureAwait(false); var existingPair = await DbContext.GroupPairs.AsNoTracking().SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.GroupUserUID == UserUID).ConfigureAwait(false);
var isHashedPassword = dto.Password.Length == 64 && dto.Password.All(IsHex); var isHashedPassword = dto.Password.Length == 64 && dto.Password.All(Uri.IsHexDigit);
var hashedPw = isHashedPassword var hashedPw = isHashedPassword
? dto.Password ? dto.Password
: StringUtils.Sha256String(dto.Password); : StringUtils.Sha256String(dto.Password);

View File

@@ -148,6 +148,13 @@ public partial class LightlessHub
if (string.IsNullOrWhiteSpace(otherCid) || string.IsNullOrWhiteSpace(myCid)) if (string.IsNullOrWhiteSpace(otherCid) || string.IsNullOrWhiteSpace(myCid))
return; return;
bool IsValidCid(string cid) => cid.Length == 64 && cid.All(Uri.IsHexDigit) && !cid.All(c => c == '0');
if (!IsValidCid(myCid) || !IsValidCid(otherCid))
{
return;
}
if (string.Equals(otherCid, myCid, StringComparison.Ordinal)) if (string.Equals(otherCid, myCid, StringComparison.Ordinal))
{ {
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, "You can't pair with yourself.").ConfigureAwait(false); await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Warning, "You can't pair with yourself.").ConfigureAwait(false);
@@ -338,6 +345,18 @@ public partial class LightlessHub
return; return;
} }
if (string.IsNullOrWhiteSpace(hashedCid) || hashedCid.Length != 64 || !hashedCid.All(c => Uri.IsHexDigit(c)))
{
_logger.LogCallWarning(LightlessHubLogger.Args("invalid cid format", UserUID, "CID", hashedCid));
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "Invalid CID format.").ConfigureAwait(false);
return;
}
if (hashedCid.All(c => c == '0'))
{
return;
}
var db = _redis.Database; var db = _redis.Database;
var broadcastKey = _broadcastConfiguration.BuildRedisKey(hashedCid); var broadcastKey = _broadcastConfiguration.BuildRedisKey(hashedCid);
@@ -438,6 +457,18 @@ public partial class LightlessHub
if (!_broadcastConfiguration.EnableBroadcasting) if (!_broadcastConfiguration.EnableBroadcasting)
return null; return null;
if (string.IsNullOrWhiteSpace(hashedCid) || hashedCid.Length != 64 || !hashedCid.All(c => Uri.IsHexDigit(c)))
{
_logger.LogCallWarning(LightlessHubLogger.Args("invalid cid format", UserUID, "CID", hashedCid));
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "Invalid CID format.").ConfigureAwait(false);
return null;
}
if (hashedCid.All(c => c == '0'))
{
return null;
}
var db = _redis.Database; var db = _redis.Database;
var key = _broadcastConfiguration.BuildRedisKey(hashedCid); var key = _broadcastConfiguration.BuildRedisKey(hashedCid);
@@ -479,6 +510,18 @@ public partial class LightlessHub
if (!_broadcastConfiguration.EnableBroadcasting) if (!_broadcastConfiguration.EnableBroadcasting)
return null; return null;
if (string.IsNullOrWhiteSpace(hashedCid) || hashedCid.Length != 64 || !hashedCid.All(c => Uri.IsHexDigit(c)))
{
_logger.LogCallWarning(LightlessHubLogger.Args("invalid cid format", UserUID, "CID", hashedCid));
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "Invalid CID format.").ConfigureAwait(false);
return null;
}
if (hashedCid.All(c => c == '0'))
{
return null;
}
var db = _redis.Database; var db = _redis.Database;
var key = _broadcastConfiguration.BuildRedisKey(hashedCid); var key = _broadcastConfiguration.BuildRedisKey(hashedCid);
@@ -542,6 +585,14 @@ public partial class LightlessHub
var tasks = new Dictionary<string, Task<RedisValueWithExpiry>>(hashedCids.Count); var tasks = new Dictionary<string, Task<RedisValueWithExpiry>>(hashedCids.Count);
foreach (var cid in hashedCids) foreach (var cid in hashedCids)
{ {
bool validHash = !string.IsNullOrWhiteSpace(cid) && cid.Length == 64 && cid.All(Uri.IsHexDigit) && !cid.All(c => c == '0');
if (!validHash)
{
tasks[cid] = Task.FromResult(new RedisValueWithExpiry(RedisValue.Null, null));
continue;
}
var key = _broadcastConfiguration.BuildRedisKey(cid); var key = _broadcastConfiguration.BuildRedisKey(cid);
tasks[cid] = db.StringGetWithExpiryAsync(key); tasks[cid] = db.StringGetWithExpiryAsync(key);
} }