Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mini Auth #1465

Merged
merged 30 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Content.Client/RCD/RCDMenu.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public RCDMenu(EntityUid owner, RCDMenuBoundUserInterface bui)
tooltip = Loc.GetString(entProto.Name);
}

tooltip = char.ToUpper(tooltip[0]) + tooltip.Remove(0, 1);
tooltip = OopsConcat(char.ToUpper(tooltip[0]).ToString(), tooltip.Remove(0, 1));

var button = new RCDMenuButton()
{
Expand Down Expand Up @@ -119,6 +119,12 @@ public RCDMenu(EntityUid owner, RCDMenuBoundUserInterface bui)
SendRCDSystemMessageAction += bui.SendRCDSystemMessage;
}

private static string OopsConcat(string a, string b)
{
// This exists to prevent Roslyn being clever and compiling something that fails sandbox checks.
return a + b;
}

private void AddRCDMenuButtonOnClickActions(Control control)
{
var radialContainer = control as RadialContainer;
Expand Down
1 change: 1 addition & 0 deletions Content.Server.Database/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,7 @@ public enum ConnectionDenyReason : byte
Whitelist = 1,
Full = 2,
Panic = 3,
Connected = 4,
}

public class ServerBanHit
Expand Down
4 changes: 2 additions & 2 deletions Content.Server/Administration/ServerApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ void IPostInjectInit.PostInject()
_sawmill = _logManager.GetSawmill("serverApi");

// Get
RegisterActorHandler(HttpMethod.Get, "/admin/info", InfoHandler);
RegisterHandler(HttpMethod.Get, "/admin/info", InfoHandler); //frontier - not sure why this action needs an actor
RegisterHandler(HttpMethod.Get, "/admin/game_rules", GetGameRules);
RegisterHandler(HttpMethod.Get, "/admin/presets", GetPresets);

Expand Down Expand Up @@ -452,7 +452,7 @@ await context.RespondJsonAsync(new GameruleResponse
/// <summary>
/// Handles fetching information.
/// </summary>
private async Task InfoHandler(IStatusHandlerContext context, Actor actor)
private async Task InfoHandler(IStatusHandlerContext context) //frontier - we had an actor here and never used it so we drop it for now until im compelled to re-add it
{
/*
Information to display
Expand Down
20 changes: 20 additions & 0 deletions Content.Server/Connection/ConnectionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System.Runtime.InteropServices;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Content.Server._NF.Auth;
using Content.Server.Administration;
using Content.Server.Database;
using Content.Server.GameTicking;
using Content.Server.Preferences.Managers;
Expand Down Expand Up @@ -48,6 +50,9 @@ public sealed class ConnectionManager : IConnectionManager
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly ILogManager _logManager = default!;

//frontier
[Dependency] private readonly MiniAuthManager _authManager = default!;

private readonly Dictionary<NetUserId, TimeSpan> _temporaryBypasses = [];
private ISawmill _sawmill = default!;

Expand Down Expand Up @@ -228,6 +233,21 @@ private async Task NetMgrOnConnecting(NetConnectingArgs e)
}
}

//Frontier
//This is our little chunk that serves as a dAuth. It takes in a comma seperated list of IP:PORT, and chekcs
//the requesting player against the list of players logged in to other servers. It is intended to be failsafe.
//In the case of Admins, it shares the same bypass setting as the soft_max_player_limit
if (!_cfg.GetCVar(CCVars.AllowMultiConnect) && !adminBypass)
{
var serverListString = _cfg.GetCVar(CCVars.ServerAuthList);
var serverList = serverListString.Split(",");
foreach (var server in serverList)
{
if (await _authManager.IsPlayerConnected(server, userId))
return (ConnectionDenyReason.Connected, Loc.GetString("multiauth-already-connected"), null);
}
}
// end Frontier
return null;
}

Expand Down
2 changes: 2 additions & 0 deletions Content.Server/Entry/EntryPoint.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Content.Server._NF.Auth;
using Content.Server.Acz;
using Content.Server.Administration;
using Content.Server.Administration.Logs;
Expand Down Expand Up @@ -103,6 +104,7 @@ public override void Init()
IoCManager.Resolve<GhostKickManager>().Initialize();
IoCManager.Resolve<ServerInfoManager>().Initialize();
IoCManager.Resolve<ServerApi>().Initialize();
IoCManager.Resolve<MiniAuthManager>();

_voteManager.Initialize();
_updateManager.Initialize();
Expand Down
3 changes: 3 additions & 0 deletions Content.Server/IoC/ServerContentIoC.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Content.Server._NF.Auth;
using Content.Server.Administration;
using Content.Server.Administration.Logs;
using Content.Server.Administration.Managers;
Expand Down Expand Up @@ -61,6 +62,8 @@ public static void Register()
IoCManager.Register<ServerDbEntryManager>();
IoCManager.Register<ISharedPlaytimeManager, PlayTimeTrackingManager>();
IoCManager.Register<ServerApi>();
IoCManager.Register<MiniAuthManager>(); //Frontier

}
}
}
88 changes: 88 additions & 0 deletions Content.Server/_NF/Auth/Auth.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Json;
using System.Net.Http.Headers;
using Content.Shared.CCVar;
using Robust.Shared.Configuration;
using JetBrains.Annotations;

namespace Content.Server._NF.Auth;

public sealed class MiniAuthManager
{
[Dependency] private readonly IConfigurationManager _cfg = default!;

private readonly HttpClient _http = new();

/// <summary>
/// Frontier function to ping a server and check to see if the given player is currently connected to the given server.
/// Servers using this function must share an admin_api token as defined in their respective server_config.toml
/// </summary>
/// <param name="address">The address of the server to ping.</param>
/// <param name="player">the GUID of the player to check for connection.</param>
/// <returns>True if the response from the server is successful and the player is connected. False in any case of error, timeout, or failure.</returns>
public async Task<bool> IsPlayerConnected(string address, Guid player)
{
var connected = false;
var statusAddress = "http://" + address + "/admin/info";

var cancel = new CancellationToken();
var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancel);
linkedToken.CancelAfter(TimeSpan.FromSeconds(10));

_http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("SS14Token", _cfg.GetCVar(CCVars.AdminApiToken));

//We need to do a try catch here because theres essentially no way to guarantee our json response is proper.
//Throughout all of this, we want it to fail to deny, not fail to allow, so if any step of our auth goes wrong,
//people can still connect.
try
{
var status = await _http.GetFromJsonAsync<InfoResponse>(statusAddress, linkedToken.Token);

foreach (var connectedPlayer in status!.Players)
{
if (connectedPlayer.UserId == player)
{
connected = true;
break;
}
}
}
catch (Exception e)
{
}
return connected;
}

/// <summary>
/// Record used to send the response for the info endpoint.
/// Frontier - This is a direct copy of ServerAPI.InfoResponse to match the json format. they kept it private so i just copied it
/// </summary>
[UsedImplicitly]
private sealed record InfoResponse
{
public required int RoundId { get; init; }
public required List<Player> Players { get; init; }
public required List<string> GameRules { get; init; }
public required string? GamePreset { get; init; }
public required MapInfo? Map { get; init; }
public required string? MOTD { get; init; }
public required Dictionary<string, object> PanicBunker { get; init; }

public sealed class Player
{
public required Guid UserId { get; init; }
public required string Name { get; init; }
public required bool IsAdmin { get; init; }
public required bool IsDeadminned { get; init; }
}

public sealed class MapInfo
{
public required string Id { get; init; }
public required string Name { get; init; }
}
}
}
5 changes: 5 additions & 0 deletions Content.Shared/CCVar/CCVars.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2045,6 +2045,11 @@ public static readonly CVarDef<float>
public static readonly CVarDef<string> TippyEntity =
CVarDef.Create("tippy.entity", "TippyClippy", CVar.SERVER | CVar.REPLICATED); // Frontier - Tippy<TippyClippy

public static readonly CVarDef<string> ServerAuthList =
CVarDef.Create("frontier.auth_servers", "", CVar.CONFIDENTIAL | CVar.SERVERONLY);

public static readonly CVarDef<bool> AllowMultiConnect =
CVarDef.Create("frontier.allow_multi_connect", true, CVar.CONFIDENTIAL | CVar.SERVERONLY);
/*
* DEBUG
*/
Expand Down
8 changes: 7 additions & 1 deletion Content.Shared/Chat/SharedChatSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,16 @@ public string SanitizeMessageCapital(string message)
if (string.IsNullOrEmpty(message))
return message;
// Capitalize first letter
message = char.ToUpper(message[0]) + message.Remove(0, 1);
message = OopsConcat(char.ToUpper(message[0]).ToString(), message.Remove(0, 1));
return message;
}

private static string OopsConcat(string a, string b)
{
// This exists to prevent Roslyn being clever and compiling something that fails sandbox checks.
return a + b;
}

public string SanitizeMessageCapitalizeTheWordI(string message, string theWordI = "i")
{
if (string.IsNullOrEmpty(message))
Expand Down
1 change: 1 addition & 0 deletions Resources/Locale/en-US/_NF/adventure/adventure.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ shipyard-rules-default2 =
shuttle-ftl-proximity = Nearby objects too massive for FTL!

changelog-tab-title-Upstream = Upstream Changelog
multiauth-already-connected = Already connected to Frontier Official servers.

public-transit-departure = Now departing for {$destination}. Estimated travel time: {$flytime} seconds.
public-transit-arrival = Thank you for choosing NT Public Transit. Next transfer to {$destination} departs in {$waittime} seconds.
Loading