mirror of
https://github.com/cadmium-im/zirconium-sharp.git
synced 2024-11-25 20:02:21 +00:00
Implement config parsing, implement removing c2s/core event handlers in router, slightly change C2S/Core Event Handler API, Host Module API
This commit is contained in:
parent
fc609869eb
commit
1996546a73
@ -6,17 +6,19 @@ namespace Zirconium.Core
|
|||||||
{
|
{
|
||||||
public class App
|
public class App
|
||||||
{
|
{
|
||||||
|
public Config Config;
|
||||||
public SessionManager SessionManager { get; }
|
public SessionManager SessionManager { get; }
|
||||||
public Router Router { get; }
|
public Router Router { get; }
|
||||||
public ModuleManager ModuleManager { get; }
|
public ModuleManager ModuleManager { get; }
|
||||||
public IHostModuleAPI HostModuleAPI { get; }
|
public IHostModuleAPI HostModuleAPI { get; }
|
||||||
public AuthManager AuthManager { get; }
|
public AuthManager AuthManager { get; }
|
||||||
|
|
||||||
public App()
|
public App(Config config)
|
||||||
{
|
{
|
||||||
|
Config = config;
|
||||||
SessionManager = new SessionManager();
|
SessionManager = new SessionManager();
|
||||||
Router = new Router(this);
|
Router = new Router(this);
|
||||||
HostModuleAPI = new HostModuleAPI(Router);
|
HostModuleAPI = new HostModuleAPI(this, Router);
|
||||||
AuthManager = new AuthManager(this);
|
AuthManager = new AuthManager(this);
|
||||||
Log.Info("Zirconium is initialized successfully");
|
Log.Info("Zirconium is initialized successfully");
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ namespace Zirconium.Core
|
|||||||
{
|
{
|
||||||
private App _app;
|
private App _app;
|
||||||
private string _secretString;
|
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)
|
public AuthManager(App app)
|
||||||
{
|
{
|
||||||
@ -18,7 +18,7 @@ namespace Zirconium.Core
|
|||||||
_secretString = Guid.NewGuid().ToString();
|
_secretString = Guid.NewGuid().ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string CreateToken(string entityID, string deviceID)
|
public string CreateToken(string entityID, string deviceID, long tokenExpirationMillis)
|
||||||
{
|
{
|
||||||
JWTPayload payload = new JWTPayload();
|
JWTPayload payload = new JWTPayload();
|
||||||
payload.DeviceID = deviceID;
|
payload.DeviceID = deviceID;
|
||||||
@ -26,11 +26,15 @@ namespace Zirconium.Core
|
|||||||
return new JwtBuilder()
|
return new JwtBuilder()
|
||||||
.WithAlgorithm(new HMACSHA256Algorithm()) // symmetric
|
.WithAlgorithm(new HMACSHA256Algorithm()) // symmetric
|
||||||
.WithSecret(_secretString)
|
.WithSecret(_secretString)
|
||||||
.AddClaim("exp", DateTimeOffset.UtcNow.AddHours(TOKEN_EXPIRATION_TIME_HOURS).ToUnixTimeSeconds())
|
.AddClaim("exp", DateTimeOffset.UtcNow.AddMilliseconds(tokenExpirationMillis).ToUnixTimeSeconds())
|
||||||
.AddClaims(payload.ToDictionary())
|
.AddClaims(payload.ToDictionary())
|
||||||
.Encode();
|
.Encode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string CreateToken(string entityID, string deviceID) {
|
||||||
|
return CreateToken(entityID, deviceID, DEFAULT_TOKEN_EXPIRATION_TIME_HOURS);
|
||||||
|
}
|
||||||
|
|
||||||
public JWTPayload ValidateToken(string token)
|
public JWTPayload ValidateToken(string token)
|
||||||
{
|
{
|
||||||
var jsonPayload = new JwtBuilder()
|
var jsonPayload = new JwtBuilder()
|
||||||
|
@ -1,23 +1,17 @@
|
|||||||
using YamlDotNet.Serialization;
|
|
||||||
|
|
||||||
namespace Zirconium.Core
|
namespace Zirconium.Core
|
||||||
{
|
{
|
||||||
public class Config
|
public class Config
|
||||||
{
|
{
|
||||||
// A list of enabled plugins (or extensions) in server
|
// A list of enabled plugins (or extensions) in server
|
||||||
[YamlMember(Alias = "enabledPlugins")]
|
|
||||||
public string[] EnabledPlugins {get; set;}
|
public string[] EnabledPlugins {get; set;}
|
||||||
|
|
||||||
// Server domain names (e.g. example.com)
|
// Server domain names (e.g. example.com)
|
||||||
[YamlMember(Alias = "serverDomains")]
|
|
||||||
public string[] ServerDomains {get; set;}
|
public string[] ServerDomains {get; set;}
|
||||||
|
|
||||||
// Path to directory with plugin assemblies
|
// Path to directory with plugin assemblies
|
||||||
[YamlMember(Alias = "pluginsDirPath")]
|
|
||||||
public string PluginsDirPath {get; set;}
|
public string PluginsDirPath {get; set;}
|
||||||
|
|
||||||
// ID of this server in terms of Cadmium federation network
|
// ID of this server in terms of Cadmium federation network
|
||||||
[YamlMember(Alias = "serverID")]
|
|
||||||
public string ServerID {get; set;}
|
public string ServerID {get; set;}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
using System;
|
using System;
|
||||||
using WebSocketSharp.Server;
|
using WebSocketSharp.Server;
|
||||||
using WebSocketSharp;
|
using WebSocketSharp;
|
||||||
@ -42,8 +43,9 @@ namespace Zirconium.Core
|
|||||||
Console.WriteLine($"Connection {ID} was created"); // TODO implement normal logging
|
Console.WriteLine($"Connection {ID} was created"); // TODO implement normal logging
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendMessage(string message) {
|
public Task SendMessage(string message) {
|
||||||
this.Send(message.ToByteArray());
|
this.Send(message.ToByteArray());
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,43 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using CommandLine;
|
||||||
|
using Nett;
|
||||||
|
using Zirconium.Core.Logging;
|
||||||
|
|
||||||
namespace Zirconium.Core
|
namespace Zirconium.Core
|
||||||
{
|
{
|
||||||
|
public class RunOptions
|
||||||
|
{
|
||||||
|
[Option('c', "config", Required = true, HelpText = "Set config path")]
|
||||||
|
public string ConfigPath { get; set; }
|
||||||
|
}
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
App app = new App();
|
string configPath = null;
|
||||||
|
Parser.Default.ParseArguments<RunOptions>(args)
|
||||||
|
.WithParsed<RunOptions>(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<Config>(configPath);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Fatal($"Error occured when parsing config - {e.Message}");
|
||||||
|
}
|
||||||
|
App app = new App(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Zirconium.Core.Models;
|
using Zirconium.Core.Models;
|
||||||
using Zirconium.Core.Modules.Interfaces;
|
using Zirconium.Core.Modules.Interfaces;
|
||||||
|
|
||||||
@ -6,56 +7,58 @@ namespace Zirconium.Core.Modules
|
|||||||
{
|
{
|
||||||
public class HostModuleAPI : IHostModuleAPI
|
public class HostModuleAPI : IHostModuleAPI
|
||||||
{
|
{
|
||||||
|
private App _app;
|
||||||
private Router _router;
|
private Router _router;
|
||||||
|
|
||||||
public HostModuleAPI(Router router)
|
public HostModuleAPI(App app, Router router)
|
||||||
{
|
{
|
||||||
_router = router;
|
_router = router;
|
||||||
|
_app = app;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FireEvent(CoreEvent coreEvent)
|
public void FireEvent(CoreEvent coreEvent)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
_router.RouteCoreEvent(coreEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GenerateAuthToken(string entityID, string deviceID, int tokenExpirationMillis)
|
public string GenerateAuthToken(string entityID, string deviceID, int tokenExpirationMillis)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return _app.AuthManager.CreateToken(entityID, deviceID, tokenExpirationMillis);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string[] GetServerDomains()
|
public string[] GetServerDomains()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return _app.Config.ServerDomains;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetServerID()
|
public string GetServerID()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return _app.Config.ServerID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Hook(IC2SMessageHandler handler)
|
public void Hook(IC2SMessageHandler handler)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
_router.AddC2SHandler(handler.GetHandlingMessageType(), handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HookCoreEvent(ICoreEventHandler 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)
|
public void Unhook(IC2SMessageHandler handler)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
_router.RemoveC2SHandler(handler.GetHandlingMessageType(), handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UnhookCoreEvent(ICoreEventHandler handler)
|
public void UnhookCoreEvent(ICoreEventHandler handler)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
_router.RemoveCoreEventHandler(handler.GetHandlingEventType(), handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,7 +3,8 @@ using Zirconium.Core.Models;
|
|||||||
namespace Zirconium.Core.Modules.Interfaces
|
namespace Zirconium.Core.Modules.Interfaces
|
||||||
{
|
{
|
||||||
public interface IC2SMessageHandler {
|
public interface IC2SMessageHandler {
|
||||||
void HandleMessage(BaseMessage message);
|
string GetHandlingMessageType();
|
||||||
|
void HandleMessage(ConnectionInfo connInfo, BaseMessage message);
|
||||||
bool IsAuthorizationRequired();
|
bool IsAuthorizationRequired();
|
||||||
string GetHandlerUniqueID();
|
string GetHandlerUniqueID();
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ namespace Zirconium.Core.Modules.Interfaces
|
|||||||
{
|
{
|
||||||
public interface ICoreEventHandler
|
public interface ICoreEventHandler
|
||||||
{
|
{
|
||||||
|
string GetHandlingEventType();
|
||||||
void HandleEvent(CoreEvent coreEvent);
|
void HandleEvent(CoreEvent coreEvent);
|
||||||
string GetHandlerUniqueID();
|
string GetHandlerUniqueID();
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,6 @@ namespace Zirconium.Core.Modules.Interfaces
|
|||||||
string GenerateAuthToken(string entityID, string deviceID, int tokenExpirationMillis);
|
string GenerateAuthToken(string entityID, string deviceID, int tokenExpirationMillis);
|
||||||
string[] GetServerDomains();
|
string[] GetServerDomains();
|
||||||
string GetServerID();
|
string GetServerID();
|
||||||
void SendMessage(string connID, BaseMessage message);
|
void SendMessage(ConnectionInfo connInfo, BaseMessage message);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -44,46 +44,43 @@ namespace Zirconium.Core
|
|||||||
{
|
{
|
||||||
if (h.IsAuthorizationRequired())
|
if (h.IsAuthorizationRequired())
|
||||||
{
|
{
|
||||||
JWTPayload tokenPayload;
|
string hash;
|
||||||
try
|
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);
|
JWTPayload tokenPayload;
|
||||||
|
try
|
||||||
var serializedMsg = JsonConvert.SerializeObject(
|
|
||||||
OtherUtils.GenerateProtocolError(
|
|
||||||
message,
|
|
||||||
"unauthorized",
|
|
||||||
"Unauthorized access",
|
|
||||||
new Dictionary<string, object>()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
connInfo.ConnectionHandler.SendMessage(serializedMsg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connInfo.LastTokenHash == "" || connInfo.LastTokenHash == null)
|
|
||||||
{
|
|
||||||
string hash;
|
|
||||||
using (SHA512 shaM = new SHA512Managed())
|
|
||||||
{
|
{
|
||||||
hash = shaM.ComputeHash(message.AuthToken.ToByteArray()).ConvertToString();
|
tokenPayload = _app.AuthManager.ValidateToken(message.AuthToken);
|
||||||
}
|
}
|
||||||
connInfo.LastTokenHash = hash;
|
catch (Exception e)
|
||||||
// TODO implement comparing last token hash and if hash isn't changed then check payload
|
{
|
||||||
// if payload already exists - then skip validating auth token
|
Log.Warning(e.Message);
|
||||||
}
|
|
||||||
|
|
||||||
connInfo.LastTokenPayload = tokenPayload;
|
var serializedMsg = JsonConvert.SerializeObject(
|
||||||
|
OtherUtils.GenerateProtocolError(
|
||||||
|
message,
|
||||||
|
"unauthorized",
|
||||||
|
"Unauthorized access",
|
||||||
|
new Dictionary<string, object>()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
connInfo.ConnectionHandler.SendMessage(serializedMsg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connInfo.LastTokenHash = hash;
|
||||||
|
connInfo.LastTokenPayload = tokenPayload;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
// probably need to wrap whole foreach body, not only HandleMessage call - need to investigate
|
// 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)
|
public void RouteCoreEvent(CoreEvent coreEvent)
|
||||||
{
|
{
|
||||||
var handlers = _coreEventsHandlers[coreEvent.Name];
|
var handlers = _coreEventsHandlers[coreEvent.Name];
|
||||||
if (handlers == null) {
|
if (handlers == null)
|
||||||
|
{
|
||||||
Log.Warning($"Drop core event {coreEvent.Name} because server hasn't proper handlers");
|
Log.Warning($"Drop core event {coreEvent.Name} because server hasn't proper handlers");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach (var h in handlers) {
|
foreach (var h in handlers)
|
||||||
|
{
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
h.HandleEvent(coreEvent);
|
h.HandleEvent(coreEvent);
|
||||||
@ -112,6 +111,13 @@ namespace Zirconium.Core
|
|||||||
this._c2sMessageHandlers[messageType].Add(handler);
|
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)
|
public void AddCoreEventHandler(string eventType, ICoreEventHandler handler)
|
||||||
{
|
{
|
||||||
if (_coreEventsHandlers.GetValueOrDefault(eventType, null) == null)
|
if (_coreEventsHandlers.GetValueOrDefault(eventType, null) == null)
|
||||||
@ -120,5 +126,12 @@ namespace Zirconium.Core
|
|||||||
}
|
}
|
||||||
this._coreEventsHandlers[eventType].Add(handler);
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,10 +5,11 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Colorful.Console" Version="1.2.10" />
|
<PackageReference Include="Colorful.Console" Version="1.2.10" />
|
||||||
|
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
||||||
<PackageReference Include="websocketsharp.core" Version="1.0.0" />
|
<PackageReference Include="websocketsharp.core" Version="1.0.0" />
|
||||||
<PackageReference Include="YamlDotNet" Version="8.1.2" />
|
|
||||||
<PackageReference Include="JWT" Version="7.2.1" />
|
<PackageReference Include="JWT" Version="7.2.1" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.3.0" />
|
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.3.0" />
|
||||||
|
<PackageReference Include="Nett" Version="0.15.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
Loading…
Reference in New Issue
Block a user