scoped tokens support and readme update

This commit is contained in:
Madpeterz 2021-02-07 21:53:01 +00:00
parent b6ada34ed5
commit 9706a94f10
11 changed files with 331 additions and 44 deletions

View file

@ -57,6 +57,16 @@ namespace BetterSecondBotShared.IO
{ {
serializer.Serialize(writer, commandsfile); serializer.Serialize(writer, commandsfile);
} }
}
public void WriteJsonTokens(JsonScopedTokens tokensfile, string targetfile)
{
JsonSerializer serializer = new JsonSerializer();
using (StreamWriter sw = new StreamWriter(@"" + root_folder + "" + targetfile))
using (JsonWriter writer = new JsonTextWriter(sw) { Formatting = Formatting.Indented })
{
serializer.Serialize(writer, tokensfile);
}
} }
public void makeOld(string targetfile) public void makeOld(string targetfile)

View file

@ -3,11 +3,19 @@ using System.Collections.Generic;
using System.Text; using System.Text;
namespace BetterSecondBotShared.Json namespace BetterSecondBotShared.Json
{ {
public class JsonScopedTokens
{
public string[] ScopedTokens { get; set; }
}
public class JsonCommandsfile public class JsonCommandsfile
{ {
public string[] CustomCommands { get; set; } public string[] CustomCommands { get; set; }
} }
public class JsonConfig public class JsonConfig
{ {
// Basics // Basics

View file

@ -53,7 +53,7 @@ namespace BetterSecondBot
*/ */
new Thread(() => new Thread(() =>
{ {
new HttpAsService(Bot, Config); new HttpAsService(Bot, Config, as_docker);
}).Start(); }).Start();
} }
if(use_self_keep_alive == true) if(use_self_keep_alive == true)

View file

@ -20,7 +20,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/localchathistory/{token}")] [Route(HttpVerbs.Get, "/localchathistory/{token}")]
public object localchatHistory(string token) public object localchatHistory(string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "chat", "localchathistory", getClientIP()) == true)
{ {
return BasicReply(JsonConvert.SerializeObject(bot.getLocalChatHistory())); return BasicReply(JsonConvert.SerializeObject(bot.getLocalChatHistory()));
} }
@ -33,7 +33,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Post, "/localchatsay/{token}")] [Route(HttpVerbs.Post, "/localchatsay/{token}")]
public object localchatSay(string token, [FormField] string message) public object localchatSay(string token, [FormField] string message)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "chat", "localchatsay", getClientIP()) == true)
{ {
bot.GetCommandsInterface.Call("say", message); bot.GetCommandsInterface.Call("say", message);
return BasicReply(JsonConvert.SerializeObject(bot.getLocalChatHistory())); return BasicReply(JsonConvert.SerializeObject(bot.getLocalChatHistory()));

View file

@ -59,7 +59,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/friends/{token}")] [Route(HttpVerbs.Get, "/friends/{token}")]
public object Friends(string token) public object Friends(string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "core", "friends", getClientIP()) == true)
{ {
return BasicReply(bot.getJsonFriendlist()); return BasicReply(bot.getJsonFriendlist());
} }
@ -75,7 +75,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/walkto/{x}/{y}/{z}/{token}")] [Route(HttpVerbs.Get, "/walkto/{x}/{y}/{z}/{token}")]
public object WalkTo(string x, string y, string z, string token) public object WalkTo(string x, string y, string z, string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "core", "walkto", getClientIP()) == true)
{ {
bool status = bot.GetCommandsInterface.Call("AutoPilot", "<"+x+","+y+","+z+">"); bool status = bot.GetCommandsInterface.Call("AutoPilot", "<"+x+","+y+","+z+">");
if (status == true) if (status == true)
@ -94,7 +94,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/gesture/{gesture}/{token}")] [Route(HttpVerbs.Get, "/gesture/{gesture}/{token}")]
public object Gesture(string gesture, string token) public object Gesture(string gesture, string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "core", "gesture", getClientIP()) == true)
{ {
bool status = bot.GetCommandsInterface.Call("PlayGesture", gesture); bool status = bot.GetCommandsInterface.Call("PlayGesture", gesture);
if (status == true) if (status == true)
@ -116,7 +116,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/teleport/{region}/{x}/{y}/{z}/{token}")] [Route(HttpVerbs.Get, "/teleport/{region}/{x}/{y}/{z}/{token}")]
public object Teleport(string region,string x, string y, string z, string token) public object Teleport(string region,string x, string y, string z, string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "core", "teleport", getClientIP()) == true)
{ {
bool status = bot.GetCommandsInterface.Call("Teleport", ""+region+"/" + x + "/" + y + "/" + z + ""); bool status = bot.GetCommandsInterface.Call("Teleport", ""+region+"/" + x + "/" + y + "/" + z + "");
if (status == true) if (status == true)
@ -135,7 +135,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/regiontile/{regionname}/{token}")] [Route(HttpVerbs.Get, "/regiontile/{regionname}/{token}")]
public object Regiontile(string regionname, string token) public object Regiontile(string regionname, string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "core", "regiontile", getClientIP()) == true)
{ {
if (bot.GetClient.Grid.GetGridRegion(regionname, GridLayerType.Objects, out GridRegion region)) if (bot.GetClient.Grid.GetGridRegion(regionname, GridLayerType.Objects, out GridRegion region))
{ {
@ -155,7 +155,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/nearmewithdetails/{token}")] [Route(HttpVerbs.Get, "/nearmewithdetails/{token}")]
public object NearmeWithDetails(string token) public object NearmeWithDetails(string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "core", "nearmewithdetails", getClientIP()) == true)
{ {
if (bot.GetClient.Network.CurrentSim != null) if (bot.GetClient.Network.CurrentSim != null)
{ {
@ -188,7 +188,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/nearme/{token}")] [Route(HttpVerbs.Get, "/nearme/{token}")]
public object Nearme(string token) public object Nearme(string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "core", "nearme", getClientIP()) == true)
{ {
if (bot.GetClient.Network.CurrentSim != null) if (bot.GetClient.Network.CurrentSim != null)
{ {
@ -224,7 +224,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/logout/{token}")] [Route(HttpVerbs.Get, "/logout/{token}")]
public object Logout(string token) public object Logout(string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "core", "logout", getClientIP()) == true)
{ {
return tokens.Expire(token); return tokens.Expire(token);
} }
@ -238,7 +238,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/version/{token}")] [Route(HttpVerbs.Get, "/version/{token}")]
public object Version(string token) public object Version(string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "core", "version", getClientIP()) == true)
{ {
return BasicReply(bot.MyVersion); return BasicReply(bot.MyVersion);
} }
@ -250,7 +250,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/name/{token}")] [Route(HttpVerbs.Get, "/name/{token}")]
public object Name(string token) public object Name(string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "core", "name", getClientIP()) == true)
{ {
return BasicReply(bot.GetClient.Self.FirstName + " " + bot.GetClient.Self.LastName); return BasicReply(bot.GetClient.Self.FirstName + " " + bot.GetClient.Self.LastName);
} }
@ -263,7 +263,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/regionname/{token}")] [Route(HttpVerbs.Get, "/regionname/{token}")]
public object Regionname(string token) public object Regionname(string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "core", "regionname", getClientIP()) == true)
{ {
if(bot.GetClient.Network.CurrentSim != null) if(bot.GetClient.Network.CurrentSim != null)
{ {
@ -280,7 +280,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/location/{token}")] [Route(HttpVerbs.Get, "/location/{token}")]
public object Location(string token) public object Location(string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "core", "location", getClientIP()) == true)
{ {
if (bot.GetClient.Network.CurrentSim != null) if (bot.GetClient.Network.CurrentSim != null)
{ {
@ -302,7 +302,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Post, "/command/{token}")] [Route(HttpVerbs.Post, "/command/{token}")]
public async Task<object> command(string token) public async Task<object> command(string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "core", "command", getClientIP()) == true)
{ {
CommandLibCall data = await HttpContext.GetRequestDataAsync<CommandLibCall>(); CommandLibCall data = await HttpContext.GetRequestDataAsync<CommandLibCall>();
string compressedArgs = string.Join("~#~", data.Args); string compressedArgs = string.Join("~#~", data.Args);

View file

@ -26,7 +26,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/ismember/{group}/{avatar}/{token}")] [Route(HttpVerbs.Get, "/ismember/{group}/{avatar}/{token}")]
public object ismember(string group,string avatar,string token) public object ismember(string group,string avatar,string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "groups", "ismember", getClientIP()) == true)
{ {
if (UUID.TryParse(group, out UUID groupuuid) == true) if (UUID.TryParse(group, out UUID groupuuid) == true)
{ {
@ -62,7 +62,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/listgroups/{token}")] [Route(HttpVerbs.Get, "/listgroups/{token}")]
public object listgroups(string token) public object listgroups(string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "groups", "listgroups", getClientIP()) == true)
{ {
Dictionary<string, string> grouppackage = new Dictionary<string, string>(); Dictionary<string, string> grouppackage = new Dictionary<string, string>();
foreach(KeyValuePair<UUID,Group> entry in bot.MyGroups) foreach(KeyValuePair<UUID,Group> entry in bot.MyGroups)
@ -83,7 +83,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/listgrouproles/{group}/{token}")] [Route(HttpVerbs.Get, "/listgrouproles/{group}/{token}")]
public object listgrouproles(string group, string token) public object listgrouproles(string group, string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "groups", "listgrouproles", getClientIP()) == true)
{ {
if (UUID.TryParse(group, out UUID groupuuid) == true) if (UUID.TryParse(group, out UUID groupuuid) == true)
{ {
@ -132,7 +132,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/listgroupswithunread/{token}")] [Route(HttpVerbs.Get, "/listgroupswithunread/{token}")]
public object listgroupswithunread(string token) public object listgroupswithunread(string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "groups", "listgroupswithunread", getClientIP()) == true)
{ {
return BasicReply(JsonConvert.SerializeObject(bot.UnreadGroupchatGroups())); return BasicReply(JsonConvert.SerializeObject(bot.UnreadGroupchatGroups()));
} }
@ -144,7 +144,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/haveunreadgroupchat/{token}")] [Route(HttpVerbs.Get, "/haveunreadgroupchat/{token}")]
public object haveunreadgroupchat(string token) public object haveunreadgroupchat(string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "groups", "haveunreadgroupchat", getClientIP()) == true)
{ {
return BasicReply(bot.HasUnreadGroupchats().ToString()); return BasicReply(bot.HasUnreadGroupchats().ToString());
} }
@ -158,7 +158,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/getgroupchat/{group}/{token}")] [Route(HttpVerbs.Get, "/getgroupchat/{group}/{token}")]
public object getgroupchat(string group, string token) public object getgroupchat(string group, string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "groups", "getgroupchat", getClientIP()) == true)
{ {
if (UUID.TryParse(group, out UUID groupUUID) == true) if (UUID.TryParse(group, out UUID groupUUID) == true)
{ {
@ -177,7 +177,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Post, "/sendgroupchat/{group}/{token}")] [Route(HttpVerbs.Post, "/sendgroupchat/{group}/{token}")]
public object sendgroupchat(string group, string token, [FormField] string message) public object sendgroupchat(string group, string token, [FormField] string message)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "groups", "sendgroupchat", getClientIP()) == true)
{ {
if (UUID.TryParse(group, out UUID groupUUID) == true) if (UUID.TryParse(group, out UUID groupUUID) == true)
{ {

View file

@ -11,6 +11,9 @@ using EmbedIO.Security;
using BetterSecondBotShared.Static; using BetterSecondBotShared.Static;
using System.Net; using System.Net;
using EmbedIO.Routing; using EmbedIO.Routing;
using BetterSecondBotShared.logs;
using BetterSecondBotShared.IO;
using Newtonsoft.Json;
namespace BetterSecondBot.HttpService namespace BetterSecondBot.HttpService
{ {
@ -19,11 +22,122 @@ namespace BetterSecondBot.HttpService
protected JsonConfig Config; protected JsonConfig Config;
protected SecondBot Bot; protected SecondBot Bot;
protected TokenStorage Tokens; protected TokenStorage Tokens;
public HttpAsService(SecondBot MainBot, JsonConfig BotConfig)
protected void loadScopedTokensFromENV()
{
int loop = 1;
bool found = true;
while (found == true)
{
if (helpers.notempty(Environment.GetEnvironmentVariable("scoped_token_" + loop.ToString())) == true)
{
processScopedTokenRaw(Environment.GetEnvironmentVariable("scoped_token_" + loop.ToString()));
}
else
{
found = false;
}
loop++;
}
}
protected void loadScopedTokensFromFile()
{
JsonScopedTokens LoadedTokens = new JsonScopedTokens
{
ScopedTokens = new string[] { "t:[XXX],ws:core" }
};
string targetfile = "scoped_tokens.json";
SimpleIO io = new SimpleIO();
if (SimpleIO.FileType(targetfile, "json") == false)
{
io.WriteJsonTokens(LoadedTokens, targetfile);
return;
}
if (io.Exists(targetfile) == false)
{
io.WriteJsonTokens(LoadedTokens, targetfile);
return;
}
string json = io.ReadFile(targetfile);
if (json.Length > 0)
{
try
{
LoadedTokens = JsonConvert.DeserializeObject<JsonScopedTokens>(json);
foreach (string loaded in LoadedTokens.ScopedTokens)
{
processScopedTokenRaw(loaded);
}
}
catch
{
io.makeOld(targetfile);
io.WriteJsonTokens(LoadedTokens, targetfile);
}
return;
}
}
protected void processScopedTokenRaw(string raw)
{
raw = raw.Replace(" ", "");
string[] bits = raw.Split(',');
string code = null;
int accessids = 0;
scopedTokenInfo stinfo = new scopedTokenInfo();
foreach(string bit in bits)
{
string[] subbits = bit.Split(':');
if(subbits[0] == "t")
{
code = subbits[1];
}
else if (subbits[0] == "cm")
{
stinfo.AllowCommands.Add(subbits[1]);
accessids++;
}
else if (subbits[0] == "cg")
{
stinfo.AllowAccessGroups.Add(subbits[1]);
accessids++;
}
else if (subbits[0] == "ws")
{
stinfo.AllowWorkgroups.Add(subbits[1]);
accessids++;
}
}
if((code != null) && (accessids > 0))
{
Tokens.AddScopedToken(code, stinfo);
LogFormater.Info("Adding scopped command " + code + " with: " + accessids.ToString() + " access types");
}
else
{
LogFormater.Warn("Scoped access code: "+raw+" did not pass checks");
}
}
public HttpAsService(SecondBot MainBot, JsonConfig BotConfig, bool running_in_docker)
{ {
Bot = MainBot; Bot = MainBot;
Config = BotConfig; Config = BotConfig;
Tokens = new TokenStorage();
// Load scoped tokens
if(running_in_docker == true)
{
// using ENV values
loadScopedTokensFromENV();
}
else
{
// from file
loadScopedTokensFromFile();
}
// Our web server is disposable // Our web server is disposable
Logger.UnregisterLogger<ConsoleLogger>(); Logger.UnregisterLogger<ConsoleLogger>();
using (var server = CreateWebServer(Config.Http_Host)) using (var server = CreateWebServer(Config.Http_Host))
@ -39,7 +153,7 @@ namespace BetterSecondBot.HttpService
private WebServer CreateWebServer(string url) private WebServer CreateWebServer(string url)
{ {
Tokens = new TokenStorage();
var server = new WebServer(o => o var server = new WebServer(o => o
.WithUrlPrefix(url) .WithUrlPrefix(url)
.WithMode(HttpListenerMode.EmbedIO)) .WithMode(HttpListenerMode.EmbedIO))
@ -123,8 +237,18 @@ namespace BetterSecondBot.HttpService
public class TokenStorage public class TokenStorage
{ {
// global access tokens
protected Dictionary<string, tokenInfo> tokens = new Dictionary<string, tokenInfo>(); protected Dictionary<string, tokenInfo> tokens = new Dictionary<string, tokenInfo>();
// scoped access tokens
protected Dictionary<string, scopedTokenInfo> scopedtokens = new Dictionary<string, scopedTokenInfo>();
public void AddScopedToken(string code, scopedTokenInfo info)
{
scopedtokens.Add(code, info);
}
public void PurgeExpired() public void PurgeExpired()
{ {
List<string> oldTokens = new List<string>(); List<string> oldTokens = new List<string>();
@ -154,7 +278,7 @@ namespace BetterSecondBot.HttpService
return "Failed to remove token"; return "Failed to remove token";
} }
public bool Allow(string code, IPAddress IPaddress) public bool Allow(string code, string workgroup, string command, IPAddress IPaddress)
{ {
if(tokens.ContainsKey(code) == true) if(tokens.ContainsKey(code) == true)
{ {
@ -169,7 +293,35 @@ namespace BetterSecondBot.HttpService
return true; return true;
} }
} }
return false; return ScopeAllow(code, workgroup, command);
}
public bool ScopeAllow(string code, string workgroup, string command)
{
if (scopedtokens.ContainsKey(code) == false)
{
return false;
}
scopedTokenInfo info = scopedtokens[code];
string build = workgroup + "/" + command;
if (info.AllowWorkgroups.Contains(workgroup) == true)
{
return true;
}
else if(info.AllowCommands.Contains(build) == true)
{
return true;
}
bool allowed = false;
foreach(string A in info.AllowAccessGroups)
{
allowed = accessgroupcontrol.isAllowed(A, workgroup, command);
if(allowed == true)
{
break;
}
}
return allowed;
} }
public string CreateToken(IPAddress IP) public string CreateToken(IPAddress IP)
@ -237,4 +389,51 @@ namespace BetterSecondBot.HttpService
public IPAddress IP = null; public IPAddress IP = null;
} }
public class scopedTokenInfo
{
public List<string> AllowWorkgroups = new List<string>();
public List<string> AllowAccessGroups = new List<string>();
public List<string> AllowCommands = new List<string>();
}
public static class accessgroupcontrol
{
public static bool isAllowed(string permsgroupname, string workgroup, string command)
{
string build = workgroup + "/" + command;
List<string> allowed = new List<string>();
if (permsgroupname == "chat")
{
allowed = new List<string>(){
"chat/localchathistory",
"chat/localchatsay",
"groups/getgroupchat",
"groups/sendgroupchat",
"groups/listgroups",
"im/chatwindows",
"im/listwithunread",
"im/getimchat",
"im/sendimchat"
};
}
else if (permsgroupname == "giver")
{
allowed = new List<string>(){
"inventory/send",
"inventory/folders",
"inventory/contents"
};
}
else if (permsgroupname == "movement")
{
allowed = new List<string>(){
"core/walkto",
"core/teleport",
"core/gesture"
};
}
return allowed.Contains(build);
}
}
} }

View file

@ -21,7 +21,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/chatwindows/{token}")] [Route(HttpVerbs.Get, "/chatwindows/{token}")]
public object chatwindows(string token) public object chatwindows(string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "im", "chatwindows", getClientIP()) == true)
{ {
return BasicReply(JsonConvert.SerializeObject(bot.GetIMChatWindowKeyNames())); return BasicReply(JsonConvert.SerializeObject(bot.GetIMChatWindowKeyNames()));
} }
@ -33,7 +33,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/listwithunread/{token}")] [Route(HttpVerbs.Get, "/listwithunread/{token}")]
public object listwithunread(string group, string token) public object listwithunread(string group, string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "im", "listwithunread", getClientIP()) == true)
{ {
List<UUID> unreadimwindows = new List<UUID>(); List<UUID> unreadimwindows = new List<UUID>();
foreach (UUID window in bot.IMChatWindows()) foreach (UUID window in bot.IMChatWindows())
@ -53,7 +53,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/haveunreadims/{token}")] [Route(HttpVerbs.Get, "/haveunreadims/{token}")]
public object haveunreadims(string token) public object haveunreadims(string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "im", "haveunreadims", getClientIP()) == true)
{ {
bool reply = false; bool reply = false;
foreach(UUID window in bot.IMChatWindows()) foreach(UUID window in bot.IMChatWindows())
@ -76,7 +76,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/getimchat/{window}/{token}")] [Route(HttpVerbs.Get, "/getimchat/{window}/{token}")]
public object getimchat(string window, string token) public object getimchat(string window, string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "im", "getimchat", getClientIP()) == true)
{ {
if (UUID.TryParse(window, out UUID windowUUID) == true) if (UUID.TryParse(window, out UUID windowUUID) == true)
{ {
@ -94,7 +94,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Post, "/sendimchat/{avatar}/{token}")] [Route(HttpVerbs.Post, "/sendimchat/{avatar}/{token}")]
public object sendimchat(string avatar, string token, [FormField] string message) public object sendimchat(string avatar, string token, [FormField] string message)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "im", "sendimchat", getClientIP()) == true)
{ {
bot.GetCommandsInterface.Call("im", avatar + "~#~" + message, UUID.Zero, "~#~"); bot.GetCommandsInterface.Call("im", avatar + "~#~" + message, UUID.Zero, "~#~");
return BasicReply("ok"); return BasicReply("ok");

View file

@ -20,7 +20,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/rezobject/{item}/{token}")] [Route(HttpVerbs.Get, "/rezobject/{item}/{token}")]
public object rezobject(string item, string token, [FormField] string newname) public object rezobject(string item, string token, [FormField] string newname)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "inventory", "rezobject", getClientIP()) == true)
{ {
bool status = bot.GetCommandsInterface.Call("RezObject", item); bool status = bot.GetCommandsInterface.Call("RezObject", item);
return BasicReply(status.ToString()); return BasicReply(status.ToString());
@ -35,7 +35,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Post, "/rename/{item}/{token}")] [Route(HttpVerbs.Post, "/rename/{item}/{token}")]
public object rename(string item, string token, [FormField] string newname) public object rename(string item, string token, [FormField] string newname)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "inventory", "rename", getClientIP()) == true)
{ {
bool status = bot.GetCommandsInterface.Call("RenameInventory", "12~#~" + item + "~#~" + newname); bool status = bot.GetCommandsInterface.Call("RenameInventory", "12~#~" + item + "~#~" + newname);
return BasicReply(status.ToString()); return BasicReply(status.ToString());
@ -50,7 +50,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/realuuid/{item}/{token}")] [Route(HttpVerbs.Get, "/realuuid/{item}/{token}")]
public object realuuid(string item, string token) public object realuuid(string item, string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "inventory", "realuuid", getClientIP()) == true)
{ {
if (UUID.TryParse(item, out UUID itemUUID) == true) if (UUID.TryParse(item, out UUID itemUUID) == true)
{ {
@ -73,7 +73,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/send/{item}/{avatar}/{token}")] [Route(HttpVerbs.Get, "/send/{item}/{avatar}/{token}")]
public object send(string item, string avatar, string token) public object send(string item, string avatar, string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "inventory", "send", getClientIP()) == true)
{ {
if (UUID.TryParse(item, out UUID itemUUID) == true) if (UUID.TryParse(item, out UUID itemUUID) == true)
{ {
@ -94,7 +94,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/delete/{item}/{isfolder}/{token}")] [Route(HttpVerbs.Get, "/delete/{item}/{isfolder}/{token}")]
public object delete(string item,string isfolder, string token) public object delete(string item,string isfolder, string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "inventory", "delete", getClientIP()) == true)
{ {
if (UUID.TryParse(item, out UUID itemUUID) == true) if (UUID.TryParse(item, out UUID itemUUID) == true)
{ {
@ -118,7 +118,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/folders/{token}")] [Route(HttpVerbs.Get, "/folders/{token}")]
public object folders(string token) public object folders(string token)
{ {
if(tokens.Allow(token, getClientIP()) == true) if(tokens.Allow(token, "inventory", "folders", getClientIP()) == true)
{ {
string reply = HelperInventory.MapFolderJson(bot); string reply = HelperInventory.MapFolderJson(bot);
if(reply != null) return BasicReply(reply); if(reply != null) return BasicReply(reply);
@ -134,7 +134,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/contents/{folderUUID}/{token}")] [Route(HttpVerbs.Get, "/contents/{folderUUID}/{token}")]
public object Contents(string folderUUID, string token) public object Contents(string folderUUID, string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "inventory", "contents", getClientIP()) == true)
{ {
if (UUID.TryParse(folderUUID, out UUID folder) == true) if (UUID.TryParse(folderUUID, out UUID folder) == true)
{ {

View file

@ -23,7 +23,7 @@ namespace BetterSecondBot.HttpService
[Route(HttpVerbs.Get, "/parcelbanlist/{token}")] [Route(HttpVerbs.Get, "/parcelbanlist/{token}")]
public object parcelbanlist(string token) public object parcelbanlist(string token)
{ {
if (tokens.Allow(token, getClientIP()) == true) if (tokens.Allow(token, "parcelestate", "parcelbanlist", getClientIP()) == true)
{ {
if (bot.GetClient.Network.CurrentSim != null) if (bot.GetClient.Network.CurrentSim != null)
{ {

View file

@ -25,9 +25,7 @@ Secondbot is a CommandLine based bot for SecondLife based on libremetaverse reta
## Releases ## Releases
These are pre compiled versions for the most upto date please use docker or compile it yourself. These are pre compiled versions for the most upto date please use docker or compile it yourself.
[Windows x64](https://github.com/Madpeterz/SecondBot/releases/tag/windows-x64) [View releases](https://github.com/Madpeterz/SecondBot/releases)
[Linux (Tested on Deb) x64](https://github.com/Madpeterz/SecondBot/releases/tag/linux-x64)
### Starting multiple bots from the same executable in windows ### Starting multiple bots from the same executable in windows
@ -66,5 +64,77 @@ and the command would look something like this
sayexample!!!say|||Hello [C_ARG_1]{-}delay|||2500{-}say|||Bye [C_ARG_2] sayexample!!!say|||Hello [C_ARG_1]{-}delay|||2500{-}say|||Bye [C_ARG_2]
### HTTP web interface
by setting
> Http_Enable to true
> Http_Host to http://*:8080
> Security_WebUIKey to a vaild code (12 letters+numbers long or more)
you will be able to connect to the bot via HTTP and use the webUI
to control the bot!
[Dev server UI](http://webui.magicmadpeter.xyz/)
or
[Host it yourself](https://github.com/Madpeterz/secondbot_web_folders)
### HTTP scoped tokens
---
Scoped tokens allow you to hardcode access to the HTTP interface (if enabled)
and set more detailed control over what areas can be accessed
plus no need to give the full http
> Security_WebUIKey
You get set these tokens up by file or Environment Variables.
##### File
> {
> "ScopedTokens": [
> "t:[10charcode],ws:core,ws:group",
> "t:[10charcode],cm:chat/localchathistory",
> ]
> }
##### Environment Variables
|Name | Value|
|--|--|
| scoped_token_1 | "t:[10charcode],ws:core,ws:group" |
| scoped_token_2 | "t:[10charcode],cg:chat" |
| scoped_token_3 | "t:[10charcode],cm:chat/localchathistory" |
### HTTP scoped tokens (info)
---
command [cm] "example: `cm:chat/localchathistory`
workspaces [ws] "example: ws: core, ws: groups"
commandgroups [cg] "example: `cg:chat`"
chat
chat/localchathistory
chat/localchatsay
groups/getgroupchat
groups/sendgroupchat
groups/listgroups
im/chatwindows
im/listwithunread
im/getimchat
im/sendimchat
giver
inventory/send
inventory/folders
inventory/contents
groupinvite
[WIP]
movement
core/walkto
core/teleport
core/gesture