Merge branch 'master' of https://github.com/shiftos-game/ShiftOS
This commit is contained in:
commit
b20d77edd1
21 changed files with 1346 additions and 142 deletions
|
@ -68,6 +68,7 @@ namespace ShiftOS.Objects
|
|||
}
|
||||
|
||||
public int LastMonthPaid { get; set; }
|
||||
public List<string> StoriesExperienced { get; set; }
|
||||
|
||||
public int CountUpgrades()
|
||||
{
|
||||
|
|
|
@ -291,10 +291,13 @@ namespace ShiftOS.Objects.ShiftFS
|
|||
{
|
||||
string[] pathlist = path.Split('/');
|
||||
int vol = Convert.ToInt32(pathlist[0].Replace(":", ""));
|
||||
if (Mounts[vol] == null)
|
||||
Mounts[vol] = new Directory();
|
||||
var dir = Mounts[vol];
|
||||
|
||||
for (int i = 1; i <= pathlist.Length - 1; i++)
|
||||
{
|
||||
dir = dir.FindDirectoryByName(pathlist[i]);
|
||||
dir = dir?.FindDirectoryByName(pathlist[i]);
|
||||
}
|
||||
return dir != null;
|
||||
|
||||
|
|
|
@ -125,5 +125,91 @@ namespace ShiftOS.Server
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
[MudRequest("getusers", typeof(string))]
|
||||
public static void GetAllUsers(string guid, string contents)
|
||||
{
|
||||
List<string> accs = new List<string>();
|
||||
if(contents == "dead")
|
||||
{
|
||||
foreach(var sve in Directory.GetFiles("deadsaves"))
|
||||
{
|
||||
if (sve.EndsWith(".save"))
|
||||
{
|
||||
var save = JsonConvert.DeserializeObject<Save>(File.ReadAllText(sve));
|
||||
accs.Add($"{save.Username}@{save.SystemName}");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
server.DispatchTo(new Guid(guid), new NetObject("h4xx0r", new ServerMessage
|
||||
{
|
||||
Name = "allusers",
|
||||
GUID = "server",
|
||||
Contents = JsonConvert.SerializeObject(accs)
|
||||
}));
|
||||
}
|
||||
|
||||
[MudRequest("mud_save_allow_dead", typeof(Save))]
|
||||
public static void SaveDead(string guid, Save sve)
|
||||
{
|
||||
if(File.Exists("saves/" + sve.Username + ".save"))
|
||||
{
|
||||
WriteEncFile("saves/" + sve.Username + ".save", JsonConvert.SerializeObject(sve));
|
||||
}
|
||||
else if(File.Exists("deadsaves/" + sve.Username + ".save"))
|
||||
{
|
||||
File.WriteAllText("deadsaves/" + sve.Username + ".save", JsonConvert.SerializeObject(sve));
|
||||
}
|
||||
}
|
||||
|
||||
[MudRequest("get_user_data", typeof(Dictionary<string, string>))]
|
||||
public static void GetUserData(string guid, Dictionary<string, string> contents)
|
||||
{
|
||||
string usr = contents["user"];
|
||||
string sys = contents["sysname"];
|
||||
|
||||
foreach(var sve in Directory.GetFiles("deadsaves"))
|
||||
{
|
||||
if (sve.EndsWith(".save"))
|
||||
{
|
||||
var saveFile = JsonConvert.DeserializeObject<Save>(File.ReadAllText(sve));
|
||||
if(saveFile.Username == usr && saveFile.SystemName == sys)
|
||||
{
|
||||
server.DispatchTo(new Guid(guid), new NetObject("1337", new ServerMessage
|
||||
{
|
||||
Name = "user_data",
|
||||
GUID = "server",
|
||||
Contents = JsonConvert.SerializeObject(saveFile)
|
||||
}));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
foreach (var sve in Directory.GetFiles("saves"))
|
||||
{
|
||||
if (sve.EndsWith(".save"))
|
||||
{
|
||||
var saveFile = JsonConvert.DeserializeObject<Save>(ReadEncFile(sve));
|
||||
if (saveFile.Username == usr && saveFile.SystemName == sys)
|
||||
{
|
||||
server.DispatchTo(new Guid(guid), new NetObject("1337", new ServerMessage
|
||||
{
|
||||
Name = "user_data",
|
||||
GUID = "server",
|
||||
Contents = JsonConvert.SerializeObject(saveFile)
|
||||
}));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
server.DispatchTo(new Guid(guid), new NetObject("n07_50_1337", new ServerMessage
|
||||
{
|
||||
Name = "user_data_not_found",
|
||||
GUID = "server"
|
||||
}));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,6 +123,27 @@ namespace ShiftOS.Server
|
|||
Console.WriteLine("Client connected.");
|
||||
server.DispatchTo(a.Guid, new NetObject("welcome", new ServerMessage { Name = "Welcome", Contents = a.Guid.ToString(), GUID = "Server" }));
|
||||
};
|
||||
|
||||
server.OnClientDisconnected += (o, a) =>
|
||||
{
|
||||
Console.WriteLine("Client disconnected.");
|
||||
};
|
||||
|
||||
server.OnClientRejected += (o, a) =>
|
||||
{
|
||||
Console.WriteLine("FUCK. Something HORRIBLE JUST HAPPENED.");
|
||||
};
|
||||
|
||||
AppDomain.CurrentDomain.UnhandledException += (o, a) =>
|
||||
{
|
||||
ChatBackend.Broadcast("**Automatic Broadcast:** The multi-user domain is restarting because of a crash.");
|
||||
#if DEBUG
|
||||
ChatBackend.Broadcast("Crash summary: " + a.ExceptionObject.ToString());
|
||||
#endif
|
||||
if(server.IsOnline == true)
|
||||
server.Stop();
|
||||
System.Diagnostics.Process.Start("ShiftOS.Server.exe");
|
||||
};
|
||||
|
||||
server.OnReceived += (o, a) =>
|
||||
{
|
||||
|
|
|
@ -114,11 +114,12 @@ namespace ShiftOS.Server
|
|||
sve.Codepoints = rnd.Next(startCP, maxAmt);
|
||||
|
||||
//FS treasure generation.
|
||||
|
||||
/*
|
||||
//create a ramdisk dir
|
||||
var dir = new ShiftOS.Objects.ShiftFS.Directory();
|
||||
//name the directory after the user
|
||||
dir.Name = sve.Username;
|
||||
dir.permissions = Objects.ShiftFS.Permissions.All;
|
||||
//json the object and mount
|
||||
string json = Newtonsoft.Json.JsonConvert.SerializeObject(dir);
|
||||
//mount it to the MUD
|
||||
|
@ -180,16 +181,19 @@ namespace ShiftOS.Server
|
|||
WriteAllBytes(kv.Value, File.ReadAllBytes(file));
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
//save the save file to disk.
|
||||
File.WriteAllText("deadsaves/" + sve.Username + ".save", Newtonsoft.Json.JsonConvert.SerializeObject(sve, Newtonsoft.Json.Formatting.Indented));
|
||||
//We don't care about the encryption algorithm because these saves can't be logged into as regular users.
|
||||
|
||||
/*
|
||||
//Now we export the mount.
|
||||
string exportedMount = ExportMount(mountid);
|
||||
//And save it to disk.
|
||||
File.WriteAllText("deadsaves/" + sve.Username + ".mfs", exportedMount);
|
||||
*/
|
||||
|
||||
|
||||
Thread.Sleep((60 * 60) * 1000); //approx. 1 hour.
|
||||
|
||||
|
@ -214,12 +218,18 @@ namespace ShiftOS.Server
|
|||
targets = new Dictionary<string, string>();
|
||||
foreach(var dir in dirs)
|
||||
{
|
||||
string sDir = dir.Replace("\\", "/");
|
||||
while (!sDir.StartsWith("shiftnet/"))
|
||||
if (!string.IsNullOrWhiteSpace(dir))
|
||||
{
|
||||
sDir = sDir.Remove(0, 1);
|
||||
string sDir = dir.Replace("\\", "/");
|
||||
if (sDir.Contains("shiftnet"))
|
||||
{
|
||||
while (!sDir.StartsWith("shiftnet"))
|
||||
{
|
||||
sDir = sDir.Remove(0, 1);
|
||||
}
|
||||
targets.Add(dir, output + "/" + sDir);
|
||||
}
|
||||
}
|
||||
targets.Add(dir, output + "/" + sDir);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
57
ShiftOS.WinForms/Applications/TutorialBox.Designer.cs
generated
Normal file
57
ShiftOS.WinForms/Applications/TutorialBox.Designer.cs
generated
Normal file
|
@ -0,0 +1,57 @@
|
|||
namespace ShiftOS.WinForms.Applications
|
||||
{
|
||||
partial class TutorialBox
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.lbltuttext = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// lbltuttext
|
||||
//
|
||||
this.lbltuttext.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.lbltuttext.Location = new System.Drawing.Point(0, 0);
|
||||
this.lbltuttext.Name = "lbltuttext";
|
||||
this.lbltuttext.Size = new System.Drawing.Size(401, 134);
|
||||
this.lbltuttext.TabIndex = 0;
|
||||
//
|
||||
// TutorialBox
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.lbltuttext);
|
||||
this.Name = "TutorialBox";
|
||||
this.Size = new System.Drawing.Size(401, 134);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Label lbltuttext;
|
||||
}
|
||||
}
|
73
ShiftOS.WinForms/Applications/TutorialBox.cs
Normal file
73
ShiftOS.WinForms/Applications/TutorialBox.cs
Normal file
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using ShiftOS.Engine;
|
||||
using System.Threading;
|
||||
|
||||
namespace ShiftOS.WinForms.Applications
|
||||
{
|
||||
|
||||
[DefaultTitle("Tutorial objective")]
|
||||
public partial class TutorialBox : UserControl, IShiftOSWindow
|
||||
{
|
||||
public TutorialBox()
|
||||
{
|
||||
InitializeComponent();
|
||||
IsComplete = false;
|
||||
lbltuttext.Text = "";
|
||||
}
|
||||
|
||||
bool stillTyping = false;
|
||||
|
||||
public void SetObjective(string text)
|
||||
{
|
||||
while (stillTyping == true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
new Thread(() =>
|
||||
{
|
||||
stillTyping = true;
|
||||
this.Invoke(new Action(() =>
|
||||
{
|
||||
lbltuttext.Text = "";
|
||||
}));
|
||||
foreach(var c in text.ToCharArray())
|
||||
{
|
||||
this.Invoke(new Action(() =>
|
||||
{
|
||||
lbltuttext.Text += c;
|
||||
}));
|
||||
Thread.Sleep(75);
|
||||
}
|
||||
stillTyping = false;
|
||||
}).Start();
|
||||
}
|
||||
|
||||
public void OnLoad()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnSkinLoad()
|
||||
{
|
||||
}
|
||||
|
||||
public bool IsComplete { get; set; }
|
||||
|
||||
public bool OnUnload()
|
||||
{
|
||||
return IsComplete;
|
||||
}
|
||||
|
||||
public void OnUpgrade()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
120
ShiftOS.WinForms/Applications/TutorialBox.resx
Normal file
120
ShiftOS.WinForms/Applications/TutorialBox.resx
Normal file
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
|
@ -52,12 +52,14 @@ namespace ShiftOS.WinForms.Controls
|
|||
|
||||
public void Write(string text)
|
||||
{
|
||||
this.Text += Localization.Parse(text);
|
||||
this.HideSelection = true;
|
||||
this.AppendText(Localization.Parse(text));
|
||||
this.HideSelection = false;
|
||||
}
|
||||
|
||||
public void WriteLine(string text)
|
||||
{
|
||||
this.Text += Localization.Parse(text) + Environment.NewLine;
|
||||
this.AppendText(Localization.Parse(text) + Environment.NewLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
608
ShiftOS.WinForms/HackerCommands.cs
Normal file
608
ShiftOS.WinForms/HackerCommands.cs
Normal file
|
@ -0,0 +1,608 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using ShiftOS.Engine;
|
||||
using ShiftOS.Objects;
|
||||
using ShiftOS.WinForms.Applications;
|
||||
using static ShiftOS.Objects.ShiftFS.Utils;
|
||||
|
||||
namespace ShiftOS.WinForms
|
||||
{
|
||||
[Namespace("puppy")]
|
||||
[RequiresUpgrade("hacker101_deadaccts")]
|
||||
[KernelMode]
|
||||
public static class KernelPuppyCommands
|
||||
{
|
||||
[Command("clear", true)]
|
||||
public static bool ClearLogs()
|
||||
{
|
||||
WriteAllText("0:/system/data/kernel.log", "");
|
||||
Console.WriteLine("<watchdog> logs cleared successfully.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[Namespace("krnl")]
|
||||
public static class KernelCommands
|
||||
{
|
||||
[Command("control", true)]
|
||||
[RequiresArgument("pass")]
|
||||
public static bool Control(Dictionary<string, object> args)
|
||||
{
|
||||
if(args["pass"].ToString() == ServerManager.thisGuid.ToString())
|
||||
{
|
||||
KernelWatchdog.Log("warn", "User has breached the kernel.");
|
||||
KernelWatchdog.EnterKernelMode();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("lock_session")]
|
||||
[KernelMode]
|
||||
public static bool LeaveControl()
|
||||
{
|
||||
KernelWatchdog.Log("inf", "User has left the kernel-mode session.");
|
||||
KernelWatchdog.LeaveKernelMode();
|
||||
KernelWatchdog.MudConnected = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[Namespace("hacker101")]
|
||||
[RequiresUpgrade("hacker101_deadaccts")]
|
||||
public static class HackerCommands
|
||||
{
|
||||
private static void writeSlow(string text)
|
||||
{
|
||||
Console.Write("[hacker101@undisclosed]: ");
|
||||
Thread.Sleep(200);
|
||||
Console.WriteLine(text);
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
[Story("hacker101_deadaccts")]
|
||||
public static void DeadAccountsStory()
|
||||
{
|
||||
if (!terminalIsOpen())
|
||||
{
|
||||
AppearanceManager.SetupWindow(new Terminal());
|
||||
}
|
||||
|
||||
var t = new Thread(() =>
|
||||
{
|
||||
Console.WriteLine("[sys@mud]: Warning: User connecting to system...");
|
||||
Thread.Sleep(75);
|
||||
Console.WriteLine("[sys@mud]: UBROADCAST: Username: hacker101 - Sysname: undisclosed");
|
||||
Thread.Sleep(50);
|
||||
Console.Write("--locking mud connection resources...");
|
||||
Thread.Sleep(50);
|
||||
Console.WriteLine("...done.");
|
||||
Console.Write("--locking user input... ");
|
||||
Thread.Sleep(75);
|
||||
TerminalBackend.PrefixEnabled = false;
|
||||
TerminalBackend.InStory = true;
|
||||
Console.WriteLine("...done.");
|
||||
|
||||
Thread.Sleep(2000);
|
||||
writeSlow($"Hello there, fellow multi-user domain user.");
|
||||
writeSlow("My name, as you can tell, is hacker101.");
|
||||
writeSlow("And yours must be... don't say it... it's " + SaveSystem.CurrentSave.Username + "@" + SaveSystem.CurrentSave.SystemName + ", right?");
|
||||
writeSlow("Of course it is.");
|
||||
writeSlow("And I bet you 10,000 Codepoints that you have... " + SaveSystem.CurrentSave.Codepoints.ToString() + " Codepoints.");
|
||||
writeSlow("Oh, and how much upgrades have you installed since you first started using ShiftOS?");
|
||||
writeSlow("That would be... uhh... " + SaveSystem.CurrentSave.CountUpgrades().ToString() + ".");
|
||||
writeSlow("I'm probably freaking you out right now. You are probably thinking that you're unsafe and need to lock yourself down.");
|
||||
writeSlow("But, don't worry, I mean no harm.");
|
||||
writeSlow("In fact, I am a multi-user domain safety activist and security professional.");
|
||||
writeSlow("I need your help with something.");
|
||||
writeSlow("Inside the multi-user domain, every now and then these 'dead' user accounts pop up.");
|
||||
writeSlow("They're infesting everything. They're in every legion, they infest chatrooms, and they take up precious hard drive space.");
|
||||
writeSlow("Eventually there's going to be tons of them just sitting there taking over the MUD. We can't have that.");
|
||||
writeSlow("It sounds like a conspiracy theory indeed, but it's true, in fact, these dead accounts hold some valuable treasures.");
|
||||
writeSlow("I'm talking Codepoints, skins, documents, the possibilities are endless.");
|
||||
writeSlow("I'm going to execute a quick sys-script that will show you how you can help get rid of these accounts, and also gain some valuable resources to help you on your digital frontier.");
|
||||
writeSlow("This script will also show you the fundamentals of security exploitation and theft of resources - which if you want to survive in the multi-user domain is paramount.");
|
||||
writeSlow("Good luck.");
|
||||
Thread.Sleep(1000);
|
||||
Console.WriteLine("--user disconnected");
|
||||
Thread.Sleep(75);
|
||||
Console.WriteLine("--commands unlocked - check sos.help.");
|
||||
Thread.Sleep(45);
|
||||
SaveSystem.SaveGame();
|
||||
Console.Write("--unlocking user input...");
|
||||
Thread.Sleep(75);
|
||||
Console.Write(" ..done");
|
||||
TerminalBackend.InStory = false;
|
||||
TerminalBackend.PrefixEnabled = true;
|
||||
Console.Write($"{SaveSystem.CurrentSave.Username}@{SaveSystem.CurrentSave.SystemName}:~$ ");
|
||||
StartHackerTutorial();
|
||||
});
|
||||
t.IsBackground = true;
|
||||
t.Start();
|
||||
}
|
||||
|
||||
internal static void StartHackerTutorial()
|
||||
{
|
||||
Desktop.InvokeOnWorkerThread(() =>
|
||||
{
|
||||
var tut = new TutorialBox();
|
||||
AppearanceManager.SetupWindow(tut);
|
||||
|
||||
new Thread(() =>
|
||||
{
|
||||
|
||||
|
||||
int tutPos = 0;
|
||||
Action ondec = () =>
|
||||
{
|
||||
if (tutPos == 2)
|
||||
tutPos++;
|
||||
};
|
||||
TerminalBackend.CommandProcessed += (o, a) =>
|
||||
{
|
||||
switch (tutPos)
|
||||
{
|
||||
|
||||
case 0:
|
||||
case 10:
|
||||
if (o.ToLower().StartsWith("mud.disconnect"))
|
||||
{
|
||||
tutPos++;
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
if (o.ToLower().StartsWith("krnl.lock_session"))
|
||||
tutPos++;
|
||||
break;
|
||||
case 1:
|
||||
if (o.ToLower().StartsWith("hacker101.brute_decrypt"))
|
||||
{
|
||||
if (a.Contains("0:/system/data/kernel.log"))
|
||||
{
|
||||
tutPos++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (o.ToLower().StartsWith("krnl.control"))
|
||||
{
|
||||
tutPos++;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if (o.ToLower().StartsWith("puppy.clear"))
|
||||
tutPos++;
|
||||
break;
|
||||
case 5:
|
||||
if (o.ToLower().StartsWith("mud.reconnect"))
|
||||
tutPos++;
|
||||
break;
|
||||
case 6:
|
||||
if (o.ToLower().StartsWith("mud.sendmsg"))
|
||||
{
|
||||
var msg = JsonConvert.DeserializeObject<dynamic>(a);
|
||||
try
|
||||
{
|
||||
if (msg.header == "getusers" && msg.body == "dead")
|
||||
tutPos++;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if (o.ToLower().StartsWith("hacker101.breach_user_password"))
|
||||
tutPos++;
|
||||
break;
|
||||
case 8:
|
||||
if (o.ToLower().StartsWith("hacker101.print_user_info"))
|
||||
tutPos++;
|
||||
break;
|
||||
case 9:
|
||||
if (o.ToLower().StartsWith("hacker101.steal_codepoints"))
|
||||
tutPos++;
|
||||
break;
|
||||
}
|
||||
};
|
||||
tut.SetObjective("Welcome to the dead account exploitation tutorial. In this tutorial you will learn the basics of hacking within the multi-user domain.");
|
||||
Thread.Sleep(1000);
|
||||
tut.SetObjective("We will start with a simple system exploit - gaining kernel-level access to ShiftOS. This can help you perform actions not ever possible in the user level.");
|
||||
Thread.Sleep(1000);
|
||||
tut.SetObjective("To gain root access, you will first need to breach the system watchdog to keep it from dialing home to DevX.");
|
||||
Thread.Sleep(1000);
|
||||
tut.SetObjective("The watchdog can only function when it has a successful connection to the multi-user domain. You will need to use the MUD Control Centre to disconnect yourself from the MUD. This will lock you out of most features. To disconnect from the multi-user domain, simply run the 'mud.disconnect' command.");
|
||||
while(tutPos == 0)
|
||||
{
|
||||
|
||||
}
|
||||
tut.SetObjective("As you can see, the kernel watchdog has shut down temporarily, however before the disconnect it was able to tell DevX that it has gone offline.");
|
||||
Thread.Sleep(1000);
|
||||
tut.SetObjective("You'll also notice that commands like the shiftorium, MUD control centre and various applications that utilize these system components no longer function.");
|
||||
Thread.Sleep(1000);
|
||||
tut.SetObjective("The watchdog, however, is still watching. DevX was smart and programmed the kernel to log all events to a local file in 0:/system/data/kernel.log.");
|
||||
Thread.Sleep(1000);
|
||||
tut.SetObjective("You will need to empty out this file before you can connect to the multi-user domain, as the watchdog will send the contents of this file straight to DevX.");
|
||||
Thread.Sleep(1000);
|
||||
tut.SetObjective("Or, you can do what we're about to do and attempt to decrypt the log and sniff out the kernel-mode access password.");
|
||||
Thread.Sleep(1000);
|
||||
tut.SetObjective("This will allow us to gain kernel-level access to our system using the krnl.control{pass:} command.");
|
||||
Thread.Sleep(1000);
|
||||
tut.SetObjective("Let's start decrypting the log file using the hacker101.brute_decrypt{file:} script. The file: argument is a string and should point to a .log file. When the script succeeds, you will see a TextPad open with the decrypted contents.");
|
||||
while(tutPos == 1)
|
||||
{
|
||||
|
||||
}
|
||||
onCompleteDecrypt += ondec;
|
||||
tut.SetObjective("This script isn't the most agile script ever, but it'll get the job done.");
|
||||
while(tutPos == 2)
|
||||
{
|
||||
|
||||
}
|
||||
onCompleteDecrypt -= ondec;
|
||||
tut.SetObjective("Alright - it's done. Here's how it's laid out. In each log entry, you have the timestamp, then the event name, then the event description.");
|
||||
Thread.Sleep(1000);
|
||||
tut.SetObjective("Look for the most recent 'mudhandshake' event. This contains the kernel access code.");
|
||||
Thread.Sleep(1000);
|
||||
tut.SetObjective("Once you have it, run 'krnl.control{pass:\"the-kernel-code-here\"}. This will allow you to gain access to the kernel.");
|
||||
while(tutPos == 3)
|
||||
{
|
||||
|
||||
}
|
||||
tut.SetObjective("You are now in kernel mode. Every command you enter will run on the kernel. Now, let's clear the watchdog's logfile and reconnect to the multi-user domain.");
|
||||
Thread.Sleep(1000);
|
||||
tut.SetObjective("To clear the log, simply run 'puppy.clear'.");
|
||||
while(tutPos == 4)
|
||||
{
|
||||
|
||||
}
|
||||
tut.SetObjective("Who's a good dog... You are, ShiftOS. Now, we can connect back to the MUD using 'mud.reconnect'.");
|
||||
Thread.Sleep(1000);
|
||||
while(tutPos == 5)
|
||||
{
|
||||
|
||||
}
|
||||
tut.SetObjective("We have now snuck by the watchdog and DevX has no idea. With kernel-level access, everything you do is not logged, however if you perform too much in one shot, you'll get kicked off and locked out of the multi-user domain temporarily.");
|
||||
Thread.Sleep(1000);
|
||||
tut.SetObjective("So, let's focus on the job. You want to get into one of those fancy dead accounts, don't ya? Well, first, we need to talk with the MUD to get a list of these accounts.");
|
||||
Thread.Sleep(1000);
|
||||
tut.SetObjective("Simply run the `mud.sendmsg` command, specifying a 'header' of \"getusers\", and a body of \"dead\".");
|
||||
while(tutPos == 6)
|
||||
{
|
||||
|
||||
}
|
||||
tut.SetObjective("Great. We now have the usernames and sysnames of all dead accounts on the MUD. Now let's use the hacker101.breach_user_password{user:,sys:} command to breach one of these accounts' passwords.");
|
||||
while(tutPos == 7)
|
||||
{
|
||||
|
||||
}
|
||||
tut.SetObjective("There - you now have access to that account. Use its password, username and sysname and run the hacker101.print_user_info{user:,pass:,sys:} command to print the entirety of this user's information.");
|
||||
while(tutPos == 8)
|
||||
{
|
||||
|
||||
}
|
||||
tut.SetObjective("Now you can see a list of the user's Codepoints among other things. Now you can steal their codepoints by using the hacker101.steal_codepoints{user:,pass:,sys;,amount:} command. Be careful. This may alert DevX.");
|
||||
while(tutPos == 9)
|
||||
{
|
||||
|
||||
}
|
||||
if(devx_alerted == true)
|
||||
{
|
||||
tut.SetObjective("Alright... enough fun and games. DevX just found out we were doing this.");
|
||||
Thread.Sleep(500);
|
||||
tut.SetObjective("Quick! Disconnect from the MUD!!");
|
||||
while(tutPos == 10)
|
||||
{
|
||||
|
||||
}
|
||||
tut.SetObjective("Now, get out of kernel mode! To do that, run krnl.lock_session.");
|
||||
while(tutPos == 11)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
tut.SetObjective("OK, that was risky, but we pulled it off. Treat yourself! But first, let's get you out of kernel mode.");
|
||||
Thread.Sleep(500);
|
||||
tut.SetObjective("First we need to get you off the MUD. Simply run mud.disconnect again.");
|
||||
while (tutPos == 10)
|
||||
{
|
||||
|
||||
}
|
||||
tut.SetObjective("Now, let's run krnl.lock_session. This will lock you back into the user mode, and reconnect you to the MUD.");
|
||||
while (tutPos == 11)
|
||||
{
|
||||
|
||||
}
|
||||
tut.SetObjective("If, for some reason, DevX DOES find out, you have to be QUICK to get off of kernel mode. You don't want to make him mad.");
|
||||
}
|
||||
|
||||
Thread.Sleep(1000);
|
||||
tut.SetObjective("So that's all for now. Whenever you're in kernel mode again, and you have access to a user account, try breaching their filesystem next time. You can use sos.help{ns:} to show commands from a specific namespace to help you find more commands easily.");
|
||||
Thread.Sleep(1000);
|
||||
tut.SetObjective("You can now close this window.");
|
||||
tut.IsComplete = true;
|
||||
|
||||
}).Start();
|
||||
});
|
||||
}
|
||||
|
||||
private static bool devx_alerted = false;
|
||||
|
||||
private static event Action onCompleteDecrypt;
|
||||
|
||||
private static bool terminalIsOpen()
|
||||
{
|
||||
foreach(var win in AppearanceManager.OpenForms)
|
||||
{
|
||||
if (win.ParentWindow is Terminal)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-_";
|
||||
|
||||
[Command("breach_user_password")]
|
||||
[KernelMode]
|
||||
[RequiresArgument("user")]
|
||||
[RequiresArgument("sys")]
|
||||
[RequiresUpgrade("hacker101_deadaccts")]
|
||||
public static bool BreachUserPassword(Dictionary<string, object> args)
|
||||
{
|
||||
string usr = args["user"].ToString();
|
||||
string sys = args["sys"].ToString();
|
||||
|
||||
ServerMessageReceived msgReceived = null;
|
||||
|
||||
Console.WriteLine("--hooking system thread...");
|
||||
|
||||
msgReceived = (msg) =>
|
||||
{
|
||||
if(msg.Name == "user_data")
|
||||
{
|
||||
var sve = JsonConvert.DeserializeObject<Save>(msg.Contents);
|
||||
var rnd = new Random();
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
string pass = "";
|
||||
for(int i = 0; i < sve.Password.Length; i++)
|
||||
{
|
||||
char c = '\0';
|
||||
while (c != sve.Password[i])
|
||||
c = chars[rnd.Next(0, chars.Length)];
|
||||
pass += c;
|
||||
Thread.Sleep(rnd.Next(25,75));
|
||||
}
|
||||
sw.Stop();
|
||||
Console.WriteLine(pass);
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("--password breached. Operation took " + sw.ElapsedMilliseconds + " milliseconds.");
|
||||
ServerManager.MessageReceived -= msgReceived;
|
||||
}
|
||||
else if(msg.Name == "user_data_not_found")
|
||||
{
|
||||
Console.WriteLine("--access denied.");
|
||||
ServerManager.MessageReceived -= msgReceived;
|
||||
}
|
||||
};
|
||||
|
||||
Console.WriteLine("--beginning brute-force attack on " + usr + "@" + sys + "...");
|
||||
Thread.Sleep(500);
|
||||
ServerManager.MessageReceived += msgReceived;
|
||||
|
||||
ServerManager.SendMessage("get_user_data", JsonConvert.SerializeObject(new
|
||||
{
|
||||
user = usr,
|
||||
sysname = sys
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("print_user_info")]
|
||||
[KernelMode]
|
||||
[RequiresArgument("pass")]
|
||||
[RequiresArgument("user")]
|
||||
[RequiresArgument("sys")]
|
||||
[RequiresUpgrade("hacker101_deadaccts")]
|
||||
public static bool PrintUserInfo(Dictionary<string, object> args)
|
||||
{
|
||||
string usr = args["user"].ToString();
|
||||
string sys = args["sys"].ToString();
|
||||
string pass = args["pass"].ToString();
|
||||
|
||||
ServerMessageReceived msgReceived = null;
|
||||
|
||||
Console.WriteLine("--hooking multi-user domain response call...");
|
||||
|
||||
msgReceived = (msg) =>
|
||||
{
|
||||
if (msg.Name == "user_data")
|
||||
{
|
||||
var sve = JsonConvert.DeserializeObject<Save>(msg.Contents);
|
||||
if(sve.Password == pass)
|
||||
{
|
||||
Console.WriteLine("Username: " + sve.Username);
|
||||
Console.WriteLine("Password: " + sve.Password);
|
||||
Console.WriteLine("System name: " + sve.SystemName);
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Codepoints: " + sve.Codepoints.ToString());
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("--access denied.");
|
||||
}
|
||||
ServerManager.MessageReceived -= msgReceived;
|
||||
|
||||
}
|
||||
else if (msg.Name == "user_data_not_found")
|
||||
{
|
||||
Console.WriteLine("--access denied.");
|
||||
ServerManager.MessageReceived -= msgReceived;
|
||||
}
|
||||
};
|
||||
|
||||
Console.WriteLine("--contacting multi-user domain...");
|
||||
Thread.Sleep(500);
|
||||
ServerManager.MessageReceived += msgReceived;
|
||||
|
||||
ServerManager.SendMessage("get_user_data", JsonConvert.SerializeObject(new
|
||||
{
|
||||
user = usr,
|
||||
sysname = sys
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("steal_codepoints")]
|
||||
[KernelMode]
|
||||
[RequiresArgument("amount")]
|
||||
[RequiresArgument("pass")]
|
||||
[RequiresArgument("user")]
|
||||
[RequiresArgument("sys")]
|
||||
[RequiresUpgrade("hacker101_deadaccts")]
|
||||
public static bool StealCodepoints(Dictionary<string, object> args)
|
||||
{
|
||||
string usr = args["user"].ToString();
|
||||
string sys = args["sys"].ToString();
|
||||
string pass = args["pass"].ToString();
|
||||
long amount = (long)args["amount"];
|
||||
|
||||
if(amount < 0)
|
||||
{
|
||||
Console.WriteLine("--invalid codepoint amount - halting...");
|
||||
return true;
|
||||
}
|
||||
|
||||
ServerMessageReceived msgReceived = null;
|
||||
|
||||
Console.WriteLine("--hooking multi-user domain response call...");
|
||||
|
||||
msgReceived = (msg) =>
|
||||
{
|
||||
if (msg.Name == "user_data")
|
||||
{
|
||||
var sve = JsonConvert.DeserializeObject<Save>(msg.Contents);
|
||||
if (sve.Password == pass)
|
||||
{
|
||||
if(amount > sve.Codepoints)
|
||||
{
|
||||
Console.WriteLine("--can't steal this many codepoints from user.");
|
||||
return;
|
||||
}
|
||||
|
||||
sve.Codepoints -= amount;
|
||||
SaveSystem.TransferCodepointsFrom(sve.Username, amount);
|
||||
ServerManager.SendMessage("mud_save_allow_dead", JsonConvert.SerializeObject(sve));
|
||||
SaveSystem.SaveGame();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("--access denied.");
|
||||
}
|
||||
|
||||
ServerManager.MessageReceived -= msgReceived;
|
||||
}
|
||||
else if (msg.Name == "user_data_not_found")
|
||||
{
|
||||
Console.WriteLine("--access denied.");
|
||||
ServerManager.MessageReceived -= msgReceived;
|
||||
}
|
||||
};
|
||||
|
||||
Console.WriteLine("--contacting multi-user domain...");
|
||||
Thread.Sleep(500);
|
||||
ServerManager.MessageReceived += msgReceived;
|
||||
|
||||
ServerManager.SendMessage("get_user_data", JsonConvert.SerializeObject(new
|
||||
{
|
||||
user = usr,
|
||||
sysname = sys
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Command("brute_decrypt", true)]
|
||||
[RequiresArgument("file")]
|
||||
public static bool BruteDecrypt(Dictionary<string, object> args)
|
||||
{
|
||||
if (FileExists(args["file"].ToString()))
|
||||
{
|
||||
string pass = new Random().Next(1000, 10000).ToString();
|
||||
string fake = "";
|
||||
Console.WriteLine("Beginning brute-force attack on password.");
|
||||
var s = new Stopwatch();
|
||||
s.Start();
|
||||
for(int i = 0; i < pass.Length; i++)
|
||||
{
|
||||
for(int num = 0; num < 10; num++)
|
||||
{
|
||||
if(pass[i].ToString() == num.ToString())
|
||||
{
|
||||
fake += num.ToString();
|
||||
Console.Write(num);
|
||||
}
|
||||
}
|
||||
}
|
||||
s.Stop();
|
||||
|
||||
Console.WriteLine("...password cracked - operation took " + s.ElapsedMilliseconds + " milliseconds.");
|
||||
var tp = new TextPad();
|
||||
AppearanceManager.SetupWindow(tp);
|
||||
WriteAllText("0:/temp.txt", ReadAllText(args["file"].ToString()));
|
||||
tp.LoadFile("0:/temp.txt");
|
||||
Delete("0:/temp.txt");
|
||||
onCompleteDecrypt?.Invoke();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("brute_decrypt: file not found");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[Namespace("storydev")]
|
||||
public static class StoryDevCommands
|
||||
{
|
||||
[Command("start", description = "Starts a story plot.", usage ="id:string")]
|
||||
[RequiresArgument("id")]
|
||||
[RemoteLock]
|
||||
public static bool StartStory(Dictionary<string, object> args)
|
||||
{
|
||||
Story.Start(args["id"].ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("unexperience", description = "Marks a story plot as not-experienced yet.", usage ="id:string")]
|
||||
[RemoteLock]
|
||||
[RequiresArgument("id")]
|
||||
public static bool Unexperience(Dictionary<string, object> args)
|
||||
{
|
||||
string id = args["id"].ToString();
|
||||
if (SaveSystem.CurrentSave.StoriesExperienced.Contains(id))
|
||||
{
|
||||
Console.WriteLine("Unexperiencing " + id + ".");
|
||||
SaveSystem.CurrentSave.StoriesExperienced.Remove(id);
|
||||
SaveSystem.SaveGame();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Story ID not found.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -214,6 +214,12 @@
|
|||
<Compile Include="Applications\Terminal.Designer.cs">
|
||||
<DependentUpon>Terminal.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Applications\TutorialBox.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Applications\TutorialBox.Designer.cs">
|
||||
<DependentUpon>TutorialBox.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="AudioManager.cs" />
|
||||
<Compile Include="Commands.cs" />
|
||||
<Compile Include="Controls\ColorControl.cs">
|
||||
|
@ -244,6 +250,7 @@
|
|||
<DependentUpon>FakeSetupScreen.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="GUIFunctions.cs" />
|
||||
<Compile Include="HackerCommands.cs" />
|
||||
<Compile Include="JobTasks.cs" />
|
||||
<Compile Include="Oobe.cs">
|
||||
<SubType>Form</SubType>
|
||||
|
@ -358,6 +365,9 @@
|
|||
<EmbeddedResource Include="Applications\Terminal.resx">
|
||||
<DependentUpon>Terminal.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Applications\TutorialBox.resx">
|
||||
<DependentUpon>TutorialBox.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="DownloadControl.resx">
|
||||
<DependentUpon>DownloadControl.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
|
|
@ -70,8 +70,10 @@ namespace ShiftOS.WinForms
|
|||
NotificationDaemon.NotificationRead += () =>
|
||||
{
|
||||
//Soon this will pop a balloon note.
|
||||
btnnotifications.Text = "Notifications (" + NotificationDaemon.GetUnreadCount().ToString() + ")";
|
||||
|
||||
this.Invoke(new Action(() =>
|
||||
{
|
||||
btnnotifications.Text = "Notifications (" + NotificationDaemon.GetUnreadCount().ToString() + ")";
|
||||
}));
|
||||
};
|
||||
|
||||
this.LocationChanged += (o, a) =>
|
||||
|
|
|
@ -30,6 +30,12 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace ShiftOS.Engine
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
|
||||
public class KernelModeAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class Command : Attribute
|
||||
{
|
||||
public string name;
|
||||
|
|
|
@ -164,7 +164,35 @@ namespace ShiftOS.Engine
|
|||
}
|
||||
}
|
||||
|
||||
[Command("reconnect")]
|
||||
[RequiresUpgrade("hacker101_deadaccts")]
|
||||
public static bool Reconnect()
|
||||
{
|
||||
Console.WriteLine("--reconnecting to multi-user domain...");
|
||||
KernelWatchdog.MudConnected = true;
|
||||
Console.WriteLine("--done.");
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("disconnect")]
|
||||
[RequiresUpgrade("hacker101_deadaccts")]
|
||||
public static bool Disconnect()
|
||||
{
|
||||
Console.WriteLine("--connection to multi-user domain severed...");
|
||||
KernelWatchdog.MudConnected = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
[Command("sendmsg")]
|
||||
[KernelMode]
|
||||
[RequiresUpgrade("hacker101_deadaccts")]
|
||||
[RequiresArgument("header")]
|
||||
[RequiresArgument("body")]
|
||||
public static bool SendMessage(Dictionary<string, object> args)
|
||||
{
|
||||
ServerManager.SendMessage(args["header"].ToString(), args["body"].ToString());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[RequiresUpgrade("mud_fundamentals")]
|
||||
|
|
70
ShiftOS_TheReturn/KernelWatchdog.cs
Normal file
70
ShiftOS_TheReturn/KernelWatchdog.cs
Normal file
|
@ -0,0 +1,70 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static ShiftOS.Objects.ShiftFS.Utils;
|
||||
|
||||
namespace ShiftOS.Engine
|
||||
{
|
||||
public static class KernelWatchdog
|
||||
{
|
||||
public static void Log(string e, string desc)
|
||||
{
|
||||
string line = $"[{DateTime.Now}] <{e}> {desc}";
|
||||
if (FileExists("0:/system/data/kernel.log"))
|
||||
{
|
||||
string contents = ReadAllText("0:/system/data/kernel.log");
|
||||
contents += Environment.NewLine + line;
|
||||
WriteAllText("0:/system/data/kernel.log", contents);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteAllText("0:/system/data/kernel.log", line);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool InKernelMode { get; private set; }
|
||||
public static bool MudConnected { get; set; }
|
||||
|
||||
public static bool IsSafe(Type type)
|
||||
{
|
||||
if (InKernelMode == true)
|
||||
return true;
|
||||
|
||||
foreach (var attrib in type.GetCustomAttributes(false))
|
||||
{
|
||||
if (attrib is KernelModeAttribute)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool IsSafe(MethodInfo type)
|
||||
{
|
||||
if (InKernelMode == true)
|
||||
return true;
|
||||
|
||||
foreach (var attrib in type.GetCustomAttributes(false))
|
||||
{
|
||||
if (attrib is KernelModeAttribute)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static void EnterKernelMode()
|
||||
{
|
||||
InKernelMode = true;
|
||||
Console.WriteLine("<kernel> Watchdog deactivated, system-level access granted.");
|
||||
}
|
||||
|
||||
public static void LeaveKernelMode()
|
||||
{
|
||||
InKernelMode = false;
|
||||
Console.WriteLine("<kernel> Kernel mode disabled.");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -109,28 +109,35 @@ namespace ShiftOS.Engine
|
|||
bool guidReceived = false;
|
||||
ServerManager.GUIDReceived += (str) =>
|
||||
{
|
||||
//Connection successful! Stop waiting!
|
||||
guidReceived = true;
|
||||
Console.WriteLine("{CONNECTION_SUCCESSFUL}");
|
||||
Console.WriteLine("Connection successful.");
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
ServerManager.Initiate("secondary4162.cloudapp.net", 13370);
|
||||
while(guidReceived == false)
|
||||
//This haults the client until the connection is successful.
|
||||
while (ServerManager.thisGuid == new Guid())
|
||||
{
|
||||
|
||||
}
|
||||
Console.WriteLine("GUID received - bootstrapping complete.");
|
||||
FinishBootstrap();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//No errors, this never gets called.
|
||||
Console.WriteLine("{ERROR}: " + ex.Message);
|
||||
Thread.Sleep(3000);
|
||||
ServerManager.StartLANServer();
|
||||
while (guidReceived == false)
|
||||
while (ServerManager.thisGuid == new Guid())
|
||||
{
|
||||
|
||||
}
|
||||
Console.WriteLine("GUID received - bootstrapping complete.");
|
||||
FinishBootstrap();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -138,64 +145,73 @@ namespace ShiftOS.Engine
|
|||
ServerManager.StartLANServer();
|
||||
}
|
||||
|
||||
ServerManager.MessageReceived += (msg) =>
|
||||
{
|
||||
if(msg.Name == "mud_savefile")
|
||||
{
|
||||
CurrentSave = JsonConvert.DeserializeObject<Save>(msg.Contents);
|
||||
}
|
||||
else if(msg.Name == "mud_login_denied")
|
||||
{
|
||||
oobe.PromptForLogin();
|
||||
}
|
||||
};
|
||||
//Nothing happens past this point - but the client IS connected! It shouldn't be stuck in that while loop above.
|
||||
|
||||
ReadSave();
|
||||
|
||||
while(CurrentSave == null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Shiftorium.Init();
|
||||
|
||||
while (CurrentSave.StoryPosition < 1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Thread.Sleep(75);
|
||||
|
||||
Thread.Sleep(50);
|
||||
Console.WriteLine("{SYSTEM_INITIATED}");
|
||||
|
||||
TerminalBackend.InStory = false;
|
||||
TerminalBackend.PrefixEnabled = true;
|
||||
Shiftorium.LogOrphanedUpgrades = true;
|
||||
Desktop.InvokeOnWorkerThread(new Action(() =>
|
||||
{
|
||||
ShiftOS.Engine.Scripting.LuaInterpreter.RunSft(Paths.GetPath("kernel.sft"));
|
||||
}));
|
||||
Desktop.InvokeOnWorkerThread(new Action(() => Desktop.PopulateAppLauncher()));
|
||||
if (CurrentSave.StoryPosition == 1)
|
||||
{
|
||||
Desktop.InvokeOnWorkerThread(new Action(() =>
|
||||
{
|
||||
TutorialManager.StartTutorial();
|
||||
|
||||
}));
|
||||
while(TutorialManager.IsInTutorial == true) { }
|
||||
GameReady?.Invoke();
|
||||
}
|
||||
else
|
||||
{
|
||||
GameReady?.Invoke();
|
||||
}
|
||||
|
||||
}));
|
||||
thread.IsBackground = true;
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
public static void FinishBootstrap()
|
||||
{
|
||||
KernelWatchdog.Log("mud_handshake", "handshake successful: kernel watchdog access code is \"" + ServerManager.thisGuid.ToString() + "\"");
|
||||
|
||||
ServerManager.MessageReceived += (msg) =>
|
||||
{
|
||||
if (msg.Name == "mud_savefile")
|
||||
{
|
||||
CurrentSave = JsonConvert.DeserializeObject<Save>(msg.Contents);
|
||||
}
|
||||
else if (msg.Name == "mud_login_denied")
|
||||
{
|
||||
oobe.PromptForLogin();
|
||||
}
|
||||
};
|
||||
|
||||
ReadSave();
|
||||
|
||||
while (CurrentSave == null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Shiftorium.Init();
|
||||
|
||||
while (CurrentSave.StoryPosition < 1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Thread.Sleep(75);
|
||||
|
||||
Thread.Sleep(50);
|
||||
Console.WriteLine("{SYSTEM_INITIATED}");
|
||||
|
||||
TerminalBackend.InStory = false;
|
||||
TerminalBackend.PrefixEnabled = true;
|
||||
Shiftorium.LogOrphanedUpgrades = true;
|
||||
Desktop.InvokeOnWorkerThread(new Action(() =>
|
||||
{
|
||||
ShiftOS.Engine.Scripting.LuaInterpreter.RunSft(Paths.GetPath("kernel.sft"));
|
||||
}));
|
||||
Desktop.InvokeOnWorkerThread(new Action(() => Desktop.PopulateAppLauncher()));
|
||||
if (CurrentSave.StoryPosition == 1)
|
||||
{
|
||||
Desktop.InvokeOnWorkerThread(new Action(() =>
|
||||
{
|
||||
TutorialManager.StartTutorial();
|
||||
|
||||
}));
|
||||
while (TutorialManager.IsInTutorial == true) { }
|
||||
GameReady?.Invoke();
|
||||
}
|
||||
else
|
||||
{
|
||||
GameReady?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public delegate void EmptyEventHandler();
|
||||
|
||||
public static List<ClientSave> Users
|
||||
|
@ -299,7 +315,7 @@ namespace ShiftOS.Engine
|
|||
System.IO.File.WriteAllText(Paths.SaveFile, Utils.ExportMount(0));
|
||||
}
|
||||
|
||||
public static void TransferCodepointsFrom(string who, int amount)
|
||||
public static void TransferCodepointsFrom(string who, long amount)
|
||||
{
|
||||
NotificationDaemon.AddNotification(NotificationType.CodepointsReceived, amount);
|
||||
CurrentSave.Codepoints += amount;
|
||||
|
|
|
@ -126,6 +126,13 @@ namespace ShiftOS.Engine
|
|||
thisGuid = new Guid(msg.Contents);
|
||||
GUIDReceived?.Invoke(msg.Contents);
|
||||
}
|
||||
else if(msg.Name == "allusers")
|
||||
{
|
||||
foreach(var acc in JsonConvert.DeserializeObject<string[]>(msg.Contents))
|
||||
{
|
||||
Console.WriteLine(acc);
|
||||
}
|
||||
}
|
||||
else if(msg.Name == "update_your_cp")
|
||||
{
|
||||
var args = JsonConvert.DeserializeObject<Dictionary<string, object>>(msg.Contents);
|
||||
|
|
|
@ -107,6 +107,7 @@
|
|||
<Compile Include="FileSkimmerBackend.cs" />
|
||||
<Compile Include="Infobox.cs" />
|
||||
<Compile Include="IShiftOSWindow.cs" />
|
||||
<Compile Include="KernelWatchdog.cs" />
|
||||
<Compile Include="Localization.cs" />
|
||||
<Compile Include="NotificationDaemon.cs" />
|
||||
<Compile Include="OutOfBoxExperience.cs" />
|
||||
|
|
|
@ -204,7 +204,19 @@ namespace ShiftOS.Engine
|
|||
}
|
||||
try
|
||||
{
|
||||
return SaveSystem.CurrentSave.Upgrades[id];
|
||||
if (SaveSystem.CurrentSave == null)
|
||||
return false;
|
||||
|
||||
if (SaveSystem.CurrentSave.StoriesExperienced == null)
|
||||
SaveSystem.CurrentSave.StoriesExperienced = new List<string>();
|
||||
|
||||
bool upgInstalled = false;
|
||||
if(SaveSystem.CurrentSave.Upgrades.ContainsKey(id))
|
||||
upgInstalled = SaveSystem.CurrentSave.Upgrades[id];
|
||||
|
||||
if(upgInstalled == false)
|
||||
return SaveSystem.CurrentSave.StoriesExperienced.Contains(id);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
|
|
@ -37,6 +37,48 @@ namespace ShiftOS.Engine
|
|||
{
|
||||
public class Story
|
||||
{
|
||||
public static void Start(string stid)
|
||||
{
|
||||
foreach (var exec in System.IO.Directory.GetFiles(Environment.CurrentDirectory))
|
||||
{
|
||||
if(exec.EndsWith(".exe") || exec.EndsWith(".dll"))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (SaveSystem.CurrentSave.StoriesExperienced == null)
|
||||
SaveSystem.CurrentSave.StoriesExperienced = new List<string>();
|
||||
var asm = Assembly.LoadFile(exec);
|
||||
foreach(var type in asm.GetTypes())
|
||||
{
|
||||
foreach(var mth in type.GetMethods(BindingFlags.Public | BindingFlags.Static))
|
||||
{
|
||||
foreach(var attrib in mth.GetCustomAttributes(false))
|
||||
{
|
||||
if(attrib is StoryAttribute)
|
||||
{
|
||||
var story = attrib as StoryAttribute;
|
||||
if(story.StoryID == stid)
|
||||
{
|
||||
mth.Invoke(null, null);
|
||||
SaveSystem.CurrentSave.StoriesExperienced.Add(stid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
throw new ArgumentException("Story ID not found: " + stid + " - Talk to Michael. NOW.");
|
||||
#else
|
||||
Debug.Print("No such story: " + stid);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
public static void RunFromInternalResource(string resource_id)
|
||||
{
|
||||
var t = typeof(Properties.Resources);
|
||||
|
@ -262,4 +304,25 @@ namespace ShiftOS.Engine
|
|||
thread.Start();
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||||
public class StoryAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="StoryAttribute"/> attribute.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of this story plot.</param>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The <see cref="StoryAttribute"/> is used to turn a static, public method into a story element. Using the specified <paramref name="id"/> argument, the ShiftOS Engine can determine whether this plot has already been experienced, and using the <see cref="Shiftorium"/> classes, the ID is treated as a special Shiftorium upgrade, and you can use the <see cref="RequiresUpgradeAttribute"/> attribute as well as the various other ways of determining whether a Shiftorium upgrade is installed to determine if this plot has been experienced.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public StoryAttribute(string id)
|
||||
{
|
||||
StoryID = id;
|
||||
}
|
||||
|
||||
public string StoryID { get; private set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,121 +139,129 @@ namespace ShiftOS.Engine
|
|||
{
|
||||
if (Shiftorium.UpgradeAttributesUnlocked(type))
|
||||
{
|
||||
foreach (var a in type.GetCustomAttributes(false))
|
||||
if (KernelWatchdog.IsSafe(type))
|
||||
{
|
||||
if (a is Namespace)
|
||||
foreach (var a in type.GetCustomAttributes(false))
|
||||
{
|
||||
var ns = a as Namespace;
|
||||
if (text.Split('.')[0] == ns.name)
|
||||
if (a is Namespace)
|
||||
{
|
||||
foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Static))
|
||||
var ns = a as Namespace;
|
||||
if (text.Split('.')[0] == ns.name)
|
||||
{
|
||||
if (Shiftorium.UpgradeAttributesUnlocked(method))
|
||||
foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Static))
|
||||
{
|
||||
if (CanRunRemotely(method, isRemote))
|
||||
if (Shiftorium.UpgradeAttributesUnlocked(method))
|
||||
{
|
||||
foreach (var ma in method.GetCustomAttributes(false))
|
||||
if (KernelWatchdog.IsSafe(method))
|
||||
{
|
||||
if (ma is Command)
|
||||
if (CanRunRemotely(method, isRemote))
|
||||
{
|
||||
var cmd = ma as Command;
|
||||
if (text.Split('.')[1] == cmd.name)
|
||||
foreach (var ma in method.GetCustomAttributes(false))
|
||||
{
|
||||
|
||||
var attr = method.GetCustomAttribute<CommandObsolete>();
|
||||
|
||||
if (attr != null)
|
||||
if (ma is Command)
|
||||
{
|
||||
string newcommand = attr.newcommand;
|
||||
if (attr.warn)
|
||||
var cmd = ma as Command;
|
||||
if (text.Split('.')[1] == cmd.name)
|
||||
{
|
||||
Console.WriteLine(Localization.Parse((newcommand == "" ? "{ERROR}" : "{WARN}") + attr.reason, new Dictionary<string, string>() {
|
||||
|
||||
var attr = method.GetCustomAttribute<CommandObsolete>();
|
||||
|
||||
if (attr != null)
|
||||
{
|
||||
string newcommand = attr.newcommand;
|
||||
if (attr.warn)
|
||||
{
|
||||
Console.WriteLine(Localization.Parse((newcommand == "" ? "{ERROR}" : "{WARN}") + attr.reason, new Dictionary<string, string>() {
|
||||
{"%newcommand", newcommand}
|
||||
}));
|
||||
}
|
||||
if (newcommand != "")
|
||||
{
|
||||
// redo the entire process running newcommand
|
||||
}
|
||||
if (newcommand != "")
|
||||
{
|
||||
// redo the entire process running newcommand
|
||||
|
||||
return RunClient(newcommand, args);
|
||||
}
|
||||
}
|
||||
return RunClient(newcommand, args);
|
||||
}
|
||||
}
|
||||
|
||||
var requiresArgs = method.GetCustomAttributes<RequiresArgument>();
|
||||
var requiresArgs = method.GetCustomAttributes<RequiresArgument>();
|
||||
|
||||
bool error = false;
|
||||
bool providedusage = false;
|
||||
bool error = false;
|
||||
bool providedusage = false;
|
||||
|
||||
foreach (RequiresArgument argument in requiresArgs)
|
||||
{
|
||||
if (!args.ContainsKey(argument.argument))
|
||||
{
|
||||
|
||||
if (!providedusage)
|
||||
foreach (RequiresArgument argument in requiresArgs)
|
||||
{
|
||||
string usageparse = "{COMMAND_" + ns.name.ToUpper() + "_" + cmd.name.ToUpper() + "_USAGE}";
|
||||
if (usageparse == Localization.Parse(usageparse))
|
||||
usageparse = "";
|
||||
else
|
||||
usageparse = Shiftorium.UpgradeInstalled("help_usage") ? Localization.Parse("{ERROR}{USAGE}" + usageparse, new Dictionary<string, string>() {
|
||||
if (!args.ContainsKey(argument.argument))
|
||||
{
|
||||
|
||||
if (!providedusage)
|
||||
{
|
||||
string usageparse = "{COMMAND_" + ns.name.ToUpper() + "_" + cmd.name.ToUpper() + "_USAGE}";
|
||||
if (usageparse == Localization.Parse(usageparse))
|
||||
usageparse = "";
|
||||
else
|
||||
usageparse = Shiftorium.UpgradeInstalled("help_usage") ? Localization.Parse("{ERROR}{USAGE}" + usageparse, new Dictionary<string, string>() {
|
||||
{"%ns", ns.name},
|
||||
{"%cmd", cmd.name}
|
||||
}) : "";
|
||||
|
||||
Console.WriteLine(usageparse);
|
||||
Console.WriteLine(usageparse);
|
||||
|
||||
providedusage = true;
|
||||
}
|
||||
providedusage = true;
|
||||
}
|
||||
|
||||
if (Shiftorium.UpgradeInstalled("help_usage"))
|
||||
{
|
||||
Console.WriteLine(Localization.Parse("{ERROR_ARGUMENT_REQUIRED}", new Dictionary<string, string>() {
|
||||
if (Shiftorium.UpgradeInstalled("help_usage"))
|
||||
{
|
||||
Console.WriteLine(Localization.Parse("{ERROR_ARGUMENT_REQUIRED}", new Dictionary<string, string>() {
|
||||
{"%argument", argument.argument}
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(Localization.Parse("{ERROR_ARGUMENT_REQUIRED_NO_USAGE}"));
|
||||
}
|
||||
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if (error)
|
||||
{
|
||||
Console.WriteLine(Localization.Parse("{ERROR_ARGUMENT_REQUIRED_NO_USAGE}"));
|
||||
throw new Exception("{ERROR_COMMAND_WRONG}");
|
||||
}
|
||||
|
||||
error = true;
|
||||
try
|
||||
{
|
||||
return (bool)method.Invoke(null, new[] { args });
|
||||
}
|
||||
catch (TargetInvocationException e)
|
||||
{
|
||||
Console.WriteLine(Localization.Parse("{ERROR_EXCEPTION_THROWN_IN_METHOD}"));
|
||||
Console.WriteLine(e.InnerException.Message);
|
||||
Console.WriteLine(e.InnerException.StackTrace);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return (bool)method.Invoke(null, new object[] { });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
throw new Exception("{ERROR_COMMAND_WRONG}");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return (bool)method.Invoke(null, new[] { args });
|
||||
}
|
||||
catch (TargetInvocationException e)
|
||||
{
|
||||
Console.WriteLine(Localization.Parse("{ERROR_EXCEPTION_THROWN_IN_METHOD}"));
|
||||
Console.WriteLine(e.InnerException.Message);
|
||||
Console.WriteLine(e.InnerException.StackTrace);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return (bool)method.Invoke(null, new object[] { });
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(text + " cannot be ran in a remote session");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(text + " cannot be ran in a remote session");
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue