+++ /dev/null
-using Impostor.Api.Innersloth;
-
-namespace Impostor.Api.Events.Announcements
-{
- /// <summary>
- /// Event fired after client requests a announcement.
- /// </summary>
- public interface IAnnouncementRequestEvent : IEvent
- {
- public interface IResponse
- {
- /// <summary>
- /// Gets or sets a value indicating whether announcement should be loaded from client's cache, can save some bytes.
- /// </summary>
- public bool UseCached { get; set; }
-
- /// <summary>
- /// Gets or sets announcement, should be null when <see cref="UseCached" /> is set to true.
- /// </summary>
- public Announcement? Announcement { get; set; }
- }
-
- /// <summary>
- /// Gets client's last announcement id.
- /// </summary>
- public int Id { get; }
-
- /// <summary>
- /// Gets client's language.
- /// </summary>
- public Language Language { get; }
-
- /// <summary>
- /// Gets or sets plugin made response.
- /// </summary>
- public IResponse Response { get; set; }
- }
-}
+++ /dev/null
-namespace Impostor.Api.Innersloth
-{
- public readonly struct Announcement
- {
- public readonly int Id;
- public readonly string Message;
-
- public Announcement(int id, string message)
- {
- Id = id;
- Message = message;
- }
- }
-}
+++ /dev/null
-namespace Impostor.Api.Net.Messages.Announcements
-{
- public static class Message00UseCache
- {
- public static void Serialize(IMessageWriter writer)
- {
- writer.StartMessage(AnnouncementsMessageFlags.UseCache);
- writer.EndMessage();
- }
-
- public static void Deserialize(IMessageReader reader)
- {
- }
- }
-}
+++ /dev/null
-namespace Impostor.Api.Net.Messages.Announcements
-{
- public static class Message01Update
- {
- public static void Serialize(IMessageWriter writer, int id, string message)
- {
- writer.StartMessage(AnnouncementsMessageFlags.SetUpdate);
- writer.WritePacked(id);
- writer.Write(message);
- writer.EndMessage();
- }
-
- public static void Deserialize(IMessageReader reader, out int id, out string message)
- {
- id = reader.ReadPackedInt32();
- message = reader.ReadString();
- }
- }
-}
+++ /dev/null
-using System.Collections.Generic;
-
-namespace Impostor.Api.Net.Messages.Announcements
-{
- public static class Message04AddLanguages
- {
- public static void Serialize(IMessageWriter writer, Dictionary<string, uint> languages)
- {
- writer.StartMessage(AnnouncementsMessageFlags.AddLanguages);
-
- writer.Write((byte)languages.Count);
- foreach (var (name, id) in languages)
- {
- writer.Write(name);
- writer.Write(id);
- }
-
- writer.EndMessage();
- }
-
- public static void Deserialize(IMessageReader reader, out Dictionary<string, uint> languages)
- {
- var length = reader.ReadByte();
- languages = new Dictionary<string, uint>(length);
-
- for (var i = 0; i < length; i++)
- {
- languages[reader.ReadString()] = reader.ReadUInt32();
- }
- }
- }
-}
+++ /dev/null
-using Impostor.Api.Innersloth;
-
-namespace Impostor.Api.Net.Messages.Announcements
-{
- public class MessageHello
- {
- public static void Deserialize(IMessageReader reader, out int announcementVersion, out int id, out Language language)
- {
- reader.ReadByte(); // SendOption header, probably added by accident
- announcementVersion = reader.ReadPackedInt32();
- id = reader.ReadPackedInt32();
- language = (Language)reader.ReadPackedInt32();
- }
- }
-}
+++ /dev/null
-namespace Impostor.Api.Net.Messages
-{
- public class AnnouncementsMessageFlags
- {
- public const byte UseCache = 0;
- public const byte SetUpdate = 1;
- public const byte AddLanguages = 4;
- }
-}
+++ /dev/null
-namespace Impostor.Api.Net.Messages.Auth
-{
- public static class Message01Complete
- {
- public static void Serialize(IMessageWriter writer, uint nonce)
- {
- writer.WritePacked(nonce);
- }
-
- public static void Deserialize(IMessageReader reader, out uint nonce)
- {
- nonce = reader.ReadUInt32();
- }
- }
-}
+++ /dev/null
-using Impostor.Api.Innersloth;
-
-namespace Impostor.Api.Net.Messages.Auth
-{
- public static class MessageHandshake
- {
- public static void Deserialize(IMessageReader reader, out int clientVersion, out Platforms platform, out string clientId)
- {
- clientVersion = reader.ReadInt32();
- platform = (Platforms)reader.ReadByte();
- clientId = reader.ReadString();
- }
- }
-}
services.AddSingleton<IEventListener, ClientEventListener>();
services.AddSingleton<IEventListener, PlayerEventListener>();
services.AddSingleton<IEventListener, MeetingEventListener>();
- services.AddSingleton<IEventListener, AnnouncementsListener>();
}
}
}
+++ /dev/null
-using Impostor.Api.Events;
-using Impostor.Api.Events.Announcements;
-using Impostor.Api.Innersloth;
-
-namespace Impostor.Plugins.Example.Handlers
-{
- public class AnnouncementsListener : IEventListener
- {
- private const int Id = 50;
-
- [EventListener]
- public void OnAnnouncementRequestEvent(IAnnouncementRequestEvent e)
- {
- if (e.Id == Id)
- {
- // Client already has announcement cached, lets just use that
- e.Response.UseCached = true;
- }
- else
- {
- // Client is receiving this announcement for the first time, window will popup
- e.Response.Announcement = new Announcement(Id, "Hello!");
- }
- }
- }
-}
+++ /dev/null
-using Impostor.Server.Utils;
-
-namespace Impostor.Server.Config
-{
- internal class AnnouncementsServerConfig
- {
- public const string Section = "AnnouncementsServer";
-
- private string? _resolvedListenIp;
-
- public bool Enabled { get; set; } = true;
-
- public string ListenIp { get; set; } = "0.0.0.0";
-
- public ushort ListenPort { get; set; } = 22024;
-
- public string ResolveListenIp()
- {
- return _resolvedListenIp ??= IpUtils.ResolveIp(ListenIp);
- }
- }
-}
+++ /dev/null
-using System.IO;
-using Impostor.Server.Utils;
-
-namespace Impostor.Server.Config
-{
- internal class AuthServerConfig
- {
- public const string Section = "AuthServer";
-
- private string? _resolvedListenIp;
-
- public bool Enabled { get; set; } = false;
-
- public string ListenIp { get; set; } = "0.0.0.0";
-
- public ushort ListenPort { get; set; } = 22025;
-
- public string Certificate { get; set; } = Path.Combine("dtls", "certificate.pem");
-
- public string PrivateKey { get; set; } = Path.Combine("dtls", "key.pem");
-
- public string ResolveListenIp()
- {
- return _resolvedListenIp ??= IpUtils.ResolveIp(ListenIp);
- }
- }
-}
+++ /dev/null
-using Impostor.Api.Events.Announcements;
-using Impostor.Api.Innersloth;
-
-namespace Impostor.Server.Events.Announcements
-{
- public class AnnouncementRequestEvent : IAnnouncementRequestEvent
- {
- public AnnouncementRequestEvent(int id, Language language)
- {
- Id = id;
- Language = language;
- }
-
- public int Id { get; }
-
- public Language Language { get; }
-
- public IAnnouncementRequestEvent.IResponse Response { get; set; } = new AnnouncementResponse();
-
- public class AnnouncementResponse : IAnnouncementRequestEvent.IResponse
- {
- public bool UseCached { get; set; } = false;
-
- public Announcement? Announcement { get; set; } = null;
- }
- }
-}
+++ /dev/null
-using System;
-using System.Net;
-using System.Net.Sockets;
-using System.Threading;
-using System.Threading.Tasks;
-using Impostor.Api.Events.Managers;
-using Impostor.Api.Net.Messages;
-using Impostor.Api.Net.Messages.Announcements;
-using Impostor.Hazel;
-using Impostor.Hazel.Udp;
-using Impostor.Server.Config;
-using Impostor.Server.Events.Announcements;
-using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.ObjectPool;
-using Microsoft.Extensions.Options;
-
-namespace Impostor.Server.Net
-{
- internal class AnnouncementsService : IHostedService
- {
- private readonly ILogger<AnnouncementsService> _logger;
- private readonly AnnouncementsServerConfig _config;
- private readonly ObjectPool<MessageReader> _readerPool;
- private readonly IEventManager _eventManager;
- private UdpConnectionListener? _connection;
-
- public AnnouncementsService(ILogger<AnnouncementsService> logger, IOptions<AnnouncementsServerConfig> config, ObjectPool<MessageReader> readerPool, IEventManager eventManager)
- {
- _logger = logger;
- _config = config.Value;
- _readerPool = readerPool;
- _eventManager = eventManager;
- }
-
- public async Task StartAsync(CancellationToken cancellationToken)
- {
- var endpoint = new IPEndPoint(IPAddress.Parse(_config.ResolveListenIp()), _config.ListenPort);
-
- var mode = endpoint.AddressFamily switch
- {
- AddressFamily.InterNetwork => IPMode.IPv4,
- AddressFamily.InterNetworkV6 => IPMode.IPv6,
- _ => throw new InvalidOperationException(),
- };
-
- _connection = new UdpConnectionListener(endpoint, _readerPool, mode)
- {
- NewConnection = OnNewConnection,
- };
-
- await _connection.StartAsync();
-
- _logger.LogInformation("Announcements server is listening on {Address}:{Port}", endpoint.Address, endpoint.Port);
- }
-
- public async Task StopAsync(CancellationToken cancellationToken)
- {
- _logger.LogWarning("Announcements server is shutting down!");
-
- if (_connection != null)
- {
- await _connection.DisposeAsync();
- }
- }
-
- private async ValueTask OnNewConnection(NewConnectionEventArgs e)
- {
- MessageHello.Deserialize(e.HandshakeData, out var announcementVersion, out var id, out var language);
-
- _logger.LogDebug("Client requested announcement (version: {Version}, id: {Id}, language: {Language})", announcementVersion, id, language);
-
- if (announcementVersion != 2)
- {
- await e.Connection.Disconnect("Unsupported announcement version");
- return;
- }
-
- var @event = new AnnouncementRequestEvent(id, language);
- await _eventManager.CallAsync(@event);
-
- var response = @event.Response;
-
- if (response.UseCached)
- {
- using var writer = MessageWriter.Get(MessageType.Reliable);
- Message00UseCache.Serialize(writer);
- await e.Connection.SendAsync(writer);
-
- _logger.LogDebug("Sent UseCache response");
- }
-
- if (response.Announcement != null)
- {
- using var writer = MessageWriter.Get(MessageType.Reliable);
- var announcement = response.Announcement.Value;
- Message01Update.Serialize(writer, announcement.Id, announcement.Message);
- await e.Connection.SendAsync(writer);
-
- _logger.LogDebug("Sent ({Id}) {Message}", announcement.Id, announcement.Message);
- }
-
- await e.Connection.Disconnect(null);
- }
- }
-}
+++ /dev/null
-using System;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Net.Sockets;
-using System.Security.Cryptography;
-using System.Security.Cryptography.X509Certificates;
-using System.Threading;
-using System.Threading.Tasks;
-using Impostor.Api.Events.Managers;
-using Impostor.Api.Net.Messages;
-using Impostor.Api.Net.Messages.Auth;
-using Impostor.Hazel;
-using Impostor.Hazel.Dtls;
-using Impostor.Server.Config;
-using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.ObjectPool;
-using Microsoft.Extensions.Options;
-
-namespace Impostor.Server.Net
-{
- internal class AuthService : IHostedService
- {
- private readonly ILogger<AuthService> _logger;
- private readonly AuthServerConfig _config;
- private readonly ObjectPool<MessageReader> _readerPool;
- private readonly IEventManager _eventManager;
- private DtlsConnectionListener? _connection;
-
- public AuthService(ILogger<AuthService> logger, IOptions<AuthServerConfig> config, ObjectPool<MessageReader> readerPool, IEventManager eventManager)
- {
- _logger = logger;
- _config = config.Value;
- _readerPool = readerPool;
- _eventManager = eventManager;
- }
-
- public async Task StartAsync(CancellationToken cancellationToken)
- {
- var endpoint = new IPEndPoint(IPAddress.Parse(_config.ResolveListenIp()), _config.ListenPort);
-
- var mode = endpoint.AddressFamily switch
- {
- AddressFamily.InterNetwork => IPMode.IPv4,
- AddressFamily.InterNetworkV6 => IPMode.IPv6,
- _ => throw new InvalidOperationException(),
- };
-
- var rsa = RSA.Create();
- rsa.ImportPkcs8PrivateKey(Convert.FromBase64String(string.Join(string.Empty, (await File.ReadAllLinesAsync(_config.PrivateKey, cancellationToken)).Where(x => !x.StartsWith("-----")))), out _);
- var cert = new X509Certificate2(_config.Certificate).CopyWithPrivateKey(rsa);
-
- _connection = new DtlsConnectionListener(endpoint, _readerPool, mode);
- _connection.SetCertificate(cert);
- _connection.NewConnection = ConnectionOnNewConnection;
-
- await _connection.StartAsync();
-
- _logger.LogInformation("Auth server is listening on {Address}:{Port}", endpoint.Address, endpoint.Port);
- }
-
- public async Task StopAsync(CancellationToken cancellationToken)
- {
- _logger.LogWarning("Auth server is shutting down!");
-
- if (_connection != null)
- {
- await _connection.DisposeAsync();
- }
- }
-
- private ValueTask ConnectionOnNewConnection(NewConnectionEventArgs e)
- {
- MessageHandshake.Deserialize(e.HandshakeData, out var clientVersion, out var platform, out var clientId);
-
- _logger.LogTrace("New authentication request: {clientVersion}, {platform}, {clientId}", clientVersion, platform, clientId);
-
- using var writer = MessageWriter.Get(MessageType.Reliable);
-
- writer.StartMessage(1);
- Message01Complete.Serialize(writer, (uint)RandomNumberGenerator.GetInt32(int.MinValue, int.MaxValue));
- writer.EndMessage();
-
- return e.Connection.SendAsync(writer);
- }
- }
-}
.GetSection(ServerRedirectorConfig.Section)
.Get<ServerRedirectorConfig>() ?? new ServerRedirectorConfig();
- var announcementsServer = host.Configuration
- .GetSection(AnnouncementsServerConfig.Section)
- .Get<AnnouncementsServerConfig>() ?? new AnnouncementsServerConfig();
-
- var authServer = host.Configuration
- .GetSection(AuthServerConfig.Section)
- .Get<AuthServerConfig>() ?? new AuthServerConfig();
-
services.AddSingleton<ServerEnvironment>();
services.AddSingleton<IServerEnvironment>(p => p.GetRequiredService<ServerEnvironment>());
services.AddSingleton<IDateTimeProvider, RealDateTimeProvider>();
services.Configure<DebugConfig>(host.Configuration.GetSection(DebugConfig.Section));
services.Configure<AntiCheatConfig>(host.Configuration.GetSection(AntiCheatConfig.Section));
services.Configure<ServerConfig>(host.Configuration.GetSection(ServerConfig.Section));
- services.Configure<AnnouncementsServerConfig>(host.Configuration.GetSection(AnnouncementsServerConfig.Section));
- services.Configure<AuthServerConfig>(host.Configuration.GetSection(AuthServerConfig.Section));
services.Configure<ServerRedirectorConfig>(host.Configuration.GetSection(ServerRedirectorConfig.Section));
if (redirector.Enabled)
services.AddSingleton<IEventManager, EventManager>();
services.AddSingleton<Matchmaker>();
services.AddHostedService<MatchmakerService>();
-
- if (announcementsServer.Enabled)
- {
- services.AddHostedService<AnnouncementsService>();
- }
-
- if (authServer.Enabled)
- {
- services.AddHostedService<AuthService>();
- }
})
.UseSerilog()
.UseConsoleLifetime()
"ListenIp": "0.0.0.0",
"ListenPort": 22023
},
- "AnnouncementsServer": {
- "Enabled": true,
- "ListenIp": "0.0.0.0",
- "ListenPort": 22024
- },
"AntiCheat": {
"Enabled": true,
"BanIpFromGame": true