Skip to content

Instantly share code, notes, and snippets.

@Vortire
Last active August 8, 2021 18:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Vortire/5583ff05b6c47211d0f6b071c833ba5c to your computer and use it in GitHub Desktop.
Save Vortire/5583ff05b6c47211d0f6b071c833ba5c to your computer and use it in GitHub Desktop.
A C# implementation of an already existing NFOServers API.
namespace NFO_HPOST_API
{
/*
*
##############################################################
#
# NFO2 API C# - Vortire.com - 2021
#
# "//" or "#" at the beginning of a line signifies a comment.
#
# You can create profiles, instructions, send GET and POST
# requests as shown below.
#
# By default, this introduction will send a GET request
# using "profile1" to the current events page of NFO.
#
#
# To call this API using this test syntax, create a text
# file called "test.txt" and call the NFO2 API like so:
#
# string[] x = NFO2.Parse(File.ReadAllText("test.txt"));
# foreach(string y in x) { Console.WriteLine(y); }
#
##############################################################
// Ensure we let the parser know we are using " -> " instead of "->"
{{spaced-seperators}}
// Create new profile
Create_Profile -> Named:profile1 -> WithEmail:example@example.com -> WithPassword:example -> WithServiceName:exampleservice
// Send GET request
Send_Get -> To:https://www.nfoservers.com/control/events.pl -> WithProfile:profile1 -> SetResultTo:currentserverstatus
# Uncomment below lines to perform POST requests
// Creating the instruction to shutdown a server
// Create_Instruction -> Named:shutd -> WithData:%shutdown%
// Requesting server shutdown
// Send_Post -> To:example.pl -> WithProfile:profile1 -> WithInstruction:shutd
*
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
public static class NFO2
{
#region MainBackend
/// <summary>
/// Contains the ability to send a specific POST request to
/// NFOServers with specific attributes applied.
///
/// Should only be called from other API functions that
/// are public.
/// </summary>
/// <param name="host">URI of the external host</param>
/// <param name="data_serviceType">The type of the service to modify</param>
/// <param name="data_serviceName">The name of the service to modify</param>
/// <param name="request_cmd">The command for NFOServers backend</param>
/// <param name="header_email">NFOServers account Email Address</param>
/// <param name="header_pswd">NFOServers account password</param>
/// <returns>The body of the request response</returns>
private static string NFOHPOST_Call_POST(string host, string data_serviceType, string data_serviceName, string request_cmd, string header_email, string header_pswd)
{
// Declare our handler and set request method
HttpWebRequest hwr_Req = (HttpWebRequest)WebRequest.Create(host);
hwr_Req.Method = "POST";
// Set request body
byte[] req_Bytes = ASCIIEncoding.ASCII.GetBytes($"cookietoken=a&name={data_serviceName}&typeofserver={data_serviceType}&{request_cmd}");
// Sanitise user input for protection
header_email = header_email.Replace(";", "");
header_pswd = header_pswd.Replace(";", "");
header_email = header_email.Replace(@"""", "");
header_pswd = header_pswd.Replace(@"""", "");
header_email = header_email.Replace("=", "");
header_pswd = header_pswd.Replace("=", "");
// Set headers
hwr_Req.ContentType = "application/x-www-form-urlencoded";
hwr_Req.ContentLength = req_Bytes.Length;
hwr_Req.Headers.Add("cookie", $"email={header_email};password={header_pswd};cookietoken=a");
hwr_Req.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
// Push request to external host
Stream hwr_Stream = hwr_Req.GetRequestStream();
hwr_Stream.Write(req_Bytes, 0, req_Bytes.Length);
// Receive (and return) response from external host
HttpWebResponse hwr_Response = hwr_Req.GetResponse() as HttpWebResponse;
using (var responseStream = hwr_Response.GetResponseStream())
using (var reader = new StreamReader(responseStream, Encoding.GetEncoding(hwr_Response.CharacterSet)))
return reader.ReadToEnd();
}
/// <summary>
/// Contains the ability to send a specific GET request to
/// NFOServers with specific attributes applied.
///
/// Should only be called from other API functions that
/// are public.
/// </summary>
/// <param name="Host">NFOServers URI</param>
/// <param name="header_email">NFOServers account email</param>
/// <param name="header_pswd">NFOSevers account password</param>
/// <param name="data_serviceName">The name of the service to modify</param>
/// <param name="data_serviceType">The type of the service to modify</param>
/// <returns>Response body</returns>
private static string NFOHGET_Call_GET(string Host, string header_email, string header_pswd, string data_serviceName, string data_serviceType)
{
// Declare our handler and form request
HttpWebRequest hwr_Req = (HttpWebRequest)WebRequest.Create(Host);
// Sanitise user input for protection
header_email = header_email.Replace(";", "");
header_pswd = header_pswd.Replace(";", "");
header_email = header_email.Replace(@"""", "");
header_pswd = header_pswd.Replace(@"""", "");
header_email = header_email.Replace("=", "");
header_pswd = header_pswd.Replace("=", "");
// Set request headers
hwr_Req.Headers.Add("cookie", $"email={header_email};password={header_pswd};cookietoken=a");
hwr_Req.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
using (HttpWebResponse response = (HttpWebResponse)hwr_Req.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
return reader.ReadToEnd();
}
}
#endregion
#region Controllers
/// <summary>
/// Tells the interpreter to look for " -> " instead of "->"
/// </summary>
private static bool UseSpacedSeperators = false;
/// <summary>
/// Stores all the profiles that can be used with the API
/// </summary>
private static Dictionary<string, Profile_Structure> Profiles = new Dictionary<string, Profile_Structure>();
/// <summary>
/// Stores all the instructions that can be used with the API
/// </summary>
private static Dictionary<string, Instruction_Structure> Instructions = new Dictionary<string, Instruction_Structure>();
/// <summary>
/// Stores all the variables that have been assigned by the API
/// </summary>
private static Dictionary<string, string> Variables = new Dictionary<string, string>();
#endregion
/// <summary>
/// Main entry point.
/// Will parse and interpret NFO2 Syntax API code
/// </summary>
/// <param name="code">Your NFO2 syntax</param>
/// <returns>All variables that have been assigned during your session</returns>
public static string[] Parse(string code)
{
// Clear known session variables
Variables.Clear();
Instructions.Clear();
UseSpacedSeperators = false;
Profiles.Clear();
// Replace any known colon arguments
if (code.Contains("http://") || code.Contains("https://"))
{
code = code.Replace("http://", "http*colon*//").Replace("https://", "https*colon*//");
}
// Replace any known instructions
code = code.Replace("%restart%", "power=softoff_then_off_then_on");
code = code.Replace("%shutdown%", "power=off");
// Parse parts and interpret them
API_Structure[] x = ParseSubLines(ParseMainLines(code.Split('\n')).ToArray()).ToArray();
foreach (API_Structure y in x)
{
ParseInstruction(y);
}
// Return variables
List<string> _variables = new List<string>();
foreach (KeyValuePair<string, string> entry in Variables)
{
_variables.Add($"{entry.Key} -> {entry.Value}");
}
return _variables.ToArray();
}
#region Parsers
/// <summary>
/// Parses a suspected condition into its actual condition
/// </summary>
/// <param name="condition"></param>
private static void Parse_Condition(string condition)
{
switch (condition)
{
case "spaced-seperators":
UseSpacedSeperators = true;
break;
}
}
/// <summary>
/// Parses all lines and removes comments and conditions
/// </summary>
/// <param name="parts"></param>
private static List<string> ParseMainLines(string[] parts)
{
List<string> parsedMainLines = new List<string>();
foreach (string part in parts)
{
if (!part.StartsWith("//") || !part.StartsWith("#"))
{
// Does the part contain the main conditions?
if (part.Contains("{{") && part.Contains("}}"))
{
// Yes, read the conditions
string _main_Conditions = Regex.Match(part, @"{{(.+?)}}").Groups[1].Value;
if (!_main_Conditions.Contains(","))
{
// Only one condition found, parse it
Parse_Condition(_main_Conditions);
}
else
{
// Several conditions found, parse each one
string[] main_Conditions = _main_Conditions.Split(',');
foreach (string condition in main_Conditions)
{
Parse_Condition(condition);
}
}
}
else
{
// No, add to parsed array
parsedMainLines.Add(part);
}
}
}
return parsedMainLines;
}
/// <summary>
/// Splits parts into subparts (splits via the main split indicator, "->" or " -> ")
/// </summary>
/// <param name="parts"></param>
private static List<API_Structure> ParseSubLines(string[] parts)
{
List<API_Structure> instructionPile = new List<API_Structure>();
// Parse through parts
foreach (string part in parts)
{
List<string> subparts = new List<string>();
if (UseSpacedSeperators)
{
subparts.AddRange(part.Split(" -> "));
}
else
{
subparts.AddRange(part.Split("->"));
}
// Create new instruction for this part
API_Structure new_instruction = new API_Structure();
try
{
new_instruction.Command = subparts[0];
new_instruction.Arg1 = subparts[1];
new_instruction.Arg2 = subparts[2];
new_instruction.Arg3 = subparts[3];
new_instruction.Arg4 = subparts[4];
new_instruction.Arg5 = subparts[5];
}
catch { } // We may catch an exception if the part does not contain the maximum number of arguments available
// Add to instruction pile
instructionPile.Add(new_instruction);
}
return instructionPile;
}
#endregion
#region Interpreter
/// <summary>
/// Parses an instruction
/// -~ Main interpreter -~
/// </summary>
/// <param name="instruction"></param>
private static void ParseInstruction(API_Structure instruction)
{
#region FindArguments
// Store / find all arguments
string Arg_Named = "";
string Arg_To = "";
string Arg_WithEmail = "";
string Arg_WithUsername = "";
string Arg_WithPassword = "";
string Arg_WithServiceName = "";
string Arg_WithData = "";
string Arg_WithProfile = "";
string Arg_WithInstruction = "";
string Arg_SetResultTo = "";
// Find Named argument
string ArgToFind = "Named";
string FoundArg = "";
if (instruction.Arg1.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg1.Split(':')[1];
}
else if (instruction.Arg2.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg2.Split(':')[1];
}
else if (instruction.Arg3.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg3.Split(':')[1];
}
else if (instruction.Arg4.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg4.Split(':')[1];
}
else if (instruction.Arg5.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg5.Split(':')[1];
}
Arg_Named = FoundArg;
// Find To argument
ArgToFind = "To";
FoundArg = "";
if (instruction.Arg1.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg1.Split(':')[1];
}
else if (instruction.Arg2.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg2.Split(':')[1];
}
else if (instruction.Arg3.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg3.Split(':')[1];
}
else if (instruction.Arg4.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg4.Split(':')[1];
}
else if (instruction.Arg5.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg5.Split(':')[1];
}
Arg_To = FoundArg;
// Find WithEmail argument
ArgToFind = "WithEmail";
FoundArg = "";
if (instruction.Arg1.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg1.Split(':')[1];
}
else if (instruction.Arg2.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg2.Split(':')[1];
}
else if (instruction.Arg3.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg3.Split(':')[1];
}
else if (instruction.Arg4.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg4.Split(':')[1];
}
else if (instruction.Arg5.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg5.Split(':')[1];
}
Arg_WithEmail = FoundArg;
// Find WithUsername argument
ArgToFind = "WithUsername";
FoundArg = "";
if (instruction.Arg1.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg1.Split(':')[1];
}
else if (instruction.Arg2.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg2.Split(':')[1];
}
else if (instruction.Arg3.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg3.Split(':')[1];
}
else if (instruction.Arg4.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg4.Split(':')[1];
}
else if (instruction.Arg5.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg5.Split(':')[1];
}
Arg_WithUsername = FoundArg;
// Find WithPassword argument
ArgToFind = "WithPassword";
FoundArg = "";
if (instruction.Arg1.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg1.Split(':')[1];
}
else if (instruction.Arg2.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg2.Split(':')[1];
}
else if (instruction.Arg3.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg3.Split(':')[1];
}
else if (instruction.Arg4.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg4.Split(':')[1];
}
else if (instruction.Arg5.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg5.Split(':')[1];
}
Arg_WithPassword = FoundArg;
// Find WithServiceName argument
ArgToFind = "WithServiceName";
FoundArg = "";
if (instruction.Arg1.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg1.Split(':')[1];
}
else if (instruction.Arg2.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg2.Split(':')[1];
}
else if (instruction.Arg3.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg3.Split(':')[1];
}
else if (instruction.Arg4.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg4.Split(':')[1];
}
else if (instruction.Arg5.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg5.Split(':')[1];
}
Arg_WithServiceName = FoundArg;
// Find WithData argument
ArgToFind = "WithData";
FoundArg = "";
if (instruction.Arg1.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg1.Split(':')[1];
}
else if (instruction.Arg2.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg2.Split(':')[1];
}
else if (instruction.Arg3.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg3.Split(':')[1];
}
else if (instruction.Arg4.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg4.Split(':')[1];
}
else if (instruction.Arg5.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg5.Split(':')[1];
}
Arg_WithData = FoundArg;
// Find WithProfile argument
ArgToFind = "WithProfile";
FoundArg = "";
if (instruction.Arg1.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg1.Split(':')[1];
}
else if (instruction.Arg2.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg2.Split(':')[1];
}
else if (instruction.Arg3.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg3.Split(':')[1];
}
else if (instruction.Arg4.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg4.Split(':')[1];
}
else if (instruction.Arg5.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg5.Split(':')[1];
}
Arg_WithProfile = FoundArg;
// Find WithInstruction argument
ArgToFind = "WithInstruction";
FoundArg = "";
if (instruction.Arg1.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg1.Split(':')[1];
}
else if (instruction.Arg2.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg2.Split(':')[1];
}
else if (instruction.Arg3.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg3.Split(':')[1];
}
else if (instruction.Arg4.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg4.Split(':')[1];
}
else if (instruction.Arg5.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg5.Split(':')[1];
}
Arg_WithInstruction = FoundArg;
// Find SetResultTo argument
ArgToFind = "SetResultTo";
FoundArg = "";
if (instruction.Arg1.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg1.Split(':')[1];
}
else if (instruction.Arg2.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg2.Split(':')[1];
}
else if (instruction.Arg3.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg3.Split(':')[1];
}
else if (instruction.Arg4.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg4.Split(':')[1];
}
else if (instruction.Arg5.Split(':')[0] == ArgToFind)
{
FoundArg = instruction.Arg5.Split(':')[1];
}
Arg_SetResultTo = FoundArg;
#endregion
#region Sanitise arguments
// Add colons back to any arguments
Arg_Named = Arg_Named.Replace("*colon*", ":");
Arg_To = Arg_To.Replace("*colon*", ":");
Arg_WithEmail = Arg_WithEmail.Replace("*colon*", ":");
Arg_WithUsername = Arg_WithUsername.Replace("*colon*", ":");
Arg_WithPassword = Arg_WithPassword.Replace("*colon*", ":");
Arg_WithServiceName = Arg_WithServiceName.Replace("*colon*", ":");
Arg_WithData = Arg_WithData.Replace("*colon*", ":");
Arg_WithProfile = Arg_WithProfile.Replace("*colon*", ":");
Arg_WithInstruction = Arg_WithInstruction.Replace("*colon*", ":");
Arg_SetResultTo = Arg_SetResultTo.Replace("*colon*", ":");
#endregion
// Switch through the commands
switch (instruction.Command)
{
case "Create_Profile":
Profile_Structure newProfileStructure = new Profile_Structure();
newProfileStructure.Name = Arg_Named;
newProfileStructure.Email = Arg_WithEmail;
newProfileStructure.Username = Arg_WithUsername;
newProfileStructure.Password = Arg_WithPassword;
newProfileStructure.ServiceName = Arg_WithServiceName;
Profiles.Add(Arg_Named, newProfileStructure);
Console.WriteLine(
$"Created new profile ({DateTime.Now}):\n" +
$" name: {newProfileStructure.Name}\n" +
$" email: {newProfileStructure.Email}\n" +
$" username: {newProfileStructure.Username}\n" +
$" password: *hidden*\n" +
$" servicename: {newProfileStructure.ServiceName}\n"
);
break;
case "Create_Instruction":
Instruction_Structure newInstructionStructure = new Instruction_Structure();
newInstructionStructure.Name = Arg_Named;
newInstructionStructure.Data = Arg_WithData;
Instructions.Add(Arg_Named, newInstructionStructure);
Console.WriteLine(
$"Created new instruction ({DateTime.Now}):\n" +
$" name: {newInstructionStructure.Name}\n" +
$" data: {newInstructionStructure.Data}\n"
);
break;
case "Send_Post":
// Get profile
Profile_Structure CProfileP = Profiles[Arg_WithProfile];
// Get instruction
Instruction_Structure CInstructionP = Instructions[Arg_WithInstruction];
// Send request
string ResultP = NFOHPOST_Call_POST(
Arg_To,
"virtual",
CProfileP.ServiceName,
CInstructionP.Data, // <- Request data
CProfileP.Email,
CProfileP.Password
);
// Set variable value
if (Arg_SetResultTo != "")
{
if (Variables.ContainsKey(Arg_SetResultTo))
{
Variables[Arg_SetResultTo] = ResultP;
}
else
{
Variables.Add(Arg_SetResultTo, ResultP);
}
}
Console.WriteLine(
$"Sent POST ({DateTime.Now}):\n" +
$" To: {Arg_To}\n" +
$" On: {CProfileP.ServiceName}\n" +
$" With request: {CInstructionP.Data}\n"
);
break;
case "Send_Get":
// Get profile
Profile_Structure CProfileG = Profiles[Arg_WithProfile];
// Send request
Console.WriteLine($"Sending GET to: {Arg_To}");
string ResultG = NFOHGET_Call_GET(
Arg_To,
CProfileG.Email,
CProfileG.Password,
CProfileG.ServiceName,
"virtual"
);
// Set variable value
if (Arg_SetResultTo != "")
{
if (Variables.ContainsKey(Arg_SetResultTo))
{
Variables[Arg_SetResultTo] = ResultG;
}
else
{
Variables.Add(Arg_SetResultTo, ResultG);
}
}
Console.WriteLine(
$"Sent GET ({DateTime.Now}):\n" +
$" To: {Arg_To}\n" +
$" On: {CProfileG.ServiceName}\n"
);
break;
}
}
#endregion
}
}
public class API_Structure
{
public string Command { get; set; } = "";
public string Arg1 { get; set; } = "";
public string Arg2 { get; set; } = "";
public string Arg3 { get; set; } = "";
public string Arg4 { get; set; } = "";
public string Arg5 { get; set; } = "";
}
public class Instruction_Structure
{
public string Name { get; set; } = "";
public string Data { get; set; } = "";
}
public class Profile_Structure
{
public string Name { get; set; } = "";
public string Email { get; set; } = "";
public string Username { get; set; } = "";
public string Password { get; set; } = "";
public string ServiceName { get; set; } = "";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment