mirror of
https://github.com/JogmansonReal/Radicade.git
synced 2026-10-26 23:49:02 -07:00
Radicade Public Code
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace RadicadeServer.Utils
|
||||
{
|
||||
public static class BuildInfo
|
||||
{
|
||||
public const string Tag = "notify-ids-numeric-string";
|
||||
|
||||
public const string NotifyIdFormat = "numeric-string";
|
||||
|
||||
public static readonly DateTime StartedUtc = DateTime.UtcNow;
|
||||
|
||||
public static DateTime? AssemblyBuiltUtc
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
var location = Assembly.GetEntryAssembly()?.Location;
|
||||
return string.IsNullOrEmpty(location) || !File.Exists(location)
|
||||
? null
|
||||
: File.GetLastWriteTimeUtc(location);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string Describe()
|
||||
=> $"{Tag}: notify ids are sent as the client enum's NUMBER in a JSON string (MessageReceived=\"2\", ModerationKick=\"22\", RefreshLogin=\"5\") - " +
|
||||
"never a bare number (the client cannot parse it) and never a name (it parses and matches no handler). " +
|
||||
$"Started {StartedUtc:u} from an assembly published {AssemblyBuiltUtc?.ToString("u") ?? "unknown"}. " +
|
||||
"If this line is missing, or the publish time is older than your deploy, the running server is not the build you just made.";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
using System.Text;
|
||||
using RadicadeServer.RecNet.Enums;
|
||||
using RadicadeServer.RecNet;
|
||||
using System.Buffers.Text;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace RadicadeServer.Utils
|
||||
{
|
||||
public static class StringTools
|
||||
{
|
||||
public static string AltGuid(this Guid guid)
|
||||
{
|
||||
return guid.ToString().Replace("-", "");
|
||||
}
|
||||
|
||||
public static string FromAES(this string encrypted, string? b64Key, string? b64IV)
|
||||
{
|
||||
if (string.IsNullOrEmpty(b64Key)) return "";
|
||||
if (string.IsNullOrEmpty(b64IV)) return "";
|
||||
|
||||
try
|
||||
{
|
||||
byte[] cipherBytes = Convert.FromBase64String(encrypted);
|
||||
byte[] keyBytes = Convert.FromBase64String(b64Key);
|
||||
byte[] ivBytes = Convert.FromBase64String(b64IV);
|
||||
|
||||
using (Aes aes = Aes.Create())
|
||||
{
|
||||
aes.KeySize = 128;
|
||||
aes.BlockSize = 128;
|
||||
aes.Key = keyBytes;
|
||||
aes.IV = ivBytes;
|
||||
aes.Mode = CipherMode.CBC;
|
||||
aes.Padding = PaddingMode.PKCS7;
|
||||
|
||||
using (MemoryStream ms = new MemoryStream(cipherBytes))
|
||||
using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Read))
|
||||
using (StreamReader sr = new StreamReader(cs, Encoding.UTF8))
|
||||
{
|
||||
return sr.ReadToEnd();
|
||||
}
|
||||
}
|
||||
} catch
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static List<CardBoxWord> ParseCardBoxWords(this string req)
|
||||
{
|
||||
var split = req.Split(';', StringSplitOptions.TrimEntries);
|
||||
var words = new List<CardBoxWord>();
|
||||
|
||||
foreach (var word in split)
|
||||
{
|
||||
words.Add(new CardBoxWord { Difficulty = CardDifficulty.CharadesEasy, EN_US = word });
|
||||
}
|
||||
|
||||
return words;
|
||||
}
|
||||
|
||||
public static string CreateTagString(List<ItemTag>? Tags)
|
||||
{
|
||||
if (Tags == null)
|
||||
return "";
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
foreach (ItemTag itemTag in Tags)
|
||||
{
|
||||
stringBuilder.Append(itemTag.Tag.ToString() + "," + ((int)itemTag.Type).ToString() + "|");
|
||||
}
|
||||
return stringBuilder.ToString().TrimEnd('|');
|
||||
}
|
||||
|
||||
public static string CreateTagString(string[]? Tags)
|
||||
{
|
||||
if (Tags == null)
|
||||
return "";
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
foreach (string itemTag in Tags)
|
||||
{
|
||||
stringBuilder.Append(itemTag.ToString() + "," + ((int)TagType.General).ToString() + "|");
|
||||
}
|
||||
return stringBuilder.ToString().TrimEnd('|');
|
||||
}
|
||||
|
||||
public static List<ItemTag> ReadTags(string Tags)
|
||||
{
|
||||
List<ItemTag> list = new List<ItemTag>();
|
||||
if (string.IsNullOrWhiteSpace(Tags)) return list;
|
||||
string[] tags = Tags.Split("|", StringSplitOptions.None);
|
||||
foreach (string text in tags)
|
||||
{
|
||||
string[] array3 = text.Split(",", StringSplitOptions.None);
|
||||
if (array3.Length != 2) continue;
|
||||
if (!int.TryParse(array3[1], out var typeValue) || !Enum.IsDefined(typeof(TagType), typeValue))
|
||||
continue;
|
||||
list.Add(new ItemTag
|
||||
{
|
||||
Tag = array3[0],
|
||||
Type = (TagType)typeValue
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<string> TagsToStrings(List<ItemTag> Tags)
|
||||
{
|
||||
List<string> list = new List<string>();
|
||||
foreach (var tag in Tags)
|
||||
{
|
||||
list.Add(tag.Tag);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static string ToBase64(this string str)
|
||||
{
|
||||
var bytes = System.Text.Encoding.UTF8.GetBytes(str);
|
||||
var b64 = Convert.ToBase64String(bytes);
|
||||
return b64;
|
||||
}
|
||||
|
||||
|
||||
private static string[] BlacklistedWords = {
|
||||
"nigger",
|
||||
"nigga",
|
||||
"faggot",
|
||||
"fag",
|
||||
"nigg",
|
||||
};
|
||||
private static string[] BlacklistedTags = {
|
||||
"rro",
|
||||
"featured"
|
||||
};
|
||||
|
||||
public static string Sanitize(this string str)
|
||||
{
|
||||
foreach (var tag in BlacklistedWords)
|
||||
{
|
||||
str = Regex.Replace(str, tag, "****", RegexOptions.IgnoreCase);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
public static bool IsPure(this string str)
|
||||
{
|
||||
if (string.IsNullOrEmpty(str)) return true;
|
||||
|
||||
foreach (var tag in BlacklistedWords)
|
||||
{
|
||||
if (Regex.IsMatch(str, tag, RegexOptions.IgnoreCase))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public static bool TagAllowed(this string str)
|
||||
{
|
||||
foreach (var tag in BlacklistedTags) {
|
||||
if (Regex.IsMatch(tag, str))
|
||||
return false;
|
||||
}
|
||||
return str.IsPure();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using RadicadeServer.API.Notifications;
|
||||
using RadicadeServer.DB;
|
||||
using RadicadeServer.RecNet.Enums.Messages;
|
||||
using RadicadeServer.RecNet.Enums.Moderation;
|
||||
using RadicadeServer.RecNet.Messages;
|
||||
using RadicadeServer.RecNet.Moderation;
|
||||
using RadicadeServer.RecNet.Notifications;
|
||||
|
||||
namespace RadicadeServer.Utils
|
||||
{
|
||||
public static class VoiceChatRestrictions
|
||||
{
|
||||
public const string NotificationId = "VoiceChatRestriction";
|
||||
|
||||
public const string Method = "Voice Restriction";
|
||||
|
||||
public const long CoachAccountId = 1;
|
||||
|
||||
public const string CoachMessage =
|
||||
"You have had your voice privileges temporarily restricted due to speech which violates the Code of Conduct.";
|
||||
|
||||
public static readonly TimeSpan DefaultDuration = TimeSpan.FromHours(24);
|
||||
|
||||
public static readonly TimeSpan MinimumDuration = TimeSpan.FromHours(1);
|
||||
|
||||
public static readonly TimeSpan MaximumDuration = TimeSpan.FromDays(30);
|
||||
|
||||
public static TimeSpan ClampDuration(TimeSpan duration)
|
||||
{
|
||||
if (duration < MinimumDuration) return MinimumDuration;
|
||||
if (duration > MaximumDuration) return MaximumDuration;
|
||||
return duration;
|
||||
}
|
||||
|
||||
public static Task<VoiceChatRestriction?> ActiveAsync(RecDBContext db, long playerId) =>
|
||||
db.VoiceChatRestrictions.AsNoTracking()
|
||||
.Where(x => x.PlayerId == playerId && x.ClearedAt == null && x.ExpiresAt > DateTime.UtcNow)
|
||||
.OrderByDescending(x => x.ExpiresAt)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
public static async Task<bool> IsRestrictedAsync(RecDBContext db, long playerId) =>
|
||||
await ActiveAsync(db, playerId) != null;
|
||||
|
||||
public static async Task<VoiceChatRestriction> ApplyAsync(
|
||||
RecDBContext db,
|
||||
long playerId,
|
||||
string reason,
|
||||
ReportCategory category,
|
||||
TimeSpan duration,
|
||||
string issuedBy,
|
||||
string? issuedByUsername = null,
|
||||
string? moderatorNote = null)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var clamped = ClampDuration(duration);
|
||||
|
||||
var restriction = await db.VoiceChatRestrictions
|
||||
.Where(x => x.PlayerId == playerId && x.ClearedAt == null && x.ExpiresAt > now)
|
||||
.OrderByDescending(x => x.ExpiresAt)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (restriction == null)
|
||||
{
|
||||
restriction = new VoiceChatRestriction
|
||||
{
|
||||
PlayerId = playerId,
|
||||
StartedAt = now,
|
||||
ExpiresAt = now + clamped
|
||||
};
|
||||
await db.VoiceChatRestrictions.AddAsync(restriction);
|
||||
}
|
||||
else
|
||||
{
|
||||
var extended = now + clamped;
|
||||
if (extended > restriction.ExpiresAt) restriction.ExpiresAt = extended;
|
||||
restriction.StartedAt = now;
|
||||
}
|
||||
|
||||
restriction.Reason = reason;
|
||||
restriction.Category = category;
|
||||
restriction.IssuedBy = issuedBy;
|
||||
restriction.IssuedByUsername = issuedByUsername;
|
||||
restriction.ModeratorNote = moderatorNote;
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
await TellPlayerAsync(playerId);
|
||||
return restriction;
|
||||
}
|
||||
|
||||
private static async Task TellPlayerAsync(long playerId)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Notify.SendMessage(playerId, new Message
|
||||
{
|
||||
Type = MessageType.CoachMessage,
|
||||
Data = CoachMessage,
|
||||
FromPlayerId = CoachAccountId
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<bool> ClearAsync(RecDBContext db, long playerId, string? clearedBy = null)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var active = await db.VoiceChatRestrictions
|
||||
.Where(x => x.PlayerId == playerId && x.ClearedAt == null && x.ExpiresAt > now)
|
||||
.ToListAsync();
|
||||
|
||||
if (active.Count == 0) return false;
|
||||
|
||||
foreach (var restriction in active)
|
||||
{
|
||||
restriction.ClearedAt = now;
|
||||
restriction.ClearedBy = clearedBy;
|
||||
}
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static object Payload(VoiceChatRestriction? restriction) => new
|
||||
{
|
||||
restricted = restriction != null,
|
||||
playerId = restriction?.PlayerId ?? 0,
|
||||
reason = restriction?.Reason ?? "",
|
||||
category = restriction?.Category.ToString() ?? "",
|
||||
startedAtUtc = restriction?.StartedAt,
|
||||
expiresAtUtc = restriction?.ExpiresAt,
|
||||
secondsRemaining = restriction == null
|
||||
? 0
|
||||
: (int)Math.Max(0, (restriction.ExpiresAt - DateTime.UtcNow).TotalSeconds)
|
||||
};
|
||||
|
||||
public static async Task PushAsync(long playerId, VoiceChatRestriction? restriction)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Notify.SendNotify(playerId, new Notification
|
||||
{
|
||||
Id = NotificationId,
|
||||
Msg = Payload(restriction)
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user