diff --git a/BSBshared/Json/JsonConfig.cs b/BSBshared/Json/JsonConfig.cs index 4855607..88c1183 100644 --- a/BSBshared/Json/JsonConfig.cs +++ b/BSBshared/Json/JsonConfig.cs @@ -44,9 +44,7 @@ namespace BetterSecondBotShared.Json // HTTP interface public bool Http_Enable { get; set; } - public int Http_Port { get; set; } public string Http_Host { get; set; } - public string Http_PublicUrl { get; set; } // Name2Key DB public bool Name2Key_Enable { get; set; } diff --git a/BSBshared/Json/JsonConfigApi.cs b/BSBshared/Json/JsonConfigApi.cs index fb237b3..5722a20 100644 --- a/BSBshared/Json/JsonConfigApi.cs +++ b/BSBshared/Json/JsonConfigApi.cs @@ -126,17 +126,9 @@ namespace BetterSecondBotShared.Json { return "Allow the bot to start a HTTP interface (Required for web UI and Post commands)"; } - else if (cmd == "Http_Port") - { - return "The port the HTTP interface should be running on"; - } else if (cmd == "Http_Host") { - return "The URL the interface is on example use \"docker\" for auto or \"http://localhost:portnum\""; - } - else if (cmd == "Http_PublicUrl") - { - return "The public url used to access the web ui"; + return "The URL the interface is on example use \"docker\" for auto or \"http://*:8080\" to listen on port 8080Note: for windows you might need to accept a firewall alert and restart the app!"; } return ""; } @@ -265,15 +257,14 @@ namespace BetterSecondBotShared.Json else if (cmd == "DiscordFull_Enable") { return "False"; } else if (cmd == "DiscordFull_Token") { return ""; } else if (cmd == "DiscordFull_ServerID") { return ""; } + else if (cmd == "DiscordFull_Keep_GroupChat") { return "False"; } return ""; } protected string GetValueHint_HTTP(string cmd) { // HTTP if (cmd == "Http_Enable") { return "False"; } - else if (cmd == "Http_Port") { return "80"; } - else if (cmd == "Http_Host") { return "http://localhost:80"; } - else if (cmd == "Http_PublicUrl") { return "http://localhost/"; } + else if (cmd == "Http_Host") { return "http://*:8080"; } return ""; } protected string GetValueHint_DiscordTTS(string cmd) @@ -409,13 +400,13 @@ namespace BetterSecondBotShared.Json { LogFormater.Warn("Http disabled: Security_WebUIKey length must be 12 or more"); } - else if (jsonConfig.Http_Port < 80) - { - LogFormater.Warn("Http disabled: Httpport range below protected range - Given: (" + jsonConfig.Http_Port + ")"); - } else if ((jsonConfig.Http_Host != "docker") && (jsonConfig.Http_Host.StartsWith("http") == false)) { - LogFormater.Warn("Http disabled: Http_Host must be vaild: http://XXXXXX or \"docker\" - Given: (" + jsonConfig.Http_Host + ")"); + LogFormater.Warn("Http disabled: Http_Host must be vaild or \"docker\" - Given: (" + jsonConfig.Http_Host + ")"); + } + else if (jsonConfig.Http_Host == "docker") + { + jsonConfig.Http_Host = "http://*:8080"; } else { diff --git a/CLI/BetterSecondBot.csproj b/CLI/BetterSecondBot.csproj index a514855..ebb6bf7 100644 --- a/CLI/BetterSecondBot.csproj +++ b/CLI/BetterSecondBot.csproj @@ -26,35 +26,18 @@ linux-x64 - - - - - - - - - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - diff --git a/CLI/CliExitOnLogout.cs b/CLI/CliExitOnLogout.cs index 40fdc58..f55dbb2 100644 --- a/CLI/CliExitOnLogout.cs +++ b/CLI/CliExitOnLogout.cs @@ -1,12 +1,8 @@ -using BetterSecondBot.HttpServer; -using BetterSecondBotShared.IO; +using BetterSecondBot.HttpService; using BetterSecondBotShared.Json; using BetterSecondBotShared.logs; using BetterSecondBotShared.Static; using BSB.bottypes; -using System; -using System.Collections.Generic; -using System.Text; using System.Threading; using static BetterSecondBot.Program; @@ -51,8 +47,11 @@ namespace BetterSecondBot Bot.Start(); if (Config.Http_Enable == true) { + /* SecondBotHttpServer my_http_server = new SecondBotHttpServer(); my_http_server.StartHttpServer(Bot, Config); + */ + new HttpAsService(Bot, Config); } if(use_self_keep_alive == true) { diff --git a/CLI/DiscordSupervisor/Status.cs b/CLI/DiscordSupervisor/Status.cs index 9c1ce6e..ea8cc00 100644 --- a/CLI/DiscordSupervisor/Status.cs +++ b/CLI/DiscordSupervisor/Status.cs @@ -16,7 +16,7 @@ namespace BetterSecondBot.DiscordSupervisor } } } - string DiscordBotStatus_laststatus = ""; + public string GetStatus() { string reply = ""; diff --git a/CLI/DiscordSupervisor/relay.cs b/CLI/DiscordSupervisor/relay.cs index df341ff..a3762a4 100644 --- a/CLI/DiscordSupervisor/relay.cs +++ b/CLI/DiscordSupervisor/relay.cs @@ -106,7 +106,7 @@ namespace BetterSecondBot.DiscordSupervisor else { controler.Bot.Debug("DiscordBotChatControler - Localchat:" + sender_name + ":" + message); - await SendMessageToChannelAsync("localchat", "" + sender_name + ":" + message, "bot", UUID.Zero, "bot").ConfigureAwait(false); + await SendMessageToChannelAsync("localchat", "" + sender_name + ": " + message, "bot", UUID.Zero, "bot").ConfigureAwait(false); } } else diff --git a/CLI/HttpServer/SecondBotHttpServer.cs b/CLI/HttpServer/SecondBotHttpServer.cs deleted file mode 100644 index ec64309..0000000 --- a/CLI/HttpServer/SecondBotHttpServer.cs +++ /dev/null @@ -1,277 +0,0 @@ -using BetterSecondBot.HttpWebUi; -using BetterSecondBotShared.IO; -using BetterSecondBotShared.Json; -using BetterSecondBotShared.logs; -using BetterSecondBotShared.Static; -using BSB; -using BSB.bottypes; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Web; - -namespace BetterSecondBot.HttpServer -{ - public class Json_http_reply - { - public bool status; - public string message; - public string redirect; - } - public class SecondBotHttpServer - { - protected HttpListener listener; - protected SecondBot Bot; - public SecondBot GetBot { get { return Bot; } } - protected JsonConfig Config; - public JsonConfig GetConfig { get { return Config; } } - protected HTTPCommandsInterface post_controler; - - protected string url = ""; - public bool ShutdownHTTP { get; set; } - public bool HTTPCnCmode { get; set; } - - public string GetStatus() - { - string reply = ""; - if(Bot == null) - { - reply += "- No bot"; - } - else - { - Bot.LastStatusMessage = Bot.GetStatus(); - reply += Bot.LastStatusMessage; - } - if(listener == null) - { - reply += " - No HTTP listener"; - } - return reply; - } - public void NewBot() - { - Bot = new SecondBot(); - } - public void KillBot() - { - Bot.GetClient.Network.Logout(); - Bot.GetClient.Network.Shutdown(OpenMetaverse.NetworkManager.DisconnectType.ClientInitiated); - Bot = null; - } - public void StartHttpServer(JsonConfig setConfig) - { - StartHttpServer(setConfig, null); - } - public void StartHttpServer(SecondBot LinkBot, JsonConfig setConfig) - { - StartHttpServer(setConfig, LinkBot); - } - protected void StartHttpServer(JsonConfig setConfig, SecondBot LinkBot) - { - Config = setConfig; - Bot = LinkBot; - int port = Math.Abs(Config.Http_Port); - url = Config.Http_Host; - if (Config.Http_Host == "docker") - { - url = "http://*:" + port.ToString() + "/"; - } - else - { - if (url.StartsWith("http://") == false) - { - url = "http://localhost:" + port.ToString() + ""; - } - if (url.EndsWith("/") == false) - { - url = "" + url + "/"; - } - } - OpenHttpService(); - } - - protected async Task HandleIncomingConnections() - { - Webui myUI = new Webui(Config,Bot); - while (Bot.KillMe == false) - { - HttpListenerContext ctx = await listener.GetContextAsync().ConfigureAwait(true); - HttpListenerRequest req = ctx.Request; - HttpListenerResponse resp = ctx.Response; - resp.Cookies = req.Cookies; - string test = req.Url.AbsoluteUri; - if (helpers.notempty(Config.Http_PublicUrl) == true) - { - // normal mapped - test = test.Replace(Config.Http_PublicUrl, ""); - - //rproxy weirdness - test = test.Replace(Config.Http_PublicUrl, ""); - Config.Http_PublicUrl = Config.Http_PublicUrl.Replace("http://", ""); - Config.Http_PublicUrl = Config.Http_PublicUrl.Replace("https://", ""); - test = test.Replace(Config.Http_PublicUrl, ""); - test = test.Replace(":" + Config.Http_Port.ToString(), ""); - } - Json_http_reply reply = new Json_http_reply(); - List http_args = test.Split('/', StringSplitOptions.RemoveEmptyEntries).ToList(); - byte[] data; - resp.StatusCode = 200; - resp.ContentType = "text/html"; - if (req.HttpMethod == "GET") - { - KeyValuePair replydata = myUI.Get_Process(resp, http_args); - if (replydata.Value != null) - { - resp.ContentType = replydata.Key; - data = replydata.Value; - resp.ContentLength64 = data.LongLength; - await resp.OutputStream.WriteAsync(data, 0, data.Length).ConfigureAwait(true); - resp.Close(); - } - else - { - data = Encoding.UTF8.GetBytes("error with service"); - resp.ContentLength64 = data.LongLength; - resp.ContentType = "text/html"; - await resp.OutputStream.WriteAsync(data, 0, data.Length).ConfigureAwait(true); - resp.Close(); - } - } - else if (req.HttpMethod == "POST") - { - string text; - using (var reader = new StreamReader(req.InputStream, req.ContentEncoding)) - { - text = reader.ReadToEnd(); - } - //"command = logout & args = &passkey = Kp83VZaEhcy" - string[] pairs = text.Split('&', StringSplitOptions.RemoveEmptyEntries); - Dictionary post_args = new Dictionary(); - foreach (string B in pairs) - { - string[] bits = B.Split('=', StringSplitOptions.RemoveEmptyEntries); - if (bits.Length == 2) - { - post_args.Add(bits[0].Trim(), HttpUtility.UrlDecode(bits[1].Trim())); - } - } - resp.StatusCode = 200; - if (myUI.Post_process(reply, resp, http_args, post_args) == true) - { - bool accept_request = false; - string why_request_failed = "Bad signing request"; - - string command = ""; - string arg = ""; - string signing_code; - - if (post_args.ContainsKey("command") == true) - { - command = post_args["command"]; - if (post_args.ContainsKey("args") == true) - { - arg = post_args["args"]; - } - if (post_args.ContainsKey("code") == true) - { - signing_code = post_args["code"]; - string raw = "" + command + "" + arg + "" + Config.Security_SignedCommandkey + ""; - string hashcheck = helpers.GetSHA1(raw); - if (hashcheck == signing_code) - { - accept_request = true; - } - } - else - { - why_request_failed = "Post missing arg value"; - } - } - else - { - why_request_failed = "Post missing command value"; - } - reply.message = why_request_failed; - reply.status = accept_request; - if (accept_request == true) - { - reply.message = String.Join("###", post_controler.Call(command, arg)); - } - } - if (reply.redirect != "") - { - if (reply.redirect != null) - { - if (reply.redirect == "/") - { - reply.redirect = Config.Http_PublicUrl; - } - else - { - reply.redirect = Config.Http_PublicUrl + reply.redirect; - } - } - - } - data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(reply)); - resp.ContentLength64 = data.LongLength; - await resp.OutputStream.WriteAsync(data, 0, data.Length).ConfigureAwait(true); - resp.Close(); - } - } - } - protected void OpenHttpService() - { - post_controler = new HTTPCommandsInterface(Bot,this); - Thread t = new Thread(delegate (object _) - { - bool ok = true; - try - { - listener = new HttpListener(); - listener.Prefixes.Add(url); - listener.Start(); - } - catch (Exception e) - { - ok = false; - LogFormater.Crit("Unable to setup http service: "+e.Message+""); - LogFormater.Crit("if running on windows please check: https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/configuring-http-and-https?redirectedfrom=MSDN"); - } - if (ok == true) - { - bool clean_exit = false; - LogFormater.Status("Listening for connections on " + url + ""); - while (clean_exit == false) - { - try - { - LogFormater.Status("HTTP ready"); - Task listenTask = HandleIncomingConnections(); - listenTask.GetAwaiter().GetResult(); - } - catch - { - LogFormater.Status("HTTP died"); - //Status("Http interface killed itself: " + e.ToString() + ""); - } - } - } - listener.Close(); - }) - { - Name = "http thead", - IsBackground = true - }; - t.Start(); - } - } -} diff --git a/CLI/HttpServer/control/Actions/logout.cs b/CLI/HttpServer/control/Actions/logout.cs deleted file mode 100644 index 76f314d..0000000 --- a/CLI/HttpServer/control/Actions/logout.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace BetterSecondBot.HttpServer.Control.Actions -{ - public class Logout : HTTP_commands - { - public override string Helpfile { get { return "Makes the bot logout Returns OK,I dont want to go if accepted"; } } - - public override string[] CallFunction(string[] args) - { - if (bot != null) - { - if (httpserver.HTTPCnCmode == true) - { - httpserver.KillBot(); - return new [] { "OK", "Bot Shutting down" }; - } - else - { - bot.KillMePlease(); - return new [] { "OK", "I dont want to go" }; - } - } - else - { - return Failed("No bot logged in"); - } - } - } -} diff --git a/CLI/HttpServer/control/Interface/cmd_lib.cs b/CLI/HttpServer/control/Interface/cmd_lib.cs deleted file mode 100644 index 5dccba1..0000000 --- a/CLI/HttpServer/control/Interface/cmd_lib.cs +++ /dev/null @@ -1,42 +0,0 @@ -using OpenMetaverse; -using System; -using System.Collections.Generic; -using System.Text; - -namespace BetterSecondBot.HttpServer.Control.Interface -{ - public class CoreCMD : HTTP_commands - { - public override string[] ArgTypes { get { return new [] { "Text","Text" }; } } - public override string[] ArgHints { get { return new [] { "Command","Args (~#~ split)" }; } } - public override string Helpfile { get { return "Calls the Commands interface via HTTP (returns OK if not rejected)"; } } - - public override int Min_Required_args { get { return 2; } } - - public override string[] CallFunction(string[] args) - { - if (bot != null) - { - if (ArgsCheck(args) == true) - { - if (bot.GetCommandsInterface.Call(args[0], args[1], UUID.Zero) == true) - { - return new [] { "OK" }; - } - else - { - return Failed("Something went wrong with the call"); - } - } - else - { - return Failed("Incorrect number of args"); - } - } - else - { - return Failed("No bot"); - } - } - } -} diff --git a/CLI/HttpServer/http_commands.cs b/CLI/HttpServer/http_commands.cs deleted file mode 100644 index 65e08d6..0000000 --- a/CLI/HttpServer/http_commands.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Linq; -using OpenMetaverse; -using BSB; -using BSB.bottypes; -using BetterSecondBotShared.API; -using BetterSecondBotShared.Json; -using BetterSecondBotShared.logs; - -namespace BetterSecondBot.HttpServer -{ - public class HTTPCommandsInterface : API_supported_interface - { - protected SecondBot bot; - protected SecondBotHttpServer httpserver; - - public HTTPCommandsInterface(SecondBot linktobot, SecondBotHttpServer sethttpserver) - { - bot = linktobot; - httpserver = sethttpserver; - API_type = typeof(HTTP_commands); - LoadCommandsList(); - } - - public string[] Call(string command, string arg) - { - command = command.ToLowerInvariant(); - HTTP_commands cmd = (HTTP_commands)GetCommand(command); - if (cmd != null) - { - cmd.Setup(bot,httpserver); - return cmd.CallFunction(arg.Split(new[] { "|||" }, StringSplitOptions.None)); - } - else - { - LogFormater.Debug("" + command + " [Failed]: I have no fucking idea what you are talking about"); - return new[] { "Failed", "I have no fucking idea what you are talking about" }; - } - } - } - - public abstract class HTTP_commands : API_interface - { - protected SecondBot bot; - protected SecondBotHttpServer httpserver; - public void Setup(SecondBot setBot,SecondBotHttpServer Sethttpserver) - { - bot = setBot; - httpserver = Sethttpserver; - } - public virtual string[] CallFunction(string[] args) - { - if (ArgsCheck(args) == true) - { - return new[] { "OK", "No override" }; - } - return Failed("Incorrect number of args"); - } - protected bool ArgsCheck(string[] args) - { - if (args.Length >= Min_Required_args) - { - return true; - } - return false; - } - protected string[] Failed(string why_failed) - { - LogFormater.Warn("HTTP: " + CommandName + " [Failed]: " + why_failed); - return new [] {"Failed",why_failed}; - } - } - - -} diff --git a/CLI/HttpService/HttpAsService.cs b/CLI/HttpService/HttpAsService.cs new file mode 100644 index 0000000..3f85bab --- /dev/null +++ b/CLI/HttpService/HttpAsService.cs @@ -0,0 +1,164 @@ +using BetterSecondBotShared.Json; +using BSB.bottypes; +using System; +using EmbedIO; +using EmbedIO.Actions; +using EmbedIO.WebApi; +using System.Threading; +using Swan.Logging; +using System.Collections.Generic; +using EmbedIO.Security; +using BetterSecondBotShared.Static; +using System.Net; +using EmbedIO.Routing; + +namespace BetterSecondBot.HttpService +{ + public class HttpAsService + { + protected JsonConfig Config; + protected SecondBot Bot; + protected TokenStorage Tokens; + public HttpAsService(SecondBot MainBot, JsonConfig BotConfig) + { + Bot = MainBot; + Config = BotConfig; + + // Our web server is disposable + Logger.UnregisterLogger(); + using (var server = CreateWebServer(Config.Http_Host)) + { + // Once we've registered our modules and configured them, we call the RunAsync() method. + server.RunAsync(); + while(Bot.KillMe == false) + { + Thread.Sleep(1000); + } + } + } + + private WebServer CreateWebServer(string url) + { + Tokens = new TokenStorage(); + var server = new WebServer(o => o + .WithUrlPrefix(url) + .WithMode(HttpListenerMode.EmbedIO)) + .WithIPBanning(o => o + .WithMaxRequestsPerSecond(10) + .WithRegexRules("HTTP exception 404") + ) + .WithWebApi("/inventory", m => m + .WithController(() => new SecondbotInventory(Bot, Tokens))) + .WithWebApi("/core", m => m + .WithController(() => new SecondbotCoreWebAPi(Config, Bot, Tokens))) + .WithModule(new ActionModule("/", HttpVerbs.Any, ctx => ctx.SendDataAsync(new { Message = "Error" }))); + return server; + } + + } + + public class TokenStorage + { + protected Dictionary tokens = new Dictionary(); + + public void PurgeExpired() + { + List oldTokens = new List(); + long now = helpers.UnixTimeNow(); + foreach (KeyValuePair entry in tokens) + { + if(entry.Value.Expires <= now) + { + oldTokens.Add(entry.Key); + } + } + foreach(string A in oldTokens) + { + tokens.Remove(A); + } + } + + public string Expire(string token) + { + if (tokens.ContainsKey(token) == true) + { + if(tokens.Remove(token) == true) + { + return "ok"; + } + } + return "Failed to remove token"; + } + + public bool Allow(string code, IPAddress IPaddress) + { + if(tokens.ContainsKey(code) == true) + { + tokenInfo info = tokens[code]; + if (info.Expires <= helpers.UnixTimeNow()) + { + PurgeExpired(); + return false; + } + if (info.IP == IPaddress) + { + return true; + } + } + return false; + } + + public string CreateToken(IPAddress IP) + { + PurgeExpired(); + bool used = true; + string last = ""; + while(used == true) + { + last = helpers.GetSHA1(last + helpers.UnixTimeNow() + new Random().Next(13256).ToString()).Substring(0, 10); + used = tokens.ContainsKey(last); + if (used == false) + { + tokenInfo Info = new tokenInfo(); + Info.IP = IP; + Info.Expires = helpers.UnixTimeNow() + (60 * 10); + } + } + return last; + } + } + + public class WebApiControllerWithTokens : WebApiController + { + protected TokenStorage tokens; + protected SecondBot bot; + + public WebApiControllerWithTokens(SecondBot mainbot, TokenStorage setuptokens) + { + bot = mainbot; + tokens = setuptokens; + } + + /* + * not yet supported but will repace the current way soon(TM) + [Route(HttpVerbs.Post, "/command/{token}")] + public string CommandLib(string token, [JsonData] CommandLibCall request) + { + return "ok"; + } + */ + + public IPAddress getClientIP() + { + return HttpContext.Request.RemoteEndPoint.Address; + } + + } + + public class tokenInfo + { + public long Expires = 0; + public IPAddress IP = null; + } + +} diff --git a/CLI/HttpService/Inventory.cs b/CLI/HttpService/Inventory.cs new file mode 100644 index 0000000..25c4865 --- /dev/null +++ b/CLI/HttpService/Inventory.cs @@ -0,0 +1,44 @@ +using BSB.bottypes; +using BSB.Static; +using EmbedIO; +using EmbedIO.Routing; +using EmbedIO.WebApi; +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace BetterSecondBot.HttpService +{ + public class SecondbotInventory : WebApiControllerWithTokens + { + public SecondbotInventory(SecondBot mainbot, TokenStorage setuptokens) : base(mainbot, setuptokens) { } + + [Route(HttpVerbs.Get, "/folders/{token}")] + public string folders(string token) + { + if(tokens.Allow(token, getClientIP()) == true) + { + return HelperInventory.MapFolderJson(bot); + } + return "Token not accepted"; + } + + [Route(HttpVerbs.Get, "/contents/{folderUUID}/{token}")] + public string Contents(string folderUUID, string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + if (UUID.TryParse(folderUUID, out UUID folder) == true) + { + return HelperInventory.MapFolderInventoryJson(bot, folder); + } + return "Invaild folder UUID"; + } + return "Token not accepted"; + + } + } + + +} diff --git a/CLI/HttpService/Secondbot.cs b/CLI/HttpService/Secondbot.cs new file mode 100644 index 0000000..8f3497b --- /dev/null +++ b/CLI/HttpService/Secondbot.cs @@ -0,0 +1,107 @@ +using BetterSecondBotShared.Json; +using BetterSecondBotShared.Static; +using BSB.bottypes; +using OpenMetaverse; +using System.Threading.Tasks; + +using EmbedIO; +using EmbedIO.Routing; +using EmbedIO.WebApi; + + +namespace BetterSecondBot.HttpService +{ + public class SecondbotCoreWebAPi : WebApiControllerWithTokens + { + + protected JsonConfig config; + public SecondbotCoreWebAPi(JsonConfig myconfig, SecondBot mainbot, TokenStorage setuptokens) : base(mainbot, setuptokens) + { + config = myconfig; + } + + [Route(HttpVerbs.Post, "/gettoken")] + public string GetToken([FormField] string authcode) + { + long now = helpers.UnixTimeNow() + 120; + int loop = 0; + bool accepted = false; + while(loop <= 30) + { + string hashA = helpers.GetSHA1((now + loop) + "" + config.Security_WebUIKey).Substring(0, 10); + string hashB = helpers.GetSHA1((now - loop) + "" + config.Security_WebUIKey).Substring(0, 10); + if ((authcode == hashA) || (authcode == hashB)) + { + accepted = true; + break; + } + loop++; + } + if(accepted == true) + { + return tokens.CreateToken(HttpContext.Request.RemoteEndPoint.Address); + } + return "Authcode not accepted"; + } + + [Route(HttpVerbs.Get, "/logout/{token}")] + public string Logout(string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + return tokens.Expire(token); + } + return "Token not accepted"; + } + + [Route(HttpVerbs.Get, "/version/{token}")] + public string Version(string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + return bot.MyVersion; + } + return "Token not accepted"; + } + + [Route(HttpVerbs.Get, "/name/{token}")] + public string Name(string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + return bot.GetClient.Self.FirstName + " " + bot.GetClient.Self.LastName; + } + return "Token not accepted"; + } + + [Route(HttpVerbs.Post, "/command/{token}")] + public async Task command(string token) + { + if (tokens.Allow(token, getClientIP()) == true) + { + CommandLibCall data = await HttpContext.GetRequestDataAsync(); + string compressedArgs = string.Join("~#~", data.Args); + string raw = data.Command + compressedArgs; + string cooked = helpers.GetSHA1(raw + config.Security_SignedCommandkey); + if (cooked == data.AuthCode) + { + bool status = bot.GetCommandsInterface.Call(data.Command, compressedArgs, UUID.Zero, "~#~"); + if (status == true) + { + return "accepted"; + } + } + } + return "Token not accepted"; + } + } + + public class CommandLibCall + { + public string Command { get; set; } + public string[] Args { get; set; } + public string AuthCode { get; set; } + } + + +} diff --git a/CLI/HttpWebUi/theme/css/site.css b/CLI/HttpWebUi/theme/css/site.css deleted file mode 100644 index 582030c..0000000 --- a/CLI/HttpWebUi/theme/css/site.css +++ /dev/null @@ -1,4 +0,0 @@ -.logo -{ - width: 100%; -} diff --git a/CLI/HttpWebUi/theme/images/favicon.png b/CLI/HttpWebUi/theme/images/favicon.png deleted file mode 100644 index dc83cd0..0000000 Binary files a/CLI/HttpWebUi/theme/images/favicon.png and /dev/null differ diff --git a/CLI/HttpWebUi/theme/images/logo.png b/CLI/HttpWebUi/theme/images/logo.png deleted file mode 100644 index 540dbea..0000000 Binary files a/CLI/HttpWebUi/theme/images/logo.png and /dev/null differ diff --git a/CLI/HttpWebUi/theme/js/site.js b/CLI/HttpWebUi/theme/js/site.js deleted file mode 100644 index bb14d91..0000000 --- a/CLI/HttpWebUi/theme/js/site.js +++ /dev/null @@ -1,201 +0,0 @@ -$( document ).ready(function() { - $(".ajaxq").submit(function(e) { - e.preventDefault(); - var form = $(this); - var url = form.attr('action'); - var method = form.attr('method'); - $.ajax({ - type: method, - url: url, - data: form.serialize(), - success: function(data) - { - try - { - jsondata = JSON.parse(data); - var redirectdelay = 1500; - if(jsondata.hasOwnProperty('status')) - { - if(jsondata.hasOwnProperty('message')) - { - if(jsondata.status == false) - { - redirectdelay = 3500; - if(jsondata.message != "") alert_warning(jsondata.message); - } - } - if(jsondata.hasOwnProperty('redirect')) - { - if(jsondata.redirect != "") - { - if(jsondata.redirect != null) - { - setTimeout(function(){ $(location).attr('href', jsondata.redirect) }, redirectdelay); - } - } - } - } - else - { - alert_error("Reply from server is not vaild please reload the page and try again."); - } - } - catch(e) - { - alert_warning("Unable to process reply, please reload the page and try again!"); - } - }, - error: function (data) - { - alert_error(data); - } - }); - }); - $(".ajax").submit(function(e) { - e.preventDefault(); - var form = $(this); - var url = form.attr('action'); - var method = form.attr('method'); - $.ajax({ - type: method, - url: url, - data: form.serialize(), - success: function(data) - { - try - { - jsondata = JSON.parse(data); - var redirectdelay = 1500; - if(jsondata.hasOwnProperty('status')) - { - if(jsondata.hasOwnProperty('message')) - { - if(jsondata.status == true) - { - if(jsondata.message != "") alert_success(jsondata.message); - } - else - { - redirectdelay = 3500; - if(jsondata.message != "") alert_warning(jsondata.message); - } - } - if(jsondata.hasOwnProperty('redirect')) - { - if(jsondata.redirect != "") - { - if(jsondata.redirect != null) - { - setTimeout(function(){ $(location).attr('href', jsondata.redirect) }, redirectdelay); - } - } - } - } - else - { - alert_error("Reply from server is not vaild please reload the page and try again."); - } - } - catch(e) - { - alert_warning("Unable to process reply, please reload the page and try again!"); - } - }, - error: function (data) - { - alert_error(data); - } - }); - }); -}); - -function alert_success(smsg) -{ - alert(smsg,"success"); -} -function alert_error(smsg) -{ - alert(smsg,"error"); -} -function alert_warning(smsg) -{ - alert(smsg,"warning"); -} -function alert(smsg,alerttype) -{ - $.notify({ - // options - message: smsg - },{ - // settings - type: alerttype - }); -} - -function update_localchat(urlbase) -{ - $.ajax({ - type: "post", - url: ""+urlbase+"ajax/localchat/get", - success: function(data) - { - try - { - jsondata = JSON.parse(data); - var redirectdelay = 1500; - if(jsondata.hasOwnProperty('status')) - { - if(jsondata.hasOwnProperty('message')) - { - if(jsondata.status == true) - { - $('#localchat').prop('readonly',false); - var text = ""; - var addon = ""; - $.each( JSON.parse(jsondata.message), function( key, value ) { - text = ""+value+""+addon+""+text+""; - addon = "\n"; - }); - $('#localchat').val(text); - $('#localchat').prop('readonly',true); - } - } - } - } - catch(e) - { - alert_warning("Unable to process reply, please reload the page and try again!"); - } - } - }); -} -function update_groupchat(urlbase,groupuuid) -{ - $.ajax({ - type: "post", - url: ""+urlbase+"ajax/groupchat/get", - data: "groupuuid="+groupuuid+"", - success: function(data) - { - try - { - jsondata = JSON.parse(data); - var redirectdelay = 1500; - if(jsondata.hasOwnProperty('status')) - { - if(jsondata.hasOwnProperty('message')) - { - if(jsondata.status == true) - { - $("localchat").val(jsondata.message); - } - } - } - } - catch(e) - { - alert_warning("Unable to process reply, please reload the page and try again!"); - } - } - }); -} \ No newline at end of file diff --git a/CLI/HttpWebUi/theme/layout/cdn.css.layout b/CLI/HttpWebUi/theme/layout/cdn.css.layout deleted file mode 100644 index ee2feb3..0000000 --- a/CLI/HttpWebUi/theme/layout/cdn.css.layout +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/CLI/HttpWebUi/theme/layout/cdn.js.layout b/CLI/HttpWebUi/theme/layout/cdn.js.layout deleted file mode 100644 index a47b628..0000000 --- a/CLI/HttpWebUi/theme/layout/cdn.js.layout +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/CLI/HttpWebUi/theme/layout/full.layout b/CLI/HttpWebUi/theme/layout/full.layout deleted file mode 100644 index 236b6d2..0000000 --- a/CLI/HttpWebUi/theme/layout/full.layout +++ /dev/null @@ -1,35 +0,0 @@ - - - [[html_title]] - [[html_title_after]] - [[html_cs_top_cdn]] - [[html_cs_top]] - - - - - - - - - - - - - - - [[page_content]] - - - - - - [[html_js_bottom_cdn]] - [[html_js_bottom]] - - - - diff --git a/CLI/HttpWebUi/theme/layout/login.block b/CLI/HttpWebUi/theme/layout/login.block deleted file mode 100644 index 8a26ea4..0000000 --- a/CLI/HttpWebUi/theme/layout/login.block +++ /dev/null @@ -1,14 +0,0 @@ - - - Bot webUI auth required - - - - - - - Login - - - - diff --git a/CLI/HttpWebUi/theme/layout/sidemenu.layout b/CLI/HttpWebUi/theme/layout/sidemenu.layout deleted file mode 100644 index 057fd2e..0000000 --- a/CLI/HttpWebUi/theme/layout/sidemenu.layout +++ /dev/null @@ -1,61 +0,0 @@ - - - [[html_title]] - [[html_title_after]] - [[html_cs_top_cdn]] - [[html_cs_top]] - - - - - - - - - - - - - - [[html_menu]] - - - - - - - - - - - - Logout - - - - - - - - - - [[page_title]] - [[page_actions]] - - - - [[page_content]] - - - - - - [[html_js_bottom_cdn]] - [[html_js_bottom]] - - - - diff --git a/CLI/HttpWebUi/webui.cs b/CLI/HttpWebUi/webui.cs deleted file mode 100644 index a58463d..0000000 --- a/CLI/HttpWebUi/webui.cs +++ /dev/null @@ -1,514 +0,0 @@ -using BetterSecondBot.HttpServer; -using BetterSecondBotShared.Json; -using BetterSecondBotShared.Static; -using BSB.bottypes; -using Microsoft.VisualBasic.CompilerServices; -using Newtonsoft.Json; -using OpenMetaverse; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Reflection; -using System.Text; -using System.Threading; - -namespace BetterSecondBot.HttpWebUi -{ - public class Webui - { - private JsonConfig siteconfig; - private SecondBot bot; - private Dictionary vaildlogincookies = new Dictionary(); - public Webui(JsonConfig setconfig, SecondBot setbot) - { - bot = setbot; - siteconfig = setconfig; - } - protected KeyValuePair Logincookievaild(HttpListenerResponse resp) - { - return Logincookievaild(resp, false); - } - protected KeyValuePair Logincookievaild(HttpListenerResponse resp, bool force_logout) - { - foreach (Cookie C in resp.Cookies) - { - if (C.Name == "logincookie") - { - if (force_logout == true) - { - if (vaildlogincookies.ContainsKey(C.Value) == true) - { - vaildlogincookies.Remove(C.Value); - } - } - else - { - if (vaildlogincookies.ContainsKey(C.Value) == true) - { - if (vaildlogincookies[C.Value] > helpers.UnixTimeNow()) - { - return new KeyValuePair(true, true); - } - } - } - resp.Cookies.Remove(C); - C.Expired = true; - resp.Cookies.Add(C); - return new KeyValuePair(true, false); - } - } - return new KeyValuePair(false, false); - } - public bool Post_process(Json_http_reply reply, HttpListenerResponse resp, List args, Dictionary post_args) - { - bool processed = false; - if (args != null) - { - if (args.Count >= 1) - { - if (args[0] == "ajax") - { - processed = true; - // webui only cares about ajax post requests - string mod = "none"; - string area = "none"; - if (args.Count >= 2) - { - mod = args[1]; - } - if (args.Count >= 3) - { - area = args[2]; - } - KeyValuePair logincheck = Logincookievaild(resp); - - if (logincheck.Key == false) - { - if (mod == "login") - { - if (post_args.ContainsKey("logincode") == true) - { - if (post_args["logincode"] == siteconfig.Security_WebUIKey) - { - reply.status = true; - string newcookiecode = ""; - while ((newcookiecode == null) || (newcookiecode == "") || (vaildlogincookies.ContainsKey(newcookiecode) == true)) - { - newcookiecode = helpers.GetSHA1(siteconfig.Security_WebUIKey + helpers.UnixTimeNow().ToString() + new Random().Next(12345).ToString()); - } - vaildlogincookies.Add(newcookiecode, helpers.UnixTimeNow() + (5 * 60)); // auto logout after 5 mins - Cookie logincookie = new Cookie("logincookie", newcookiecode) - { - Expires = DateTime.Now.AddDays(1), - Path = "/" - }; - resp.Cookies.Add(logincookie); - Console.WriteLine("Cookie created: " + logincookie.Value + " <=> " + newcookiecode + ""); - reply.message = "ok"; - reply.redirect = "/"; - } - else - { - reply.status = false; - reply.message = "fail"; - } - } - else - { - reply.status = false; - reply.message = "Missing code"; - } - } - else - { - reply.status = false; - reply.message = "No access"; - } - } - else - { - if (logincheck.Value == true) - { - reply.status = true; - // logged in - if (mod == "logout") - { - Logincookievaild(resp, true); - reply.message = "logged-out"; - reply.redirect = "/"; - reply.status = false; - } - else if(mod == "interface") - { - if (area == "get") - { - reply.message = JsonConvert.SerializeObject(bot.GetLastCommands(30)); - } - else if(area == "send") - { - if (post_args.ContainsKey("message") == true) - { - string[] bits = post_args["message"].Split("|||"); - if(bits.Length == 2) - { - reply.status = bot.GetCommandsInterface.Call(bits[0], bits[1]); - if(reply.status == true) - { - reply.message = "ok"; - } - else - { - reply.message = "Failed"; - } - } - else - { - reply.status = bot.GetCommandsInterface.Call(post_args["message"]); - if (reply.status == true) - { - reply.message = "ok"; - } - else - { - reply.message = "Failed"; - } - } - } - else - { - reply.message = "No message"; - reply.status = false; - } - } - else - { - reply.message = "Unknown area"; - reply.status = false; - } - } - else if (mod == "localchat") - { - if (area == "get") - { - reply.message = JsonConvert.SerializeObject(bot.getLocalChatHistory()); - } - else if (area == "send") - { - if (post_args.ContainsKey("message") == true) - { - bot.AddToLocalChat("{Via WebGUI}", post_args["message"]); - bot.GetClient.Self.Chat("{Via WebGUI} "+ post_args["message"], 0,ChatType.Normal); - reply.message = "ok"; - reply.status = true; - } - else - { - reply.message = "No message"; - reply.status = false; - } - } - else - { - reply.message = "Unknown area"; - reply.status = false; - } - } - else if (mod == "groupchat") - { - if (area == "list") - { - Dictionary groupname_uuid = new Dictionary(); - foreach (KeyValuePair entry in bot.MyGroups) - { - groupname_uuid.Add(entry.Key.ToString(), entry.Value.Name); - } - reply.message = JsonConvert.SerializeObject(groupname_uuid); - } - if (area == "get") - { - if (post_args.ContainsKey("groupuuid") == true) - { - if (UUID.TryParse(post_args["groupuuid"], out UUID groupuuid) == true) - { - reply.message = JsonConvert.SerializeObject(bot.GetGroupchat(groupuuid)); - } - else - { - reply.message = "Unable to process group uuid"; - reply.status = false; - } - } - else - { - reply.message = "No groupuuid"; - reply.status = false; - } - } - else if (area == "send") - { - if (post_args.ContainsKey("groupuuid") == true) - { - if (UUID.TryParse(post_args["groupuuid"], out UUID groupuuid) == true) - { - if (post_args.ContainsKey("message") == true) - { - bot.GetClient.Self.RequestJoinGroupChat(groupuuid); - Thread.Sleep(100); - bot.GetClient.Self.InstantMessageGroup(groupuuid, "{Via WebGUI} " + post_args["message"]); - bot.AddToGroupchat(groupuuid, "{Via WebGUI}", post_args["message"]); - reply.message = "ok"; - reply.status = true; - } - else - { - reply.message = "No message"; - reply.status = false; - } - } - else - { - reply.message = "Unable to process group uuid"; - reply.status = false; - } - } - else - { - reply.message = "No groupuuid"; - reply.status = false; - } - } - else - { - reply.message = "Unknown area"; - reply.status = false; - } - } - else if (mod == "im") - { - if (area == "list") - { - reply.message = JsonConvert.SerializeObject(bot.GetIMChatWindowKeyNames()); - } - else if (area == "send") - { - if (post_args.ContainsKey("avataruuid") == true) - { - if (UUID.TryParse(post_args["avataruuid"], out UUID avataruuid) == true) - { - if (post_args.ContainsKey("message") == true) - { - bot.GetCommandsInterface.Call("im", "" + avataruuid.ToString() + "~#~{Via WebGUI} " + post_args["message"]); - reply.message = "ok"; - reply.status = true; - } - else - { - reply.message = "No message"; - - } - } - else - { - reply.message = "Unable to process avatar uuid"; - reply.status = false; - } - } - else - { - reply.message = "No avataruuid"; - reply.status = false; - } - } - else if (area == "get") - { - if (post_args.ContainsKey("avataruuid") == true) - { - if (UUID.TryParse(post_args["avataruuid"], out UUID avataruuid) == true) - { - reply.message = JsonConvert.SerializeObject(bot.GetIMChatWindow(avataruuid)); - } - else - { - reply.message = "Unable to process avatar uuid"; - reply.status = false; - } - } - else - { - reply.message = "No avataruuid"; - reply.status = false; - } - } - else - { - reply.message = "Unknown area"; - reply.status = false; - } - } - else - { - reply.message = "No action"; - reply.status = false; - } - } - else - { - // login expired - reply.message = "login-expired"; - reply.redirect = "/"; - Logincookievaild(resp, true); - } - } - } - } - } - return !processed; - } - public string Html_logged_in(string mod, string area) - { - string layout = helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), "sidemenu.layout"); - Dictionary swaps = new Dictionary(); - - - string pagetitle = "Dashboard"; - string pagecontent = ""; - string pageactions = ""; - string js_onready = ""; - string[] menu_text = new string[] { "Localchat", "Groupchat", "IMs", "Interface" }; - string[] menu_links = new string[] { "localchat", "groupchat", "im", "interface" }; - string[] meni_icons = new string[] { "fas fa-comment", "fas fa-comments", "fas fa-users","fas fa-robot" }; - int loop = 0; - string menu = ""; - while (loop < menu_text.Count()) - { - string active = ""; - if (menu_links[loop] == mod) active = "active"; - menu = "" + menu + " " + menu_text[loop] + ""; - loop++; - } - swaps.Add("html_menu", menu); - if (mod == "none") - { - pagecontent = "Please select a menu item on the left"; - } - else if(mod == "localchat") - { - pagetitle = "Localchat"; - pagecontent = " - Loading local chat please wait -" + - "" + - "" + - "Send"+ - ""; - js_onready = "setInterval(function(){ update_localchat(\"" + siteconfig.Http_PublicUrl+"\"); },400);"; - - } - else if (mod == "groupchat") - { - pagetitle = "Group chat"; - pagecontent = ""; - if (area == "none") - { - - } - - - - } - swaps.Add("html_title", pagetitle); - swaps.Add("page_actions", pageactions); - swaps.Add("page_content", pagecontent); - swaps.Add("page_title", pagetitle); - swaps.Add("html_cs_top", ""); - swaps.Add("html_js_bottom", ""); - swaps.Add("html_js_onready", js_onready); - foreach (KeyValuePair A in swaps) - { - layout = layout.Replace("[[" + A.Key + "]]", A.Value); - } - return layout; - } - public string Html_logged_out() - { - string layout = helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), "full.layout"); - layout = layout.Replace("[[page_content]]", helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), "login.block")); - layout = layout.Replace("[[html_js_onready]]", ""); - layout = layout.Replace("[[html_cs_top]]", ""); - layout = layout.Replace("[[html_js_bottom]]", ""); - layout = layout.Replace("[[html_title]]", siteconfig.Basic_BotUserName); - return layout; - } - public KeyValuePair Get_Process(HttpListenerResponse resp, List args) - { - - // get content - if (args != null) - { - if (args.Count >= 1) - { - if (args[0] == "theme") - { - if (args.Count >= 2) - { - if (args[1] == "images") - { - return new KeyValuePair("image/png", helpers.ReadResourceFileBinary(Assembly.GetExecutingAssembly(), args[2])); - } - else if (args[1] == "css") - { - return new KeyValuePair("text/css", Encoding.UTF8.GetBytes(helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), args[2]))); - } - else if (args[1] == "js") - { - return new KeyValuePair("text/javascript", Encoding.UTF8.GetBytes(helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), args[2]))); - } - } - } - } - } - // get display - KeyValuePair logincheck = Logincookievaild(resp); - if (logincheck.Key == true) - { - if (logincheck.Value == false) - { - Logincookievaild(resp, true); - } - } - string reply_with; - if (logincheck.Value == false) - { - reply_with = Html_logged_out(); - } - else - { - string mod = "none"; - string area = "none"; - if (args.Count >= 1) - { - mod = args[0]; - } - if (args.Count >= 2) - { - area = args[1]; - } - - if (mod == "logout") - { - Logincookievaild(resp, true); - reply_with = Html_logged_out(); - } - else - { - // logged in - reply_with = Html_logged_in(mod, area); - } - } - reply_with = reply_with.Replace("[[url_base]]", siteconfig.Http_PublicUrl); - reply_with = reply_with.Replace("[[html_title_after]]", "Secondbot web UI"); - reply_with = reply_with.Replace("[[html_cs_top_cdn]]", helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), "cdn.css.layout")); - reply_with = reply_with.Replace("[[html_js_bottom_cdn]]", helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), "cdn.js.layout")); - return new KeyValuePair("text/html", Encoding.UTF8.GetBytes(reply_with)); - } - } -} diff --git a/CLI/WikiMake/wiki_header.txt b/CLI/WikiMake/wiki_header.txt index 28a6b76..8e3fcf5 100644 --- a/CLI/WikiMake/wiki_header.txt +++ b/CLI/WikiMake/wiki_header.txt @@ -1,28 +1,28 @@ - - -Secondbot Wiki [[AREA]] - - - - - - - SecondBot Wiki - - - - - - Main commands [Core] - JSON [Bot Config file] - Restrained Love API [RLV] - Post [HTTP] - - - Get Source - SL group - - - - + + +Secondbot Wiki [[AREA]] + + + + + + + SecondBot Wiki + + + + + + Main commands [Core] + JSON [Bot Config file] + Restrained Love API [RLV] + WebLink [HTTP] + + + Get Source + SL group + + + + \ No newline at end of file diff --git a/CLI/WikiMake/wikimake.cs b/CLI/WikiMake/wikimake.cs index 008cf95..8a4b531 100644 --- a/CLI/WikiMake/wikimake.cs +++ b/CLI/WikiMake/wikimake.cs @@ -17,7 +17,7 @@ namespace BetterSecondBot.WikiMake protected string html_footer = ""; protected string buildVersion = ""; protected SimpleIO io; - protected Dictionary seen_command_names = new Dictionary(); + protected Dictionary seen_command_names = new Dictionary(); public string CreateRoot() @@ -28,7 +28,7 @@ namespace BetterSecondBot.WikiMake sb.Append(buildVersion); sb.Append(""); sb.Append("InterfaceCommandsStatus"); - foreach (KeyValuePair> entry in api_reports) + foreach (KeyValuePair> entry in api_reports) { sb.Append(""); sb.Append("[[AREA]]"); - if(workspace != "") + if (workspace != "") { sb.Append(" / [[WORKSPACE]]"); } @@ -103,7 +102,7 @@ namespace BetterSecondBot.WikiMake int minargs = shared_interface.GetCommandArgs(c); string[] arg_types = shared_interface.GetCommandArgTypes(c); string[] arg_hints = shared_interface.GetCommandArgHints(c); - if(area == "Core") + if (area == "Core") { StringBuilder ExampleCall = new StringBuilder(); ExampleCall.Append("Example: [[COMMAND]]"); @@ -194,9 +193,9 @@ namespace BetterSecondBot.WikiMake sb.Append(buildVersion); sb.Append(""); sb.Append("CommandMin args"); - foreach(string c in cmds) + foreach (string c in cmds) { - if(shared_interface.GetCommandWorkspace(c) == workspace) + if (shared_interface.GetCommandWorkspace(c) == workspace) { int args = shared_interface.GetCommandArgs(c); sb.Append("Build: "); + sb.Append(buildVersion); + sb.Append(""); + sb.Append("Interface: [[AREA]]"); + if (workspace != "") + { + sb.Append(" / [[WORKSPACE]]"); + } + sb.Append("[[COMMAND]]"); + sb.Append("[[URLENDPOINT]]/[[WORKSPACE]]/[[COMMAND]]/[[URLADDON]]"); + sb.Append("Method: [[APIMETHOD]]"); + sb.Append(""); + sb.Append("[[HELP]]"); + Dictionary> values = HTTP.getCommandArgs(workspace, c); + int ValueCount = values.Count; + + if (ValueCount > 0) + { + sb.Append("Args helper"); + sb.Append("NameTypeHint"); + foreach (KeyValuePair> entry in values) + { + string hint = entry.Value.Value; + string type = entry.Value.Key; + if (entry.Value.Key.Contains("Optional") == true) + { + type = type.Replace("Optional", "{Optional} "); + } + else if (entry.Value.Key == "URLARG") + { + type = "URL arg"; + } + sb.Append("" + entry.Key + "" + type + "" + hint + ""); + } + sb.Append(""); + } + + string[] returnvalues = HTTP.getReturnsValues(workspace, c); + if (returnvalues.Length > 0) + { + sb.Append("Possible replys"); + sb.Append(""); + foreach (string entry in returnvalues) + { + sb.Append(""+entry+""); + } + sb.Append(""); + } + + + + sb = DebugModeCreateWiki.MenuActive(sb, area); + sb.Append(html_footer); + sb.Replace("[[COMMAND]]", c); + sb.Replace("[[URLENDPOINT]]", "http://localhost:8080"); + sb.Replace("[[APIMETHOD]]", HTTP.getCommandMethod(workspace, c)); + sb.Replace("[[URLADDON]]", getURLargs(values)); + sb.Replace("[[HELP]]", HTTP.getCommandAbout(workspace, c)); + sb.Replace("[[MINARGS]]", ValueCount.ToString()); + sb.Replace("[[WORKSPACE]]", workspace); + sb.Replace("[[AREA]]", area); + sb.Replace("[[SUBFOLDER]]", ""); + sb.Replace("[[RETURNROOT]]", "../"); + string target_file = "" + area + "" + workspace + "" + c + ".html"; + io.writefile(target_file, sb.ToString()); + } + } + } + + protected void HTTPmenu(string area, HTTPendpoint HTTP) + { + api_reports.Add(area, new KeyValuePair(HTTP.getFullCount(), "Basic")); + + // create index + StringBuilder sb = new StringBuilder(); + sb.Append(html_header); + sb.Append("Interface:"); + sb.Append("HTTP"); + sb.Append(""); + sb.Append("Build: "); + sb.Append(buildVersion); + sb.Append(""); + sb.Append("WorkspaceCommands"); + foreach (string workspace in HTTP.getEndPoints()) + { + string workspace_link = "" + workspace + ""; + sb.Append(""); + sb.Append(workspace_link); + sb.Append(""); + sb.Append(HTTP.getEndpointCount(workspace).ToString()); + sb.Append(""); + } + sb.Append(""); + sb.Replace("[[SUBFOLDER]]", ""); + sb.Replace("[[RETURNROOT]]", "../"); + sb.Replace("[[AREA]]", area); + sb.Append(html_footer); + sb = DebugModeCreateWiki.MenuActive(sb, area); + io.writefile("" + area + ".html", sb.ToString()); + } + + protected void HTTPWorkspaces(string area, HTTPendpoint HTTP) + { + foreach (string workspace in HTTP.getEndPoints()) + { + StringBuilder sb = new StringBuilder(); + sb.Append(html_header); + sb.Append("Interface: [[AREA]]"); + if (workspace != "") + { + sb.Append(" / [[WORKSPACE]]"); + } + sb.Append(""); + sb.Append("Build: "); + sb.Append(buildVersion); + sb.Append(""); + sb.Append("CommandMin args"); + foreach (string c in HTTP.getEndpointCommands(workspace)) + { + int args = HTTP.getCommandArgCount(workspace, c); + sb.Append(""); + sb.Append(c); + sb.Append(""); + sb.Append(args.ToString()); + sb.Append(""); + } + sb.Append(""); + sb.Replace("[[SUBFOLDER]]", ""); + sb.Replace("[[RETURNROOT]]", "../"); + sb.Replace("[[WORKSPACE]]", workspace); + sb.Replace("[[AREA]]", area); + sb.Append(html_footer); + sb = DebugModeCreateWiki.MenuActive(sb, area); + string target_file = "" + area + "" + workspace + ".html"; + io.writefile(target_file, sb.ToString()); + } + } + } + + public class HTTPendpoint + { + protected List endpoints = new List(); + public HTTPendpoint() + { + Endpoint core = new Endpoint(); + core.name = "core"; + core.callable.Add(new gettoken()); + core.callable.Add(new logout()); + core.callable.Add(new version()); + core.callable.Add(new name()); + core.callable.Add(new command()); + endpoints.Add(core); + Endpoint inventory = new Endpoint(); + inventory.name = "inventory"; + inventory.callable.Add(new contents()); + inventory.callable.Add(new folders()); + endpoints.Add(inventory); + } + + public string getCommandMethod(string endpoint, string command) + { + foreach (Endpoint End in endpoints) + { + if (End.name == endpoint) + { + foreach (APIcall api in End.callable) + { + if (api.name == command) + { + return api.type; + } + } + } + } + return "?"; + } + + public string getCommandAbout(string endpoint, string command) + { + foreach (Endpoint End in endpoints) + { + if (End.name == endpoint) + { + foreach (APIcall api in End.callable) + { + if (api.name == command) + { + return api.about; + } + } + } + } + return "?"; + } + + public string[] getReturnsValues(string endpoint, string command) + { + foreach (Endpoint End in endpoints) + { + if (End.name == endpoint) + { + foreach (APIcall api in End.callable) + { + if (api.name == command) + { + return api.returns.ToArray(); + } + } + } + } + return new string[] { }; + } + + + + public int getCommandArgCount(string endpoint, string command) + { + foreach (Endpoint End in endpoints) + { + if (End.name == endpoint) + { + foreach (APIcall api in End.callable) + { + if (api.name == command) + { + return api.values.Count; + } + } + } + } + return 0; + } + + public string[] getEndpointCommands(string endpointname) + { + List commands = new List(); + foreach (Endpoint End in endpoints) + { + if (End.name == endpointname) + { + foreach (APIcall api in End.callable) + { + commands.Add(api.name); + } + } + } + return commands.ToArray(); + } + + public string[] getEndPoints() + { + List names = new List(); + foreach (Endpoint End in endpoints) + { + names.Add(End.name); + } + return names.ToArray(); + } + + public int getEndpointCount(string endpointname) + { + foreach (Endpoint End in endpoints) + { + if (End.name == endpointname) + { + return End.callable.Count; + } + } + return 0; + } + + public int getFullCount() + { + int count = 0; + foreach (Endpoint End in endpoints) + { + count += End.callable.Count; + } + return count; + } + + public Dictionary> getCommandArgs(string endpoint, string command) + { + Dictionary> empty = new Dictionary>(); + foreach (Endpoint End in endpoints) + { + if (End.name == endpoint) + { + foreach (APIcall api in End.callable) + { + if (api.name == command) + { + return api.values; + } + } + } + } + return empty; + + } + + } + + public class Endpoint + { + public string name = "Notset"; + public List callable = new List(); + } + + abstract public class APIcall + { + public string name { get { return GetType().Name.ToLowerInvariant(); } } + public string type = "get"; + public string about = "A API call that is missing its about value"; + public Dictionary> values = new Dictionary>(); + public List returns = new List(); + public bool RequiresToken = true; + + public APIcall() + { + Setup(); + } + public virtual void Setup() + { + if (RequiresToken == true) + { + returns.Add("Token not accepted"); + values.Add( + "token", + new KeyValuePair( + "URLARG", + "the api access token") + ); + } + } + } + + abstract public class postAPIcall : APIcall + { + public override void Setup() + { + type = "post"; + base.Setup(); + } + } + + public class gettoken : postAPIcall + { + public override void Setup() + { + RequiresToken = false; + about = "Requests a new token (Vaild for 10 mins) to use with all other requests"; + values.Add("Authcode", new KeyValuePair("string", "the first 10 chars of SHA1(unixtime+WebUIkey)unixtime can be +- 30 of the bots time.")); + returns = new List(); + returns.Add("Authcode not accepted"); + returns.Add("New API Token"); + base.Setup(); + } + } + + public class logout : APIcall + { + public override void Setup() + { + about = "A API call that is missing its about value"; + returns.Add("ok"); + returns.Add("Failed to remove token"); + base.Setup(); + } + } + + public class version : APIcall + { + public override void Setup() + { + about = "Gets the bots build version"; + returns.Add("Bot build version"); + base.Setup(); + } + } + + public class name : APIcall + { + public override void Setup() + { + about = "Gets the name of the bot"; + returns.Add("Fistname Lastname"); + base.Setup(); + } + } + + public class command : postAPIcall + { + public override void Setup() + { + about = "Makes a request to the core commands lib"; + values.Add( + "body", + new KeyValuePair( + "JsonObject", + "A JSON object formated as followsCommand: stringArgs: string[]AuthCode: string========See LSL example on how to create a core command auth code") + ); + returns.Add("accepted"); + base.Setup(); + } + } + + public class contents : APIcall + { + public override void Setup() + { + about = "Requests the contents of a folder as an array of InventoryMapItemFormated as followsInventoryMapItemid: UUIDname: Stringtypename: String"; + values.Add( + "folderUUID", + new KeyValuePair( + "URLARG", + "the folder to fetch (Found via: inventory/folders)") + ); + returns.Add("array of InventoryMapItem"); + base.Setup(); + } + } + + public class folders : APIcall + { + public override void Setup() + { + about = "Requests the inventory folder layout as a json object InventoryMapFolderFormated as followsInventoryMapItemid: UUIDname: Stringsubfolders: InventoryMapFolder[]"; + returns.Add("array of InventoryMapFolder"); + base.Setup(); + } + } + } diff --git a/Core/BSB.csproj b/Core/BSB.csproj index ce419aa..90e779d 100644 --- a/Core/BSB.csproj +++ b/Core/BSB.csproj @@ -21,8 +21,8 @@ false linux-x64 - - + +
Please select a menu item on the left