Krailon's HTTPD

From Hack Wars Wiki

Jump to: navigation, search

Contents

Krailon's HTTPD Script

Overview

Note: This is the version I'm currently working on, so it's a little unstable. Please use it only as a reference, as I may screw a bunch of stuff up as I add and modify things.

This script serves as a soon-to-be feature rich HTTPD server that will display HTML pages to users that connect to it. I also use this script to test new language features I plan on implementing. It made sense that I use this script because it's the easiest and most versatile to interact with. This also has the bonus of enabling me to share both the script's core functionality, as well as my HackScript extentions (new language features), in the same place.

Feature List

  • Dynamic Pages - Pages are loaded from .html files stored on your virtual hard drive.
    • You might want to buy a bigger hard drive if you plan to have a lot of pages.
  • Whitelist - The server employs a whitelist containing each page's security permissions, which can be configured to allow access to individual users, just you, or everyone.
  • Secure Areas - Any content in your pages' HTML enclosed in "<@ ... @>" tags is only shown to you. I'm debating creating a whitelist system for secure areas.
  • Error Handling - All IO errors are logged to a log file you specify, making debugging MUCH easier
    • You have to create this log file yourself
  • Comprehensive Access Logging - Every user that connects is logged in a log file
    • By default it uses the same log file that errors are written to, but I'm going to move this to a seperate traffic log file soon
  • Player Name/IP Substitution - All "<%player%>' tags in a page's HTML are replaced with the player's name, which must be stored in a database file
    • You have to create and, more importantly, populate this file yourself
    • You obviously have to stick to the format the script expects, unless you modify it yourself of course
    • The format is actually quite robust, supporting comments and exceptions (for partial IPs, etc):
      • Format -> "xxx.xxx.x.xxx:PlayerName|Unknown (comment)"
      • Everything after the IP and player name is basically ignored, so comment format is unimportant
      • If the player name is not known, just use "Unknown" and the script will use their IP
      • Add an asterisk (*) in front of any line that is to be ignored (partial IPs like 192.437.?.??? or something where you don't know what the rest is)

Enter() Code

This code is the core of the script and goes in the Enter() section

// Public Note: This section is basically a combo documentation/changelist/plans area.
// * -> bug fixes
// + -> feature implementations
// $ -> modifications
// @ -> future plans
//
//
// {Changelist}
// * FINALLTY Got rid of the last nasty little bug that wouldn't go away!!
// + "Secure Zone" feature IS DONE!
// 
// {Language Extensions}
// @ Hashlist ({key:val} pair)
// @ Include (code file inclusion)
int main() {
    string logFile = "Events.log"; // The universal log file's filename
    string IPDB = "IPDB"; // The "player_name <-> IP" database
    string visitor = getVisitorIP();
    string page = fetchGetVariable("page") + ".html"; // The requested page
    string whitelist = readFile("whitelist.dat"); // The site authentication list
    string userDB[] = split(readFile(IPDB), char(10));
    string player = "";
    string html;
    boolean authed = false;
 
    // Check the requested page and the visitor's IP address against the authentication data
    if (indexOf(whitelist, page, 0) > -1 && page != ".html") {
        string whitelines[] = split(whitelist, char(10));
 
        for (int i = 0; i < length(whitelines); i++) {
            if (strlen(page) < strlen(whitelines[i])) {
                if (indexOf(whitelines[i], page, 0) > -1 && (indexOf(whitelines[i], visitor, 0) > -1 {!!} indexOf(whitelines[i], "*", 0) > -1)) {
                    // Visitor has authenticated successfully
                    authed = true;
                }
            }
        }
    }
 
    if (visitor == "terribletriojoe-is-a-noob.hw") {
        // Hardwired bitch.
        authed = false; // Fuck off and I'll remove this :)
    }
    else if (visitor == "neuronet.hw") {
        authed = true; // Gotta let myself in :)
    }
 
    // Load the IPDB and attempt to pull a name from it
    for (int i = 0; i < length(userDB); i++) {
        string cLine = userDB[i];
        string cIP = substr(cLine, 0, indexOf(cLine, ":", 0) - 1);// = substr(cLine, 0, strlen(visitor));
 
        // Cut out any comments
        if (indexOf(cLine, " ", 0) > -1) {
            cLine = substr(cLine, 0, indexOf(cLine, " ", 0));
        }
 
        // Check the visitor's IP against the IP on the current line, skipping any starred lines
        if (substr(cLine, 0, 1) != "*" && visitor == cIP) {
            player = substr(cLine, indexOf(cLine, ":", 0) + 1, strlen(cLine));
        }
    }
 
    // Load the requested page if the visitor has passed authentication, otherwise load the unauthenticated page
    if (authed {!!} page == ".html") {
        // Attempt to load the menu
        if (fileExists("menu.html")) {
            WriteContent("menu", readFile("menu.html"), authed);
        }
        else {
            Log("Microsite Error: unable to locate 'menu.html'!");
        }
 
        if (page == ".html") {
            // [Index Page] //
            html = readFile("index.html");
 
            // Replace %visitor% with the player's name (if we have it) or their IP (if we don't)
            if (player == "") {
                if (indexOf(html, "%visitor", 0) > -1) {
                    html = replaceAll(html, "%visitor%", visitor);
                }
            }
            else {
                if (indexOf(html, "%visitor", 0) > -1) {
                    html = replaceAll(html, "%visitor%", player);
                }
            }
 
            // Log the successful authentication and access of the visitor to the requested page
            if (visitor != "neuronet.hw") {
                if (player == "" {!!} player == "Unknown") {
                    Log(visitor + " connected to the site");
                }
                else {
                    Log(player + " connected to the site");
                }
            }
        }
        else {
            // [Other Pages] //
            if (fileExists(page)) {
                html = readFile(page);
 
                if (page == "controlpanel.html") {
                    // If the requested page is the control panel we need to initialize the globals' values
                    html = InitGlobals(html);
 
                    // Log the successful authentication and access of the visitor to the control panel
                    if (visitor != "neuronet.hw") {
                        if (player == "" {!!} player == "Unknown") {
                            Log(visitor + " successfully authenticated and connected to the control panel");
                        }
                        else {
                            Log(player + " successfully authenticated and connected to the control panel");
                        }
                    }
                }
                else {
                    if (visitor != "neuronet.hw") {
                        if (player == "" {!!} player == "Unknown") {
                            Log(visitor + " successfully authenticated and connected to " + page);
                        }
                        else {
                            Log(player + " successfully authenticated and connected to " + page);
                        }
                    }                    
                }
            }
            else {
                Log("Microsite Error: Unable to locate '" + page + "'.");
            }
        }
 
        // Write out the content!
        WriteContent("main", html, authed);
    }
    else {
        // Log the access and attempt to load unauth.html
        if (player == "" {!!} player == "Unknown") {
            Log(visitor + " failed to authenticate for access to " + page + ".");
        }
        else {
            Log(player + " failed to authenciate for access to " + page + ".");
        }
 
        // Make sure the unauth page's file exists before loading it
        if (fileExists("unauth.html")) {
            // Load the unauth page's HTML
            html = readFile("unauth.html");
 
            // Insert the player's name (if we have it) or IP (if we don't) into the page's HTML
            if (player == "") {
                if (indexOf(html, "%visitor", 0) > -1) {
                    html = replaceAll(html, "%visitor%", visitor);
                }
            }
            else {
                if (indexOf(html, "%visitor", 0) >-1) {
                    html = replaceAll(html, "%visitor%", player);
                }
            }
 
            // Write it out!
            WriteContent("main", html, authed);
        }
        else {
            Log("Microsite Error: Unable to locate 'unauth.html'.");
        }
    }
}
 
// =-=-=-=-= Helper Routines =-=-=-=-= //
 
// Wrapper for replaceAll(), inserts the global variables' contents into the HTML of the globals page
string InitGlobals(string GlobalsPage) {
    string global;
    string html = GlobalsPage;
 
    // Loop through each global variable
    for (int i = 0; i < 20; i++) {
        global = getGlobal(i);
 
        // Insert the global variable's contents into the page's HTML so the page can initialize the dropbox to the right value
        html = replaceAll(html, "glob" + (i + 1) + "val", global);
    }
 
    return html;
}
 
// Logs messages to the HDD log file
void Log(string Data) {
    // Logs a message to the universal log file (set at the top of the script), prepending the date and time to the message
    writeFile(logFile, readFile(logFile) + "[" + getDate() + "][" + getTime() + "] " + Data + char(10));
}
 
// Wrapper for replaceContent(), also handles Secure Zones
void WriteContent(string ContentID, string Contents, boolean Authed) {
    int pos;
 
    // Modify "secure zones" based on authentication status
    while (indexOf(Contents, "<@", 0) > -1) {
        pos = indexOf(Contents, "<@", 0);
 
        if (indexOf(Contents, "@>", 0) == -1) {
            // Display an nice error page if the Secure Zone tags aren't all matched up (I think it'll work even if they're in the wrong order)
            Contents = "<center><h1> There was an error in the page's Secure Zone syntax</h1><br />Don't worry, I already know about it. It'll be fixed as soon as possible! ^_^<br /><image src='http://upload.wikimedia.org/wikipedia/commons/thumb/f/f0/Error.svg/497px-Error.svg.png' /></center>";
            Log("Microsite Error: Unable to modify secure zone starting with '" + substr(Contents, pos, pos + 10) + "\, no end tag detected"); 
        }
        else {
            string zone = substr(Contents, pos, indexOf(Contents, "@>", 0) + 2);
 
            if (Authed) {
                // Since there's no single instance replacement function I have to extract the entire zone to remove the tags, then copy the new tagless version over top of the old one :(
                string newZone = replaceAll(zone, "<@", "");
                newZone = replaceAll(newZone, "@>", "");
                Contents = replaceAll(Contents, zone, newZone);
            }
            else {
                // Replace the zone with nothing (aka strip it out)
                Contents = replaceAll(Contents, zone, "");
           }
        }
    }
 
    replaceContent(ContentID, Contents);
}
 
// =-=-=-=-= Hastlist Routines =-=-=-=-= //
// Note: From a few months ago, don't really feel like working on it right now with classes and such.
// Don't expect this to change for a while...
 
string AddKey(string hashlist[], string key, string value) {
    for (int i = 0; i < length(hashlist); i++) {
        if (substr(hashlist[i], 0, indexOf(hashlist[i], ":", 0)) == key) {
            return join(hashlist, ";");
        }
    }
 
    string newHashlist[length(hashlist) + 1];
    for (int i = 0; i <= length(hashlist); i++) {
        if (i < length(hashlist)) {
            newHashlist[i] = hashlist[i];
        }
        else {
            newHashlist[i] = key + ":" + value;
        }
    }
 
    return join(newHashlist, ";");
}
 
string RemoveKey(string hashlist[], string key) {
    boolean keyFound = false;
    int i;
 
    for (i = 0; i < length(hashlist); i++) {
        if (substr(hashlist[i], 0, indexOf(hashlist[i], ":", 0)) == key) {
            string newHashlist[length(hashlist) - 1];
            keyFound = true;
            break;
        }
    }
 
    if (!keyFound) {
        return join(hashlist, ";");
    }
    else {
        for (int j = 0; j < length(hashlist); j++) {
            if (j < i) {
                newHashlist[j] = hashlist[j];
            }
            else {
                newHashlist[j] = hashlist[j + 1];
            }
        }
 
        return join(newHashlist, ";");
    }
}
 
string GetValue(string hashlist[], string key) {
    for (int i = 0; i < length(hashlist); i++) {
        if (substr(hashlist[i], 0, length(key)) == key) {
            return substr(hashlist[i], indexOf(hashlist[i], ":", 0) + 1, length(hashlist[i]) - (length(key) + 1));
        }
    }
 
    return "";
}


Submit() Code

This code handles the custom script control panel portion of the site, which is only available to me and a select few (at least on MY site :P). I'll add my control panel .html code to this page when I sort out the bugs that seem to have crippled its functionality.

int main(){
    string visitor = getVisitorIP();
 
    if (visitor == "MY_IP"){
        // Here we need to get the values from the page and assign them to the matching globals
        for (int i = 0; i < 20; i++){
            setGlobal(i, GetParam("g" + (i + 1)));
        }
    }
    else{
        message(visitor, "Your changes have not been saved. I gave you viewing access, not modifying acces... ;)");
    }
}
 
string GetParam(string Name){
    return getParameter(Name);
}


Language Extensions

If this gets too big I'll move it to it's own section.

  • Hashlist - A new type supported by it's own small set of API functions
  • Remote Library Inclusion - Composed of an Include("lib_filename") function and a Call("function_name") function
    • This would allow you to create small libraries and store them in separate files (similar to almost any programming language)
    • Makes code 10x more portable, reduces script size as repeated segments can be offloaded to libraries
    • This MAY never get finished, it depends on how hard it is to parse and evaluate HackScript....with HackScript :P (I hope I'm not being too ambitious...)
    • *COUGH* BIG language feature suggestion *COUGH*

Kerby 06:15, 3 March 2011 (UTC)

Personal tools