diff --git a/.vs/config/applicationhost.config b/.vs/config/applicationhost.config new file mode 100644 index 000000000..de613a419 --- /dev/null +++ b/.vs/config/applicationhost.config @@ -0,0 +1,1020 @@ + + + + + + + +
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+
+ + +
+
+
+
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Admin/Commands.cs b/Admin/Commands.cs index 1ecf1a11a..37b65645c 100644 --- a/Admin/Commands.cs +++ b/Admin/Commands.cs @@ -14,7 +14,7 @@ namespace IW4MAdmin public override async Task ExecuteAsync(Event E) { await E.Origin.Tell("^5Loaded Plugins:"); - foreach (SharedLibrary.Extensions.IPlugin P in PluginImporter.potentialPlugins) + foreach (SharedLibrary.Interfaces.IPlugin P in PluginImporter.potentialPlugins) { await E.Origin.Tell(String.Format("^3{0} ^7[v^3{1}^7] by ^5{2}^7", P.Name, P.Version, P.Author)); } diff --git a/Admin/IW4M ADMIN.csproj b/Admin/IW4M ADMIN.csproj index c5ed3fb00..1c9d9a239 100644 --- a/Admin/IW4M ADMIN.csproj +++ b/Admin/IW4M ADMIN.csproj @@ -198,18 +198,6 @@ PreserveNewest - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - diff --git a/Admin/Kayak.cs b/Admin/Kayak.cs index 537648a73..206d801da 100644 --- a/Admin/Kayak.cs +++ b/Admin/Kayak.cs @@ -9,11 +9,11 @@ using Kayak; namespace IW4MAdmin { - class Scheduler: ISchedulerDelegate + class Scheduler : ISchedulerDelegate { public void OnException(IScheduler scheduler, Exception e) { - Manager.GetInstance().Logger.Write("Web service has encountered an error - " + e.StackTrace); + Manager.GetInstance().Logger.Write("Web service has encountered an error - " + e.Message); } public void OnStop(IScheduler scheduler) @@ -24,27 +24,27 @@ namespace IW4MAdmin class Request : IHttpRequestDelegate { - public void OnRequest(HttpRequestHead request, IDataProducer requestBody, IHttpResponseDelegate response) + public void OnRequest(HttpRequestHead request, IDataProducer requestBody, IHttpResponseDelegate response, string IP) { - // Manager.GetInstance().mainLog.Write("HTTP request received", SharedLibrary.Log.Level.Debug); + // Program.getManager().mainLog.Write("HTTP request received", SharedLibrary.Log.Level.Debug); NameValueCollection querySet = new NameValueCollection(); - + if (request.QueryString != null) querySet = System.Web.HttpUtility.ParseQueryString(SharedLibrary.Utilities.removeNastyChars(request.QueryString)); - querySet.Set("IP", ((DefaultKayakServer)(WebService.webService)).clientAddress.Address.ToString()); + querySet.Set("IP", IP); SharedLibrary.HttpResponse requestedPage = WebService.getPage(request.Path, querySet, request.Headers); var headers = new HttpResponseHead() - { - Status = "200 OK", - Headers = new Dictionary() + { + Status = "200 OK", + Headers = new Dictionary() { { "Content-Type", requestedPage.contentType }, { "Content-Length", requestedPage.content.Length.ToString() }, { "Access-Control-Allow-Origin", "*" }, } - }; + }; foreach (var key in requestedPage.additionalHeaders.Keys) headers.Headers.Add(key, requestedPage.additionalHeaders[key]); diff --git a/Admin/Plugins.cs b/Admin/Plugins.cs index 8595934cb..243d536cf 100644 --- a/Admin/Plugins.cs +++ b/Admin/Plugins.cs @@ -3,7 +3,7 @@ using System.IO; using System.Collections.Generic; using System.Reflection; using SharedLibrary; -using SharedLibrary.Extensions; +using SharedLibrary.Interfaces; namespace IW4MAdmin { diff --git a/Admin/Server.cs b/Admin/Server.cs index 35f353b46..1bb497800 100644 --- a/Admin/Server.cs +++ b/Admin/Server.cs @@ -58,12 +58,6 @@ namespace IW4MAdmin if (P.clientID < 0 || P.clientID > (Players.Count-1)) // invalid index return false; - if (P.Name == null || P.Name == String.Empty || P.Name.Length <= 1) - await this.ExecuteCommandAsync("clientkick " + P.clientID + " \"Please set a name using /name ^7\""); - - if (Players.Find(existingPlayer => (existingPlayer != null && existingPlayer.Name.Equals(P.Name)) && existingPlayer.clientID != P.clientID) != null) - await this.ExecuteCommandAsync("clientkick " + P.clientID + " \"Someone is using your name. Set a new name using ^5/name ^7\""); - if (Players[P.clientID] != null && Players[P.clientID].npID == P.npID) // if someone has left and a new person has taken their spot between polls return true; @@ -224,10 +218,7 @@ namespace IW4MAdmin Log.Write("Client at " + cNum + " disconnecting...", Log.Level.Debug); await ExecuteEvent(new Event(Event.GType.Disconnect, "", Leaving, null, this)); - lock (Players) - { - Players[cNum] = null; - } + Players[cNum] = null; ClientNum--; } @@ -368,7 +359,7 @@ namespace IW4MAdmin { await ProcessEvent(E); - foreach (SharedLibrary.Extensions.IPlugin P in PluginImporter.potentialPlugins) + foreach (SharedLibrary.Interfaces.IPlugin P in PluginImporter.potentialPlugins) { try { @@ -385,16 +376,19 @@ namespace IW4MAdmin } } - async Task PollPlayersAsync() + async Task PollPlayersAsync() { var CurrentPlayers = await this.GetStatusAsync(); for (int i = 0; i < Players.Count; i++) + { if (CurrentPlayers.Find(p => p.clientID == i) == null && Players[i] != null) await RemovePlayer(i); + } + + foreach (var P in CurrentPlayers) + await AddPlayer(P); - foreach (Player P in CurrentPlayers) - await AddPlayer(P); } long l_size = -1; diff --git a/Admin/WebService.cs b/Admin/WebService.cs index 2951f2650..174f270db 100644 --- a/Admin/WebService.cs +++ b/Admin/WebService.cs @@ -44,9 +44,19 @@ namespace IW4MAdmin string[] webConfig = System.IO.File.ReadAllLines("config\\web.cfg"); var address = Dns.GetHostAddresses(webConfig[0])[0]; int port = Convert.ToInt32(webConfig[1]); - - using (ss.Listen(new IPEndPoint(address, port))) - S.Start(); + + try + { + using (ss.Listen(new IPEndPoint(address, port))) + S.Start(); + } + + catch (Exception e) + { + Console.WriteLine("Unable to start webservice ( port is probably in use ): " + e.Message); + Thread.Sleep(5000); + Environment.Exit(-1); + } } catch (Exception) @@ -68,7 +78,7 @@ namespace IW4MAdmin { IFile f = new IFile(path.Replace("/", "\\").Substring(1)); - + if (path.Contains(".css")) { HttpResponse css = new HttpResponse(); @@ -77,7 +87,7 @@ namespace IW4MAdmin css.contentType = "text/css"; f.Close(); return css; - + } else if (path.Contains(".js")) @@ -89,8 +99,8 @@ namespace IW4MAdmin f.Close(); return css; } - f.Close(); - + f.Close(); + } requestedPage = new Error404(); @@ -173,7 +183,7 @@ namespace IW4MAdmin { var info = new List(); - foreach(Server S in Manager.GetInstance().Servers) + foreach (Server S in Manager.GetInstance().Servers) { ServerInfo eachServer = new ServerInfo(); eachServer.serverName = S.getName(); @@ -289,7 +299,7 @@ namespace IW4MAdmin S.ExecuteEvent(remoteEvent); - while(S.commandResult.Count > 0) + while (S.commandResult.Count > 0) cmd.Result.Add(S.commandResult.Dequeue()); } else @@ -342,7 +352,8 @@ namespace IW4MAdmin from = Int32.Parse(querySet["from"]); List selectedPenalties; - try { + try + { selectedPenalties = Manager.GetInstance().Servers.First().Bans.OrderByDescending(x => x.When).ToList().GetRange(Convert.ToInt32(querySet["from"]), 15); } @@ -415,7 +426,7 @@ namespace IW4MAdmin IFile penalities = new IFile("webfront\\penalties.html"); S.Append(penalities.getLines()); penalities.Close(); - + S.Append(loadFooter()); return S.ToString(); @@ -476,7 +487,7 @@ namespace IW4MAdmin } } - class PubbansJSON: IPage + class PubbansJSON : IPage { public string getName() { @@ -531,9 +542,9 @@ namespace IW4MAdmin PageInfo pi = new PageInfo(); pi.pagePath = p.getPath(); - // pi.pageType = p.getPage(querySet, headers).contentType; + // pi.pageType = p.getPage(querySet, headers).contentType; pi.pageName = p.getName(); - pi.visible = p.isVisible(); + pi.visible = p.isVisible(); pages.Add(pi); } @@ -580,17 +591,19 @@ namespace IW4MAdmin resp.contentType = getContentType(); resp.additionalHeaders = new Dictionary(); + bool authed = Manager.GetInstance().Servers.First().clientDB.getAdmins().FindAll(x => x.IP == querySet["IP"]).Count > 0; + if (querySet["id"] != null) { matchedPlayers.Add(Manager.GetInstance().Servers.First().clientDB.getPlayer(Convert.ToInt32(querySet["id"]))); } - else if(querySet["npID"] != null) + else if (querySet["npID"] != null) { matchedPlayers.Add(Manager.GetInstance().Servers.First().clientDB.getPlayers(new List { querySet["npID"] }).First()); } - else if(querySet["name"] != null) + else if (querySet["name"] != null) { matchedPlayers = Manager.GetInstance().Servers.First().clientDB.findPlayers(querySet["name"]); } @@ -607,7 +620,7 @@ namespace IW4MAdmin { foreach (var pp in matchedPlayers) { - if (pp == null) continue; + if (pp == null) continue; var playerAliases = Manager.GetInstance().Servers.First().getAliases(pp); PlayerInfo eachPlayer = new PlayerInfo(); @@ -617,6 +630,9 @@ namespace IW4MAdmin eachPlayer.playerName = pp.Name; eachPlayer.playernpID = pp.npID; eachPlayer.forumID = -1; + eachPlayer.authed = authed; + if (eachPlayer.forumID < 500000) + eachPlayer.showV2Features = true; foreach (var a in playerAliases) { @@ -625,10 +641,10 @@ namespace IW4MAdmin } eachPlayer.playerConnections = pp.Connections; - eachPlayer.lastSeen = SharedLibrary.Utilities.timePassed(pp.LastConnection); + eachPlayer.lastSeen = Utilities.timePassed(pp.LastConnection); pInfo.Add(eachPlayer); - - } + + } resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(pInfo); return resp; @@ -669,6 +685,7 @@ namespace IW4MAdmin { public string pageName; public string pagePath; + public string pageType; public bool visible; } @@ -685,6 +702,8 @@ namespace IW4MAdmin public List playerIPs; public int playerConnections; public string lastSeen; + public bool showV2Features; + public bool authed; } [Serializable] @@ -704,4 +723,4 @@ namespace IW4MAdmin { public List Result; } -} +} \ No newline at end of file diff --git a/Admin/lib/Kayak.dll b/Admin/lib/Kayak.dll index da5f9b8b8..d9eb6a3cb 100644 Binary files a/Admin/lib/Kayak.dll and b/Admin/lib/Kayak.dll differ diff --git a/Admin/lib/SharedLibrary.dll b/Admin/lib/SharedLibrary.dll index 83d314f40..e1a0d44ca 100644 Binary files a/Admin/lib/SharedLibrary.dll and b/Admin/lib/SharedLibrary.dll differ diff --git a/Admin/webfront/header.html b/Admin/webfront/header.html index 50c8225ca..2a142bc13 100644 --- a/Admin/webfront/header.html +++ b/Admin/webfront/header.html @@ -1,9 +1,9 @@ - + IW4MAdmin by RaidMax - + @@ -23,7 +23,71 @@ $.getJSON("_userinfo", function(response) { function showErrorMessage(msg) { - $('.alertBox').html(msg).addClass('error').slideDown("fast"); + message = "An unknown error occurred!"; + switch(msg) + { + case 0: + message = "No error"; + break; + case 1: + message = "Permission denied"; + break; + case 2: + message = "User exists"; + break; + case 3: + message = "Invalid user"; + break; + case 4: + message = "Incorrect username or password"; + break; + case 5: + message = "No credentials entered"; + break; + case 6: + message = "User not authorized"; + break; + case 7: + message = "Password too long"; + break; + case 8: + message = "Username too long"; + break; + case 9: + message = "Bad profile data entered"; + break; + case 10: + message = "Invalid session"; + break; + case 11: + message = "Bad thread content entered"; + break; + case 12: + message = "No thread content entered"; + break; + case 13: + message = "Thread content too long"; + break; + case 14: + message = "Thread title too long"; + break; + case 15: + message = "Invalid thread specified"; + break; + case 16: + message = "Could not save reply"; + break; + case 17: + message = "Invalid category specified"; + break; + case 18: + message = "Empty category"; + break; + case 19: + message = "Password do not match"; + break; + } + $('.alertBox').html(message).addClass('error').slideDown("fast"); } function parseGet(val) { @@ -74,7 +138,7 @@ function formatMessages(messages) var chats = ""; $.each(messages, function(i, chat) { chats += - "
" + chat['Name'] + ":
" + $("
").html(chat['Message']).text() + "
\ + "
" + $("
").html(chat['Name']).text()+ ":
" + $("
").html(chat['Message']).text() + "
\
" }); return chats; @@ -93,9 +157,9 @@ function getPages() function shouldHideAction(author) { // fixme dynamic - if (user.rank == null || author.ranking == null) + if (author.ranking == null) return " display: none"; - else if (user.rank.name == "Moderator" || user.rank.name == "Administrator" || user.username == author.username) + else if (user.user.ranking.name == "Moderator" || user.user.ranking.name == "Administrator" || user.user.id == author.id) return ""; else { return " display: none"; @@ -107,7 +171,7 @@ function formatPlayers(players) var p = ""; for (i = 0; i < players.length; i++) { - p += ""; + p += "
" + getColorForLevel(players[1*i]['playerLevel'], $(""; if (i % 2 == 1 && i != 0 ) p += "
"; } @@ -132,7 +196,7 @@ function getDate(datestr) function checkPrivilege() { - $.getJSON("_userinfo", function(response) { if (response.rank.id != 1) window.location.replace("home"); else $('.infoBox').show(); }); + $.getJSON("_userinfo", function (response) { if (response.user.ranking.id != 1) window.location.replace("home"); else $('.infoBox').show(); }); } diff --git a/Admin/webfront/main.css b/Admin/webfront/main.css index 0c8825ffd..1a28a075c 100644 --- a/Admin/webfront/main.css +++ b/Admin/webfront/main.css @@ -15,7 +15,7 @@ div#header #navContainer .navEntry a { padding: 1.2vw; width: 4vw; } div#header #navContainer .navEntry:hover { background-color: rgb(34, 34, 34); } div#content { margin: 3em 10%; } -div#content .serverContainer { background-color: #191919; margin: 2em 0; font-size: 1.75vw; } +div#content .serverContainer { background-color: #191919; margin: 2em 0; font-size: 1.25vw; } div#content hr { border-width: 0; height: 0.25em; background-color: #007ACC; } div#content .serverInfo { width: 100%; } div#content .serverInfo .tableCell { padding: 0 0.5em; } @@ -25,10 +25,10 @@ div#content .serverPlayers { text-align: right; width: calc( 100% / 3); backgrou div#content .serverMap { text-align: center; width: calc( 100% / 3); background-color: #007ACC; } div#content .serverPlayerList {float: right; margin: 0.5em; } div#content .serverChatList { float: left; margin: 0.5em } -div#content .playerName { font-size: 1.357vw; color: rgba(78, 140, 77, 0.64); width: 10em; text-align: right; } +div#content .playerName { font-size: 1.1vw; color: rgba(78, 140, 77, 0.64); width: 10em; text-align: right; } div#content .playerName:hover { color: rgb(0, 122, 204) !important; } -div#content .chatPlayerName { font-weight: bold; font-size: 1.357vw; color:#fff; padding-right: 0.5em; opacity: 0.5; } -div#content .chatPlayerMessage {font-size: 1.357vw; color: #fff; opacity: 1; } +div#content .chatPlayerName { font-weight: bold; font-size: 1.1vw; color:#fff; padding-right: 0.5em; opacity: 0.5; } +div#content .chatPlayerMessage {font-size: 1.1vw; color: #fff; opacity: 1; } div#content .playerPenalty, div#content .playerInfo { margin: 0 auto; padding: 1em 10px; background-color: #181818; width: calc(100% - 20px); } div#content .penaltyName { width: 14.28%; } @@ -74,7 +74,7 @@ div.infoBox .header { text-align: center; background-color: #007ACC; padding: 0. div.infoBox form { padding: 10px; } div.infoBox { width: 50%; margin: 0 auto; background-color: #181818; border: 1em solid #007ACC; border-width: 0 0 0.25em 0; min-width: 550px; } div.infoBox input[type="text"], div.infoBox input[type="password"] { width: 70%; } -div.infoBox input[type="submit"] { width: 20%; background-color: #007ACC; font-size: 16pt; border: none; color: #fff; font-size: 15pt; padding: 0.5em 10px; margin: 0.25em; } +div.infoBox input[type="submit"], #userCP input[type="submit"] { width: 20%; background-color: #007ACC; font-size: 16pt; border: none; color: #fff; font-size: 15pt; padding: 0.5em 10px; margin: 0.25em; } div.alertBox { display: none; margin-top: 15px; margin-left: 15px; } @@ -88,8 +88,8 @@ div#recentTitle { position: relative; top: -1em; } div#view .threadPreview { background-color: #181818; padding: 0 10px; width: calc(100% - 20px); } div#view .threadPreview .threadTitle { padding: 0 0.5em; width: 80%; } div#view .threadPreview .threadInfo { font-size: 9pt; text-align: right; width: 50%; } -div#view .categoryDescription { font-size: 9pt; opacity: 0.5; margin-left: 2em; position: relative; top: -2.5px; } -div#content .individualThreadInfo { border-bottom: 1px solid rgba(255, 255, 255, 0.2); padding: 0.5em 0; display: table; width: 100%; } +div#view .categoryDescription { font-size: 10.5pt; opacity: 0.5; margin-left: 2em; position: relative; top: -2.5px; } +div#content .individualThreadInfo { border-bottom: 1px solid rgba(255, 255, 255, 0.2); padding: 0.5em 1em; display: table; width: calc(100% - 2em); } div#content .individualThreadInfo:nth-child(3) { border-bottom: none; padding-bottom: 0.5em; } div#content .individualThreadInfo i { font-size: 16pt; width: 16pt; } div.title a:link:hover, div.title a:visited:hover { color: #ff6633 !important; } @@ -123,6 +123,7 @@ div#threadContainer .threadContent { margin: 1em 0; font-size: 11pt; word-break div#threadContainer .threadContent img { max-width: 100%;} div#threadContainer .threadContent a { color: rgb(0, 122, 204) !important; } div#threadContainer .threadContent a:hover { color: #fff !important; } +div.threadContent ol, div.threadContent ol { margin: 1em; } div.categoryThread .threadActions { color: rgba(255, 69, 69, 0.85); font-size: 18pt; width: 19px; } @@ -181,14 +182,19 @@ div#userAvatar { width: 20em; height: 20em; background-size: contain; margin-ri .themeBlue { color: #007ACC !important; } .themeBlue:hover { color: #fff !important; } .themeOrange { color: #ff6633; } -.themeOrage:hover{ color: #007ACC !important; } +.themeOrange:hover{ color: #007ACC !important; } -div.threadInfo .actionHover { float: right; color: rgba(255, 69, 69, 0.85); } +div.threadInfo .actionHover { float: right; color: rgba(255, 69, 69, 0.85); margin: 0 4px; } .actionHover { cursor: pointer; } .actionHover:hover { color: #007ACC !important; } +.actionHover.actionEdit { color:#007ACC !important; } .datThing { background-color: #007ACC; font-size: 16pt; border: none; color: #fff; font-size: 15pt; padding: 0.5em 10px; } span.light { opacity: 0.5; } span.userTitle span:hover {color: #007ACC !important; } + +input#bannercolor { margin: 0.35em; width: 265px; border: none; height: 45px; } + + div#footer { position: fixed; bottom: 0.5em; right: 0.5em; opacity: 0.5; } diff --git a/Admin/webfront/players.html b/Admin/webfront/players.html index 255c8577f..70eb83117 100644 --- a/Admin/webfront/players.html +++ b/Admin/webfront/players.html @@ -17,37 +17,61 @@ function getPrevPage() else return 0; } -function formatHidden(data) + +function formatHidden(data, authed) { - var p = "
Expand
"; - $.each(data, function(i, dat) { - p += "" + dat + "
" - }) + var p = "
Expand
"; + + if (authed) { + $.each(data, function (i, dat) { + p += "" + dat + "
" + }) + } + + else + p += "Hidden"; p += "
" return p; } + function printPlayer(player, i) { - $("#playersTable").append( - "
\ - \ -
"+ formatHidden(player['playerAliases']) + "
\ -
"+ formatHidden(player['playerIPs']) + "
\ -
"+ getColorForLevel(player['playerLevel'], player['playerLevel']) + "
\ -
"+ player['playerConnections'] + "
\ -
\ - \ + var p = ""; + p += + "
\ + \ +
" + formatHidden(player['playerAliases'], player.authed) + "
\ +
" + formatHidden(player['playerIPs'], player.authed) + "
\ +
" + getColorForLevel(player['playerLevel'], player['playerLevel']) + "
\ +
" + player['playerConnections'] + "
"; + + if (player.showV2Features) + { + p += + "
\ + \ \ \ \ \ \ -
\ -
"+ checkJustNow(player['lastSeen']) + "
\ -
" - ) +
"; + } + + else + { + p+= + "
" + } + + p += + "
" + checkJustNow(player['lastSeen']) + "
\ +
"; + + $("#playersTable").append(p); + } function getPlayer(ident, identValue) @@ -59,7 +83,7 @@ function getPlayer(ident, identValue) $.each(result, function(i, player) { printPlayer(player, i); }); - }).done(function (data) { $(".loader").fadeOut(); }); + }).done(function (data) { $(".loader").fadeOut(); }); } $( document ).ready(function() { @@ -72,8 +96,8 @@ $( document ).ready(function() { } }); -$('#content').on('click', '.hiddenWrapper', function(){ - $(this).find('.hiddenElements').toggle() +$('#content').on('click', 'div.hiddenWrapper span', function(){ + $(this).parent().find('.hiddenElements').toggle() }); diff --git a/Auto Restart Plugin/Main.cs b/Auto Restart Plugin/Main.cs index 462d2ab9f..421a8c98c 100644 --- a/Auto Restart Plugin/Main.cs +++ b/Auto Restart Plugin/Main.cs @@ -1,6 +1,6 @@ using System; using SharedLibrary; -using SharedLibrary.Extensions; +using SharedLibrary.Interfaces; using System.Threading.Tasks; namespace Auto_Restart_Plugin diff --git a/EventAPI/Plugin.cs b/EventAPI/Plugin.cs index 0aaa8856b..04dd0c233 100644 --- a/EventAPI/Plugin.cs +++ b/EventAPI/Plugin.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; using SharedLibrary; -using SharedLibrary.Extensions; +using SharedLibrary.Interfaces; using System.Threading.Tasks; namespace EventAPI diff --git a/MessageboardPlugin/Forum.cs b/MessageboardPlugin/Forum.cs index 9442bb444..f6345a6c7 100644 --- a/MessageboardPlugin/Forum.cs +++ b/MessageboardPlugin/Forum.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using System.Text; using SharedLibrary; using System.Collections.Specialized; @@ -17,7 +18,7 @@ namespace MessageBoard.Forum private const int MAX_SESSIONS = 64; public const int TITLE_MAXLENGTH = 30; public const int CONTENT_MAXLENGTH = 8192; - public const int USERNAME_MAXLENGTH = 16; + public const int USERNAME_MAXLENGTH = 30; public const int PASSWORD_MAXLENGTH = 64; public Rank guestRank; @@ -36,6 +37,7 @@ namespace MessageBoard.Forum USER_NOTAUTHORIZED, USER_PASSWORDTOOLONG, USER_USERNAMETOOLONG, + USER_BADPROFILEDATA, SESSION_INVALID, THREAD_BADDATA, THREAD_EMPTYDATA, @@ -44,7 +46,8 @@ namespace MessageBoard.Forum THREAD_INVALID, REPLY_SAVEFAILED, CATEGORY_INVALID, - CATEGORY_EMPTY + CATEGORY_EMPTY, + USER_MISMATCHEDPASSWORD } public Manager() @@ -60,13 +63,13 @@ namespace MessageBoard.Forum { Session newSession = getSession(sessionID); newSession.sessionStartTime = DateTime.Now; - Console.WriteLine("Matching session was found - {0}", sessionID); + //Console.WriteLine("Matching session was found - {0}", sessionID); addSession(newSession); } catch (Exceptions.SessionException) { - Console.WriteLine("No session was found so we are adding a new one"); + //Console.WriteLine("No session was found so we are adding a new one"); Session newSession = new Session(new User(), sessionID); addSession(newSession); } @@ -95,6 +98,16 @@ namespace MessageBoard.Forum return requestedUser; } + public User getUser(string username) + { + User requestedUser = database.getUser(username); + + if (requestedUser == null) + throw new Exceptions.UserException("User not found"); + + return requestedUser; + } + public ForumThread getThread(int threadID) { ForumThread requestedThread = database.getThread(threadID); @@ -150,7 +163,7 @@ namespace MessageBoard.Forum if (activeSessions.Count >= MAX_SESSIONS) activeSessions.RemoveAt(0); - //activeSessions.RemoveAll(x => (x.sessionID == sess.sessionID && sess.sessionUser.ranking.equivalentRank > x.sessionUser.ranking.equivalentRank)); + activeSessions.RemoveAll(x => x.sessionUser.ranking.name == "Guest" && x.sessionID == sess.sessionID); //Console.WriteLine(String.Format("Adding new session [{0}] [{1}]", sess.sessionID, sess.sessionUser.username)); @@ -158,7 +171,7 @@ namespace MessageBoard.Forum activeSessions.Add(sess); // if it's a guest session, we don't want to save them in the database... - if (sess.sessionUser.ranking.equivalentRank > Player.Permission.User) + if (sess.sessionUser.ranking.name != "Guest") { database.setSession(sess.sessionUser.id, sess.sessionID); sess.sessionUser.lastLogin = DateTime.Now; @@ -171,6 +184,24 @@ namespace MessageBoard.Forum public void removeSession(string sessID) { activeSessions.RemoveAll(x => x.sessionID == sessID); + database.removeSession(sessID); + } + + public ProfileSettings getProfileSettings(int userid) + { + var retrieved = database.getProfileSettings(userid); + if (retrieved == null) + { + if (userid > 0) + { + var profile = new ProfileSettings(userid); + database.addProfileSettings(profile); + return profile; + } + return new ProfileSettings(0); + } + else + return retrieved; } public ErrorCode addUser(User newUser, Session userSession) @@ -183,6 +214,8 @@ namespace MessageBoard.Forum newUser.ranking = AdminRank; User createdUser = database.addUser(newUser, userSession); + database.addProfileSettings(new ProfileSettings(createdUser.id)); + removeSession(userSession.sessionID); return addSession(new Session(createdUser, userSession.sessionID)); } @@ -191,6 +224,11 @@ namespace MessageBoard.Forum database.updateUser(updatedUser); } + public void updateUserProfile(ProfileSettings updatedUserProfile) + { + database.updateProfileSettings(updatedUserProfile); + } + public ErrorCode updateThread(ForumThread newThread) { if (database.updateThread(newThread)) @@ -218,7 +256,7 @@ namespace MessageBoard.Forum public ErrorCode authorizeUser(string username, string password, string sessionID) { - User toAuth = database.getUser(username); + User toAuth = database.getUser(username.ToLower()); if (toAuth == null) return ErrorCode.USER_BADCREDENTIALS; @@ -270,6 +308,8 @@ namespace MessageBoard.Forum var registerJSON = new Pages.RegisterJSON(); var userinfoJSON = new Pages.userinfoJSON(); var viewUser = new Pages.ViewUser(); + var userCP = new Pages.UserCP(); + var updateUserJSON = new Pages.updateUserJSON(); var categoriesJSON = new Pages.categoriesJSON(); var category = new Pages.ViewCategory(); var categorythreadsJSON = new Pages.categorythreadsJSON(); @@ -289,6 +329,8 @@ namespace MessageBoard.Forum forumPages.Add(registerJSON); forumPages.Add(userinfoJSON); forumPages.Add(viewUser); + forumPages.Add(userCP); + forumPages.Add(updateUserJSON); forumPages.Add(categoriesJSON); forumPages.Add(category); forumPages.Add(categorythreadsJSON); @@ -308,6 +350,8 @@ namespace MessageBoard.Forum SharedLibrary.WebService.pageList.Add(registerJSON); SharedLibrary.WebService.pageList.Add(userinfoJSON); SharedLibrary.WebService.pageList.Add(viewUser); + SharedLibrary.WebService.pageList.Add(userCP); + SharedLibrary.WebService.pageList.Add(updateUserJSON); SharedLibrary.WebService.pageList.Add(categoriesJSON); SharedLibrary.WebService.pageList.Add(category); SharedLibrary.WebService.pageList.Add(categorythreadsJSON); @@ -366,7 +410,7 @@ namespace MessageBoard.Forum if (requestHeaders.ContainsKey("Cookie")) { - Console.WriteLine("JSON request contains session header - " + requestHeaders["Cookie"]); + //Console.WriteLine("JSON request contains session header - " + requestHeaders["Cookie"]); string cookie = requestHeaders["Cookie"].Split('=')[1]; Plugin.Main.forum.startSession(cookie); currentSession = Plugin.Main.forum.getSession(cookie); @@ -552,6 +596,30 @@ namespace MessageBoard.Forum } } + public class UserCP : ForumPage + { + public UserCP() : base(false) + { + + } + + public override string getName() + { + return "Forum - User Control Panel"; + } + + public override string getPath() + { + return base.getPath() + "/usercp"; + } + + public override string getContent(NameValueCollection querySet, IDictionary headers) + { + string content = loadFile("forum\\usercp.html"); + return templatation(content); + } + } + public class ViewThread : ForumPage { public ViewThread() : base(false) @@ -622,10 +690,29 @@ namespace MessageBoard.Forum result.destination = base.getPath() + "/error"; try { + + string username = DNA.Text.TextEngine.Text(querySet["username"]); + string password = DNA.Text.TextEngine.Text(querySet["password"]); + string email = DNA.Text.TextEngine.Text(querySet["email"]); + + bool validEmail = Regex.IsMatch(email, + @"^(?("")("".+?(? Manager.USERNAME_MAXLENGTH) + throw new Exceptions.UserException("Username is too long"); + + if (password.Length > Manager.PASSWORD_MAXLENGTH) + throw new Exceptions.UserException("Password is too long"); + byte[] passwordSalt = Encryption.PasswordHasher.GenerateSalt(); - string b64PasswordHash = Convert.ToBase64String(Encryption.PasswordHasher.ComputeHash(querySet["password"], passwordSalt)); + string b64PasswordHash = Convert.ToBase64String(Encryption.PasswordHasher.ComputeHash(password, passwordSalt)); - User registeringUser = new User(querySet["username"], querySet["hiddenUsername"], querySet["email"], b64PasswordHash, Convert.ToBase64String(passwordSalt), Plugin.Main.forum.UserRank); + User registeringUser = new User(username, querySet["hiddenUsername"], email, b64PasswordHash, Convert.ToBase64String(passwordSalt), Plugin.Main.forum.UserRank); currentSession = new Session(registeringUser, currentSession.sessionID); var addUserResult = Plugin.Main.forum.addUser(registeringUser, currentSession); @@ -643,7 +730,9 @@ namespace MessageBoard.Forum } } - catch (Exception E) { + catch (Exception E) + { + //logme result.errorCode = Manager.ErrorCode.USER_INVALID; } @@ -665,11 +754,12 @@ namespace MessageBoard.Forum UserInfo info = new UserInfo(); bool validUserSelection = true; - User requestedUser = null; try { - requestedUser = Plugin.Main.forum.getUser(Convert.ToInt32(querySet["id"])); + int userid = Convert.ToInt32(querySet["id"]); + info.user = Plugin.Main.forum.getUser(userid); + info.profile = Plugin.Main.forum.getProfileSettings(userid); } catch (FormatException) @@ -684,41 +774,120 @@ namespace MessageBoard.Forum validUserSelection = false; } - if (validUserSelection) + if (!validUserSelection) { - resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(requestedUser); + info.user = currentSession.sessionUser; + try + { + info.profile = Plugin.Main.forum.getProfileSettings(info.user.id); + } + + catch (Exceptions.UserException) + { + //logme + } } - else + /*// this should not be a thing but ok... + Player matchedPlayer = Plugin.Main.stupidServer.clientDB.getPlayer(querySet["ip"]); + + if (matchedPlayer != null) + info.matchedUsername = matchedPlayer.Name;*/ + + resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(info); + return resp; + } + } + + public class updateUserJSON : JSONPage + { + public override string getPath() + { + return base.getPath() + "/_updateuser"; + } + + public override HttpResponse getPage(NameValueCollection querySet, IDictionary requestHeaders) + { + var resp = base.getPage(querySet, requestHeaders); + var aResp = new ActionResponse(); + + bool passwordUpdateRequest = false; + + if (querySet["username"] == null || currentSession.sessionUser.id == 0) + aResp.errorCode = Manager.ErrorCode.USER_INVALID; + else if (querySet["bannercolor"] == null) + aResp.errorCode = Manager.ErrorCode.USER_BADPROFILEDATA; + if (querySet["updatedpassword"] != null && querySet["updatedpasswordrepeat"] != null && querySet["updatedpassword"].Length > 0 && querySet["updatedpasswordrepeat"].Length > 0) + passwordUpdateRequest = true; + + if (aResp.errorCode == Manager.ErrorCode.NO_ERROR) { - if (querySet.Get("setavatarurl") != null) + string username = DNA.Text.TextEngine.Text(querySet["username"]); + string bannercolor = DNA.Text.TextEngine.Text(querySet["bannercolor"]); + string avatarURL = DNA.Text.TextEngine.Text(querySet["avatarurl"]); + string password = null; + + if (passwordUpdateRequest) { - if (currentSession.sessionUser.ranking.name != "Guest") + password = DNA.Text.TextEngine.Text(querySet["updatedpassword"]); + string passwordRepeat = DNA.Text.TextEngine.Text(querySet["updatedpasswordrepeat"]); + if (!password.Equals(passwordRepeat)) { - currentSession.sessionUser.avatarURL = querySet["setavatarurl"]; - Plugin.Main.forum.updateUser(currentSession.sessionUser); - resp.content = "OK!"; - return resp; + password = null; + aResp.errorCode = Manager.ErrorCode.USER_MISMATCHEDPASSWORD; + } + + else if (password.Length > Manager.PASSWORD_MAXLENGTH) + { + password = null; + aResp.errorCode = Manager.ErrorCode.USER_PASSWORDTOOLONG; } } + User existingUser = null; + try + { + existingUser = Plugin.Main.forum.getUser(username); + } + + catch (Exceptions.UserException) + { + + } + + + if (existingUser != null && existingUser.id != currentSession.sessionUser.id) + aResp.errorCode = Manager.ErrorCode.USER_DUPLICATE; else { - info.email = currentSession.sessionUser.email; - info.username = currentSession.sessionUser.username; - info.rank = currentSession.sessionUser.ranking; + var profile = Plugin.Main.forum.getProfileSettings(currentSession.sessionUser.id); + if (username.Length <= Manager.USERNAME_MAXLENGTH) + currentSession.sessionUser.updateUsername(username); + else + aResp.errorCode = Manager.ErrorCode.USER_USERNAMETOOLONG; + currentSession.sessionUser.updateAvatar(avatarURL); - // this should not be a thing but ok... - Player matchedPlayer = Plugin.Main.stupidServer.clientDB.getPlayer(querySet["ip"]); + if (passwordUpdateRequest && aResp.errorCode == Manager.ErrorCode.NO_ERROR) + { + byte[] passwordSalt = Encryption.PasswordHasher.GenerateSalt(); + string b64PasswordHash = Convert.ToBase64String(Encryption.PasswordHasher.ComputeHash(password, passwordSalt)); + currentSession.sessionUser.updatePassword(Convert.ToBase64String(passwordSalt), b64PasswordHash); + } - if (matchedPlayer != null) - info.matchedUsername = matchedPlayer.Name; - - resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(info); + Plugin.Main.forum.updateUser(currentSession.sessionUser); + if (bannercolor.Length == 7) + profile.bannerColor = bannercolor; + Plugin.Main.forum.updateUserProfile(profile); + } } - return resp; + aResp.success = aResp.errorCode == Manager.ErrorCode.NO_ERROR; + if (aResp.success) + aResp.destination = "usercp"; + + resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(aResp); + return resp; } } @@ -737,7 +906,10 @@ namespace MessageBoard.Forum try { - var result = Plugin.Main.forum.authorizeUser(querySet["username"], querySet["password"], currentSession.sessionID); + string username = DNA.Text.TextEngine.Text(querySet["username"]); + string password = DNA.Text.TextEngine.Text(querySet["password"]); + + var result = Plugin.Main.forum.authorizeUser(username, password, currentSession.sessionID); aResp.success = result == Manager.ErrorCode.NO_ERROR; aResp.errorCode = result; aResp.destination = "home"; @@ -881,13 +1053,24 @@ namespace MessageBoard.Forum var thread = Plugin.Main.forum.getThread(Convert.ToInt32(querySet["id"])); if ((thread.threadCategory.permissions.Find(x => x.rankID == currentSession.sessionUser.ranking.id).actionable & Permission.Action.READ) != Permission.Action.READ) - throw new Exceptions.PermissionException("You cannot view this post"); + throw new Exceptions.PermissionException("User cannot view this post"); var replies = Plugin.Main.forum.getReplies(thread.id); resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(new ThreadView(thread, replies)); aResp.success = true; } + + else if (querySet.Get("replyid") != null) + { + var thread = Plugin.Main.forum.getReply(Convert.ToInt32(querySet["replyid"])); + + //if ((thread.threadCategory.permissions.Find(x => x.rankID == currentSession.sessionUser.ranking.id).actionable & Permission.Action.READ) != Permission.Action.READ) + // throw new Exceptions.PermissionException("User cannot view this post"); + + resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(thread); + aResp.success = true; + } } catch (FormatException) @@ -961,15 +1144,15 @@ namespace MessageBoard.Forum else { //fixsecurity - var markdownParser = new MarkdownDeep.Markdown(); - string markdownContent = markdownParser.Transform(querySet["content"]); - markdownContent = Uri.EscapeDataString(markdownContent); - string title = Uri.EscapeDataString(querySet["title"]); + var fmtr = new DNA.Text.BBCodeFormatter(); + string content = fmtr.Format(Uri.UnescapeDataString(querySet["content"])); + string title = DNA.Text.TextEngine.Text(Uri.UnescapeDataString(querySet["title"])); - if (thread.updateTitle(title) && thread.updateContent(markdownContent)) + if (thread.updateTitle(title) && thread.updateContent(content)) { aResp.errorCode = Plugin.Main.forum.updateThread(thread); aResp.success = aResp.errorCode == Manager.ErrorCode.NO_ERROR; + aResp.destination = "thread?id=" + thread.id; } else aResp.errorCode = Manager.ErrorCode.THREAD_EMPTYDATA; @@ -980,7 +1163,7 @@ namespace MessageBoard.Forum else if (querySet.Get("replyid") != null) { var reply = Plugin.Main.forum.getReply(Convert.ToInt32(querySet["replyid"])); - + if (currentSession.sessionUser.id == 0 || reply.author.id != currentSession.sessionUser.id && (reply.threadCategory.permissions.Find(x => x.rankID == currentSession.sessionUser.ranking.id).actionable & Permission.Action.MODIFY) != Permission.Action.MODIFY) throw new Exceptions.PermissionException("User cannot modify this reply"); @@ -992,6 +1175,40 @@ namespace MessageBoard.Forum aResp.destination = "thread?id=" + reply.threadid; } + else if (querySet.Get("content") != null) + { + if (querySet.Get("content") == null || querySet.Get("title") == null) + throw new Exceptions.ThreadException("Invalid update data"); + + if (querySet.Get("content").Length > Manager.CONTENT_MAXLENGTH) + { + aResp.errorCode = Manager.ErrorCode.THREAD_CONTENTTOOLONG; + } + + else if (querySet.Get("title").Length > Manager.TITLE_MAXLENGTH) + { + aResp.errorCode = Manager.ErrorCode.THREAD_TITLETOOLONG; + } + + else + { + int threadID = Convert.ToInt32(querySet["threadid"]); + //fixsecurity + var fmtr = new DNA.Text.BBCodeFormatter(); + string content = fmtr.Format(Uri.UnescapeDataString(querySet["content"])); + string title = DNA.Text.TextEngine.Text(Uri.UnescapeDataString(querySet["title"])); + + if (reply.updateTitle(title) && reply.updateContent(content)) + { + aResp.errorCode = Plugin.Main.forum.updateReply(reply); + aResp.success = aResp.errorCode == Manager.ErrorCode.NO_ERROR; + aResp.destination = "thread?id=" + threadID; + } + else + aResp.errorCode = Manager.ErrorCode.THREAD_EMPTYDATA; + } + } + } resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(aResp); @@ -1043,15 +1260,14 @@ namespace MessageBoard.Forum if (querySet["content"].Length < Manager.CONTENT_MAXLENGTH && querySet["title"].Length <= Manager.TITLE_MAXLENGTH) { - var markdownParser = new MarkdownDeep.Markdown(); - string markdownContent = markdownParser.Transform(querySet["content"]); - markdownContent = Uri.EscapeDataString(markdownContent); - string title = Uri.EscapeDataString(querySet["title"]); + var fmtr = new DNA.Text.BBCodeFormatter(); + string content = fmtr.Format(Uri.UnescapeDataString(querySet["content"])); + string title = DNA.Text.TextEngine.Text(Uri.UnescapeDataString(querySet["title"])); if (querySet.Get("threadid") != null) { var replyThread = Plugin.Main.forum.getThread(Convert.ToInt32(querySet.Get("threadid"))); - var reply = new Post(title, replyThread.getID(), markdownContent, currentSession.sessionUser); + var reply = new Post(title, replyThread.getID(), content, currentSession.sessionUser); aResp.errorCode = Plugin.Main.forum.addPost(replyThread, reply); aResp.destination = String.Format("thread?id={0}", replyThread.id); @@ -1064,7 +1280,7 @@ namespace MessageBoard.Forum if ((threadCategory.permissions.Find(x => x.rankID == currentSession.sessionUser.ranking.id).actionable & Permission.Action.WRITE) == Permission.Action.WRITE) { - ForumThread newThread = new ForumThread(title, markdownContent, currentSession.sessionUser, threadCategory); + ForumThread newThread = new ForumThread(title, content, currentSession.sessionUser, threadCategory); aResp.errorCode = Plugin.Main.forum.addThread(newThread); aResp.destination = String.Format("category?id={0}", threadCategory.id); @@ -1118,6 +1334,7 @@ namespace MessageBoard.Forum if (s.sessionUser.ranking.id > 0 && (DateTime.Now - s.sessionStartTime).TotalMinutes < 5 && s.sessionUser.username != "Guest") stats.onlineUsers.Add(s.sessionUser); } + stats.onlineUsers.OrderByDescending(x => x.ranking.equivalentRank); resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(stats); return resp; diff --git a/MessageboardPlugin/MessageboardPlugin.csproj b/MessageboardPlugin/MessageboardPlugin.csproj index d1f080f60..decbd7f06 100644 --- a/MessageboardPlugin/MessageboardPlugin.csproj +++ b/MessageboardPlugin/MessageboardPlugin.csproj @@ -37,13 +37,6 @@ - - - {d51eeceb-438a-47da-870f-7d7b41bc24d6} - SharedLibrary - False - - @@ -58,11 +51,15 @@ + + ..\packages\CodeKicker.BBCode.5.0.0.0\lib\net35\CodeKicker.BBCode.dll + True + ..\packages\CryptSharp.1.2.0.1\lib\net35\CryptSharp.dll - - ..\packages\MarkdownDeep.NET.1.5\lib\.NetFramework 3.5\MarkdownDeep.dll + + ..\packages\DNA.Text.2.1.1.10633\lib\DNA.Text.dll True @@ -71,10 +68,16 @@ + + ..\SharedLibrary\bin\Release\System.Data.SQLite.dll + False + + + @@ -99,6 +102,19 @@ PreserveNewest + + PreserveNewest + + + + + + + + {d51eeceb-438a-47da-870f-7d7b41bc24d6} + SharedLibrary + False + @@ -106,8 +122,10 @@ copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)Admin\bin\$(ConfigurationName)\plugins\MessageBoardPlugin.dll" xcopy /E /Y "$(TargetDir)forum" "$(SolutionDir)Admin\bin\$(ConfigurationName)\forum" -copy /Y "$(TargetDir)MarkdownDeep.dll" "$(SolutionDir)Admin\bin\$(ConfigurationName)\lib\MarkdownDeep.dll" +copy /Y "$(TargetDir)DNA.Text.dll" "$(SolutionDir)Admin\bin\$(ConfigurationName)\lib\DNA.Text.dll" copy /Y "$(TargetDir)CryptSharp.dll" "$(SolutionDir)Admin\bin\$(ConfigurationName)\lib\CryptSharp.dll" + +copy /Y "$(TargetDir)CodeKicker.BBcode.dll" "$(SolutionDir)Admin\bin\$(ConfigurationName)\lib\CodeKicker.BBcode.dll" copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)BUILD\plugins\"