From aa1efd1c73f6d26802e85555611165ea35ac1dd4 Mon Sep 17 00:00:00 2001 From: antisnatchor Date: Mon, 22 Oct 2012 16:09:34 +1100 Subject: [PATCH] Added new IPEC admin_ui tab. This includes the new Wterm-based interactive shell to communicate with the BeEF_bind shellcode. --- .../admin_ui/controllers/panel/index.html | 7 +- extensions/admin_ui/media/css/wterm.css | 28 ++ .../media/javascript/ui/panel/ZombieTab.js | 8 +- .../javascript/ui/panel/tabs/ZombieTabIpec.js | 357 +++++++++++++++ .../media/javascript/wterm/wterm.jquery.js | 415 ++++++++++++++++++ 5 files changed, 811 insertions(+), 4 deletions(-) create mode 100644 extensions/admin_ui/media/css/wterm.css create mode 100644 extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabIpec.js create mode 100644 extensions/admin_ui/media/javascript/wterm/wterm.jquery.js diff --git a/extensions/admin_ui/controllers/panel/index.html b/extensions/admin_ui/controllers/panel/index.html index 31c92c23c..c49b0c3d5 100644 --- a/extensions/admin_ui/controllers/panel/index.html +++ b/extensions/admin_ui/controllers/panel/index.html @@ -28,7 +28,12 @@ <%= script_tag 'ui/panel/tabs/ZombieTabRider.js' %> <%= script_tag 'ui/panel/tabs/ZombieTabXssRays.js' %> - <%= script_tag 'ui/panel/PanelViewer.js' %> + <%= script_tag 'wterm/wterm.jquery.js' %> + <%= stylesheet_tag 'wterm.css' %> + + <%= script_tag 'ui/panel/tabs/ZombieTabIpec.js' %> + + <%= script_tag 'ui/panel/PanelViewer.js' %> <%= script_tag 'ui/panel/DataGrid.js' %> <%= script_tag 'ui/panel/MainPanel.js' %> <%= script_tag 'ui/panel/ZombieTab.js' %> diff --git a/extensions/admin_ui/media/css/wterm.css b/extensions/admin_ui/media/css/wterm.css new file mode 100644 index 000000000..064e8cd41 --- /dev/null +++ b/extensions/admin_ui/media/css/wterm.css @@ -0,0 +1,28 @@ +/* + * Copyright 2012 Wade Alcorn wade@bindshell.net + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* Basic Terminal CSS */ +.wterm_terminal { background: #000; color: #fff; font-size: 1em; font-family: monospace; padding: 3px; width: 100%; height: 100%; display: block; overflow-x: none; overflow-y: auto; } + +/* TODO: Input Box Width is faulty */ +.wterm_terminal input { background: transparent; border: 0; color: #fff; width: 100%; font-size: 1em; font-family: monospace; outline: none; } +.wterm_terminal div:first { margin-bottom: 1em; } +.wterm_terminal .wterm_prompt { float: left; clear: left; } +.wterm_terminal form { float: left; margin: 0px; width: 75%; } + +/* Themes */ +.wterm_theme_green_on_black { background: #000; color: #0f0; } +.wterm_theme_green_on_black input { background: transparent; border: 0; color: #0f0; } + diff --git a/extensions/admin_ui/media/javascript/ui/panel/ZombieTab.js b/extensions/admin_ui/media/javascript/ui/panel/ZombieTab.js index cea031726..3e8466e55 100644 --- a/extensions/admin_ui/media/javascript/ui/panel/ZombieTab.js +++ b/extensions/admin_ui/media/javascript/ui/panel/ZombieTab.js @@ -20,8 +20,10 @@ ZombieTab = function(zombie) { commands_tab = new ZombieTab_Commands(zombie); requester_tab = new ZombieTab_Requester(zombie); xssrays_tab = new ZombieTab_XssRaysTab(zombie); - - ZombieTab.superclass.constructor.call(this, { + ipec_tab = new ZombieTab_IpecTab(zombie); + + + ZombieTab.superclass.constructor.call(this, { id:"current-browser", activeTab: 0, loadMask: {msg:'Loading browser...'}, @@ -32,7 +34,7 @@ ZombieTab = function(zombie) { forceFit: true, type: 'fit' }, - items:[main_tab, log_tab, commands_tab, requester_tab, xssrays_tab] + items:[main_tab, log_tab, commands_tab, requester_tab, xssrays_tab, ipec_tab] }); }; diff --git a/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabIpec.js b/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabIpec.js new file mode 100644 index 000000000..ca4dbb325 --- /dev/null +++ b/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabIpec.js @@ -0,0 +1,357 @@ +// +// Copyright 2012 Wade Alcorn wade@bindshell.net +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +/* + * The Ipec Tab panel for the selected zombie. + */ + +ZombieTab_IpecTab = function(zombie) { + + var commands_statusbar = new Beef_StatusBar('ipec-bbar-zombie-'+zombie.session); + + var req_pagesize = 30; + + var ipec_config_panel = new Ext.Panel({ + id: 'ipec-config-zombie-'+zombie.session, + title: 'Scan Config', + layout: 'fit', + autoscroll: true + }); + + function get_rest_token(){ + var token = ""; + var url = "/ui/modules/getRestfulApiToken.json"; + $jwterm.ajax({ + contentType: 'application/json', + dataType: 'json', + type: 'GET', + url: url, + async: false, + processData: false, + success: function(data){ + token = data.token; + console.log(token); + }, + error: function(){ + console.log("Error getting RESTful API token"); + } + }); + return token; + } + + function get_module_id(name, token){ + var id = ""; + var url = "/api/modules/search/" + name + "?token=" + token; + $jwterm.ajax({ + contentType: 'application/json', + dataType: 'json', + type: 'GET', + url: url, + async: false, + processData: false, + success: function(data){ + id = data.id; + }, + error: function(){ + console.log("Error getting module id."); + } + }); + return id; + } + + + function escape_html(str) { + str = str.toString(); + str = str.replace(//g, '>'); +// str = str.replace(/\u0022/g, '"'); + str = str.replace(/\u0027/g, '''); + str = str.replace(/\"\"/g, ''); + str = str.replace(/\\r/g, ''); + str = str.replace(/\\n/g, '
'); + str = str.replace(/\\\\/g, '\\'); + str = str.replace(/\\t/g, '    '); +// str = str.replace(/\\/g, '\'); + return str; + } + + + function initTerminal(zombie){ + String.prototype.reverse = function() { + return this.split('').reverse().join(''); + }; + + $jwterm( document ).ready( function() { + $jwterm('#wterm').wterm( { WIDTH: '100%', HEIGHT: '100%', WELCOME_MESSAGE: 'Welcome to BeEF Bind interactive shell. To Begin Using type \'help\'' }); + }); + + var target_ip = ""; + var target_port = ""; + + var command_directory = { + 'eval': function( tokens ) { + tokens.shift(); + var expression = tokens.join( ' ' ); + var result = ''; + try { + result = eval( expression ); + } catch( e ) { + result = 'Error: ' + e.message; + } + return result; + }, + + 'date': function( tokens ) { + var now = new Date(); + return now.getDate() + '-' + + now.getMonth() + '-' + + ( 1900 + now.getYear() ) + }, + + 'cap': function( tokens ) { + tokens.shift(); + return tokens.join( ' ' ).toUpperCase(); + }, + + 'go': function( tokens ) { + var url = tokens[1]; + document.location.href = url; + }, + + 'target': function(tokens){ + target_ip = tokens[1]; + target_port = tokens[2]; + return "Target is now " + tokens[1] + ":" + tokens[2]; + }, + + + 'exec': function(tokens){ + if(target_ip.length == 0 || target_port.length == 0) + return "Error: target ip or port not set." + + tokens.shift(); //remove the first element (exec) + var cmd = tokens.join(' '); //needed in case of commands with options + cmd = cmd.replace(/\\/g, '\\\\'); //needed to prevent JS errors (\ need to be escaped) + + var token = get_rest_token(); + var mod_id = get_module_id("BeEF_bind_shell", token); + + var uri = "/api/modules/" + zombie.session + "/" + mod_id + "?token=" + token; + + var result = null; + + $jwterm.ajax({ + contentType: 'application/json', + data: JSON.stringify({"rhost":target_ip, "rport":target_port, "path":"/", "cmd":cmd}), + dataType: 'json', + type: 'POST', + url: uri, + async: false, + processData: false, + success: function(data){ + console.log("data: " + data.command_id); + result = "Command [" + data.command_id + "] sent successfully"; + }, + error: function(){ + console.log("Error sending command"); + return "Error sending command"; + } + }); + + return result; + }, + + 'get': function(tokens){ + var command_id = tokens[1]; + + if(command_id != null){ + + var token = get_rest_token(); + var mod_id = get_module_id("BeEF_bind_shell", token); + + var uri_results = "/api/modules/" + zombie.session + "/" + mod_id + "/" + + command_id + "?token=" + token; + var results = ""; + $jwterm.ajax({ + contentType: 'application/json', + dataType: 'json', + type: 'GET', + url: uri_results, + async: false, + processData: false, + success: function(data){ + $jwterm.each(data, function(i){ + console.log("result [" + i +"]: " + $jwterm.parseJSON(data[i].data).data); + results += $jwterm.parseJSON(data[i].data).data; + }); + + }, + error: function(){ + console.log("Error sending command"); + return "Error sending command"; + } + }); + results = escape_html(results); + if(results.charAt(0) == '"' && results.charAt(results.length-1) == '"') + results = results.slice(1,results.length-1); + + return results; + } + }, + + 'strrev': { + PS1: 'strrev $', + + EXIT_HOOK: function() { + return 'exit interface commands'; + }, + + START_HOOK: function() { + return 'exit interface commands'; + }, + + DISPATCH: function( tokens ) { + return tokens.join('').reverse(); + } + } + }; + + for( var j in command_directory ) { + $jwterm.register_command( j, command_directory[j] ); + } + + $jwterm.register_command( 'help', function() { + return 'target - Usage: target <IP> <port> - Send commands to the specified IP:port
' + + 'exec - Usage exec <command> <command options> - Exec a command, returns the command id.
' + + 'get - Usage get <command id> - Retrieve command results given a specified command id.
' + + }); + }; + + + var ipec_terminal_panel = new Ext.Panel({ + id: 'ipec-terminal-zombie-'+zombie.session, + title: 'Terminal', + layout: 'fit', + padding: '1 1 1 1', + autoScroll: true, + html: "
", + listeners: { + afterrender : function(){ + initTerminal(zombie); + } + } + + }); + + var ipec_logs_store = new Ext.ux.data.PagingJsonStore({ + storeId: 'ipec-logs-store-zombie-' + zombie.session, + url: '/ui/ipec/zombie.json', + remoteSort: false, + autoDestroy: true, + autoLoad: false, + root: 'logs', + + fields: ['id', 'vector_method', 'vector_name', 'vector_poc'], + sortInfo: {field: 'id', direction: 'DESC'}, + + baseParams: { + nonce: Ext.get("nonce").dom.value, + zombie_session: zombie.session + } + }); + + var ipec_logs_bbar = new Ext.PagingToolbar({ + pageSize: req_pagesize, + store: ipec_logs_store, + displayInfo: true, + displayMsg: 'Displaying history {0} - {1} of {2}', + emptyMsg: 'No history to display' + }); + + var ipec_logs_grid = new Ext.grid.GridPanel({ + id: 'ipec-logs-grid-zombie-' + zombie.session, + store: ipec_logs_store, + bbar: ipec_logs_bbar, + border: false, + loadMask: {msg:'Loading History...'}, + + viewConfig: { + forceFit:true + }, + + view: new Ext.grid.GridView({ + forceFit: true, + emptyText: "No History", + enableRowBody:true + }), + + columns: [ + {header: 'Id', width: 10, sortable: true, dataIndex: 'id', hidden:true}, + {header: 'Vector Method', width: 30, sortable: true, dataIndex: 'vector_method', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, + {header: 'Vector Name', width: 40, sortable: true, dataIndex: 'vector_name', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}}, + {header: 'Vector PoC', sortable: true, dataIndex: 'vector_poc', renderer: function(value){return $jEncoder.encoder.encodeForHTML(value)}} + ], + + listeners: { + afterrender: function(datagrid) { + datagrid.store.reload({params:{start:0,limit:req_pagesize, sort: "date", dir:"DESC"}}); + } + } + }); + + var ipec_logs_panel = new Ext.Panel({ + id: 'ipec-logs-panel-zombie-'+zombie.session, + title: 'Logs', + items:[ipec_logs_grid], + layout: 'fit', + + listeners: { + activate: function(ipec_logs_panel) { + ipec_logs_panel.items.items[0].store.reload(); + } + } + }); + + function genScanSettingsPanel(zombie, bar, value) { + + panel = Ext.getCmp('ipec-config-zombie-'+zombie.session); + panel.setTitle('Prompt'); + panel.add(ipec_terminal_panel); +// panel.add(form); + } + + ZombieTab_IpecTab.superclass.constructor.call(this, { + id: 'ipec-log-tab-'+zombie.session, + title: 'Ipec', + activeTab: 0, + viewConfig: { + forceFit: true, + type: 'fit', + autoScroll:true + }, + items: [ipec_config_panel], + bbar: commands_statusbar, + listeners: { + afterrender : function(){ + genScanSettingsPanel(zombie, commands_statusbar); + }, + autoScroll:true + + } + }); +}; + +Ext.extend(ZombieTab_IpecTab, Ext.TabPanel, {} ); \ No newline at end of file diff --git a/extensions/admin_ui/media/javascript/wterm/wterm.jquery.js b/extensions/admin_ui/media/javascript/wterm/wterm.jquery.js new file mode 100644 index 000000000..11262b0d1 --- /dev/null +++ b/extensions/admin_ui/media/javascript/wterm/wterm.jquery.js @@ -0,0 +1,415 @@ +/** + * @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 + * */ + +( 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 ); + if( data ) { update_content( get_current_prompt(), 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 );