diff --git a/ShiftOS.Objects/Save.cs b/ShiftOS.Objects/Save.cs index ddf41ff..a901a92 100644 --- a/ShiftOS.Objects/Save.cs +++ b/ShiftOS.Objects/Save.cs @@ -27,6 +27,10 @@ namespace ShiftOS.Objects private dynamic _settings = new SettingsObject(); + public Guid ID { get; set; } + + public bool IsMUDAdmin { get; set; } + public dynamic Settings { get diff --git a/ShiftOS.Server.WebAdmin/Program.cs b/ShiftOS.Server.WebAdmin/Program.cs index 91e4831..b624ee7 100644 --- a/ShiftOS.Server.WebAdmin/Program.cs +++ b/ShiftOS.Server.WebAdmin/Program.cs @@ -45,6 +45,24 @@ namespace ShiftOS.Server.WebAdmin { templateParams.Add("{logout}", "
  • Log out
  • "); } + if (SystemManager.MudIsRunning()) + { + templateParams.Add("{mud_power}", "
  • Power off
  • "); + templateParams.Add("{mud_restart}", "
  • Restart
  • "); + } + else + { + templateParams.Add("{mud_power}", "
  • Power on
  • "); + templateParams.Add("{mud_restart}", ""); + } + + if(templateParams["{logout}"] == "") + { + templateParams["{mud_power}"] = ""; + templateParams["{mud_restart}"] = ""; + + } + switch (page) { case "status": @@ -97,23 +115,61 @@ namespace ShiftOS.Server.WebAdmin public static class SystemManager { + public static bool MudIsRunning() + { + var processes = System.Diagnostics.Process.GetProcessesByName("ShiftOS.Server"); + return processes.Length > 0; + } + + public static void KillMud() + { + var processes = System.Diagnostics.Process.GetProcessesByName("ShiftOS.Server"); + for(int i = 0; i < processes.Length; i++) + { + try + { + processes[i].Kill(); + } + catch + { + } + } + } + public static List GetClaims(string username) { - foreach (var user in JsonConvert.DeserializeObject>(ShiftOS.Server.Program.ReadEncFile("users.json"))) + foreach(var save in GetSaves()) { - if(user.Username == username) + if (save.IsMUDAdmin) { - return user.Claims; + return new List { "User", "Admin" }; } } return new List(new[] { "User" }); } + public static Save[] GetSaves() + { + List saves = new List(); + if (Directory.Exists("saves")) + { + foreach(var saveFile in Directory.GetFiles("saves")) + { + try + { + saves.Add(JsonConvert.DeserializeObject(Server.Program.ReadEncFile(saveFile))); + } + catch { } + } + } + return saves.ToArray(); + } + public static bool Login(string username, string password, out Guid id) { - foreach (var user in JsonConvert.DeserializeObject>(ShiftOS.Server.Program.ReadEncFile("users.json"))) + foreach (var user in GetSaves()) { - if (user.Username == username && user.Password == Encryption.Encrypt(password)) + if (user.Username == username && user.Password == password) { id = user.ID; return true; @@ -184,6 +240,40 @@ namespace ShiftOS.Server.WebAdmin return new Channel(); } + public static string BuildSaveListing(Save[] list) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine(""); + + sb.AppendLine(@" + + + + + + +"); + + foreach(var save in list) + { + sb.AppendLine($@" + + + + + + +"); + } + + sb.AppendLine("
    UsernameSystem NameCodepointsShiftorium UpgradesIs MUD AdminActions
    {save.Username}{save.SystemName}{save.Codepoints}{save.CountUpgrades()} installed, {save.Upgrades.Count} total{save.IsMUDAdmin} + Toggle admin + Delete save +
    "); + return sb.ToString(); + } + + public static string GetAllChats() { StringBuilder sb = new StringBuilder(); @@ -208,15 +298,40 @@ namespace ShiftOS.Server.WebAdmin {chat.DiscordBotToken} Edit - Delete + Delete "); + sb.AppendLine(CreateModal(chat.ID, "Delete " + chat.Name + "?", "Are you sure you want to delete this chat?", "/deletechat/" + chat.ID)); } } sb.AppendLine(""); return sb.ToString(); } + public static string CreateModal(string id, string title, string msg, string callbackUrl) + { + return $@"
    +
    + + +
    +
    + +

    {title}

    +
    +
    +

    {msg}

    +
    +
    + Yes + +
    +
    + +
    +
    "; + } + public static string GetCPWorth() { if (System.IO.Directory.Exists("saves")) @@ -253,7 +368,7 @@ namespace ShiftOS.Server.WebAdmin public static MudUserIdentity GetIdentity(Guid id) { - foreach (var user in JsonConvert.DeserializeObject>(ShiftOS.Server.Program.ReadEncFile("users.json"))) + foreach (var user in GetSaves()) { if (user.ID == id) { @@ -262,13 +377,50 @@ namespace ShiftOS.Server.WebAdmin } return null; } + + internal static void MakeAdmin(string username) + { + Save sav = null; + foreach(var save in GetSaves()) + { + if (save.Username == username) + sav = save; + } + if(sav != null) + { + sav.IsMUDAdmin = true; + Server.Program.WriteEncFile("saves/" + username + ".save", JsonConvert.SerializeObject(sav)); + } + } + + internal static Save[] GetAdmins() + { + var saves = new List(); + foreach(var save in GetSaves()) + { + if(save.IsMUDAdmin == true) + { + saves.Add(save); + } + } + return saves.ToArray(); + } } public class MudUser { + [FriendlyName("Username")] + [FriendlyDescription("The username you will appear as in-game.")] public string Username { get; set; } + + [FriendlyName("Password")] + [FriendlyDescription("A password that you will use to log in to the admin panel and the game.")] public string Password { get; set; } - public List Claims { get; set; } + + [FriendlyName("System name")] + [FriendlyDescription("An in-game hostname for your account. In ShiftOS, your user ID is always yourusername@yoursystemname. Be creative.")] + public string SystemName { get; set; } + public Guid ID { get; set; } } @@ -299,18 +451,30 @@ namespace ShiftOS.Server.WebAdmin { Get["/login"] = parameters => { - if (System.IO.File.Exists("users.json")) + if (SystemManager.GetSaves().Length > 0) { - return PageBuilder.Build("login", new Dictionary + if (SystemManager.GetAdmins().Length > 0) + { + return PageBuilder.Build("login", new Dictionary { {"{logout}", "" } }); + } + else + { + return PageBuilder.Build("initialsetup", new Dictionary + { + {"{logout}", "" }, + {"{savelist}", BuildSaveList() } + }); + } } else { - return PageBuilder.Build("initialsetup", new Dictionary + return PageBuilder.Build("bla", new Dictionary { - {"{logout}", "" } + {"{body}", Properties.Resources.NoUsersFound }, + {"{user_create_form}", SystemManager.BuildFormFromObject(new MudUser()) } }); } }; @@ -322,54 +486,169 @@ namespace ShiftOS.Server.WebAdmin Post["/login"] = parameters => { - var p = this.Bind(); - Guid id = new Guid(); - if (System.IO.File.Exists("users.json")) + if (SystemManager.GetSaves().Length > 0) { - if (SystemManager.Login(p.username, p.password, out id) == true) + if (SystemManager.GetAdmins().Length == 0) { - return this.Login(id); + var user = this.Bind(); + SystemManager.MakeAdmin(user.username); + Guid id = new Guid(); + if(SystemManager.Login(user.username, user.password, out id) == true) + { + return this.Login(id); + } + return new UserModule().Redirect("/login"); } else { - return PageBuilder.Build("loginFailed", new Dictionary - { - {"{logout}", "" } - }); + var user = this.Bind(); + Guid id = new Guid(); + if (SystemManager.Login(user.username, user.password, out id) == true) + { + return this.Login(id); + } + return new UserModule().Redirect("/login"); } } else { - var mudUser = new MudUser(); - mudUser.Username = p.username; - mudUser.Password = Encryption.Encrypt(p.password); - mudUser.Claims = new List(new[] { "Admin" }); - mudUser.ID = Guid.NewGuid(); - id = mudUser.ID; - List users = new List(new[] { mudUser }); - ShiftOS.Server.Program.WriteEncFile("users.json", JsonConvert.SerializeObject(users, Formatting.Indented)); - return this.Login(id); + var newUser = this.Bind(); + var save = new Save(); + save.Username = newUser.Username; + save.SystemName = newUser.SystemName; + save.Password = newUser.Password; + save.Codepoints = 0; + save.MyShop = ""; + save.Upgrades = new Dictionary(); + save.IsMUDAdmin = true; + save.StoryPosition = 1; + + if (!Directory.Exists("saves")) + Directory.CreateDirectory("saves"); + save.ID = Guid.NewGuid(); + + Server.Program.WriteEncFile("saves/" + save.Username + ".save", JsonConvert.SerializeObject(save)); + return this.Login(save.ID); } }; } + + private string BuildSaveList() + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine(""); + sb.AppendLine($@" + + + + +"); + + foreach(var save in SystemManager.GetSaves()) + { + sb.AppendLine($@" + + + + +"); + } + + sb.AppendLine("
    UsernameSystem nameCodepointsActions
    {save.Username}{save.SystemName}{save.Codepoints}
    + + +
    "); + return sb.ToString(); + } } public class UserModule : NancyModule { + public string Redirect(string url) + { + return $@" + + + +"; + } + public UserModule() { this.RequiresAuthentication(); this.RequiresClaims("Admin"); Get["/"] = _ => { - return statusBuilder(); + return Redirect("/status"); }; + + Get["/toggleadmin/{id}"] = parameters => + { + string id = parameters.id; + for (int i = 0; i < SystemManager.GetSaves().Length; i++) + { + var save = SystemManager.GetSaves()[i]; + if(save.ID.ToString() == id) + { + save.IsMUDAdmin = !save.IsMUDAdmin; + Server.Program.WriteEncFile("saves/" + save.Username + ".save", JsonConvert.SerializeObject(save)); + } + } + return Redirect("/saves"); + + }; + + Get["/deletesave/{username}"] = parameters => + { + + + string id = parameters.username; + for (int i = 0; i < SystemManager.GetSaves().Length; i++) + { + if (SystemManager.GetSaves()[i].Username.ToString() == id) + { + File.Delete("saves/" + SystemManager.GetSaves()[i].Username + ".save"); + } + } + return Redirect("/saves"); + }; + + + Get["/saves"] = _ => + { + return PageBuilder.Build("bla", new Dictionary + { + { "{body}", Properties.Resources.GenericTableList }, + { "{listtitle}", "Test subjects" }, + { "{listdesc}", "Below is a list of test subjects (save files) on your multi-user domain. You can see their username, system name, Codepoints, amount of installed upgrades, and you can also perform basic actions on each save." }, + { "{list}", SystemManager.BuildSaveListing(SystemManager.GetSaves()) } + }); + }; + Get["/status"] = _ => { return statusBuilder(); }; + + Get["/deletechat/{id}"] = parameters => + { + string chatID = parameters.id; + var chats = JsonConvert.DeserializeObject>(File.ReadAllText("chats.json")); + for(int i = 0; i < chats.Count; i++) + { + try + { + if (chats[i].ID == chatID) + chats.RemoveAt(i); + } + catch { } + } + File.WriteAllText("chats.json", JsonConvert.SerializeObject(chats, Formatting.Indented)); + return Redirect("/chats"); + }; + Get["/chats"] = _ => { return chatsListBuilder(); @@ -410,7 +689,7 @@ namespace ShiftOS.Server.WebAdmin File.WriteAllText("chats.json", JsonConvert.SerializeObject(chats, Formatting.Indented)); - return chatsListBuilder(); + return Redirect("/chats"); }; Get["/editchat/{id}"] = parameters => @@ -447,9 +726,34 @@ namespace ShiftOS.Server.WebAdmin } File.WriteAllText("chats.json", JsonConvert.SerializeObject(chats, Formatting.Indented)); - return chatsListBuilder(); + return Redirect("/chats"); }; + Get["/poweron"] = _ => + { + if (!SystemManager.MudIsRunning()) + { + System.Diagnostics.Process.Start("ShiftOS.Server.exe"); + } + return Redirect("/"); + }; + + Get["/poweroff"] = _ => + { + if (SystemManager.MudIsRunning()) + { + SystemManager.KillMud(); + } + return Redirect("/"); + }; + Get["/restart"] = _ => + { + if (SystemManager.MudIsRunning()) + { + SystemManager.KillMud(); + } + return Redirect("/poweron"); + }; } private string statusBuilder() diff --git a/ShiftOS.Server.WebAdmin/Properties/Resources.Designer.cs b/ShiftOS.Server.WebAdmin/Properties/Resources.Designer.cs index a3e1d67..6df3fde 100644 --- a/ShiftOS.Server.WebAdmin/Properties/Resources.Designer.cs +++ b/ShiftOS.Server.WebAdmin/Properties/Resources.Designer.cs @@ -88,6 +88,19 @@ namespace ShiftOS.Server.WebAdmin.Properties { } } + /// + /// Looks up a localized string similar to <h3>{listtitle}</h3> + /// + ///<p>{listdesc}</p> + /// + ///{list}. + /// + internal static string GenericTableList { + get { + return ResourceManager.GetString("GenericTableList", resourceCulture); + } + } + /// /// Looks up a localized string similar to <html> /// <head> @@ -97,7 +110,7 @@ namespace ShiftOS.Server.WebAdmin.Properties { /// <link rel="stylesheet" href="http://getshiftos.ml/css/theme.css"/> /// /// <!-- Latest compiled and minified JavaScript --> - /// <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5I [rest of string was truncated]";. + /// <script src="https://code.jquery.com/jquery-3.1.1.js" integrity="sha256-16cdPddA6VdVInumRGo6IbivbERE8p7C [rest of string was truncated]";. /// internal static string HtmlTemplate { get { @@ -127,17 +140,25 @@ namespace ShiftOS.Server.WebAdmin.Properties { } } + /// + /// Looks up a localized string similar to <h3>No users found.</h3> + /// + ///<p>Your multi-user domain is newly-created. Before you can use the admin panel, you must create a ShiftOS user to act as the administrator of the MUD.</p> + /// + ///{user_create_form}. + /// + internal static string NoUsersFound { + get { + return ResourceManager.GetString("NoUsersFound", resourceCulture); + } + } + /// /// Looks up a localized string similar to <h1>Initial setup</h1> /// - ///<p>Welcome to your multi-user domain. If you are seeing this screen, it means that the web administration panel is successfully running and listening for requests. Before you can start using the admin panel you must create an Admin account. This account will let you log in and manage other authorized users, manage saves, Shiftnet pages and other information.</p> + ///<p>This multi-user domain contains some users, however none of them are administrators. Please choose your user to make it an admin.</p> /// - ///<p>To continue, type a username and password.</p> - /// - ///<form method="post" action=""> - /// <table class="table"> - /// <tr> - /// [rest of string was truncated]";. + ///{savelist}. /// internal static string SetupView { get { diff --git a/ShiftOS.Server.WebAdmin/Properties/Resources.resx b/ShiftOS.Server.WebAdmin/Properties/Resources.resx index 7fa664a..b756946 100644 --- a/ShiftOS.Server.WebAdmin/Properties/Resources.resx +++ b/ShiftOS.Server.WebAdmin/Properties/Resources.resx @@ -124,12 +124,18 @@ ..\Resources\ChatListView.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + ..\Resources\GenericTableList.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + ..\Resources\HtmlTemplate.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 ..\Resources\LoginView.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + + ..\Resources\NoUsersFound.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 + ..\Resources\SetupView.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252 diff --git a/ShiftOS.Server.WebAdmin/Resources/GenericTableList.txt b/ShiftOS.Server.WebAdmin/Resources/GenericTableList.txt new file mode 100644 index 0000000..3cbfd6e --- /dev/null +++ b/ShiftOS.Server.WebAdmin/Resources/GenericTableList.txt @@ -0,0 +1,5 @@ +

    {listtitle}

    + +

    {listdesc}

    + +{list} \ No newline at end of file diff --git a/ShiftOS.Server.WebAdmin/Resources/HtmlTemplate.txt b/ShiftOS.Server.WebAdmin/Resources/HtmlTemplate.txt index cdb6e0d..82893e9 100644 --- a/ShiftOS.Server.WebAdmin/Resources/HtmlTemplate.txt +++ b/ShiftOS.Server.WebAdmin/Resources/HtmlTemplate.txt @@ -6,6 +6,7 @@ + @@ -21,34 +22,36 @@ Test subjects
  • - Shiftnet + Shiftnet (NYI)
  • - Scripts + Scripts (NYI)
  • - Legions + Legions (NYI)
  • Chats
  • - Shops -
  • -
  • - Help + Shops (NYI)
  • -
    +
    {body} + +

    ShiftOS - MUD admin panel - Copyright © 2017 ShiftOS developers

    diff --git a/ShiftOS.Server.WebAdmin/Resources/NoUsersFound.txt b/ShiftOS.Server.WebAdmin/Resources/NoUsersFound.txt new file mode 100644 index 0000000..7524fa5 --- /dev/null +++ b/ShiftOS.Server.WebAdmin/Resources/NoUsersFound.txt @@ -0,0 +1,5 @@ +

    No users found.

    + +

    Your multi-user domain is newly-created. Before you can use the admin panel, you must create a ShiftOS user to act as the administrator of the MUD.

    + +{user_create_form} \ No newline at end of file diff --git a/ShiftOS.Server.WebAdmin/Resources/SetupView.txt b/ShiftOS.Server.WebAdmin/Resources/SetupView.txt index d1226dd..9e83a45 100644 --- a/ShiftOS.Server.WebAdmin/Resources/SetupView.txt +++ b/ShiftOS.Server.WebAdmin/Resources/SetupView.txt @@ -1,22 +1,5 @@

    Initial setup

    -

    Welcome to your multi-user domain. If you are seeing this screen, it means that the web administration panel is successfully running and listening for requests. Before you can start using the admin panel you must create an Admin account. This account will let you log in and manage other authorized users, manage saves, Shiftnet pages and other information.

    +

    This multi-user domain contains some users, however none of them are administrators. Please choose your user to make it an admin.

    -

    To continue, type a username and password.

    - -
    - - - - - - - - - - - - - -
    Username:
    Password:
    -
    \ No newline at end of file +{savelist} \ No newline at end of file diff --git a/ShiftOS.Server.WebAdmin/ShiftOS.Server.WebAdmin.csproj b/ShiftOS.Server.WebAdmin/ShiftOS.Server.WebAdmin.csproj index 3eaca2f..faec295 100644 --- a/ShiftOS.Server.WebAdmin/ShiftOS.Server.WebAdmin.csproj +++ b/ShiftOS.Server.WebAdmin/ShiftOS.Server.WebAdmin.csproj @@ -109,6 +109,12 @@ + + + + + +