diff --git a/blash.css b/blash.css index da09cb0..da4f52e 100644 --- a/blash.css +++ b/blash.css @@ -17,6 +17,16 @@ input.promptInput width : 500px; } +input.password +{ + background-color : black; + border : 0; + color : #888; + font-family : Terminus, courier, monospace, fixed; + font-size : 13px; + width : 500px; +} + div#blashWindow { width : 800px; diff --git a/blash.js b/blash.js index b2d1cce..bc46107 100644 --- a/blash.js +++ b/blash.js @@ -48,6 +48,12 @@ function blash () /** Check if this is the first command given in this session (for fixing
stuff) */ this.__first_cmd = true; + + /** Variable set if the prompt is re-generated automatically after a command was given */ + this.auto_prompt_refresh = true; + + /** Variable set if the focus should be automatically set to the prompt line after a command */ + this.auto_prompt_focus = true; /**************************************/ this.loadCommand = function ( cmd ) @@ -139,48 +145,55 @@ function blash () } } - var value = this.prompt.value; - var out = this.cmdOut.innerHTML; - - var text = ( shell.json.promptText ) ? shell.json.promptText : "[%n@%m %W] $ "; - text = shell.unescapePrompt ( text, shell.json.promptSequences ); - - this.window.removeChild ( this.prompt ); - this.window.removeChild ( this.cmdOut ); - - if ( this.__first_cmd && this.prompt.value.length > 0 ) + if ( this.auto_prompt_refresh ) { - this.window.innerHTML += value + '
' + out + text; - this.__first_cmd = false; - } else { - if ( out ) + var value = this.prompt.value; + var out = this.cmdOut.innerHTML; + + var text = ( shell.json.promptText ) ? shell.json.promptText : "[%n@%m %W] $ "; + text = shell.unescapePrompt ( text, shell.json.promptSequences ); + + this.window.removeChild ( this.prompt ); + this.window.removeChild ( this.cmdOut ); + + if ( this.__first_cmd && this.prompt.value.length > 0 ) { - if ( out.match ( /^\s*\s*/ )) + this.window.innerHTML += value + '
' + out + text; + this.__first_cmd = false; + } else { + if ( out ) { - out = ''; + if ( out.match ( /^\s*\s*/ )) + { + out = ''; + } } + + this.window.innerHTML += value + '
' + out + text; } - this.window.innerHTML += value + '
' + out + text; + this.prompt = document.createElement ( 'input' ); + this.prompt.setAttribute ( 'name', 'blashPrompt' ); + this.prompt.setAttribute ( 'type', 'text' ); + this.prompt.setAttribute ( 'class', 'promptInput' ); + this.prompt.setAttribute ( 'autocomplete', 'off' ); + this.prompt.setAttribute ( 'onkeydown', 'shell.getKey ( event )' ); + this.prompt.setAttribute ( 'onkeyup', 'this.focus()' ); + this.prompt.setAttribute ( 'onblur', 'return false' ); + + this.cmdOut = document.createElement ( 'div' ); + this.cmdOut.setAttribute ( 'id', 'blashCmdOut' ); + this.cmdOut.setAttribute ( 'class', 'blashCmdOut' ); + this.cmdOut.innerHTML = '
'; + + this.window.appendChild ( this.prompt ); + this.window.appendChild ( this.cmdOut ); + + if ( this.auto_prompt_focus ) + { + this.prompt.focus(); + } } - - this.prompt = document.createElement ( 'input' ); - this.prompt.setAttribute ( 'name', 'blashPrompt' ); - this.prompt.setAttribute ( 'type', 'text' ); - this.prompt.setAttribute ( 'class', 'promptInput' ); - this.prompt.setAttribute ( 'autocomplete', 'off' ); - this.prompt.setAttribute ( 'onkeydown', 'shell.getKey ( event )' ); - this.prompt.setAttribute ( 'onkeyup', 'this.focus()' ); - this.prompt.setAttribute ( 'onblur', 'return false' ); - - this.cmdOut = document.createElement ( 'div' ); - this.cmdOut.setAttribute ( 'id', 'blashCmdOut' ); - this.cmdOut.setAttribute ( 'class', 'blashCmdOut' ); - this.cmdOut.innerHTML = '
'; - - this.window.appendChild ( this.prompt ); - this.window.appendChild ( this.cmdOut ); - this.prompt.focus(); } else if ( key == 38 || key == 40 ) { if ( key == 38 ) { @@ -332,18 +345,24 @@ function blash () } } - this.prompt.focus(); - setTimeout ( function() { shell.prompt.focus(); }, 1 ); - - if ( this.prompt.setSelectionRange ) + if ( this.auto_prompt_focus ) { - this.prompt.setSelectionRange ( this.prompt.value.length, this.prompt.value.length ); + this.prompt.focus(); + setTimeout ( function() { shell.prompt.focus(); }, 1 ); + + if ( this.prompt.setSelectionRange ) + { + this.prompt.setSelectionRange ( this.prompt.value.length, this.prompt.value.length ); + } } return false; } - this.prompt.focus(); + if ( this.auto_prompt_focus ) + { + this.prompt.focus(); + } } this.unescapePrompt = function ( prompt, sequences ) @@ -374,6 +393,54 @@ function blash () return prompt; } + /** + * \brief Refresh the shell prompt + * \param clearTerm Set this variable as true if you want also to clear the terminal screen + * \param clearOut Set this variable as true if you want to clear the latest output command + */ + this.refreshPrompt = function ( clearTerm, clearOut ) + { + var value = this.prompt.value; + var out = this.cmdOut.innerHTML; + var text = ( this.json.promptText ) ? this.json.promptText : "[%n@%m %W] $ "; + text = this.unescapePrompt ( text, this.json.promptSequences ); + + this.window.removeChild ( this.prompt ); + this.window.removeChild ( this.cmdOut ); + + if ( clearTerm ) + { + this.window.innerHTML = ''; + } + + if ( !clearOut ) + { + if ( out.length > 0 ) + { + var outDiv = document.createElement ( 'span' ); + outDiv.innerHTML = '
' + out + '
' + text; + this.window.appendChild ( outDiv ); + } + } + + this.prompt = document.createElement ( 'input' ); + this.prompt.setAttribute ( 'name', 'blashPrompt' ); + this.prompt.setAttribute ( 'type', 'text' ); + this.prompt.setAttribute ( 'class', 'promptInput' ); + this.prompt.setAttribute ( 'autocomplete', 'off' ); + this.prompt.setAttribute ( 'onkeydown', 'shell.getKey ( event )' ); + this.prompt.setAttribute ( 'onkeyup', 'this.focus()' ); + this.prompt.setAttribute ( 'onblur', 'return false' ); + + this.cmdOut = document.createElement ( 'div' ); + this.cmdOut.setAttribute ( 'id', 'blashCmdOut' ); + this.cmdOut.setAttribute ( 'class', 'blashCmdOut' ); + + this.window.appendChild ( this.prompt ); + this.window.appendChild ( this.cmdOut ); + this.prompt.focus(); + } + this.unescapePromptSequence = function ( prompt, sequence, text, default_text ) { var re = new RegExp ( "([^\]?)" + sequence, "g" ); diff --git a/blash.json b/blash.json index 327eb11..974ff6c 100644 --- a/blash.json +++ b/blash.json @@ -189,11 +189,13 @@ "cat", "cd", "clear", + "echo", "eval", "find", "ls", "man", "pwd", + "useradd", "whoami", ], } diff --git a/commands/clear.json b/commands/clear.json index c049011..5e9fff6 100644 --- a/commands/clear.json +++ b/commands/clear.json @@ -9,30 +9,7 @@ "action" : function ( arg ) { var out = ''; - var text = ( shell.json.promptText ) ? shell.json.promptText : "[%n@%m %W] $ "; - text = shell.unescapePrompt ( text, shell.json.promptSequences ); - - shell.window.removeChild ( shell.prompt ); - shell.window.removeChild ( shell.cmdOut ); - shell.window.innerHTML = ''; - - shell.prompt = document.createElement ( 'input' ); - shell.prompt.setAttribute ( 'name', 'blashPrompt' ); - shell.prompt.setAttribute ( 'type', 'text' ); - shell.prompt.setAttribute ( 'class', 'promptInput' ); - shell.prompt.setAttribute ( 'autocomplete', 'off' ); - shell.prompt.setAttribute ( 'onkeydown', 'shell.getKey ( event )' ); - shell.prompt.setAttribute ( 'onkeyup', 'this.focus()' ); - shell.prompt.setAttribute ( 'onblur', 'return false' ); - - shell.cmdOut = document.createElement ( 'div' ); - shell.cmdOut.setAttribute ( 'id', 'blashCmdOut' ); - shell.cmdOut.setAttribute ( 'class', 'blashCmdOut' ); - - shell.window.appendChild ( shell.prompt ); - shell.window.appendChild ( shell.cmdOut ); - shell.prompt.focus(); - + shell.refreshPrompt ( true ); return out; }, } diff --git a/commands/echo.json b/commands/echo.json new file mode 100644 index 0000000..2acfa33 --- /dev/null +++ b/commands/echo.json @@ -0,0 +1,15 @@ +{ + "name" : "echo", + + "info" : { + "syntax" : "echo [text]", + "brief" : "Display a line of text", + }, + + "action" : function ( arg ) + { + var out = arg + "
\n"; + return out; + }, +} + diff --git a/commands/useradd.json b/commands/useradd.json new file mode 100644 index 0000000..c1dc323 --- /dev/null +++ b/commands/useradd.json @@ -0,0 +1,113 @@ +{ + "name" : "useradd", + + "info" : { + "syntax" : "useradd <username>", + "brief" : "Create a new user on the system", + }, + + "password" : '', + "repeatPassword" : '', + + "keyPassword" : function ( e ) + { + var evt = ( window.event ) ? window.event : e; + var key = ( evt.charCode ) ? evt.charCode : evt.keyCode; + var password = document.getElementsByName ( "password" )[0]; + var repeatPassword = document.getElementsByName ( "repeatPassword" )[0]; + var repeatPasswordText = document.getElementById ( "repeatPasswordText" ); + + if ( key == 13 && password.value.length > 0 ) + { + repeatPassword.style.visibility = 'visible'; + repeatPasswordText.style.visibility = 'visible'; + repeatPassword.focus(); + } + }, + + "keyRepeatPassword" : function ( e ) + { + var evt = ( window.event ) ? window.event : e; + var key = ( evt.charCode ) ? evt.charCode : evt.keyCode; + var password = document.getElementsByName ( "password" )[0]; + var repeatPassword = document.getElementsByName ( "repeatPassword" )[0]; + var repeatPasswordText = document.getElementById ( "repeatPasswordText" ); + + if ( key == 13 && password.value.length > 0 ) + { + if ( password.value != repeatPassword.value ) + { + shell.cmdOut.innerHTML = 'The passwords do not match'; + } else { + var users_php = window.location.href; + users_php = users_php.replace ( /\/([a-zA-Z\.]+)$/, '/modules/users/users.php' ); + params = 'action=add&user=' + escape ( shell.newuser ) + '&pass=' + md5 ( password.value ); + + var http = new XMLHttpRequest(); + http.open ( "POST", users_php, true ); + http.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + http.setRequestHeader("Content-length", params.length); + http.setRequestHeader("Connection", "close"); + + http.onreadystatechange = function () + { + if ( http.readyState == 4 && http.status == 200 ) + { + if ( http.responseText.length > 0 ) + { + shell.cmdOut.innerHTML = http.responseText; + } else { + shell.cmdOut.innerHTML = ''; + } + + shell.refreshPrompt ( false, false ); + } + } + + http.send ( params ); + shell.cmdOut.innerHTML = ''; + } + + shell.auto_prompt_focus = true; + shell.auto_prompt_refresh = true; + shell.refreshPrompt ( false, false ); + } + }, + + "action" : function ( arg ) + { + var out = ''; + + if ( !arg || arg.length == 0 ) + { + return "Usage: " + this.name + " <username>
\n"; + } + + shell.keyPassword = this.keyPassword; + shell.keyRepeatPassword = this.keyRepeatPassword; + shell.newuser = arg; + + if ( shell.__first_cmd ) + { + shell.cmdOut.innerHTML = '
'; + shell.__first_cmd = false; + } + + shell.cmdOut.innerHTML += 'Password: ' + + '
' + + '
'; + + shell.auto_prompt_focus = false; + shell.auto_prompt_refresh = false; + + this.password = document.getElementsByName ( "password" )[0]; + this.password.focus(); + + return out; + }, +} + diff --git a/index.html b/index.html index aad07ae..5c6f0b4 100644 --- a/index.html +++ b/index.html @@ -2,6 +2,7 @@ Blash - An AJAX interactive shell emulator for web browsing + diff --git a/md5.js b/md5.js new file mode 100644 index 0000000..e09c081 --- /dev/null +++ b/md5.js @@ -0,0 +1,209 @@ +/** +* +* MD5 (Message-Digest Algorithm) +* http://www.webtoolkit.info/ +* +**/ + +function md5 (string) +{ + + function RotateLeft(lValue, iShiftBits) { + return (lValue<>>(32-iShiftBits)); + } + + function AddUnsigned(lX,lY) { + var lX4,lY4,lX8,lY8,lResult; + lX8 = (lX & 0x80000000); + lY8 = (lY & 0x80000000); + lX4 = (lX & 0x40000000); + lY4 = (lY & 0x40000000); + lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF); + if (lX4 & lY4) { + return (lResult ^ 0x80000000 ^ lX8 ^ lY8); + } + if (lX4 | lY4) { + if (lResult & 0x40000000) { + return (lResult ^ 0xC0000000 ^ lX8 ^ lY8); + } else { + return (lResult ^ 0x40000000 ^ lX8 ^ lY8); + } + } else { + return (lResult ^ lX8 ^ lY8); + } + } + + function F(x,y,z) { return (x & y) | ((~x) & z); } + function G(x,y,z) { return (x & z) | (y & (~z)); } + function H(x,y,z) { return (x ^ y ^ z); } + function I(x,y,z) { return (y ^ (x | (~z))); } + + function FF(a,b,c,d,x,s,ac) { + a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac)); + return AddUnsigned(RotateLeft(a, s), b); + }; + + function GG(a,b,c,d,x,s,ac) { + a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac)); + return AddUnsigned(RotateLeft(a, s), b); + }; + + function HH(a,b,c,d,x,s,ac) { + a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac)); + return AddUnsigned(RotateLeft(a, s), b); + }; + + function II(a,b,c,d,x,s,ac) { + a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac)); + return AddUnsigned(RotateLeft(a, s), b); + }; + + function ConvertToWordArray(string) { + var lWordCount; + var lMessageLength = string.length; + var lNumberOfWords_temp1=lMessageLength + 8; + var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64; + var lNumberOfWords = (lNumberOfWords_temp2+1)*16; + var lWordArray=Array(lNumberOfWords-1); + var lBytePosition = 0; + var lByteCount = 0; + while ( lByteCount < lMessageLength ) { + lWordCount = (lByteCount-(lByteCount % 4))/4; + lBytePosition = (lByteCount % 4)*8; + lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount)<>>29; + return lWordArray; + }; + + function WordToHex(lValue) { + var WordToHexValue="",WordToHexValue_temp="",lByte,lCount; + for (lCount = 0;lCount<=3;lCount++) { + lByte = (lValue>>>(lCount*8)) & 255; + WordToHexValue_temp = "0" + lByte.toString(16); + WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length-2,2); + } + return WordToHexValue; + }; + + function Utf8Encode(string) { + string = string.replace(/\r\n/g,"\n"); + var utftext = ""; + + for (var n = 0; n < string.length; n++) { + + var c = string.charCodeAt(n); + + if (c < 128) { + utftext += String.fromCharCode(c); + } + else if((c > 127) && (c < 2048)) { + utftext += String.fromCharCode((c >> 6) | 192); + utftext += String.fromCharCode((c & 63) | 128); + } + else { + utftext += String.fromCharCode((c >> 12) | 224); + utftext += String.fromCharCode(((c >> 6) & 63) | 128); + utftext += String.fromCharCode((c & 63) | 128); + } + + } + + return utftext; + }; + + var x=Array(); + var k,AA,BB,CC,DD,a,b,c,d; + var S11=7, S12=12, S13=17, S14=22; + var S21=5, S22=9 , S23=14, S24=20; + var S31=4, S32=11, S33=16, S34=23; + var S41=6, S42=10, S43=15, S44=21; + + string = Utf8Encode(string); + + x = ConvertToWordArray(string); + + a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476; + + for (k=0;k + + + +XML; + +?> diff --git a/modules/users/users.php b/modules/users/users.php new file mode 100644 index 0000000..e381134 --- /dev/null +++ b/modules/users/users.php @@ -0,0 +1,68 @@ +user ); $i++ ) + { + if ( !strcasecmp ( $xml->user[$i]['name'], $username )) + { + print "The specified user already exists\n"; + return 1; + } + } + + $newuser = $xml->addChild ( 'user' ); + $newuser->addAttribute ( 'name', $username ); + $newuser->addAttribute ( 'pass', $password ); + $newuser->addAttribute ( 'home', '/home/' . $username ); + + if ( !( $fp = fopen ( 'userlist.php', 'w' ))) + { + print "Unable to add the specified user, unknown error\n"; + return 1; + } + + fwrite ( $fp, "asXML() . "\nXML;\n\n?>\n" ); + fclose ( $fp ); + + print 'User "'.$username.' successfully added, home directory set to "/home/'.$username."\"\n"; + break; +} + +?> +