WebUI -> Login/Logout and session vaildation (More work than you would expect)
This commit is contained in:
parent
1803e4d529
commit
07ca5edbcb
7 changed files with 231 additions and 73 deletions
|
|
@ -5,17 +5,25 @@ 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;
|
||||
|
||||
namespace BetterSecondBot.HttpServer
|
||||
{
|
||||
public class json_http_reply
|
||||
{
|
||||
public bool status;
|
||||
public string message;
|
||||
public string redirect;
|
||||
}
|
||||
public class SecondBotHttpServer
|
||||
{
|
||||
protected HttpListener listener;
|
||||
|
|
@ -95,18 +103,20 @@ namespace BetterSecondBot.HttpServer
|
|||
HttpListenerContext ctx = await listener.GetContextAsync().ConfigureAwait(true);
|
||||
HttpListenerRequest req = ctx.Request;
|
||||
HttpListenerResponse resp = ctx.Response;
|
||||
resp.Cookies = req.Cookies;
|
||||
string test = req.Url.AbsolutePath.Substring(1);
|
||||
if (helpers.notempty(Config.Http_PublicUrl) == true)
|
||||
{
|
||||
test = test.Replace(Config.Http_PublicUrl, "");
|
||||
}
|
||||
json_http_reply reply = new json_http_reply();
|
||||
List<string> http_args = test.Split('/', StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
byte[] data;
|
||||
resp.StatusCode = 200;
|
||||
resp.ContentType = "text/html";
|
||||
if (req.HttpMethod == "GET")
|
||||
{
|
||||
KeyValuePair<string, byte[]> replydata = myUI.Get_Process(http_args, req.Cookies);
|
||||
KeyValuePair<string, byte[]> replydata = myUI.Get_Process(req, resp, http_args);
|
||||
if (replydata.Value != null)
|
||||
{
|
||||
resp.ContentType = replydata.Key;
|
||||
|
|
@ -142,16 +152,8 @@ namespace BetterSecondBot.HttpServer
|
|||
post_args.Add(bits[0].Trim(), bits[1].Trim());
|
||||
}
|
||||
}
|
||||
|
||||
resp.StatusCode = 200;
|
||||
KeyValuePair<bool, string> UI_process = myUI.Post_process(http_args,post_args);
|
||||
if (UI_process.Key == false)
|
||||
{
|
||||
data = Encoding.UTF8.GetBytes(UI_process.Value);
|
||||
resp.ContentLength64 = data.LongLength;
|
||||
await resp.OutputStream.WriteAsync(data, 0, data.Length).ConfigureAwait(true);
|
||||
}
|
||||
else
|
||||
if (myUI.Post_process(reply, req, resp, http_args, post_args) == true)
|
||||
{
|
||||
bool accept_request = false;
|
||||
string why_request_failed = "Bad signing request";
|
||||
|
|
@ -186,19 +188,24 @@ namespace BetterSecondBot.HttpServer
|
|||
{
|
||||
why_request_failed = "Post missing command value";
|
||||
}
|
||||
reply.message = why_request_failed;
|
||||
reply.status = accept_request;
|
||||
if (accept_request == true)
|
||||
{
|
||||
data = Encoding.UTF8.GetBytes(String.Join("###", post_controler.Call(command, arg)));
|
||||
reply.message = String.Join("###", post_controler.Call(command, arg));
|
||||
}
|
||||
else
|
||||
{
|
||||
resp.StatusCode = 417;
|
||||
data = Encoding.UTF8.GetBytes(why_request_failed);
|
||||
}
|
||||
resp.ContentLength64 = data.LongLength;
|
||||
await resp.OutputStream.WriteAsync(data, 0, data.Length);
|
||||
}
|
||||
|
||||
if(reply.redirect != "")
|
||||
{
|
||||
if(reply.redirect == "/")
|
||||
{
|
||||
reply.redirect = "";
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,13 @@ $( document ).ready(function() {
|
|||
}
|
||||
if(jsondata.hasOwnProperty('redirect'))
|
||||
{
|
||||
setTimeout(function(){ $(location).attr('href', jsondata.redirect) }, redirectdelay);
|
||||
if(jsondata.redirect != "")
|
||||
{
|
||||
if(jsondata.redirect != null)
|
||||
{
|
||||
setTimeout(function(){ $(location).attr('href', jsondata.redirect) }, redirectdelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"/>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha256-L/W5Wfqfa0sdBNIKN9cG6QA5F2qx4qICmU2VgLruv9Y=" crossorigin="anonymous" />
|
||||
<link href="https://stackpath.bootstrapcdn.com/bootswatch/4.4.1/cyborg/bootstrap.min.css" rel="stylesheet" integrity="sha384-l7xaoY0cJM4h9xh1RfazbgJVUZvdtyLWPueWNtLAphf/UbBgOVzqbOTogxPwYLHM" crossorigin="anonymous"/>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/js/bootstrap.bundle.js" integrity="sha256-Z1t+wxZ7Eh5T1sK6aePWMhEQOghR4jZVLwjwrUZAReE=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap-notify@3.1.3/bootstrap-notify.min.js"></script>
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
<form action="[[url_base]]ajax/login/start" method="post" class="ajax">
|
||||
<div class="row mt-1">
|
||||
<div class="col-8 offset-2">
|
||||
<input name="password" class="form-control" type="password" placeholder="Please enter your auth code"/></div>
|
||||
<input name="logincode" class="form-control" type="password" placeholder="Please enter your auth code"/></div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<div class="col-12"><button class="btn btn-primary btn-block" type="submit">Login</button></div>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
</div>
|
||||
<div class="row align-items-end">
|
||||
<div class="col-5">
|
||||
<a href="[[url_base]]login/logout"><button type="button" class="btn btn-block btn-secondary btn-sml">Logout</button></a>
|
||||
<a href="[[url_base]]ajax/logout"><button type="button" class="btn btn-block btn-secondary btn-sml">Logout</button></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using BetterSecondBotShared.Json;
|
||||
using BetterSecondBot.HttpServer;
|
||||
using BetterSecondBotShared.Json;
|
||||
using BetterSecondBotShared.Static;
|
||||
using BSB.bottypes;
|
||||
using System;
|
||||
|
|
@ -14,79 +15,222 @@ namespace BetterSecondBot.HttpWebUi
|
|||
{
|
||||
JsonConfig siteconfig;
|
||||
SecondBot bot;
|
||||
Dictionary<string, long> vaildlogincookies = new Dictionary<string, long>();
|
||||
public webui(JsonConfig setconfig,SecondBot setbot)
|
||||
{
|
||||
bot = setbot;
|
||||
siteconfig = setconfig;
|
||||
}
|
||||
public KeyValuePair<bool, string> Post_process(List<string> args, Dictionary<string,string> post_args)
|
||||
protected KeyValuePair<bool, bool> logincookievaild(HttpListenerRequest reqs, HttpListenerResponse resp)
|
||||
{
|
||||
if(args != null)
|
||||
return logincookievaild(reqs, resp, false);
|
||||
}
|
||||
protected KeyValuePair<bool,bool> logincookievaild(HttpListenerRequest reqs, HttpListenerResponse resp,bool force_logout)
|
||||
{
|
||||
foreach (Cookie C in resp.Cookies)
|
||||
{
|
||||
if(args.Count == 1)
|
||||
if (C.Name == "logincookie")
|
||||
{
|
||||
Cookie old = C;
|
||||
if (force_logout == true)
|
||||
{
|
||||
if (vaildlogincookies.ContainsKey(C.Value) == true)
|
||||
{
|
||||
vaildlogincookies.Remove(C.Value);
|
||||
}
|
||||
Console.WriteLine("Cookie wiped");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vaildlogincookies.ContainsKey(C.Value) == true)
|
||||
{
|
||||
if (vaildlogincookies[C.Value] > helpers.UnixTimeNow())
|
||||
{
|
||||
Console.WriteLine("Cookie ok");
|
||||
return new KeyValuePair<bool, bool>(true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Cookie expired");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Cookie not vaild");
|
||||
}
|
||||
}
|
||||
resp.Cookies.Remove(C);
|
||||
C.Expired = true;
|
||||
resp.Cookies.Add(C);
|
||||
return new KeyValuePair<bool, bool>(true, false);
|
||||
}
|
||||
}
|
||||
Console.WriteLine("No cookie");
|
||||
return new KeyValuePair<bool, bool>(false, false);
|
||||
}
|
||||
public bool Post_process(json_http_reply reply,HttpListenerRequest reqs, HttpListenerResponse resp,List<string> args, Dictionary<string,string> 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
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return new KeyValuePair<bool, string>(false, "");
|
||||
}
|
||||
public KeyValuePair<string,byte[]> Get_Process(List<string> args,CookieCollection cookies)
|
||||
{
|
||||
Cookie logincookie = null;
|
||||
foreach(Cookie C in cookies)
|
||||
{
|
||||
if(C.Name == "logincookie")
|
||||
{
|
||||
logincookie = C;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (logincookie == null)
|
||||
{
|
||||
if (args != null)
|
||||
{
|
||||
if (args.Count >= 1)
|
||||
{
|
||||
if (args[0] == "theme")
|
||||
string mod = "none";
|
||||
string area = "none";
|
||||
if (args.Count >= 2)
|
||||
{
|
||||
if (args.Count >= 2)
|
||||
mod = args[1];
|
||||
}
|
||||
if (args.Count >= 3)
|
||||
{
|
||||
area = args[2];
|
||||
}
|
||||
KeyValuePair<bool, bool> logincheck = logincookievaild(reqs, resp);
|
||||
|
||||
if (logincheck.Key == false)
|
||||
{
|
||||
if (mod == "login")
|
||||
{
|
||||
if (args[1] == "images")
|
||||
if (post_args.ContainsKey("logincode") == true)
|
||||
{
|
||||
return new KeyValuePair<string, byte[]>("image/png", helpers.ReadResourceFileBinary(Assembly.GetExecutingAssembly(), args[2]));
|
||||
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);
|
||||
logincookie.Expires = DateTime.Now.AddDays(1);
|
||||
logincookie.Path = "/";
|
||||
resp.Cookies.Add(logincookie);
|
||||
Console.WriteLine("Cookie created: "+ logincookie.Value+" <=> "+ newcookiecode+"");
|
||||
reply.message = "ok";
|
||||
reply.redirect = "/";
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.message = "fail";
|
||||
}
|
||||
}
|
||||
else if (args[1] == "css")
|
||||
else
|
||||
{
|
||||
return new KeyValuePair<string, byte[]>("text/css", Encoding.UTF8.GetBytes(helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), args[2])));
|
||||
}
|
||||
else if (args[1] == "js")
|
||||
{
|
||||
return new KeyValuePair<string, byte[]>("text/javascript", Encoding.UTF8.GetBytes(helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), args[2])));
|
||||
reply.message = "Missing code";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reply.message = "No access";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logincheck.Value == true)
|
||||
{
|
||||
reply.status = true;
|
||||
// logged in
|
||||
if (mod == "logout")
|
||||
{
|
||||
logincookievaild(reqs, resp, true);
|
||||
reply.message = "logged-out";
|
||||
}
|
||||
reply.message = "No action";
|
||||
}
|
||||
else
|
||||
{
|
||||
// login expired
|
||||
reply.message = "login-expired";
|
||||
reply.redirect = "/";
|
||||
logincookievaild(reqs, resp,true);
|
||||
}
|
||||
}
|
||||
return new KeyValuePair<string, byte[]>("text/html", null);
|
||||
}
|
||||
}
|
||||
string layout = helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), "full.layout");
|
||||
layout = layout.Replace("[[page_content]]", helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), "login.block"));
|
||||
layout = layout.Replace("[[url_base]]", siteconfig.Http_PublicUrl);
|
||||
layout = layout.Replace("[[html_title_after]]", "Secondbot web UI");
|
||||
layout = layout.Replace("[[html_title]]", siteconfig.Basic_BotUserName);
|
||||
layout = layout.Replace("[[html_cs_top]]", helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), "cdn.css.layout"));
|
||||
layout = layout.Replace("[[html_js_bottom]]", helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), "cdn.js.layout"));
|
||||
|
||||
layout = layout.Replace("[[html_js_onready]]", "");
|
||||
return new KeyValuePair<string, byte[]>("text/html", Encoding.UTF8.GetBytes(layout));
|
||||
}
|
||||
return !processed;
|
||||
}
|
||||
|
||||
public KeyValuePair<string, byte[]> 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("[[url_base]]", siteconfig.Http_PublicUrl);
|
||||
layout = layout.Replace("[[html_title_after]]", "Secondbot web UI");
|
||||
layout = layout.Replace("[[html_title]]", siteconfig.Basic_BotUserName);
|
||||
layout = layout.Replace("[[html_cs_top]]", helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), "cdn.css.layout"));
|
||||
layout = layout.Replace("[[html_js_bottom]]", helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), "cdn.js.layout"));
|
||||
|
||||
layout = layout.Replace("[[html_js_onready]]", "");
|
||||
return new KeyValuePair<string, byte[]>("text/html", Encoding.UTF8.GetBytes(layout));
|
||||
}
|
||||
public KeyValuePair<string,byte[]> Get_Process(HttpListenerRequest reqs, HttpListenerResponse resp, List<string> 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<string, byte[]>("image/png", helpers.ReadResourceFileBinary(Assembly.GetExecutingAssembly(), args[2]));
|
||||
}
|
||||
else if (args[1] == "css")
|
||||
{
|
||||
return new KeyValuePair<string, byte[]>("text/css", Encoding.UTF8.GetBytes(helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), args[2])));
|
||||
}
|
||||
else if (args[1] == "js")
|
||||
{
|
||||
return new KeyValuePair<string, byte[]>("text/javascript", Encoding.UTF8.GetBytes(helpers.ReadResourceFile(Assembly.GetExecutingAssembly(), args[2])));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// get display
|
||||
KeyValuePair<bool, bool> logincheck = logincookievaild(reqs, resp);
|
||||
if(logincheck.Key == true)
|
||||
{
|
||||
if(logincheck.Value == false)
|
||||
{
|
||||
logincookievaild(reqs, resp, true);
|
||||
}
|
||||
}
|
||||
if (logincheck.Value == false)
|
||||
{
|
||||
return html_logged_out();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new KeyValuePair<string, byte[]>("text/html", null);
|
||||
string mod = "none";
|
||||
string area = "none";
|
||||
if (args.Count >= 1)
|
||||
{
|
||||
mod = args[0];
|
||||
}
|
||||
if (args.Count >= 2)
|
||||
{
|
||||
area = args[1];
|
||||
}
|
||||
if (mod == "logout")
|
||||
{
|
||||
logincookievaild(reqs, resp, true);
|
||||
return html_logged_out();
|
||||
}
|
||||
else
|
||||
{
|
||||
// logged in
|
||||
return new KeyValuePair<string, byte[]>("text/html", Encoding.UTF8.GetBytes("logged in"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue