Update bot - move webhook server to main bot
This commit is contained in:
parent
2345db0da0
commit
58e593c898
6 changed files with 366 additions and 2 deletions
|
@ -6,7 +6,7 @@ using System.Reflection;
|
||||||
[assembly: AssemblyCompany("ZNI")]
|
[assembly: AssemblyCompany("ZNI")]
|
||||||
[assembly: AssemblyAlgorithmId(System.Configuration.Assemblies.AssemblyHashAlgorithm.MD5)]
|
[assembly: AssemblyAlgorithmId(System.Configuration.Assemblies.AssemblyHashAlgorithm.MD5)]
|
||||||
[assembly: AssemblyCopyright("© 2020 Tara Piccari")]
|
[assembly: AssemblyCopyright("© 2020 Tara Piccari")]
|
||||||
[assembly: AssemblyFileVersion("5.405")]
|
[assembly: AssemblyFileVersion("5.513")]
|
||||||
[assembly: AssemblyDescription("Second Life Bot - BotCore5")]
|
[assembly: AssemblyDescription("Second Life Bot - BotCore5")]
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ namespace Bot.Assemble
|
||||||
public class ASMInfo
|
public class ASMInfo
|
||||||
{
|
{
|
||||||
public static string BotName = "ZBotCore";
|
public static string BotName = "ZBotCore";
|
||||||
public static double BotVer = 5.405;
|
public static double BotVer = 5.513;
|
||||||
public static string GitPassword
|
public static string GitPassword
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
@ -55,6 +55,8 @@ namespace Bot
|
||||||
|
|
||||||
public string GitPassword { get; set; } = "NOT_SET";
|
public string GitPassword { get; set; } = "NOT_SET";
|
||||||
|
|
||||||
|
public int WebServerPort { get; set; } = 35591;
|
||||||
|
|
||||||
public Dictionary<UUID, int> BotAdmins { get; set; } = new Dictionary<UUID, int>();
|
public Dictionary<UUID, int> BotAdmins { get; set; } = new Dictionary<UUID, int>();
|
||||||
|
|
||||||
|
|
||||||
|
|
58
WebHookServer/HookCmds.cs
Normal file
58
WebHookServer/HookCmds.cs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Bot.WebHookServer
|
||||||
|
{
|
||||||
|
class HookCmds
|
||||||
|
{
|
||||||
|
|
||||||
|
public HttpListener listener;
|
||||||
|
public void OnWebHook(IAsyncResult ar)
|
||||||
|
{
|
||||||
|
HttpListenerContext CTX = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CTX = listener.EndGetContext(ar);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
BotSession.Instance.Logger.info(log: "ERROR: Getting the end context for the listener failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
listener.BeginGetContext(OnWebHook, null);
|
||||||
|
|
||||||
|
|
||||||
|
Stream body = CTX.Request.InputStream;
|
||||||
|
StreamReader SR = new StreamReader(body, CTX.Request.ContentEncoding);
|
||||||
|
string Response = SR.ReadToEnd();
|
||||||
|
|
||||||
|
if (!Directory.Exists("request_log")) Directory.CreateDirectory("request_log");
|
||||||
|
|
||||||
|
|
||||||
|
string RequestPath = CTX.Request.RawUrl;
|
||||||
|
if (RequestPath.EndsWith("/")) RequestPath = RequestPath.Substring(0, RequestPath.Length - 1);
|
||||||
|
|
||||||
|
string CustomReplyStr = "";
|
||||||
|
|
||||||
|
WebhookRegistry.HTTPResponseData reply = WebhookRegistry.Instance.RunCommand(RequestPath, Response, CTX.Request.Headers, CTX.Request.HttpMethod);
|
||||||
|
|
||||||
|
|
||||||
|
CustomReplyStr = reply.ReplyString;
|
||||||
|
byte[] buffer = Encoding.UTF8.GetBytes("\n" + CustomReplyStr);
|
||||||
|
CTX.Response.ContentLength64 = buffer.Length;
|
||||||
|
CTX.Response.AddHeader("Server", "1.6");
|
||||||
|
CTX.Response.StatusCode = reply.Status;
|
||||||
|
if (reply.ReturnContentType != "" && reply.ReturnContentType != null)
|
||||||
|
{
|
||||||
|
CTX.Response.ContentType = reply.ReturnContentType;
|
||||||
|
}
|
||||||
|
Stream output = CTX.Response.OutputStream;
|
||||||
|
output.Write(buffer, 0, buffer.Length);
|
||||||
|
output.Close();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
76
WebHookServer/WebHookServer.cs
Normal file
76
WebHookServer/WebHookServer.cs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
|
||||||
|
Licensed under the GPLv2
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bot;
|
||||||
|
using Bot.CommandSystem;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Bot.WebHookServer
|
||||||
|
{
|
||||||
|
class GitServer : IProgram
|
||||||
|
{
|
||||||
|
public HttpListener listener;
|
||||||
|
public MessageHandler.MessageHandleEvent MHEx;
|
||||||
|
public string ProgramName
|
||||||
|
{
|
||||||
|
get { return "GitServer"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float ProgramVersion
|
||||||
|
{
|
||||||
|
get { return 1.6f; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string getTick()
|
||||||
|
{
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void passArguments(string data)
|
||||||
|
{
|
||||||
|
// dont throw, just silently do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadConfiguration()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onIMEvent(object sender, InstantMessageEventArgs e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public void run(GridClient client, MessageHandler MH, CommandRegistry registry)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
listener = new HttpListener();
|
||||||
|
MHEx = MH.callbacks;
|
||||||
|
listener.Prefixes.Add($"https://*:{MainConfiguration.Instance.WebServerPort}/");
|
||||||
|
|
||||||
|
listener.Start();
|
||||||
|
var hc = new HookCmds();
|
||||||
|
hc.listener = listener;
|
||||||
|
|
||||||
|
listener.BeginGetContext(hc.OnWebHook, null);
|
||||||
|
|
||||||
|
}catch(Exception e)
|
||||||
|
{
|
||||||
|
BotSession.Instance.MHE(MessageHandler.Destinations.DEST_LOCAL, UUID.Zero, "Error: Program could not escalate to Admin Privileges. WebHook engine not running");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
WebHookServer/WebhookAttribs.cs
Normal file
25
WebHookServer/WebhookAttribs.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
|
||||||
|
Licensed under the GPLv2
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Bot.WebHookServer
|
||||||
|
{
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
|
||||||
|
public class WebhookAttribs : Attribute
|
||||||
|
{
|
||||||
|
public string Path = "";
|
||||||
|
public MethodInfo AssignedMethod = null;
|
||||||
|
public string HTTPMethod = "GET";
|
||||||
|
public WebhookAttribs(string WebPath)
|
||||||
|
{
|
||||||
|
Path = WebPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
203
WebHookServer/WebhookRegistry.cs
Normal file
203
WebHookServer/WebhookRegistry.cs
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright © 2019 Tara Piccari (Aria; Tashia Redrose)
|
||||||
|
Licensed under the GPLv2
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.IO;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Bot.WebHookServer
|
||||||
|
{
|
||||||
|
public sealed class WebhookRegistry
|
||||||
|
{
|
||||||
|
private static WebhookRegistry _reg = null;
|
||||||
|
private static readonly object locks = new object();
|
||||||
|
static WebhookRegistry()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
public static WebhookRegistry Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (locks)
|
||||||
|
{
|
||||||
|
if(_reg == null)
|
||||||
|
{
|
||||||
|
_reg = new WebhookRegistry();
|
||||||
|
_reg.LocateHooks();
|
||||||
|
}
|
||||||
|
return _reg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Dictionary<string, WebhookAttribs> hooks = new Dictionary<string, WebhookAttribs>();
|
||||||
|
|
||||||
|
public void LocateHooks()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for(i = 0; i< AppDomain.CurrentDomain.GetAssemblies().Length; i++)
|
||||||
|
{
|
||||||
|
// Grab Assembly
|
||||||
|
Assembly asm = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
asm = AppDomain.CurrentDomain.GetAssemblies()[i];
|
||||||
|
}catch(Exception e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(asm != null)
|
||||||
|
{
|
||||||
|
int ii = 0;
|
||||||
|
for(ii = 0; ii<asm.GetTypes().Length; ii++)
|
||||||
|
{
|
||||||
|
Type T = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
T = asm.GetTypes()[ii];
|
||||||
|
}catch(Exception e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
if(T != null)
|
||||||
|
{
|
||||||
|
// Grab the WebHook Attribute
|
||||||
|
if (T.IsClass)
|
||||||
|
{
|
||||||
|
foreach(MethodInfo mi in T.GetMethods())
|
||||||
|
{
|
||||||
|
WebhookAttribs[] wha = (WebhookAttribs[])mi.GetCustomAttributes(typeof(WebhookAttribs), false);
|
||||||
|
//
|
||||||
|
int ix = 0;
|
||||||
|
for(ix=0;ix<wha.Length;ix++)
|
||||||
|
{
|
||||||
|
WebhookAttribs attribu = wha[ix];
|
||||||
|
attribu.AssignedMethod = mi;
|
||||||
|
hooks.Add(attribu.Path, attribu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch(Exception e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public HTTPResponseData RunCommand(string path, string body, NameValueCollection headers, string method)
|
||||||
|
{
|
||||||
|
// Run the command then return the response string from the server
|
||||||
|
HTTPResponseData NotFound = new HTTPResponseData();
|
||||||
|
NotFound.ReplyString = "More water is required!";
|
||||||
|
NotFound.Status = 418;
|
||||||
|
//HTTPResponseData hrd = (HTTPResponseData)fnc.Invoke(obj, new object[] { body, headers });
|
||||||
|
//
|
||||||
|
HTTPResponseData hrd = NotFound;
|
||||||
|
|
||||||
|
foreach (WebhookAttribs zAPIPath in hooks.Values)
|
||||||
|
{
|
||||||
|
// compare strings; If a % symbol is located, then skip that so long as the inbound string matches totally.
|
||||||
|
// Append the value of % in the inbound request to the array passed to the function
|
||||||
|
List<string> arguments = new List<string>();
|
||||||
|
string sCheck = zAPIPath.Path;
|
||||||
|
bool Found = true; // Default to true
|
||||||
|
if (method != zAPIPath.HTTPMethod) Found = false;
|
||||||
|
|
||||||
|
string[] aCheck = sCheck.Split(new[] { '/' });
|
||||||
|
string[] actualRequest = path.Split(new[] { '/', '?' }); // if it contains a ?, we'll put that into the GETBody
|
||||||
|
string theArgs = "";
|
||||||
|
|
||||||
|
if (path.Contains('?'))
|
||||||
|
{
|
||||||
|
// continue
|
||||||
|
string[] tmp1 = path.Split(new[] { '?' });
|
||||||
|
theArgs = tmp1[1];
|
||||||
|
actualRequest = tmp1[0].Split(new[] { '/' });
|
||||||
|
|
||||||
|
}
|
||||||
|
if (actualRequest.Length == aCheck.Length)
|
||||||
|
{
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < aCheck.Length; i++)
|
||||||
|
{
|
||||||
|
// TODO: CHANGE THIS SLOPPY MESS TO REGEX.. FOR NOW IT WORKS!
|
||||||
|
if (aCheck[i] == "%")
|
||||||
|
{
|
||||||
|
arguments.Add(actualRequest[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
if (aCheck[i] == actualRequest[i])
|
||||||
|
{
|
||||||
|
// we're good!
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// check other path hooks before returning 404!
|
||||||
|
Found = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else Found = false;
|
||||||
|
|
||||||
|
arguments.Add(theArgs);
|
||||||
|
|
||||||
|
if (Found)
|
||||||
|
{
|
||||||
|
// Run the method
|
||||||
|
Console.WriteLine("Running: " + zAPIPath.Path + "; " + zAPIPath.AssignedMethod.Name + "; For inbound: " + path);
|
||||||
|
object _method = Activator.CreateInstance(zAPIPath.AssignedMethod.DeclaringType);
|
||||||
|
hrd = (HTTPResponseData)zAPIPath.AssignedMethod.Invoke(_method, new object[] { arguments, body, method, headers });
|
||||||
|
|
||||||
|
// Console.WriteLine("====> " + hrd.ReplyString);
|
||||||
|
|
||||||
|
return hrd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// an API Path wasn't found
|
||||||
|
// check the filesystem
|
||||||
|
string[] noArgPath = path.Split(new[] { '?' });
|
||||||
|
if (File.Exists($"htdocs/{noArgPath[0]}")) // This will provide a way to display HTML to the user. If the server must process data internally, please use a method & attribute. Nothing is stopping you from also loading in a HTML/js file and returning a stylized response.
|
||||||
|
{
|
||||||
|
hrd.Status = 200;
|
||||||
|
hrd.ReplyString = File.ReadAllText($"htdocs/{noArgPath[0]}");
|
||||||
|
Dictionary<string, string> customHeaders = null; // This is mainly going to be used in instances where the domain-server needs a document but CORS isnt set
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
return hrd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct HTTPResponseData
|
||||||
|
{
|
||||||
|
public int Status;
|
||||||
|
public string ReplyString;
|
||||||
|
public string ReturnContentType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue