Commands now being accepted!
This commit is contained in:
parent
3aa9ddc73f
commit
b9c1fb9511
2 changed files with 551 additions and 315 deletions
|
|
@ -6,13 +6,13 @@ using OpenMetaverse;
|
|||
using OpenMetaverse.Assets;
|
||||
using BetterSecondBotShared.Static;
|
||||
using BetterSecondBotShared.logs;
|
||||
using BetterSecondBot.HttpService;
|
||||
using Core.Static;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
using System.Net.Http;
|
||||
using BetterSecondBotShared.Json;
|
||||
|
||||
using BetterSecondBot.HttpService;
|
||||
using Core.Static;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
using System.Net.Http;
|
||||
using BetterSecondBotShared.Json;
|
||||
|
||||
namespace BetterSecondBot.bottypes
|
||||
{
|
||||
public abstract class CommandsBot : StorageBot
|
||||
|
|
@ -130,37 +130,37 @@ namespace BetterSecondBot.bottypes
|
|||
|
||||
public override void AfterBotLoginHandler()
|
||||
{
|
||||
if (reconnect == false)
|
||||
{
|
||||
loadCommands();
|
||||
LoadCustomCommands();
|
||||
if (reconnect == false)
|
||||
{
|
||||
loadCommands();
|
||||
LoadCustomCommands();
|
||||
}
|
||||
Client.Self.RequestBalance();
|
||||
base.AfterBotLoginHandler();
|
||||
}
|
||||
|
||||
public string[] getFullListOfCommands()
|
||||
{
|
||||
List<string> output = new List<string>();
|
||||
foreach(string A in endpointcommandmap.Keys)
|
||||
{
|
||||
output.Add(A.ToLowerInvariant());
|
||||
}
|
||||
return output.ToArray();
|
||||
public string[] getFullListOfCommands()
|
||||
{
|
||||
List<string> output = new List<string>();
|
||||
foreach(string A in endpointcommandmap.Keys)
|
||||
{
|
||||
output.Add(A.ToLowerInvariant());
|
||||
}
|
||||
return output.ToArray();
|
||||
}
|
||||
|
||||
public string[] GetFullListOfCommandsWithCustoms()
|
||||
{
|
||||
List<string> output = new List<string>();
|
||||
foreach (string A in endpointcommandmap.Keys)
|
||||
{
|
||||
output.Add(A.ToLowerInvariant());
|
||||
}
|
||||
foreach(string A in custom_commands.Keys)
|
||||
{
|
||||
output.Add(A.ToLowerInvariant());
|
||||
}
|
||||
return output.ToArray();
|
||||
public string[] GetFullListOfCommandsWithCustoms()
|
||||
{
|
||||
List<string> output = new List<string>();
|
||||
foreach (string A in endpointcommandmap.Keys)
|
||||
{
|
||||
output.Add(A.ToLowerInvariant());
|
||||
}
|
||||
foreach(string A in custom_commands.Keys)
|
||||
{
|
||||
output.Add(A.ToLowerInvariant());
|
||||
}
|
||||
return output.ToArray();
|
||||
}
|
||||
|
||||
public void NotecardAddContent(string target_notecard_storage_id, string content)
|
||||
|
|
@ -259,37 +259,37 @@ namespace BetterSecondBot.bottypes
|
|||
}
|
||||
|
||||
|
||||
protected void JsonChatControler(string message, string sender_name, UUID sender_uuid, bool avatar, bool group, UUID group_uuid, bool localchat, bool fromme)
|
||||
{
|
||||
if((group == true) || (localchat == true) || (fromme == true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
bool frommaster = true;
|
||||
if (sender_uuid != master_uuid)
|
||||
{
|
||||
frommaster = false;
|
||||
}
|
||||
if (frommaster == true)
|
||||
{
|
||||
if (message == "fakerestart")
|
||||
{
|
||||
AlertMessageEventArgs Alertargs = new AlertMessageEventArgs("this is a fake restart message",new Random().Next(99999).ToString(), new OpenMetaverse.StructuredData.OSDMap());
|
||||
AlertEvent(this, Alertargs);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
JsonApiDefine APIE = JsonConvert.DeserializeObject<JsonApiDefine>(message);
|
||||
|
||||
CoreCommandLib(sender_uuid, frommaster, APIE.cmd, APIE.args, APIE.signing, APIE.reply);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogFormater.Crit("[CoreCommandLib] exploded: " + e.Message + "");
|
||||
}
|
||||
protected void JsonChatControler(string message, string sender_name, UUID sender_uuid, bool avatar, bool group, UUID group_uuid, bool localchat, bool fromme)
|
||||
{
|
||||
if((group == true) || (localchat == true) || (fromme == true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
bool frommaster = true;
|
||||
if (sender_uuid != master_uuid)
|
||||
{
|
||||
frommaster = false;
|
||||
}
|
||||
if (frommaster == true)
|
||||
{
|
||||
if (message == "fakerestart")
|
||||
{
|
||||
AlertMessageEventArgs Alertargs = new AlertMessageEventArgs("this is a fake restart message",new Random().Next(99999).ToString(), new OpenMetaverse.StructuredData.OSDMap());
|
||||
AlertEvent(this, Alertargs);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
JsonApiDefine APIE = JsonConvert.DeserializeObject<JsonApiDefine>(message);
|
||||
|
||||
CoreCommandLib(sender_uuid, frommaster, APIE.cmd, APIE.args, APIE.signing, APIE.reply);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogFormater.Crit("[CoreCommandLib] exploded: " + e.Message + "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -301,231 +301,182 @@ namespace BetterSecondBot.bottypes
|
|||
|
||||
protected override void BotChatControler(string message, string sender_name, UUID sender_uuid, bool avatar, bool group, UUID group_uuid, bool localchat, bool fromme)
|
||||
{
|
||||
base.BotChatControler(message, sender_name, sender_uuid, avatar, group, group_uuid, localchat, fromme);
|
||||
if ((group == true) || (localchat == true) || (fromme == true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
JsonApiDefine APIE = JsonConvert.DeserializeObject<JsonApiDefine>(message);
|
||||
JsonChatControler(message, sender_name, sender_uuid, avatar, group, group_uuid, localchat, fromme);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Old style [non json] to json converter [to be phased out]
|
||||
string signing_code = "";
|
||||
string[] S1 = message.Split(new[] { "@@@" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (S1.Length == 2)
|
||||
{
|
||||
signing_code = S1[1];
|
||||
}
|
||||
S1 = S1[0].Split(new[] { "#|#" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
string outputto = "none";
|
||||
if (S1.Length == 2)
|
||||
{
|
||||
outputto = S1[1];
|
||||
}
|
||||
S1 = S1[0].Split(new[] { "|||" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
string[] args = new string[] { };
|
||||
if (S1.Length == 2)
|
||||
{
|
||||
args = S1[1].Split(new[] { "~#~" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
JsonApiDefine Apihandoff = new JsonApiDefine();
|
||||
Apihandoff.cmd = S1[0];
|
||||
Apihandoff.args = args;
|
||||
Apihandoff.reply = outputto;
|
||||
Apihandoff.signing = signing_code;
|
||||
message = JsonConvert.SerializeObject(Apihandoff);
|
||||
JsonChatControler(message, sender_name, sender_uuid, avatar, group, group_uuid, localchat, fromme);
|
||||
}
|
||||
}
|
||||
|
||||
protected KeyValuePair<bool,string> callAPIcommand(string command, string[] args)
|
||||
{
|
||||
command = commandnameLowerToReal[command.ToLowerInvariant()];
|
||||
try
|
||||
{
|
||||
string ott = Tokens.OneTimeToken();
|
||||
WebApiControllerWithTokens Endpoint = commandEndpoints[endpointcommandmap[command]];
|
||||
MethodInfo theMethod = Endpoint.GetType().GetMethod(command);
|
||||
if (theMethod != null)
|
||||
{
|
||||
List<string> argsList = args.ToList();
|
||||
argsList.Add(ott);
|
||||
string reply = "Inconnect number of args expected: " + theMethod.GetParameters().Count().ToString() + " but got: " + argsList.Count.ToString();
|
||||
bool status = false;
|
||||
if (argsList.Count == theMethod.GetParameters().Count())
|
||||
{
|
||||
status = true;
|
||||
try
|
||||
{
|
||||
if (Endpoint == null)
|
||||
{
|
||||
return new KeyValuePair<bool, string>(false, "Endpoint is null");
|
||||
}
|
||||
if (argsList.Count == 0)
|
||||
{
|
||||
return new KeyValuePair<bool, string>(false, "Zero args at final check require at min 1");
|
||||
}
|
||||
object[] argsWorker = argsList.ToArray<object>();
|
||||
object processed = theMethod.Invoke(Endpoint, argsWorker);
|
||||
reply = "Error";
|
||||
if(processed != null)
|
||||
{
|
||||
reply = JsonConvert.SerializeObject(processed);
|
||||
}
|
||||
return new KeyValuePair<bool, string>(status, reply);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new KeyValuePair<bool, string>(false, e.Message);
|
||||
}
|
||||
}
|
||||
return new KeyValuePair<bool, string>(status, reply);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new KeyValuePair<bool, string>(false, "theMethod is null");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new KeyValuePair<bool, string>(false, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
protected void CoreCommandLib(UUID sender, bool Master, string command, string[] args, string signingcode, string targetreply)
|
||||
{
|
||||
bool accepted = Master;
|
||||
if(accepted == false)
|
||||
{
|
||||
string raw = "" + command + "" + string.Join("~#~", args) + "" + myconfig.Security_SignedCommandkey + "";
|
||||
string hashcheck = helpers.GetSHA1(raw);
|
||||
if (hashcheck == signingcode)
|
||||
{
|
||||
accepted = true;
|
||||
}
|
||||
}
|
||||
if (accepted == true)
|
||||
{
|
||||
CallAPI(command, args, targetreply);
|
||||
}
|
||||
}
|
||||
|
||||
public string CallAPI(string command, string[] args)
|
||||
{
|
||||
return CallAPI(command, args, "None");
|
||||
}
|
||||
public string CallAPI(string command, string[] args, string replyvia)
|
||||
{
|
||||
return CallAPI(command, args, replyvia, false);
|
||||
}
|
||||
|
||||
protected string customCommand(string command, string[] args, string replyvia, bool customcommand)
|
||||
{
|
||||
if (customcommand == true)
|
||||
{
|
||||
SmartCommandReply(false, replyvia, "Custom command lockout", command);
|
||||
return "Custom command lockout";
|
||||
}
|
||||
int commands_issued = 0;
|
||||
foreach (string A in custom_commands[command])
|
||||
{
|
||||
List<string> command_args_split = A.Split(new[] { "|||" }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
int loop = 1;
|
||||
string args_passed = "";
|
||||
if (command_args_split.Count() == 2)
|
||||
{
|
||||
args_passed = command_args_split[1];
|
||||
while ((loop <= 5) && (loop <= args.Length))
|
||||
{
|
||||
args_passed = args_passed.Replace("[C_ARG_" + loop.ToString() + "]", args[loop - 1]);
|
||||
loop++;
|
||||
}
|
||||
}
|
||||
CallAPI(command_args_split[0], args_passed.Split("~#~"), "None", true);
|
||||
commands_issued++;
|
||||
}
|
||||
return "Issued "+ commands_issued.ToString()+" commands";
|
||||
}
|
||||
public string CallAPI(string command, string[] args, string replyvia, bool customcommand)
|
||||
{
|
||||
if (command == null)
|
||||
{
|
||||
return "No command";
|
||||
}
|
||||
if (replyvia == null)
|
||||
{
|
||||
replyvia = "none";
|
||||
}
|
||||
KeyValuePair<bool, string> statusreply = new KeyValuePair<bool, string>(false, "Not processed");
|
||||
if (commandnameLowerToReal.ContainsKey(command.ToLowerInvariant()) == false)
|
||||
{
|
||||
if (custom_commands.ContainsKey(command) == false)
|
||||
{
|
||||
SmartCommandReply(false, replyvia, "Unknown command", command);
|
||||
return "{ status: \"false\", message: \"Unknown\" }";
|
||||
}
|
||||
statusreply = new KeyValuePair<bool, string>(true, customCommand(command, args, replyvia, customcommand));
|
||||
}
|
||||
else
|
||||
{
|
||||
statusreply = callAPIcommand(command, args);
|
||||
}
|
||||
SmartCommandReply(statusreply.Key, replyvia, statusreply.Value, command);
|
||||
return "{ status: \"" + statusreply.Key.ToString() + "\", message: \""+ statusreply.Value+"\" command: \""+command+"\", args: \""+string.Join("~#~",args)+"\" }";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
protected void loadCommands()
|
||||
{
|
||||
commandsLoaded = true;
|
||||
Dictionary<string, Type> commandmodules = http_commands_helper.getCommandModules();
|
||||
foreach (Type entry in commandmodules.Values)
|
||||
{
|
||||
LoadCommandEndpoint(entry);
|
||||
}
|
||||
base.BotChatControler(message, sender_name, sender_uuid, avatar, group, group_uuid, localchat, fromme);
|
||||
if ((group == true) || (localchat == true) || (fromme == true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
JsonApiDefine APIE = JsonConvert.DeserializeObject<JsonApiDefine>(message);
|
||||
JsonChatControler(message, sender_name, sender_uuid, avatar, group, group_uuid, localchat, fromme);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Old style [non json] to json converter [to be phased out]
|
||||
string signing_code = "";
|
||||
string[] S1 = message.Split(new[] { "@@@" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (S1.Length == 2)
|
||||
{
|
||||
signing_code = S1[1];
|
||||
}
|
||||
S1 = S1[0].Split(new[] { "#|#" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
string outputto = "none";
|
||||
if (S1.Length == 2)
|
||||
{
|
||||
outputto = S1[1];
|
||||
}
|
||||
S1 = S1[0].Split(new[] { "|||" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
string[] args = new string[] { };
|
||||
if (S1.Length == 2)
|
||||
{
|
||||
args = S1[1].Split(new[] { "~#~" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
JsonApiDefine Apihandoff = new JsonApiDefine();
|
||||
Apihandoff.cmd = S1[0];
|
||||
Apihandoff.args = args;
|
||||
Apihandoff.reply = outputto;
|
||||
Apihandoff.signing = signing_code;
|
||||
message = JsonConvert.SerializeObject(Apihandoff);
|
||||
JsonChatControler(message, sender_name, sender_uuid, avatar, group, group_uuid, localchat, fromme);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void LoadCommandEndpoint(Type endpointtype)
|
||||
{
|
||||
WebApiControllerWithTokens controler = (WebApiControllerWithTokens)Activator.CreateInstance(endpointtype, args: new object[] { this, Tokens });
|
||||
controler.disableIPlockout();
|
||||
commandEndpoints.Add(endpointtype.Name, controler);
|
||||
foreach (MethodInfo M in endpointtype.GetMethods())
|
||||
{
|
||||
bool isCallable = false;
|
||||
foreach (CustomAttributeData At in M.CustomAttributes)
|
||||
{
|
||||
if (At.AttributeType.Name == "RouteAttribute")
|
||||
{
|
||||
isCallable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isCallable == true)
|
||||
{
|
||||
if (endpointcommandmap.ContainsKey(M.Name) == true)
|
||||
{
|
||||
Warn("Namespace: "+endpointtype.Name+" / Command: " + M.Name + " already found in " + endpointcommandmap[M.Name]);
|
||||
continue;
|
||||
}
|
||||
if(commandnameLowerToReal.ContainsKey(M.Name.ToLowerInvariant()) == true)
|
||||
{
|
||||
Warn("Namespace: " + endpointtype.Name + " / Command: " + M.Name + " already found in " + endpointcommandmap[M.Name]);
|
||||
continue;
|
||||
}
|
||||
endpointcommandmap.Add(M.Name, endpointtype.Name);
|
||||
commandnameLowerToReal.Add(M.Name.ToLowerInvariant(), M.Name);
|
||||
}
|
||||
}
|
||||
protected KeyValuePair<bool,string> callAPIcommand(string command, string[] args)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected void CoreCommandLib(UUID sender, bool Master, string command, string[] args, string signingcode, string targetreply)
|
||||
{
|
||||
bool accepted = Master;
|
||||
if(accepted == false)
|
||||
{
|
||||
string raw = "" + command + "" + string.Join("~#~", args) + "" + myconfig.Security_SignedCommandkey + "";
|
||||
string hashcheck = helpers.GetSHA1(raw);
|
||||
if (hashcheck == signingcode)
|
||||
{
|
||||
accepted = true;
|
||||
}
|
||||
}
|
||||
if (accepted == true)
|
||||
{
|
||||
CallAPI(command, args, targetreply);
|
||||
}
|
||||
}
|
||||
|
||||
public string CallAPI(string command, string[] args)
|
||||
{
|
||||
return CallAPI(command, args, "None");
|
||||
}
|
||||
public string CallAPI(string command, string[] args, string replyvia)
|
||||
{
|
||||
return CallAPI(command, args, replyvia, false);
|
||||
}
|
||||
|
||||
protected string customCommand(string command, string[] args, string replyvia, bool customcommand)
|
||||
{
|
||||
if (customcommand == true)
|
||||
{
|
||||
SmartCommandReply(false, replyvia, "Custom command lockout", command);
|
||||
return "Custom command lockout";
|
||||
}
|
||||
int commands_issued = 0;
|
||||
foreach (string A in custom_commands[command])
|
||||
{
|
||||
List<string> command_args_split = A.Split(new[] { "|||" }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
int loop = 1;
|
||||
string args_passed = "";
|
||||
if (command_args_split.Count() == 2)
|
||||
{
|
||||
args_passed = command_args_split[1];
|
||||
while ((loop <= 5) && (loop <= args.Length))
|
||||
{
|
||||
args_passed = args_passed.Replace("[C_ARG_" + loop.ToString() + "]", args[loop - 1]);
|
||||
loop++;
|
||||
}
|
||||
}
|
||||
CallAPI(command_args_split[0], args_passed.Split("~#~"), "None", true);
|
||||
commands_issued++;
|
||||
}
|
||||
return "Issued "+ commands_issued.ToString()+" commands";
|
||||
}
|
||||
public string CallAPI(string command, string[] args, string replyvia, bool customcommand)
|
||||
{
|
||||
if (command == null)
|
||||
{
|
||||
return "No command";
|
||||
}
|
||||
if (replyvia == null)
|
||||
{
|
||||
replyvia = "none";
|
||||
}
|
||||
KeyValuePair<bool, string> statusreply = new KeyValuePair<bool, string>(false, "Not processed");
|
||||
if (commandnameLowerToReal.ContainsKey(command.ToLowerInvariant()) == false)
|
||||
{
|
||||
if (custom_commands.ContainsKey(command) == false)
|
||||
{
|
||||
SmartCommandReply(false, replyvia, "Unknown command", command);
|
||||
return "{ status: \"false\", message: \"Unknown\" }";
|
||||
}
|
||||
statusreply = new KeyValuePair<bool, string>(true, customCommand(command, args, replyvia, customcommand));
|
||||
}
|
||||
else
|
||||
{
|
||||
statusreply = callAPIcommand(command, args);
|
||||
}
|
||||
SmartCommandReply(statusreply.Key, replyvia, statusreply.Value, command);
|
||||
return "{ status: \"" + statusreply.Key.ToString() + "\", message: \""+ statusreply.Value+"\" command: \""+command+"\", args: \""+string.Join("~#~",args)+"\" }";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
protected void loadCommands()
|
||||
{
|
||||
commandsLoaded = true;
|
||||
Dictionary<string, Type> commandmodules = http_commands_helper.getCommandModules();
|
||||
foreach (Type entry in commandmodules.Values)
|
||||
{
|
||||
LoadCommandEndpoint(entry);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void LoadCommandEndpoint(Type endpointtype)
|
||||
{
|
||||
WebApiControllerWithTokens controler = (WebApiControllerWithTokens)Activator.CreateInstance(endpointtype, args: new object[] { this, Tokens });
|
||||
controler.disableIPlockout();
|
||||
commandEndpoints.Add(endpointtype.Name, controler);
|
||||
foreach (MethodInfo M in endpointtype.GetMethods())
|
||||
{
|
||||
bool isCallable = false;
|
||||
foreach (CustomAttributeData At in M.CustomAttributes)
|
||||
{
|
||||
if (At.AttributeType.Name == "RouteAttribute")
|
||||
{
|
||||
isCallable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isCallable == true)
|
||||
{
|
||||
if (endpointcommandmap.ContainsKey(M.Name) == true)
|
||||
{
|
||||
Warn("Namespace: "+endpointtype.Name+" / Command: " + M.Name + " already found in " + endpointcommandmap[M.Name]);
|
||||
continue;
|
||||
}
|
||||
if(commandnameLowerToReal.ContainsKey(M.Name.ToLowerInvariant()) == true)
|
||||
{
|
||||
Warn("Namespace: " + endpointtype.Name + " / Command: " + M.Name + " already found in " + endpointcommandmap[M.Name]);
|
||||
continue;
|
||||
}
|
||||
endpointcommandmap.Add(M.Name, endpointtype.Name);
|
||||
commandnameLowerToReal.Add(M.Name.ToLowerInvariant(), M.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
using OpenMetaverse;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OpenMetaverse;
|
||||
using SecondBotEvents.Config;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace SecondBotEvents.Services
|
||||
{
|
||||
|
|
@ -13,6 +18,50 @@ namespace SecondBotEvents.Services
|
|||
public CommandsService(EventsSecondBot setMaster) : base(setMaster)
|
||||
{
|
||||
myConfig = new CommandsConfig(master.fromEnv, master.fromFolder);
|
||||
loadCommands();
|
||||
}
|
||||
|
||||
protected void loadCommands()
|
||||
{
|
||||
Dictionary<string, Type> commandmodules = http_commands_helper.getCommandModules();
|
||||
foreach (Type entry in commandmodules.Values)
|
||||
{
|
||||
LoadCommandEndpoint(entry);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void LoadCommandEndpoint(Type endpointtype)
|
||||
{
|
||||
CommandsAPI controler = (CommandsAPI)Activator.CreateInstance(endpointtype, args: new object[] { master });
|
||||
controler.disableIPlockout();
|
||||
commandEndpoints.Add(endpointtype.Name, controler);
|
||||
foreach (MethodInfo M in endpointtype.GetMethods())
|
||||
{
|
||||
bool isCallable = false;
|
||||
foreach (CustomAttributeData At in M.CustomAttributes)
|
||||
{
|
||||
if (At.AttributeType.Name == "RouteAttribute")
|
||||
{
|
||||
isCallable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isCallable == true)
|
||||
{
|
||||
if (endpointcommandmap.ContainsKey(M.Name) == true)
|
||||
{
|
||||
LogFormater.Warn("Namespace: " + endpointtype.Name + " / Command: " + M.Name + " already found in " + endpointcommandmap[M.Name]);
|
||||
continue;
|
||||
}
|
||||
if (commandnameLowerToReal.ContainsKey(M.Name.ToLowerInvariant()) == true)
|
||||
{
|
||||
LogFormater.Warn("Namespace: " + endpointtype.Name + " / Command: " + M.Name + " already found in " + endpointcommandmap[M.Name]);
|
||||
continue;
|
||||
}
|
||||
endpointcommandmap.Add(M.Name, endpointtype.Name);
|
||||
commandnameLowerToReal.Add(M.Name.ToLowerInvariant(), M.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string,int> acceptTokens = new Dictionary<string,int>();
|
||||
|
|
@ -68,20 +117,6 @@ namespace SecondBotEvents.Services
|
|||
acceptNewCommands = false;
|
||||
}
|
||||
|
||||
protected void BotClientRestart(object o, BotClientNotice e)
|
||||
{
|
||||
acceptNewCommands = false;
|
||||
Console.WriteLine("Commands service [Attached to new client]");
|
||||
master.botClient.client.Network.LoggedOut += BotLoggedOut;
|
||||
master.botClient.client.Network.SimConnected += BotLoggedIn;
|
||||
}
|
||||
|
||||
protected void BotLoggedOut(object o, LoggedOutEventArgs e)
|
||||
{
|
||||
master.botClient.client.Network.SimConnected += BotLoggedIn;
|
||||
Console.WriteLine("Commands service [Waiting for connect]");
|
||||
}
|
||||
|
||||
protected void BotImMessage(object o, InstantMessageEventArgs e)
|
||||
{
|
||||
if(acceptNewCommands == false)
|
||||
|
|
@ -96,51 +131,187 @@ namespace SecondBotEvents.Services
|
|||
{
|
||||
return;
|
||||
}
|
||||
bool acceptMessage = true;
|
||||
bool requireSigning = false;
|
||||
bool acceptMessage = false;
|
||||
bool requireSigning = true;
|
||||
switch (e.IM.Dialog)
|
||||
{
|
||||
case InstantMessageDialog.MessageFromObject:
|
||||
{
|
||||
requireSigning = true;
|
||||
acceptMessage = true;
|
||||
break;
|
||||
}
|
||||
case InstantMessageDialog.MessageFromAgent: // shared with SessionSend
|
||||
case InstantMessageDialog.SessionSend:
|
||||
{
|
||||
if(e.IM.GroupIM == false)
|
||||
if(e.IM.GroupIM == true) // groups are unable to issue commands
|
||||
{
|
||||
acceptMessage = false;
|
||||
break;
|
||||
}
|
||||
if (myConfig.GetOnlySelectedAvs() == false)
|
||||
{
|
||||
acceptMessage = false;
|
||||
break;
|
||||
}
|
||||
requireSigning = false;
|
||||
acceptMessage = myConfig.GetAvsCSV().Contains(e.IM.FromAgentName);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
acceptMessage = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (requireSigning == true)
|
||||
{
|
||||
acceptMessage = acceptMessageSigned(e.IM.Message);
|
||||
}
|
||||
if (acceptMessage == false)
|
||||
if(acceptMessage == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SignedCommand C = new SignedCommand(e.IM.Message,
|
||||
requireSigning,
|
||||
myConfig.GetEnforceTimeWindow(),
|
||||
myConfig.GetTimeWindowSecs(),
|
||||
myConfig.GetSharedSecret()
|
||||
);
|
||||
if (C.accepted == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
KeyValuePair<bool, string> reply = runCommand(C);
|
||||
if(C.replyTarget != null)
|
||||
{
|
||||
SmartCommandReply(reply.Key, C.replyTarget, reply.Value, C.command);
|
||||
}
|
||||
}
|
||||
|
||||
protected bool acceptMessageSigned(string message)
|
||||
protected void SmartCommandReply(bool run_status, string target, string output, string command)
|
||||
{
|
||||
return false;
|
||||
string mode = "CHAT";
|
||||
UUID target_avatar = UUID.Zero;
|
||||
int target_channel = 0;
|
||||
if (target.StartsWith("http://"))
|
||||
{
|
||||
mode = "HTTP";
|
||||
}
|
||||
else if (UUID.TryParse(target, out target_avatar) == true)
|
||||
{
|
||||
mode = "IM";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (int.TryParse(target, out target_channel) == false)
|
||||
{
|
||||
mode = "None";
|
||||
}
|
||||
}
|
||||
if (mode == "CHAT")
|
||||
{
|
||||
if (target_channel <= 0)
|
||||
{
|
||||
LogFormater.Crit("[SmartReply] output Channel must be zero or higher - using 99");
|
||||
target_channel = 999;
|
||||
}
|
||||
master.botClient.client.Self.Chat(output, target_channel, ChatType.Normal);
|
||||
}
|
||||
else if (mode == "IM")
|
||||
{
|
||||
master.botClient.client.Self.InstantMessage(target_avatar, output);
|
||||
}
|
||||
else if (mode == "HTTP")
|
||||
{
|
||||
Dictionary<string, string> values = new Dictionary<string, string>
|
||||
{
|
||||
{ "reply", output },
|
||||
{ "command", command },
|
||||
};
|
||||
|
||||
var content = new FormUrlEncodedContent(values);
|
||||
try
|
||||
{
|
||||
HTTPclient.PostAsync(target, content);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogFormater.Crit("[SmartReply] HTTP failed: " + e.Message + "");
|
||||
}
|
||||
}
|
||||
}
|
||||
protected HttpClient HTTPclient = new HttpClient();
|
||||
|
||||
public KeyValuePair<bool, string> runCommand(SignedCommand C)
|
||||
{
|
||||
C.command = commandnameLowerToReal[C.command.ToLowerInvariant()];
|
||||
try
|
||||
{
|
||||
string ott = SingleUseToken();
|
||||
CommandsAPI Endpoint = commandEndpoints[endpointcommandmap[C.command]];
|
||||
MethodInfo theMethod = Endpoint.GetType().GetMethod(C.command);
|
||||
if (theMethod != null)
|
||||
{
|
||||
List<string> argsList = C.args.ToList();
|
||||
argsList.Add(ott);
|
||||
string reply = "Inconnect number of args expected: " + theMethod.GetParameters().Count().ToString() + " but got: " + argsList.Count.ToString();
|
||||
bool status = false;
|
||||
if (argsList.Count == theMethod.GetParameters().Count())
|
||||
{
|
||||
status = true;
|
||||
try
|
||||
{
|
||||
if (Endpoint == null)
|
||||
{
|
||||
return new KeyValuePair<bool, string>(false, "Endpoint is null");
|
||||
}
|
||||
if (argsList.Count == 0)
|
||||
{
|
||||
return new KeyValuePair<bool, string>(false, "Zero args at final check require at min 1");
|
||||
}
|
||||
object[] argsWorker = argsList.ToArray<object>();
|
||||
object processed = theMethod.Invoke(Endpoint, argsWorker);
|
||||
reply = "Error";
|
||||
if (processed != null)
|
||||
{
|
||||
reply = JsonConvert.SerializeObject(processed);
|
||||
}
|
||||
return new KeyValuePair<bool, string>(status, reply);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new KeyValuePair<bool, string>(false, e.Message);
|
||||
}
|
||||
}
|
||||
return new KeyValuePair<bool, string>(status, reply);
|
||||
}
|
||||
return new KeyValuePair<bool, string>(false, "theMethod is null");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new KeyValuePair<bool, string>(false, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public string[] getFullListOfCommands()
|
||||
{
|
||||
List<string> output = new List<string>();
|
||||
foreach (string A in endpointcommandmap.Keys)
|
||||
{
|
||||
output.Add(A.ToLowerInvariant());
|
||||
}
|
||||
return output.ToArray();
|
||||
}
|
||||
|
||||
protected Dictionary<string, CommandsAPI> commandEndpoints = new Dictionary<string, CommandsAPI>();
|
||||
protected Dictionary<string, string> endpointcommandmap = new Dictionary<string, string>(); // command = endpoint
|
||||
protected Dictionary<string, string> commandnameLowerToReal = new Dictionary<string, string>();
|
||||
|
||||
protected void BotClientRestart(object o, BotClientNotice e)
|
||||
{
|
||||
acceptNewCommands = false;
|
||||
Console.WriteLine("Commands service [Attached to new client]");
|
||||
master.botClient.client.Network.LoggedOut += BotLoggedOut;
|
||||
master.botClient.client.Network.SimConnected += BotLoggedIn;
|
||||
}
|
||||
|
||||
protected void BotLoggedOut(object o, LoggedOutEventArgs e)
|
||||
{
|
||||
master.botClient.client.Network.SimConnected += BotLoggedIn;
|
||||
Console.WriteLine("Commands service [Waiting for connect]");
|
||||
}
|
||||
|
||||
protected void BotLoggedIn(object o, SimConnectedEventArgs e)
|
||||
|
|
@ -151,4 +322,118 @@ namespace SecondBotEvents.Services
|
|||
Console.WriteLine("Commands service [accepting IM commands]");
|
||||
}
|
||||
}
|
||||
|
||||
public class SignedCommand
|
||||
{
|
||||
public string command;
|
||||
public string signingCode;
|
||||
public string[] args;
|
||||
public string replyTarget;
|
||||
public bool accepted = false;
|
||||
public long unixtimeOfCommand = 0;
|
||||
public SignedCommand(string input, bool requireSigning, bool requireTimewindow, int windowSize, string secret)
|
||||
{
|
||||
unpackInput(input);
|
||||
if (requireSigning == false)
|
||||
{
|
||||
accepted = true; // just accept the command
|
||||
return;
|
||||
}
|
||||
long dif = SecondbotHelpers.UnixTimeNow() - unixtimeOfCommand;
|
||||
if ((requireTimewindow == true) && ((unixtimeOfCommand == 0) || (dif > windowSize))) // bad time window
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ((signingCode == null) ) // no signing code
|
||||
{
|
||||
return;
|
||||
}
|
||||
string raw = command;
|
||||
raw = raw + string.Join("~#~", args);
|
||||
if (requireTimewindow == true)
|
||||
{
|
||||
raw = raw + unixtimeOfCommand.ToString();
|
||||
}
|
||||
raw = raw + secret;
|
||||
string cooked = SecondbotHelpers.GetSHA1(raw);
|
||||
if (cooked != signingCode)
|
||||
{
|
||||
return; // invaild signing code
|
||||
}
|
||||
accepted = true;
|
||||
|
||||
|
||||
}
|
||||
protected void unpackInput(string input)
|
||||
{
|
||||
if (IsValidJson(input) == false)
|
||||
{
|
||||
unpackStringToClass(input);
|
||||
return;
|
||||
}
|
||||
unpackJsonToClass();
|
||||
}
|
||||
protected JToken obj = null;
|
||||
protected void unpackStringToClass(string input)
|
||||
{
|
||||
// command|||args~#~args~#~args#|#reply_target@@@sha1 [inc time if required];|;unixtime of command
|
||||
|
||||
string[] bits = input.Split(";|;");
|
||||
if(bits.Length == 2)
|
||||
{
|
||||
unixtimeOfCommand = Convert.ToInt32(bits[1]);
|
||||
}
|
||||
bits = bits[0].Split("#|#");
|
||||
if(bits.Length == 2)
|
||||
{
|
||||
replyTarget = bits[1];
|
||||
}
|
||||
bits = bits[0].Split("|||");
|
||||
command = bits[0];
|
||||
args = new string[] { };
|
||||
if(bits.Length == 2)
|
||||
{
|
||||
args = bits[1].Split("~#~");
|
||||
}
|
||||
}
|
||||
protected void unpackJsonToClass()
|
||||
{
|
||||
command = jsonHelper.GetValue<string>(obj, "cmd", null);
|
||||
args = jsonHelper.GetValue<string[]>(obj, "args", null);
|
||||
signingCode = jsonHelper.GetValue<string>(obj, "signing", null);
|
||||
replyTarget = jsonHelper.GetValue<string>(obj, "reply", null);
|
||||
unixtimeOfCommand = jsonHelper.GetValue<long>(obj, "unixtime", 0);
|
||||
}
|
||||
|
||||
private bool IsValidJson(string strInput)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(strInput)) { return false; }
|
||||
strInput = strInput.Trim();
|
||||
if ((strInput.StartsWith("{") && strInput.EndsWith("}")) || //For object
|
||||
(strInput.StartsWith("[") && strInput.EndsWith("]"))) //For array
|
||||
{
|
||||
try
|
||||
{
|
||||
obj = JToken.Parse(strInput);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class jsonHelper
|
||||
{
|
||||
public static T GetValue<T>(this JToken jToken, string key, T defaultValue = default(T))
|
||||
{
|
||||
dynamic ret = jToken[key];
|
||||
if (ret == null) return defaultValue;
|
||||
if (ret is JObject) return JsonConvert.DeserializeObject<T>(ret.ToString());
|
||||
return (T)ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue