Update bot - move webhook server to main bot

This commit is contained in:
Zontreck 2020-04-19 22:34:34 -07:00
parent 2345db0da0
commit 58e593c898
6 changed files with 366 additions and 2 deletions

View file

@ -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

View file

@ -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
View 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();
}
}
}

View 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");
}
}
}
}

View 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;
}
}
}

View 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;
}
}
}