/* * Copyright (c) 2006-2015 Wade Alcorn - wade@bindshell.net * Browser Exploitation Framework (BeEF) - http://beefproject.com * See the file 'doc/COPYING' for copying permission */ /** * @Author : venkatakrishnan ganesh * @file : wterm.jquery.js * @url : http://wterminal.appspot.com * @desc : * * Allows Emulation of Terminal on the browser. * Completely Extendible. * Command History. * Commandline Editing. * * Modified by antisnatchor (also to prevent XSS, see line 270) * */ ( function( $ ) { var VERSION = '0.0.4'; /** * * @function : get_defaults * @returns : Object * @desc : Returns Global Defaults * * */ var get_defaults = function() { return { // PS1 : The Primary Prompt PS1 : 'BeEF-bind-$', // TERMINAL_CLASS // Will be applied to the primary terminal container TERMINAL_CLASS : 'wterm_terminal', // PROMPT_CLASS // Will Applied to prompt container PROMPT_CLASS : 'wterm_prompt', // THEME_CLASS_PREFIX // All Theme Classes will be prefixed by this string THEME_CLASS_PREFIX : 'wterm_theme', // DEFAULT_THEME // The theme that is applied by default DEFAULT_THEME : '_green_on_black', // HIGHLIGHT_CLASS // The Class that is applied to highlighted text HIGHLIGHT_CLASS : 'wterm_highlight', // KEYWORD_CLASS // The Class that is applied to keywords KEYWORD_CLASS : 'wterm_keyword', // CONTENT_CLASS // The Class that is applied to content section KEYWORD_CLASS : 'wterm_content', // WIDTH | HIGHT // Explicitly set width and height of the terminal // container. This may also be done in TERMINAL_CLASS WIDTH : '90%', HEIGHT : '90%', // WELCOME_MESSAGE // Message to be shown when the terminal is first // published WELCOME_MESSAGE : 'Welcome to Wterm version-' + VERSION , // NOT_FOUND // Message to be published if the command is not found // Note: "CMD" will be replaced with the actual command NOT_FOUND : '
CMD: Command Not Found
', // AUTOCOMPLETE // Is Autocomplete feature Enabled // Please see the manual on how AUTOCOMPLETE is implemented AUTOCOMPLETE : true, // HISTORY // Is Command History Enabled HISTORY : true, // HISTORY // No of entries to be stored in HISTORY HISTORY_ENTRIES : 100, // AJAX_METHOD // The HTTP Method that must be used for Ajax Requests AJAX_METHOD : 'GET', // AJAX_PARAMETER // The GET/POST parameter that should be used to make requests AJAX_PARAM : 'tokens', // ERROR_PREFIX // Prefix For Error Messages ERROR_PREFIX : 'An Error Occured: ' }; }; /** * @property : dispatch * @accessor : $.register_command ( See Below ) * @private * @desc : * * dispatch table stores command name and action * to be taken when user enters a command. See * Manual for more details on how to implement * your own commands * **/ var dispatch = { }; /** * * @method : wterm * @public * @desc : Sets up the terminal on the JQ object that * represents a ( or a group ) of HTML NODE (s) * **/ $.fn.wterm = function( options ) { // Merge defaults with options var settings = get_defaults(); $.extend( true, settings, options ); // JQ Plugin surprised?? return this.each( function() { var element = $( this ); var history = [ ]; var hcurrent = null; // Set up some markup in the element // required for terminal emulation element.addClass( settings.TERMINAL_CLASS ).addClass( settings.THEME_CLASS_PREFIX + settings.DEFAULT_THEME ); if( settings.WIDTH && settings.HEIGHT ) element.css( { width: settings.WIDTH, height: settings.HEIGHT } ) element.html( '' ).append( '
' + settings.WELCOME_MESSAGE + '
' ); element.append( '
' ); element.append( '
' + settings.PS1 + ' ' + '
' ); // Representing prompt, form, input and content section // in the terminal var _prompt = element.find( 'div:last span:last' ); var input_form = element.find( 'div:last form' ); var input = element.find( 'div:last form input' ); var content = element.find( '.' + settings.CONTENT_CLASS ); // Custom Dispatcher var cdispatch = null; // Temprary storage for autocomplete configuration var ac_save = null; // Temporary store for current prompt var cprompt = null; // Curson always needs to be on the prompt input.focus(); element.click( function() { input.focus(); } ); /** * @method : hide * @private : * @desc : Hides the prompt **/ var hide = function() { _prompt.hide(); }; /** * @method : show * @private : * @desc : Shows the prompt **/ var show = function() { _prompt.show(); input.focus(); }; /** * @method : update_content * @private : * @desc : Updates the content section * @args : current_prompt, command, data **/ var update_content = function( p, cmd, data ) { content.append( '
' + p + ' ' + cmd + '
' + ( ( data ) ? data : '' ) + '
' ); }; /** * @method : clear_content * @private : * @desc : Updates the content section * @args : current_prompt, command, data **/ var clear_content = function() { content.html( '' ); }; // Add the command to the dispatch dispatch.clear = clear_content; /** * @method : set_prompt * @private : * @desc : Set the current prompt * @args : string **/ set_prompt = function( p ) { if( p && p.length ) element.find( '.' + settings.PROMPT_CLASS).html( p + ' ' ); }; /** * * @method : Anonymous * @private : * @event_handler * **/ input_form.submit( function( e ) { e.preventDefault(); e.stopPropagation(); var value = input.attr( 'value' ); if( settings.HISTORY ) { if( history.length > settings.HISTORY_ENTRIES ) history.shift(); history.push( value ); } // Reset The Input input.attr( 'value', '' ); var tokens = value.split( /\s+/ ); var key = tokens[0]; hide(); var get_current_prompt = function() { return ( cprompt ) ? cprompt : settings.PS1; } var _dispatch = function( key, tokens ) { if( typeof key === 'function' ) { data = key( tokens ); /* * antisnatchor: preventing XSS */ if( data ) { update_content( get_current_prompt(), $jEncoder.encoder.encodeForJavascript(value), data)} } else if( typeof key === 'string' ) { var to_send = { }; to_send[ settings.AJAX_PARAM ] = tokens.join( ' ' ); var on_complete = function( data, text_status ) { update_content( get_current_prompt(), value, data ) }; $[ settings.AJAX_METHOD.toLowerCase() ]( key, to_send, on_complete ); } }; if( key == '' ) { update_content( get_current_prompt() , '' ) } else if( cdispatch && key == 'exit' ) { // Recover old configuration and Dispatch exit hook settings.AUTOCOMPLETE = ( ac_save ) ? ac_save : false ; // Todo: test what happens when exit hook is not defined if( cdispatch.EXIT_HOOK ) { _dispatch( cdispatch.EXIT_HOOK, tokens ); } else { _dispatch( function() { return '' }, tokens ); } // Clear temporary values cdispatch = null; cprompt = null; // Reset the prompt set_prompt( settings.PS1 ); } else if( cdispatch ) { // Dispatch to the custom dispatcher _dispatch( cdispatch.DISPATCH, tokens ); } else if( dispatch[ key ] ) { if( typeof dispatch[ key ] === 'object' ) { cdispatch = dispatch[ key ]; cprompt = cdispatch.PS1 || key; set_prompt( cprompt ); ac_save = settings.AUTOCOMPLETE; settings.AUTOCOMPLETE = false; // Todo:See what happens if start hook is not defined if( cdispatch.START_HOOK ) { _dispatch( cdispatch.START_HOOK, tokens ); } else { // A stupid Hack _dispatch( function() { return '' }, tokens ); } } else { _dispatch( dispatch[ key ], tokens ); } } else { update_content( settings.PS1, value, settings.NOT_FOUND.replace( 'CMD', tokens[0] )); } show(); } ); /** * * @method : Anonymous * @private : * @event_handler * **/ input.keydown( function( e ) { var keycode = e.keyCode; switch( keycode ) { case 9: e.preventDefault(); if( settings.AUTOCOMPLETE ) { var commands = [ ]; var current_value = input.attr( 'value' ); // Command Completion if( current_value.match( /^[^\s]{0,}$/ ) ) { for( i in dispatch ) { if( current_value == '' ) { commands.push( i ); } else if( i.indexOf( current_value ) == 0 ) { commands.push( i ); } } if( commands.length > 1 ) { update_content( settings.PS1, current_value, commands.join( '
' ) ); } else if( commands.length == 1 ) { input.attr( 'value', commands.pop() + ' ' ); } } } break; // History Up case 38: e.preventDefault(); if( settings.HISTORY ) { hcurrent = ( hcurrent === null )? history.length - 1 : ( hcurrent == 0 ) ? history.length - 1 : hcurrent - 1; input.attr( 'value', history[ hcurrent ] ); } break; // History Down case 40: e.preventDefault(); if( settings.HISTORY ) { if( hcurrent === null || hcurrent == (history.length - 1 ) ) break; hcurrent++; input.attr( 'value', history[ hcurrent ] ); } break; default: break; } }); }); }; $.register_command = function( command, dispatch_method ) { try { if( typeof dispatch_method === 'function' || typeof dispatch_method === 'string' || typeof dispatch_method === 'object' ) { dispatch[ command ] = dispatch_method; } else { throw 'Dispatch needs to be a method'; } } catch ( e ) { // Error Handling here } }; })( jQuery ); var $jwterm = jQuery.noConflict();