Skip to content

Commit

Permalink
feat: basic auth for all api endpoints (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
DarkAtra authored Jun 1, 2024
1 parent a6845c7 commit dc2bbd3
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 3 deletions.
50 changes: 47 additions & 3 deletions Plugin.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Reflection;
using System.Collections.Generic;
using System.Reflection;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using Bloodstone.API;
Expand All @@ -15,18 +17,34 @@ namespace v_rising_discord_bot_companion;
[Reloadable]
public class Plugin : BasePlugin {

public static ManualLogSource Logger = null!;
public static ManualLogSource Logger { get; private set; } = null!;
public static Plugin Instance { get; private set; } = null!;
private Harmony? _harmony;
private Component? _queryDispatcher;

private PluginConfig? _pluginConfig;
private ConfigEntry<string> _basicAuthUsers;

public Plugin() {

Instance = this;
Logger = Log;

_basicAuthUsers = Config.Bind(
"Authentication",
"BasicAuthUsers",
"",
"A list of comma separated username:password entries that are allowed to query the HTTP API."
);
}

public override void Load() {

if (!VWorld.IsServer) {
Log.LogInfo($"Plugin {MyPluginInfo.PLUGIN_GUID} must be installed on the server side.");
return;
}

Logger = Log;

// Plugin startup logic
Log.LogInfo($"Plugin {MyPluginInfo.PLUGIN_GUID} version {MyPluginInfo.PLUGIN_VERSION} is loaded!");
Expand All @@ -45,6 +63,32 @@ public override bool Unload() {
if (_queryDispatcher != null) {
Object.Destroy(_queryDispatcher);
}
_pluginConfig = null;
return true;
}

public PluginConfig GetPluginConfig() {
_pluginConfig ??= ParsePluginConfig();
return (PluginConfig) _pluginConfig;
}

private PluginConfig ParsePluginConfig() {

var basicAuthUsers = new List<BasicAuthUser>();
foreach (var basicAuthUser in _basicAuthUsers.Value.Split(",")) {
var parts = basicAuthUser.Split(":");
if (parts.Length == 2) {
basicAuthUsers.Add(
new BasicAuthUser(
Username: parts[0].Trim(),
Password: parts[1].Trim()
)
);
}
}

return new PluginConfig(
BasicAuthUsers: basicAuthUsers
);
}
}
12 changes: 12 additions & 0 deletions PluginConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Collections.Generic;

namespace v_rising_discord_bot_companion;

public readonly record struct PluginConfig(
List<BasicAuthUser> BasicAuthUsers
);

public readonly record struct BasicAuthUser(
string Username,
string Password
);
64 changes: 64 additions & 0 deletions command/HttpReceiveServicePatches.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System.Linq;
using HarmonyLib;
using Il2CppSystem.Net;
using Il2CppSystem.Security.Principal;
using ProjectM.Network;

namespace v_rising_discord_bot_companion.command;

[HarmonyPatch(typeof(HttpServiceReceiveThread))]
public class HttpReceiveServicePatches {

[HarmonyPrefix]
[HarmonyPatch("IsAllowed")]
public static bool IsAllowed(HttpListenerContext context, ref bool __result) {

var pluginConfig = Plugin.Instance.GetPluginConfig();

if (pluginConfig.BasicAuthUsers.Count <= 0) {
return true;
}

var currentBasicAuthUser = ParseBasicAuthUser(context);
if (!currentBasicAuthUser.HasValue) {
__result = false;
return false;
}

__result = IsAuthorized((BasicAuthUser) currentBasicAuthUser);
return __result;
}

private static BasicAuthUser? ParseBasicAuthUser(HttpListenerContext context) {

context.ParseAuthentication(AuthenticationSchemes.Basic);

if (context.user == null) {
return null;
}

var principal = context.user.TryCast<GenericPrincipal>();
var identity = principal?.m_identity.TryCast<HttpListenerBasicIdentity>();

if (identity == null) {
return null;
}

var username = identity.Name;
var password = identity.password;

if (username == null || password == null) {
return null;
}

return new BasicAuthUser(
Username: username,
Password: password
);
}

private static bool IsAuthorized(BasicAuthUser currentBasicAuthUser) {
return Plugin.Instance.GetPluginConfig().BasicAuthUsers
.Count(it => it.Username.Equals(currentBasicAuthUser.Username) && it.Password.Equals(currentBasicAuthUser.Password)) == 1;
}
}
3 changes: 3 additions & 0 deletions command/ServerWebAPISystemPatches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class ServerWebAPISystemPatches {
public static void OnCreate(ServerWebAPISystem __instance) {

if (!SettingsManager.ServerHostSettings.API.Enabled) {
Plugin.Logger.LogInfo($"HTTP API is not enabled.");
return;
}

Expand All @@ -50,6 +51,8 @@ public static void OnCreate(ServerWebAPISystem __instance) {
"GET",
BuildAdapter(_ => VampireDownedServerEventSystemPatches.getPvpKills())
));

Plugin.Logger.LogInfo($"Added v-rising-discord-bot endpoints.");
}

private static HttpServiceReceiveThread.RequestHandler BuildAdapter(Func<HttpListenerContext, object> commandHandler) {
Expand Down
28 changes: 28 additions & 0 deletions http-requests.http
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,31 @@ GET http://localhost:25570/v-rising-discord-bot/player-activities

### Get pvp kills
GET http://localhost:25570/v-rising-discord-bot/pvp-kills

### Metrics
GET http://localhost:25570/metrics

### Console
GET http://localhost:25570/console/v1?input=sendserverannouncement some message

### Messages
POST http://localhost:25570/api/message/v1
Content-Type: application/json

{
"message": "the actual message"
}

### Shutdown
POST http://localhost:25570/api/shutdown/v1
Content-Type: application/json

{
"shutdown": true
}

### Save
POST http://localhost:25570/api/save/v1
Content-Type: application/json

{}

0 comments on commit dc2bbd3

Please sign in to comment.