tuiHoneyPot

front and back end of my TUI honeypot
Log | Files | Refs | README

faketerminal.js (23525B)


      1 if (!window.FakeTerminal) {
      2     window.FakeTerminal = {};
      3 }
      4 
      5 if (!window.FakeTerminal.command) {
      6     window.FakeTerminal.command = {};
      7 }
      8 
      9 window.FakeTerminal.defaultOptions = {
     10     username: "root",
     11     hostname: window.location.host,
     12     history: 1e3,
     13     prompt: "[%username%@%hostname%: %cwd%] ",
     14     login: null,
     15     cwd: "~"
     16 };
     17 
     18 window.FakeTerminal.main = function(el, options) {
     19     var base = this;
     20     if (!jQuery) {
     21         throw "FakeTerminal: jQuery required";
     22     } else {
     23         var $ = jQuery;
     24     }
     25     base.$el = $(el);
     26     base.originalHtml = "";
     27     base.existingText = [];
     28     base.executingCommand = {
     29         instance: null,
     30         deferred: null
     31     };
     32     base.keymap = {
     33         ENTER: 13,
     34         UP: 38,
     35         DOWN: 40,
     36         C: 67,
     37         D: 68,
     38         U: 85
     39     };
     40     base.output = null;
     41     base.input = null;
     42     base.filesystem = null;
     43     base.history = null;
     44     base.__construct = function() {
     45         base.$el.trigger("ft:init", [ base ]);
     46         base.options = $.extend({}, window.FakeTerminal.defaultOptions, options);
     47         base.originalHtml = base.$el.get(0).outerHTML;
     48         base.existingText = base.$el.get(0).innerHTML ? base.$el.get(0).innerHTML.split("\n") : [];
     49         base.$el.addClass("faketerminal").empty();
     50         base.bindListeners();
     51         base.output = new window.FakeTerminal.output(base);
     52         base.input = new window.FakeTerminal.input(base);
     53         base.filesystem = new window.FakeTerminal.filesystem(base);
     54         base.history = new window.FakeTerminal.history(base);
     55         for (var i = 0, j = base.existingText.length; i < j; i++) {
     56             if (base.existingText.length > 1 && i === 0) {
     57                 continue;
     58             } else if (base.existingText.length > 1 && i === base.existingText.length - 1) {
     59                 continue;
     60             }
     61             base.output.write($.trim(base.existingText[i]));
     62         }
     63         base.input.focus();
     64         base.$el.trigger("ft:ready", [ base ]);
     65         if (base.options.login) {
     66             base.exec(base.options.login);
     67         }
     68     };
     69     base.bindListeners = function() {
     70         base.$el.on("click", function() {
     71             base.input.focus();
     72         }).on("keyup", function(e) {
     73             if (e.ctrlKey && e.which === base.keymap.C) {
     74                 base.input.ctrlC();
     75             } else if (e.ctrlKey && e.which === base.keymap.U) {
     76                 base.input.ctrlU();
     77             }
     78         });
     79     };
     80     base.findCommand = function(command) {
     81         var cmdInstance;
     82         if (typeof window.FakeTerminal.command[command] === "function") {
     83             cmdInstance = new window.FakeTerminal.command[command](base);
     84         }
     85         return cmdInstance;
     86     };
     87     base.getPrompt = function() {
     88         var hostname, username, cwd, text;
     89         if (typeof base.options.hostname === "function") {
     90             hostname = base.options.hostname.call();
     91         } else {
     92             hostname = base.options.hostname;
     93         }
     94         if (typeof base.options.username === "function") {
     95             username = base.options.username.call();
     96         } else {
     97             username = base.options.username;
     98         }
     99         if (typeof base.options.cwd === "function") {
    100             cwd = base.options.cwd.call();
    101         } else {
    102             cwd = base.options.cwd;
    103         }
    104         username = username.toLowerCase().replace(/[^a-z0-9]/g, "");
    105         text = base.options.prompt;
    106         text = text.replace(/%hostname%/g, hostname);
    107         text = text.replace(/%username%/g, username);
    108         text = text.replace(/%cwd%/g, cwd);
    109         return base.colorize(text);
    110     };
    111     base.colorize = function(line) {
    112         line = line.replace(/<([a-zA-Z].+?)>/g, '<span class="color--$1">', line);
    113         line = line.replace(/<\/([a-zA-Z].+)>/g, "</span>", line);
    114         return line;
    115     };
    116     base.scrollToBottom = function() {
    117         base.$el.scrollTop(base.$el.get(0).scrollHeight);
    118         return base;
    119     };
    120     base.destroy = function() {
    121         base.$el.replaceWith($(base.originalHtml));
    122         base.$el.trigger("ft:destroy", [ base ]);
    123         return base;
    124     };
    125     base.exec = function(commandString, hidden) {
    126         var deferred, command, userArgs, commandInstance;
    127         deferred = new $.Deferred();
    128         commandString = $.trim(commandString);
    129         if (!hidden) {
    130             base.output.write(commandString, true);
    131         }
    132         if (commandString.length === 0) {
    133             deferred.reject();
    134             return deferred.promise();
    135         }
    136         command = $.trim(commandString.split(" ").slice(0, 1));
    137         userArgs = commandString.split(" ").slice(1);
    138         commandInstance = base.findCommand(command);
    139         if (commandInstance) {
    140             if (base.executingCommand.instance) {
    141                 base.executingCommand.instance.terminate();
    142                 base.executingCommand.instance = null;
    143                 base.executingCommand.deferred = null;
    144             }
    145             base.input.disable();
    146             base.executingCommand.instance = commandInstance;
    147             base.executingCommand.deferred = commandInstance.execute.apply(commandInstance, userArgs).done(function() {
    148                 deferred.resolve(arguments);
    149             }).fail(function() {
    150                 deferred.reject(arguments);
    151             }).always(function() {
    152                 base.input.enable().focus();
    153             });
    154         } else if (command.length > 0) {
    155             if (!hidden) {
    156                 base.output.write('command not found: "' + command + '"');
    157             }
    158             deferred.reject();
    159         } else {
    160             deferred.reject();
    161         }
    162         if (!hidden) {
    163             base.history.push(command);
    164         }
    165         base.$el.trigger("ft:command", [ base, command ]);
    166         return deferred.promise();
    167     };
    168     base.__construct();
    169 };
    170 
    171 window.FakeTerminal.output = function(instance) {
    172     var base = this;
    173     base.$screen = null;
    174     base.__construct = function() {
    175         base.$screen = $("<div>").addClass("faketerminal__screen");
    176         instance.$el.append(base.$screen);
    177         return base;
    178     };
    179     base.write = function(line, prompt) {
    180         var $line = $("<div>").addClass("faketerminal__screen__line");
    181         if (prompt) {
    182             $line.append($("<div>").addClass("faketerminal__prompt").html(instance.getPrompt()));
    183         }
    184         line = instance.colorize(line);
    185         line = line.replace(/ /g, "&nbsp;", line);
    186         line = line.replace(/<span&nbsp;class="/g, '<span class="', line);
    187         line = line.replace(/<div&nbsp;class="/g, '<div class="', line);
    188         $line.append(line);
    189         base.$screen.append($line);
    190         instance.scrollToBottom();
    191         return base;
    192     };
    193     base.clear = function() {
    194         base.$screen.empty();
    195         return base;
    196     };
    197     return base.__construct();
    198 };
    199 
    200 window.FakeTerminal.input = function(instance) {
    201     var base = this;
    202     base.$input = null;
    203     base.$request = null;
    204     base.$commandLine = null;
    205     base.$inputRequest = null;
    206     base.__construct = function() {
    207         base.$prompt = $("<div>").addClass("faketerminal__prompt").attr("autocorrect", "off").attr("autocapitalize", "none").html(instance.getPrompt());
    208         base.$input = $("<input>").on("keyup", function(e) {
    209             switch (e.which) {
    210               case instance.keymap.ENTER:
    211                 instance.exec(base.read()).done(function() {
    212                     base.$prompt.html(instance.getPrompt());
    213                 });
    214                 break;
    215 
    216               case instance.keymap.UP:
    217               case instance.keymap.DOWN:
    218                 base.set(instance.history.browse(e.which));
    219                 break;
    220             }
    221         });
    222         base.$commandLine = $("<div>").addClass("faketerminal__commandline");
    223         base.$request = $("<input>");
    224         base.$inputRequest = $("<div>").addClass("faketerminal__commandline faketerminal__commandline--request");
    225         instance.$el.append(base.$commandLine.append(base.$prompt).append(base.$input)).append(base.$inputRequest.append(base.$request));
    226         base.enable();
    227         base.disableRequest();
    228         return base;
    229     };
    230     base.read = function() {
    231         var value = base.$input.val();
    232         base.$input.val("");
    233         return value;
    234     };
    235     base.request = function(type) {
    236         type = type || "TEXT";
    237         type = type.toUpperCase();
    238         switch (type) {
    239           case "TEXT":
    240             return base.requestText();
    241             break;
    242 
    243           case "BOOL":
    244           case "BOOLEAN":
    245             return base.requestBool();
    246             break;
    247 
    248           case "PASSWORD":
    249             return base.requestPassword();
    250             break;
    251 
    252           default:
    253             throw "Invalid request type";
    254             break;
    255         }
    256     };
    257     base.requestText = function(muteOutput) {
    258         var deferred = new $.Deferred();
    259         base.enableRequest();
    260         base.$request.on("keyup", function(e) {
    261             if (e.which === instance.keymap.ENTER) {
    262                 var value = $.trim(base.$request.val());
    263                 if (!muteOutput) {
    264                     instance.output.write(value);
    265                 }
    266                 deferred.resolve(value);
    267                 instance.$el.trigger("ft:command", [ instance, value ]);
    268             }
    269         });
    270         deferred.always(function() {
    271             base.disableRequest();
    272             base.$request.off("keyup");
    273         });
    274         return deferred.promise();
    275     };
    276     base.requestBool = function() {
    277         var deferred = new $.Deferred();
    278         base.requestText().done(function(value) {
    279             value = $.trim(String(value).toLowerCase());
    280             if ([ "1", "true", "yes", "y", "ok" ].indexOf(value) !== -1) {
    281                 deferred.resolve();
    282             } else {
    283                 deferred.reject();
    284             }
    285         });
    286         return deferred.promise();
    287     };
    288     base.requestPassword = function() {
    289         var deferred = new $.Deferred();
    290         base.$request.addClass("is-password");
    291         instance.output.write("Password:");
    292         base.requestText(true).done(function(value) {
    293             base.$request.removeClass("is-password");
    294             deferred.resolve(value);
    295         });
    296         return deferred.promise();
    297     };
    298     base.set = function(command) {
    299         base.$input.val(command);
    300     };
    301     base.focus = function() {
    302         if (base.$input.is(":visible")) {
    303             base.$input.focus();
    304         } else if (base.$request.is(":visible")) {
    305             base.$request.focus();
    306         }
    307         return base;
    308     };
    309     base.enable = function() {
    310         base.$commandLine.show();
    311         base.focus();
    312         return base;
    313     };
    314     base.disable = function() {
    315         base.$commandLine.hide();
    316         base.$input.val("");
    317         return base;
    318     };
    319     base.enableRequest = function() {
    320         base.$inputRequest.show();
    321         base.focus();
    322         return base;
    323     };
    324     base.disableRequest = function() {
    325         base.$inputRequest.hide();
    326         base.$request.val("");
    327         return base;
    328     };
    329     base.ctrlC = function() {
    330         if (instance.executingCommand.instance) {
    331             instance.executingCommand.instance.terminate();
    332             instance.executingCommand.instance = null;
    333             instance.executingCommand.deferred = null;
    334             instance.output.write("^C", true);
    335         } else {
    336             var value = base.read();
    337             if (value.length) {
    338                 instance.output.write(value, true);
    339                 instance.output.write("^C", true);
    340             }
    341             instance.output.write("", true);
    342         }
    343         base.disableRequest();
    344         base.focus();
    345         return base;
    346     };
    347     base.ctrlU = function() {
    348         base.$input.val("");
    349         return base;
    350     };
    351     return base.__construct();
    352 };
    353 
    354 window.FakeTerminal.filesystem = function(instance) {
    355     var base = this;
    356     base.__construct = function() {
    357         return base;
    358     };
    359     return base.__construct();
    360 };
    361 
    362 window.FakeTerminal.history = function(instance) {
    363     var base = this;
    364     base.counter = 0;
    365     base.items = [];
    366     base.browseIndex = null;
    367     base.__construct = function() {
    368         return base;
    369     };
    370     base.push = function(command) {
    371         base.counter++;
    372         base.items.push({
    373             counter: base.counter,
    374             command: command
    375         });
    376         if (base.items.length > instance.options.history) {
    377             base.items = base.items.slice(base.items.length - instance.options.history);
    378         }
    379     };
    380     base.browse = function(direction) {
    381         if (direction === instance.keymap.UP) {
    382             if (base.browseIndex === null) {
    383                 base.browseIndex = base.items.length;
    384             }
    385             base.browseIndex--;
    386             if (base.browseIndex < 0) {
    387                 base.browseIndex = 0;
    388             }
    389         } else if (direction === instance.keymap.DOWN) {
    390             if (base.browseIndex === null) {
    391                 base.browseIndex = 0;
    392             }
    393             base.browseIndex++;
    394             if (base.browseIndex >= base.items.length) {
    395                 base.browseIndex = base.items.length;
    396             }
    397         }
    398         if (base.items[base.browseIndex]) {
    399             return base.items[base.browseIndex].command;
    400         } else {
    401             return null;
    402         }
    403     };
    404     return base.__construct();
    405 };
    406 
    407 window.FakeTerminal.command = function(instance) {
    408     var base = this;
    409     base.deferred = new $.Deferred();
    410     base.info = function() {
    411         return {
    412             private: true
    413         };
    414     };
    415     base.execute = function() {
    416         base.deferred.resolve();
    417         return base.deferred.promise();
    418     };
    419     base.terminate = function() {
    420         base.deferred.reject();
    421     };
    422 };
    423 
    424 window.FakeTerminal.command.challenge1 = function(instance) {
    425     window.FakeTerminal.command.apply(this, arguments);
    426     const base = this;
    427     base.info = () => {
    428         return {
    429             description: "Enter challenge 1"
    430         };
    431     };
    432     base.execute = () => {
    433         window.location = "/challenge/1";
    434         base.deferred.resolve();
    435         return base.deferred.promise();
    436     };
    437     return base;
    438 };
    439 
    440 window.FakeTerminal.command.challenge2 = function(instance) {
    441     window.FakeTerminal.command.apply(this, arguments);
    442     const base = this;
    443     base.info = () => {
    444         return {
    445             description: "Enter challenge 2"
    446         };
    447     };
    448     base.execute = () => {
    449         window.location = "/challenge/2";
    450         base.deferred.resolve();
    451         return base.deferred.promise();
    452     };
    453     return base;
    454 };
    455 
    456 window.FakeTerminal.command.challenge3 = function(instance) {
    457     window.FakeTerminal.command.apply(this, arguments);
    458     const base = this;
    459     base.info = () => {
    460         return {
    461             description: "Enter challenge 3"
    462         };
    463     };
    464     base.execute = () => {
    465         window.location = "/challenge/3";
    466         base.deferred.resolve();
    467         return base.deferred.promise();
    468     };
    469     return base;
    470 };
    471 
    472 window.FakeTerminal.command.clear = function(instance) {
    473     window.FakeTerminal.command.apply(this, arguments);
    474     const base = this;
    475     base.info = function() {
    476         return {
    477             description: "Clears the screen"
    478         };
    479     };
    480     base.execute = function() {
    481         instance.output.clear();
    482         base.deferred.resolve();
    483         return base.deferred.promise();
    484     };
    485     return base;
    486 };
    487 
    488 window.FakeTerminal.command.echo = function(instance) {
    489     window.FakeTerminal.command.apply(this, arguments);
    490     const base = this;
    491     base.info = function() {
    492         return {
    493             description: "Writes an argument to the standard output"
    494         };
    495     };
    496     base.execute = function() {
    497         const args = $.makeArray(arguments);
    498         let returnVal;
    499         returnVal = args.join(" ");
    500         returnVal = $.trim(returnVal);
    501         returnVal = returnVal.replace(/["']/g, "");
    502         returnVal = returnVal.replace(/["']/g, "");
    503         if (returnVal.length === 0) {
    504             returnVal = " ";
    505         }
    506         instance.output.write(returnVal);
    507         base.deferred.resolve();
    508         return base.deferred.promise();
    509     };
    510     return base;
    511 };
    512 
    513 window.FakeTerminal.command.help = function(instance) {
    514     window.FakeTerminal.command.apply(this, arguments);
    515     const base = this;
    516     base.info = function() {
    517         return {
    518             description: "Displays information about the available commands"
    519         };
    520     };
    521     base.execute = function() {
    522         let returnVal = [];
    523         let commandInfo = {};
    524         if (arguments.length === 0) {
    525             returnVal.push("The following commands are available, run <info>help [command]</info> to find out more.");
    526             returnVal.push(" ");
    527             let commandString = "";
    528             $.each(window.FakeTerminal.command, function(command) {
    529                 const temp = instance.findCommand(command);
    530                 if (!temp) {
    531                     return;
    532                 }
    533                 if (typeof temp.info === "function") {
    534                     commandInfo = temp.info();
    535                     if (typeof commandInfo.private === "boolean" && commandInfo.private === true) {
    536                         return;
    537                     }
    538                 }
    539                 commandString += command + "    ";
    540             });
    541             returnVal.push(commandString);
    542             returnVal.push(" ");
    543         } else {
    544             const command = instance.findCommand(arguments[0]);
    545             if (command) {
    546                 if (typeof command.info === "function") {
    547                     commandInfo = command.info();
    548                     if (typeof commandInfo.description === "string") {
    549                         returnVal = [ " ", arguments[0] + " -- <comment>" + commandInfo.description + "</comment>", " " ];
    550                     } else if (typeof commandInfo.description === "object") {
    551                         returnVal = commandInfo.description;
    552                     }
    553                 }
    554                 if (returnVal.length === 0) {
    555                     returnVal = [ " ", 'No description for "' + command + '"', " " ];
    556                 }
    557             } else {
    558                 returnVal = [ " ", '"' + command + '" is not a valid command', " " ];
    559             }
    560         }
    561         for (let i = 0; i < returnVal.length; i++) {
    562             instance.output.write(returnVal[i]);
    563         }
    564         base.deferred.resolve();
    565         return base.deferred.promise();
    566     };
    567     return base;
    568 };
    569 
    570 window.FakeTerminal.command.history = function(instance) {
    571     window.FakeTerminal.command.apply(this, arguments);
    572     const base = this;
    573     base.info = function() {
    574         return {
    575             description: "Displays the command history, up to " + instance.options.historyLength + " items"
    576         };
    577     };
    578     base.execute = function() {
    579         instance.output.write("  ");
    580         for (var i = 0; i < instance.history.items.length; i++) {
    581             instance.output.write(instance.history.items[i].counter + "  " + instance.history.items[i].command);
    582         }
    583         instance.output.write("  ");
    584         base.deferred.resolve();
    585         return base.deferred.promise();
    586     };
    587     return base;
    588 };
    589 
    590 window.FakeTerminal.command.login = function(instance) {
    591     window.FakeTerminal.command.apply(this, arguments);
    592     const base = this;
    593     base.info = () => {
    594         return {
    595             description: "Login into an existing account"
    596         };
    597     };
    598     base.execute = () => {
    599         let username;
    600         let password;
    601         instance.output.write("Username: ");
    602         instance.input.request("text").done(value => {
    603             username = value;
    604             instance.input.request("password").done(async value => {
    605                 password = value;
    606                 if (await login(username, password)) {
    607                     window.location = "/";
    608                 } else {
    609                     instance.output.write("<comment>Username / password combination is wrong</comment>");
    610                 }
    611                 base.deferred.resolve();
    612             });
    613         }).fail(() => {
    614             instance.output.write("<error>Something went wrong.</error>");
    615             base.deferred.resolve();
    616         });
    617         return base.deferred.promise();
    618     };
    619     return base;
    620 };
    621 
    622 window.FakeTerminal.command.logout = function(instance) {
    623     window.FakeTerminal.command.apply(this, arguments);
    624     const base = this;
    625     base.info = () => {
    626         return {
    627             description: "Logout of the current session"
    628         };
    629     };
    630     base.execute = async () => {
    631         destroyStorage();
    632         if (!await logout()) {
    633             instance.output.write("Could not logout!");
    634         } else {
    635             window.location = "/";
    636         }
    637         base.deferred.resolve();
    638         return base.deferred.promise();
    639     };
    640 };
    641 
    642 window.FakeTerminal.command.ls = function(instance) {
    643     window.FakeTerminal.command.apply(this, arguments);
    644     const base = this;
    645     base.info = () => {
    646         return {
    647             description: "List the files in the current working directory"
    648         };
    649     };
    650     base.execute = () => {
    651         instance.output.write("This is a test");
    652         base.deferred.resolve();
    653         return base.deferred.promise();
    654     };
    655     return base;
    656 };
    657 
    658 window.FakeTerminal.command.register = function(instance) {
    659     window.FakeTerminal.command.apply(this, arguments);
    660     const base = this;
    661     base.info = () => {
    662         return {
    663             description: "Register an account"
    664         };
    665     };
    666     base.execute = () => {
    667         let username;
    668         let password;
    669         instance.output.write("Username: ");
    670         instance.input.request("text").done(value => {
    671             username = value;
    672             instance.input.request("password").done(async value => {
    673                 password = value;
    674                 if (await register(username, password)) {
    675                     instance.output.write(`<comment>User ${username} registered successfully!</comment>`);
    676                 } else {
    677                     instance.output.write("<comment>Could not register, something went wrong</comment>");
    678                 }
    679                 base.deferred.resolve();
    680             });
    681         }).fail(() => {
    682             instance.output.write("<error>Something went wrong.</error>");
    683             base.deferred.resolve();
    684         });
    685         return base.deferred.promise();
    686     };
    687     return base;
    688 };
    689 
    690 window.FakeTerminal.command.user = function(instance) {
    691     window.FakeTerminal.command.apply(this, arguments);
    692     const base = this;
    693     base.info = () => {
    694         return {
    695             description: "Configure your user, in our special GUI"
    696         };
    697     };
    698     base.execute = () => {
    699         window.location = "/userpanel/";
    700         base.deferred.resolve();
    701         return base.deferred.promise();
    702     };
    703     return base;
    704 };
    705 
    706 window.FakeTerminal.command.whoami = function(instance) {
    707     window.FakeTerminal.command.apply(this, arguments);
    708     const base = this;
    709     base.info = function() {
    710         return {
    711             description: "Prints the user's username to standard output"
    712         };
    713     };
    714     base.execute = function() {
    715         instance.output.write(instance.options.username);
    716         base.deferred.resolve();
    717         return base.deferred.promise();
    718     };
    719     return base;
    720 };
    721 
    722 (function($) {
    723     $.fn.faketerminal = function(options) {
    724         return this.each(function() {
    725             $(this).data("instance", new window.FakeTerminal.main(this, options));
    726         });
    727     };
    728 })(jQuery);
    729 //# sourceMappingURL=faketerminal.js.map