@@ -0,0 +1,24 @@ | |||
using System; | |||
using System.IO; | |||
namespace MQTTnet.Server.Configuration | |||
{ | |||
public static class PathHelper | |||
{ | |||
public static string ExpandPath(string path) | |||
{ | |||
if (path == null) | |||
{ | |||
return null; | |||
} | |||
var uri = new Uri(path, UriKind.RelativeOrAbsolute); | |||
if (!uri.IsAbsoluteUri) | |||
{ | |||
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path); | |||
} | |||
return path; | |||
} | |||
} | |||
} |
@@ -4,6 +4,8 @@ namespace MQTTnet.Server.Configuration | |||
{ | |||
public class ScriptingSettingsModel | |||
{ | |||
public string ScriptsPath { get; set; } | |||
public List<string> IncludePaths { get; set; } | |||
} | |||
} |
@@ -7,12 +7,12 @@ using MQTTnet.Server.Scripting; | |||
namespace MQTTnet.Server.Mqtt | |||
{ | |||
public class MqttConnectionValidator : IMqttServerConnectionValidator | |||
public class MqttServerConnectionValidator : IMqttServerConnectionValidator | |||
{ | |||
private readonly PythonScriptHostService _pythonScriptHostService; | |||
private readonly ILogger _logger; | |||
public MqttConnectionValidator(PythonScriptHostService pythonScriptHostService, ILogger<MqttConnectionValidator> logger) | |||
public MqttServerConnectionValidator(PythonScriptHostService pythonScriptHostService, ILogger<MqttServerConnectionValidator> logger) | |||
{ | |||
_pythonScriptHostService = pythonScriptHostService ?? throw new ArgumentNullException(nameof(pythonScriptHostService)); | |||
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); | |||
@@ -24,18 +24,22 @@ namespace MQTTnet.Server.Mqtt | |||
{ | |||
var pythonContext = new PythonDictionary | |||
{ | |||
{ "client_id", context.ClientId }, | |||
{ "endpoint", context.Endpoint }, | |||
{ "is_secure_connection", context.IsSecureConnection }, | |||
{ "client_id", context.ClientId }, | |||
{ "username", context.Username }, | |||
{ "password", context.Password }, | |||
{ "raw_password", context.RawPassword }, | |||
{ "result", PythonConvert.Pythonfy(context.ReturnCode) } | |||
{ "raw_password", new Bytes(context.RawPassword) }, | |||
{ "clean_session", context.CleanSession}, | |||
{ "authentication_method", context.AuthenticationMethod}, | |||
{ "authentication_data", new Bytes(context.AuthenticationData)}, | |||
{ "result", PythonConvert.Pythonfy(context.ReasonCode) } | |||
}; | |||
_pythonScriptHostService.InvokeOptionalFunction("on_validate_client_connection", pythonContext); | |||
context.ReturnCode = PythonConvert.ParseEnum<MqttConnectReturnCode>((string)pythonContext["result"]); | |||
context.ReasonCode = PythonConvert.ParseEnum<MqttConnectReasonCode>((string)pythonContext["result"]); | |||
} | |||
catch (Exception exception) | |||
{ |
@@ -30,7 +30,7 @@ namespace MQTTnet.Server.Mqtt | |||
private readonly MqttClientDisconnectedHandler _mqttClientDisconnectedHandler; | |||
private readonly MqttClientSubscribedTopicHandler _mqttClientSubscribedTopicHandler; | |||
private readonly MqttClientUnsubscribedTopicHandler _mqttClientUnsubscribedTopicHandler; | |||
private readonly MqttConnectionValidator _mqttConnectionValidator; | |||
private readonly MqttServerConnectionValidator _mqttConnectionValidator; | |||
private readonly IMqttServer _mqttServer; | |||
private readonly MqttSubscriptionInterceptor _mqttSubscriptionInterceptor; | |||
private readonly PythonScriptHostService _pythonScriptHostService; | |||
@@ -43,7 +43,7 @@ namespace MQTTnet.Server.Mqtt | |||
MqttClientDisconnectedHandler mqttClientDisconnectedHandler, | |||
MqttClientSubscribedTopicHandler mqttClientSubscribedTopicHandler, | |||
MqttClientUnsubscribedTopicHandler mqttClientUnsubscribedTopicHandler, | |||
MqttConnectionValidator mqttConnectionValidator, | |||
MqttServerConnectionValidator mqttConnectionValidator, | |||
MqttSubscriptionInterceptor mqttSubscriptionInterceptor, | |||
MqttApplicationMessageInterceptor mqttApplicationMessageInterceptor, | |||
MqttServerStorage mqttServerStorage, | |||
@@ -35,7 +35,7 @@ namespace MQTTnet.Server.Mqtt | |||
return; | |||
} | |||
_path = ExpandPath(); | |||
_path = PathHelper.ExpandPath(_mqttSettings.RetainedApplicationMessages.Path); | |||
// The retained application messages are stored in a separate thread. | |||
// This is mandatory because writing them to a slow storage (like RaspberryPi SD card) | |||
@@ -115,18 +115,5 @@ namespace MQTTnet.Server.Mqtt | |||
return null; | |||
} | |||
} | |||
private string ExpandPath() | |||
{ | |||
var path = _mqttSettings.RetainedApplicationMessages.Path; | |||
var uri = new Uri(path, UriKind.RelativeOrAbsolute); | |||
if (!uri.IsAbsoluteUri) | |||
{ | |||
path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path); | |||
} | |||
return path; | |||
} | |||
} | |||
} |
@@ -17,7 +17,7 @@ namespace MQTTnet.Server.Scripting | |||
{ | |||
private readonly IDictionary<string, object> _proxyObjects = new ExpandoObject(); | |||
private readonly List<PythonScriptInstance> _scriptInstances = new List<PythonScriptInstance>(); | |||
private readonly string _scriptsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Scripts"); | |||
private readonly string _scriptsPath; | |||
private readonly ScriptingSettingsModel _scriptingSettings; | |||
private readonly ILogger<PythonScriptHostService> _logger; | |||
private readonly ScriptEngine _scriptEngine; | |||
@@ -29,6 +29,8 @@ namespace MQTTnet.Server.Scripting | |||
_scriptEngine = IronPython.Hosting.Python.CreateEngine(); | |||
_scriptEngine.Runtime.IO.SetOutput(pythonIOStream, Encoding.UTF8); | |||
_scriptsPath = PathHelper.ExpandPath(scriptingSettings.ScriptsPath); | |||
} | |||
public void Configure() | |||
@@ -186,13 +188,7 @@ namespace MQTTnet.Server.Scripting | |||
foreach (var path in _scriptingSettings.IncludePaths) | |||
{ | |||
var effectivePath = path; | |||
var uri = new Uri(effectivePath, UriKind.RelativeOrAbsolute); | |||
if (!uri.IsAbsoluteUri) | |||
{ | |||
effectivePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, effectivePath); | |||
} | |||
var effectivePath = PathHelper.ExpandPath(path); | |||
if (Directory.Exists(effectivePath)) | |||
{ | |||
@@ -25,20 +25,45 @@ def on_validate_client_connection(context): | |||
print(context) | |||
# Access some custom data here which was inserted upon connect and may use it for validation. | |||
mqtt_net_server.write_shared_data(context["client_id"], {"custom_value_1": 1, "custom_value_2": True}) | |||
return | |||
# Supported results: | |||
# * success | |||
# * unspecified_error | |||
# * malformed_packet | |||
# * protocol_error | |||
# * implementation_specific_error | |||
# * unsupported_protocol_version | |||
# * client_identifier_not_valid | |||
# * bad_user_name_or_password | |||
# * not_authorized | |||
# * server_unavailable | |||
# * server_busy | |||
# * banned | |||
# * bad_authentication_method | |||
# * topic_name_invalid | |||
# * packet_too_large | |||
# * quota_exceeded | |||
# * payload_format_invalid | |||
# * retain_not_supported | |||
# * qos_not_supported | |||
# * use_another_server | |||
# * server_moved | |||
# * connection_rate_exceeded | |||
if context["client_id"] != "test_client": | |||
context["result"] = "connection_refused_not_authorized" | |||
context["result"] = "bad_user_name_or_password" | |||
return | |||
if context["username"] != "bud spencer": | |||
context["result"] = "connection_refused_not_authorized" | |||
context["result"] = "bad_user_name_or_password" | |||
return | |||
if context["password_string"] != "secret": | |||
context["result"] = "connection_refused_not_authorized" | |||
context["result"] = "bad_user_name_or_password" | |||
print(context) | |||
@@ -3,7 +3,6 @@ using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Net; | |||
using Microsoft.AspNetCore.Authentication; | |||
using Microsoft.AspNetCore.Authentication.Cookies; | |||
using Microsoft.AspNetCore.Builder; | |||
using Microsoft.AspNetCore.Hosting; | |||
using Microsoft.AspNetCore.Mvc; | |||
@@ -17,7 +16,6 @@ using MQTTnet.Server.Logging; | |||
using MQTTnet.Server.Mqtt; | |||
using MQTTnet.Server.Scripting; | |||
using MQTTnet.Server.Scripting.DataSharing; | |||
using Swashbuckle.AspNetCore.SwaggerGen; | |||
using Swashbuckle.AspNetCore.SwaggerUI; | |||
namespace MQTTnet.Server.Web | |||
@@ -111,7 +109,7 @@ namespace MQTTnet.Server.Web | |||
services.AddSingleton<MqttClientDisconnectedHandler>(); | |||
services.AddSingleton<MqttClientSubscribedTopicHandler>(); | |||
services.AddSingleton<MqttClientUnsubscribedTopicHandler>(); | |||
services.AddSingleton<MqttConnectionValidator>(); | |||
services.AddSingleton<MqttServerConnectionValidator>(); | |||
services.AddSingleton<MqttSubscriptionInterceptor>(); | |||
services.AddSingleton<MqttApplicationMessageInterceptor>(); | |||
@@ -48,6 +48,7 @@ | |||
"EnableDebugLogging": false | |||
}, | |||
"Scripting": { | |||
"ScriptsPath": "Scripts", | |||
"IncludePaths": [ | |||
"Lib", | |||
"/usr/lib/python2.7", | |||