From 1996546a73d37967c10f724c90f653c44957c5e1 Mon Sep 17 00:00:00 2001 From: ChronosX88 Date: Wed, 15 Jul 2020 22:08:32 +0400 Subject: [PATCH] Implement config parsing, implement removing c2s/core event handlers in router, slightly change C2S/Core Event Handler API, Host Module API --- src/Zirconium/Core/App.cs | 6 +- src/Zirconium/Core/AuthManager.cs | 10 ++- src/Zirconium/Core/Config.cs | 6 -- src/Zirconium/Core/ConnectionHandler.cs | 4 +- src/Zirconium/Core/Main.cs | 33 +++++++- src/Zirconium/Core/Modules/HostModuleAPI.cs | 25 +++--- .../Modules/Interfaces/IC2SMessageHandler.cs | 3 +- .../Modules/Interfaces/ICoreEventHandler.cs | 1 + .../Core/Modules/Interfaces/IHostModuleAPI.cs | 2 +- src/Zirconium/Core/Router.cs | 77 +++++++++++-------- src/Zirconium/Zirconium.csproj | 3 +- 11 files changed, 111 insertions(+), 59 deletions(-) diff --git a/src/Zirconium/Core/App.cs b/src/Zirconium/Core/App.cs index aea8416..5ca92ce 100644 --- a/src/Zirconium/Core/App.cs +++ b/src/Zirconium/Core/App.cs @@ -6,17 +6,19 @@ namespace Zirconium.Core { public class App { + public Config Config; public SessionManager SessionManager { get; } public Router Router { get; } public ModuleManager ModuleManager { get; } public IHostModuleAPI HostModuleAPI { get; } public AuthManager AuthManager { get; } - public App() + public App(Config config) { + Config = config; SessionManager = new SessionManager(); Router = new Router(this); - HostModuleAPI = new HostModuleAPI(Router); + HostModuleAPI = new HostModuleAPI(this, Router); AuthManager = new AuthManager(this); Log.Info("Zirconium is initialized successfully"); } diff --git a/src/Zirconium/Core/AuthManager.cs b/src/Zirconium/Core/AuthManager.cs index af0c8e7..3239d09 100644 --- a/src/Zirconium/Core/AuthManager.cs +++ b/src/Zirconium/Core/AuthManager.cs @@ -10,7 +10,7 @@ namespace Zirconium.Core { private App _app; private string _secretString; - private const int TOKEN_EXPIRATION_TIME_HOURS = 24; + private const long DEFAULT_TOKEN_EXPIRATION_TIME_HOURS = 24 * 3600000; public AuthManager(App app) { @@ -18,7 +18,7 @@ namespace Zirconium.Core _secretString = Guid.NewGuid().ToString(); } - public string CreateToken(string entityID, string deviceID) + public string CreateToken(string entityID, string deviceID, long tokenExpirationMillis) { JWTPayload payload = new JWTPayload(); payload.DeviceID = deviceID; @@ -26,11 +26,15 @@ namespace Zirconium.Core return new JwtBuilder() .WithAlgorithm(new HMACSHA256Algorithm()) // symmetric .WithSecret(_secretString) - .AddClaim("exp", DateTimeOffset.UtcNow.AddHours(TOKEN_EXPIRATION_TIME_HOURS).ToUnixTimeSeconds()) + .AddClaim("exp", DateTimeOffset.UtcNow.AddMilliseconds(tokenExpirationMillis).ToUnixTimeSeconds()) .AddClaims(payload.ToDictionary()) .Encode(); } + public string CreateToken(string entityID, string deviceID) { + return CreateToken(entityID, deviceID, DEFAULT_TOKEN_EXPIRATION_TIME_HOURS); + } + public JWTPayload ValidateToken(string token) { var jsonPayload = new JwtBuilder() diff --git a/src/Zirconium/Core/Config.cs b/src/Zirconium/Core/Config.cs index 687e3f0..a6c1c6b 100644 --- a/src/Zirconium/Core/Config.cs +++ b/src/Zirconium/Core/Config.cs @@ -1,23 +1,17 @@ -using YamlDotNet.Serialization; - namespace Zirconium.Core { public class Config { // A list of enabled plugins (or extensions) in server - [YamlMember(Alias = "enabledPlugins")] public string[] EnabledPlugins {get; set;} // Server domain names (e.g. example.com) - [YamlMember(Alias = "serverDomains")] public string[] ServerDomains {get; set;} // Path to directory with plugin assemblies - [YamlMember(Alias = "pluginsDirPath")] public string PluginsDirPath {get; set;} // ID of this server in terms of Cadmium federation network - [YamlMember(Alias = "serverID")] public string ServerID {get; set;} } } \ No newline at end of file diff --git a/src/Zirconium/Core/ConnectionHandler.cs b/src/Zirconium/Core/ConnectionHandler.cs index 4429e9b..e029233 100644 --- a/src/Zirconium/Core/ConnectionHandler.cs +++ b/src/Zirconium/Core/ConnectionHandler.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using System; using WebSocketSharp.Server; using WebSocketSharp; @@ -42,8 +43,9 @@ namespace Zirconium.Core Console.WriteLine($"Connection {ID} was created"); // TODO implement normal logging } - public void SendMessage(string message) { + public Task SendMessage(string message) { this.Send(message.ToByteArray()); + return Task.CompletedTask; } } } diff --git a/src/Zirconium/Core/Main.cs b/src/Zirconium/Core/Main.cs index 9f8ba21..ea6ed26 100644 --- a/src/Zirconium/Core/Main.cs +++ b/src/Zirconium/Core/Main.cs @@ -1,12 +1,43 @@ using System; +using CommandLine; +using Nett; +using Zirconium.Core.Logging; namespace Zirconium.Core { + public class RunOptions + { + [Option('c', "config", Required = true, HelpText = "Set config path")] + public string ConfigPath { get; set; } + } class Program { static void Main(string[] args) { - App app = new App(); + string configPath = null; + Parser.Default.ParseArguments(args) + .WithParsed(o => + { + configPath = o.ConfigPath; + }) + .WithNotParsed(errs => + { + foreach (var err in errs) + { + Log.Error($"Error occured when parsing run options - {err.Tag}"); + } + Environment.Exit(1); + }); + Config config = null; + try + { + config = Toml.ReadFile(configPath); + } + catch (Exception e) + { + Log.Fatal($"Error occured when parsing config - {e.Message}"); + } + App app = new App(config); } } } diff --git a/src/Zirconium/Core/Modules/HostModuleAPI.cs b/src/Zirconium/Core/Modules/HostModuleAPI.cs index 898ccf4..37f2676 100644 --- a/src/Zirconium/Core/Modules/HostModuleAPI.cs +++ b/src/Zirconium/Core/Modules/HostModuleAPI.cs @@ -1,4 +1,5 @@ using System; +using Newtonsoft.Json; using Zirconium.Core.Models; using Zirconium.Core.Modules.Interfaces; @@ -6,56 +7,58 @@ namespace Zirconium.Core.Modules { public class HostModuleAPI : IHostModuleAPI { + private App _app; private Router _router; - public HostModuleAPI(Router router) + public HostModuleAPI(App app, Router router) { _router = router; + _app = app; } public void FireEvent(CoreEvent coreEvent) { - throw new NotImplementedException(); + _router.RouteCoreEvent(coreEvent); } public string GenerateAuthToken(string entityID, string deviceID, int tokenExpirationMillis) { - throw new NotImplementedException(); + return _app.AuthManager.CreateToken(entityID, deviceID, tokenExpirationMillis); } public string[] GetServerDomains() { - throw new NotImplementedException(); + return _app.Config.ServerDomains; } public string GetServerID() { - throw new NotImplementedException(); + return _app.Config.ServerID; } public void Hook(IC2SMessageHandler handler) { - throw new NotImplementedException(); + _router.AddC2SHandler(handler.GetHandlingMessageType(), handler); } public void HookCoreEvent(ICoreEventHandler handler) { - throw new NotImplementedException(); + _router.AddCoreEventHandler(handler.GetHandlingEventType(), handler); } - public void SendMessage(string connID, BaseMessage message) + public void SendMessage(ConnectionInfo connInfo, BaseMessage message) { - throw new NotImplementedException(); + connInfo.ConnectionHandler.SendMessage(JsonConvert.SerializeObject(message)); } public void Unhook(IC2SMessageHandler handler) { - throw new NotImplementedException(); + _router.RemoveC2SHandler(handler.GetHandlingMessageType(), handler); } public void UnhookCoreEvent(ICoreEventHandler handler) { - throw new NotImplementedException(); + _router.RemoveCoreEventHandler(handler.GetHandlingEventType(), handler); } } } \ No newline at end of file diff --git a/src/Zirconium/Core/Modules/Interfaces/IC2SMessageHandler.cs b/src/Zirconium/Core/Modules/Interfaces/IC2SMessageHandler.cs index ba159f7..b40f5f9 100644 --- a/src/Zirconium/Core/Modules/Interfaces/IC2SMessageHandler.cs +++ b/src/Zirconium/Core/Modules/Interfaces/IC2SMessageHandler.cs @@ -3,7 +3,8 @@ using Zirconium.Core.Models; namespace Zirconium.Core.Modules.Interfaces { public interface IC2SMessageHandler { - void HandleMessage(BaseMessage message); + string GetHandlingMessageType(); + void HandleMessage(ConnectionInfo connInfo, BaseMessage message); bool IsAuthorizationRequired(); string GetHandlerUniqueID(); } diff --git a/src/Zirconium/Core/Modules/Interfaces/ICoreEventHandler.cs b/src/Zirconium/Core/Modules/Interfaces/ICoreEventHandler.cs index febfce0..baaefcc 100644 --- a/src/Zirconium/Core/Modules/Interfaces/ICoreEventHandler.cs +++ b/src/Zirconium/Core/Modules/Interfaces/ICoreEventHandler.cs @@ -4,6 +4,7 @@ namespace Zirconium.Core.Modules.Interfaces { public interface ICoreEventHandler { + string GetHandlingEventType(); void HandleEvent(CoreEvent coreEvent); string GetHandlerUniqueID(); } diff --git a/src/Zirconium/Core/Modules/Interfaces/IHostModuleAPI.cs b/src/Zirconium/Core/Modules/Interfaces/IHostModuleAPI.cs index fa48487..ee0decc 100644 --- a/src/Zirconium/Core/Modules/Interfaces/IHostModuleAPI.cs +++ b/src/Zirconium/Core/Modules/Interfaces/IHostModuleAPI.cs @@ -12,6 +12,6 @@ namespace Zirconium.Core.Modules.Interfaces string GenerateAuthToken(string entityID, string deviceID, int tokenExpirationMillis); string[] GetServerDomains(); string GetServerID(); - void SendMessage(string connID, BaseMessage message); + void SendMessage(ConnectionInfo connInfo, BaseMessage message); } } \ No newline at end of file diff --git a/src/Zirconium/Core/Router.cs b/src/Zirconium/Core/Router.cs index 1a4b403..a89eb1a 100644 --- a/src/Zirconium/Core/Router.cs +++ b/src/Zirconium/Core/Router.cs @@ -44,46 +44,43 @@ namespace Zirconium.Core { if (h.IsAuthorizationRequired()) { - JWTPayload tokenPayload; - try + string hash; + using (SHA512 shaM = new SHA512Managed()) { - tokenPayload = _app.AuthManager.ValidateToken(message.AuthToken); + hash = shaM.ComputeHash(message.AuthToken.ToByteArray()).ConvertToString(); } - catch (Exception e) + if (connInfo.LastTokenHash != hash) { - Log.Warning(e.Message); - - var serializedMsg = JsonConvert.SerializeObject( - OtherUtils.GenerateProtocolError( - message, - "unauthorized", - "Unauthorized access", - new Dictionary() - ) - ); - connInfo.ConnectionHandler.SendMessage(serializedMsg); - return; - } - - if (connInfo.LastTokenHash == "" || connInfo.LastTokenHash == null) - { - string hash; - using (SHA512 shaM = new SHA512Managed()) + JWTPayload tokenPayload; + try { - hash = shaM.ComputeHash(message.AuthToken.ToByteArray()).ConvertToString(); + tokenPayload = _app.AuthManager.ValidateToken(message.AuthToken); } - connInfo.LastTokenHash = hash; - // TODO implement comparing last token hash and if hash isn't changed then check payload - // if payload already exists - then skip validating auth token - } + catch (Exception e) + { + Log.Warning(e.Message); - connInfo.LastTokenPayload = tokenPayload; + var serializedMsg = JsonConvert.SerializeObject( + OtherUtils.GenerateProtocolError( + message, + "unauthorized", + "Unauthorized access", + new Dictionary() + ) + ); + connInfo.ConnectionHandler.SendMessage(serializedMsg); + return; + } + + connInfo.LastTokenHash = hash; + connInfo.LastTokenPayload = tokenPayload; + } } Task.Run(() => - { + { // probably need to wrap whole foreach body, not only HandleMessage call - need to investigate - h.HandleMessage(message); + h.HandleMessage(connInfo, message); }); } } @@ -91,11 +88,13 @@ namespace Zirconium.Core public void RouteCoreEvent(CoreEvent coreEvent) { var handlers = _coreEventsHandlers[coreEvent.Name]; - if (handlers == null) { + if (handlers == null) + { Log.Warning($"Drop core event {coreEvent.Name} because server hasn't proper handlers"); return; } - foreach (var h in handlers) { + foreach (var h in handlers) + { Task.Run(() => { h.HandleEvent(coreEvent); @@ -112,6 +111,13 @@ namespace Zirconium.Core this._c2sMessageHandlers[messageType].Add(handler); } + public void RemoveC2SHandler(string messageType, IC2SMessageHandler handler) + { + if (!this._c2sMessageHandlers[messageType].Remove(handler)) { + Log.Warning("attempt to remove c2s handler which doesn't exist in router"); + } + } + public void AddCoreEventHandler(string eventType, ICoreEventHandler handler) { if (_coreEventsHandlers.GetValueOrDefault(eventType, null) == null) @@ -120,5 +126,12 @@ namespace Zirconium.Core } this._coreEventsHandlers[eventType].Add(handler); } + + public void RemoveCoreEventHandler(string eventType, ICoreEventHandler handler) + { + if (!this._coreEventsHandlers[eventType].Remove(handler)) { + Log.Warning("attempt to remove core handler which doesn't exist in router"); + } + } } } \ No newline at end of file diff --git a/src/Zirconium/Zirconium.csproj b/src/Zirconium/Zirconium.csproj index 2984bd2..6b309bb 100644 --- a/src/Zirconium/Zirconium.csproj +++ b/src/Zirconium/Zirconium.csproj @@ -5,10 +5,11 @@ + - + \ No newline at end of file