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