diff --git a/extensions/admin_ui/api/handler.rb b/extensions/admin_ui/api/handler.rb index 310f96630..4fa031267 100644 --- a/extensions/admin_ui/api/handler.rb +++ b/extensions/admin_ui/api/handler.rb @@ -33,7 +33,7 @@ module API #NOTE: order counts! make sure you know what you're doing if you add files esapi = %w(esapi/Class.create.js esapi/jquery-1.6.4.min.js esapi/jquery-encoder-0.1.0.js) ux = %w(ui/common/beef_common.js ux/PagingStore.js ux/StatusBar.js ux/TabCloseMenu.js) - panel = %w(ui/panel/common.js ui/panel/DistributedEngine.js ui/panel/PanelStatusBar.js ui/panel/tabs/ZombieTabDetails.js ui/panel/tabs/ZombieTabLogs.js ui/panel/tabs/ZombieTabCommands.js ui/panel/tabs/ZombieTabRider.js ui/panel/tabs/ZombieTabXssRays.js wterm/wterm.jquery.js ui/panel/tabs/ZombieTabIpec.js ui/panel/tabs/ZombieTabAutorun.js ui/panel/PanelViewer.js ui/panel/DataGrid.js ui/panel/MainPanel.js ui/panel/ZombieTab.js ui/panel/ZombieTabs.js ui/panel/zombiesTreeList.js ui/panel/ZombiesMgr.js ui/panel/Logout.js ui/panel/WelcomeTab.js) + panel = %w(ui/panel/common.js ui/panel/DistributedEngine.js ui/panel/PanelStatusBar.js ui/panel/tabs/ZombieTabDetails.js ui/panel/tabs/ZombieTabLogs.js ui/panel/tabs/ZombieTabCommands.js ui/panel/tabs/ZombieTabRider.js ui/panel/tabs/ZombieTabXssRays.js wterm/wterm.jquery.js ui/panel/tabs/ZombieTabIpec.js ui/panel/tabs/ZombieTabAutorun.js ui/panel/PanelViewer.js ui/panel/DataGrid.js ui/panel/MainPanel.js ui/panel/ZombieTab.js ui/panel/ZombieTabs.js ui/panel/zombiesTreeList.js ui/panel/ZombiesMgr.js ui/panel/Logout.js ui/panel/WelcomeTab.js ui/panel/ModuleSearching.js) global_js = esapi + ux + panel diff --git a/extensions/admin_ui/media/javascript/ui/panel/ModuleSearching.js b/extensions/admin_ui/media/javascript/ui/panel/ModuleSearching.js new file mode 100644 index 000000000..ffdbe12e1 --- /dev/null +++ b/extensions/admin_ui/media/javascript/ui/panel/ModuleSearching.js @@ -0,0 +1,64 @@ +/* + * Keyword search for command module panel. + * Words in query are searched as separated queries. You can search for exact matching using double qoutes arround query + */ + +function search_module(module_tree, query_string) { + if ( query_string.search(/\w/) == -1 ) + return tree_array; + + // copy module tree w/o ExtJS service properties + var tree_array = new Array(); + for ( var i = 0; i < module_tree.length; i++ ) + tree_array.push(module_tree[i].attributes); + + var json_object = jQuery.extend(true, [], tree_array); + + // split query string into separate words and exact phrases + query_string = query_string.replace(/"\s*"/g, " ").replace(/\s+/g, " ").match(/"[^"]+"|\S+/g); + query_string.forEach(prepare_query_string); + + var result = json_object.filter(form_new_modules_tree); + result.forEach(recount_modules_and_expand_directories); + + return result; + + // remove quotes from phrases for exact match + function prepare_query_string(string, index, array){ + array[index] = string.toLowerCase().replace(/"/g, ""); + } + + // True if this.toString() contains str + function check_module_name(str) { + return Boolean(this.toString().toLowerCase().replace(/\s\([0-9]+\)/g,"").indexOf(str) + 1); + } + + // func for JSON filter + // Build a new tree from modules which are appropriate for any part of query + function form_new_modules_tree(element) { + if ( query_string.some(check_module_name, element.text) ) + return true; + if ( element.children ) { + element.children = element.children.filter(form_new_modules_tree); + return Boolean(element.children.length); + } + return false; + } + + function recount_modules_and_expand_directories(element) { + if ( element.children ) { + element.expanded = true; + var modules_in_directory = element.children.length; + // visit all + for ( var i = 0; i < element.children.length; i++ ) + if ( element.children ) + modules_in_directory += recount_modules_and_expand_directories(element.children[i]); + // expand them + element.children.forEach(recount_modules_and_expand_directories); + // and set new number of modules in directory + element.text = element.text.replace(/([-_ 0-9a-zA-Z]+)\(([0-9]+)\)/, "$1(" + modules_in_directory + ")") + return modules_in_directory - 1; + } + return 0; + } +} diff --git a/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabCommands.js b/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabCommands.js index 281ffe40c..9329d6425 100644 --- a/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabCommands.js +++ b/extensions/admin_ui/media/javascript/ui/panel/tabs/ZombieTabCommands.js @@ -9,6 +9,7 @@ * Loaded in /ui/panel/index.html */ ZombieTab_Commands = function(zombie) { + var originalRoot; var command_module_config = new Ext.Panel({ id: 'zombie-command-module-config-'+zombie.session, @@ -92,14 +93,44 @@ ZombieTab_Commands = function(zombie) { } }; + var command_module_tree_search = new Ext.form.TextField( { + emptyText: 'Search', + id: 'module-search-' + zombie.session, + style: { + width: '100%' + }, + listeners: { + specialkey : function(field,e){ + if(e.getKey() == e.ENTER){ + if( field.getValue() ){ + var root = { + text: "Search results", + children: search_module(originalRoot, field.getValue()) + }; + command_module_tree.setRootNode(root); + } else + command_module_tree.setRootNode(originalRoot); + + } + } + } + }); + + var command_module_tree_search_panel = new Ext.Panel({ + id: "zombie-command-modules-search-panel"+zombie.session, + items: [ command_module_tree_search ], + width: 190, + minSize: 190, + maxSize: 500, + region: 'north' + }); + var command_module_tree = new Ext.tree.TreePanel({ id: "zombie-command-modules"+zombie.session, - title: "Module Tree", - border: true, - region: 'west', + region: 'center', width: 190, minSize: 190, - maxSize: 500, // if some command module names are even longer, adjust this value + maxSize: 500, useArrows: true, autoScroll: true, animate: true, @@ -119,6 +150,7 @@ ZombieTab_Commands = function(zombie) { load: function(treeloader, node, response) { // Hide loading mask after tree is fully loaded treeloader.treeLoadingMask.hide(); + originalRoot = command_module_tree.root.childNodes; return true; } } @@ -133,18 +165,34 @@ ZombieTab_Commands = function(zombie) { }, 'activate' : function() { }, + 'deactivate' : function() { + }, 'select' : function() { }, 'keyup' : function() { }, 'render' : function(c) { - c.getEl().on('keyup', function() { - LoadCommandPanelEvent(Ext.getCmp('zombie-command-modules'+zombie.session).getSelectionModel().getSelectedNode(),true); - }); - } + c.getEl().on('keyup', function(a) { + LoadCommandPanelEvent(Ext.getCmp('zombie-command-modules'+zombie.session).getSelectionModel().getSelectedNode(),true); + }); + } } }); + var command_module_tree_container = new Ext.Panel({ + id: "zombie-command-modules-container"+zombie.session, + title: "Module Tree", + border: true, + width: 190, + minSize: 190, + maxSize: 500, // if some command module names are even longer, adjust this value + layout: 'border', + region: 'west', + split: true, + items: [ command_module_tree_search_panel,command_module_tree ], + }); + + var commands_statusbar = new Beef_StatusBar(zombie.session); ZombieTab_Commands.superclass.constructor.call(this, { @@ -160,13 +208,14 @@ ZombieTab_Commands = function(zombie) { collapsible: false, split: true }, - items: [command_module_tree, - new Ext.Panel({ - id: 'zombie-command-module-west-'+zombie.session, - region: 'center', - layout: 'border', - border: false, - items: [command_module_grid, command_module_config] + items: [ + command_module_tree_container, + new Ext.Panel({ + id: 'zombie-command-module-west-'+zombie.session, + region: 'center', + layout: 'border', + border: false, + items: [command_module_grid, command_module_config] })] },