/*
* Zed Attack Proxy (ZAP) and its related class files.
*
* ZAP is an HTTP/HTTPS proxy for assessing web application security.
*
* 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.
*/
package org.zaproxy.zap.extension.keyboard;
import java.awt.Component;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.KeyStroke;
import org.apache.commons.collections.map.ReferenceMap;
import org.apache.log4j.Logger;
import org.parosproxy.paros.Constant;
import org.parosproxy.paros.extension.ExtensionAdaptor;
import org.parosproxy.paros.extension.ExtensionHook;
import org.parosproxy.paros.view.View;
import org.zaproxy.zap.utils.DesktopUtils;
import org.zaproxy.zap.view.ZapMenuItem;
public class ExtensionKeyboard extends ExtensionAdaptor {
private static final Logger logger = Logger.getLogger(ExtensionKeyboard.class);
public static final String NAME = "ExtensionKeyboard";
private OptionsKeyboardShortcutPanel optionsKeyboardPanel = null;
private KeyboardParam keyboardParam = null;
private ReferenceMap map = new ReferenceMap();
private KeyboardAPI api = null;
public ExtensionKeyboard() {
super();
initialize();
}
private void initialize() {
this.setName(NAME);
this.setOrder(2000); // Really want this to be added late on
}
@Override
public void hook(ExtensionHook extensionHook) {
if (getView() != null) {
// Usually options are loaded in daemon mode, but really no point for keyboard shortcuts;)
extensionHook.addOptionsParamSet(getKeyboardParam());
extensionHook.getHookView().addOptionPanel(getOptionsKeyboardPanel());
// Ditto the API
api = new KeyboardAPI(this);
extensionHook.addApiImplementor(api);
}
}
protected KeyboardParam getKeyboardParam() {
if (keyboardParam == null) {
keyboardParam = new KeyboardParam();
}
return keyboardParam;
}
@Override
public void optionsLoaded() {
if (View.isInitialised()) {
logger.info("Initializing keyboard shortcuts");
initAllMenuItems(View.getSingleton().getMainFrame().getMainMenuBar().getMenuFile());
initAllMenuItems(View.getSingleton().getMainFrame().getMainMenuBar().getMenuEdit());
initAllMenuItems(View.getSingleton().getMainFrame().getMainMenuBar().getMenuAnalyse());
initAllMenuItems(View.getSingleton().getMainFrame().getMainMenuBar().getMenuReport());
initAllMenuItems(View.getSingleton().getMainFrame().getMainMenuBar().getMenuTools());
initAllMenuItems(View.getSingleton().getMainFrame().getMainMenuBar().getMenuView());
initAllMenuItems(View.getSingleton().getMainFrame().getMainMenuBar().getMenuHelp());
}
}
public void registerMenuItem(ZapMenuItem zme) {
KeyboardMapping mapping = menuToMapping(zme);
String identifier = mapping.getIdentifier();
if (identifier != null) {
this.map.put(identifier, mapping);
} else {
logger.warn("ZapMenuItem \"" + mapping.getName() + "\" has a null identifier.");
}
}
private void initAllMenuItems(JMenu menu) {
for (Component c: menu.getMenuComponents()) {
if (c instanceof ZapMenuItem) {
this.registerMenuItem((ZapMenuItem)c);
} else if (c instanceof JMenu) {
initAllMenuItems((JMenu)c);
} else if (c instanceof JMenuItem) {
JMenuItem menuItem = (JMenuItem) c;
logger.debug("Unable to set accelerators on menu " + menuItem.getText());
}
}
}
private KeyboardMapping menuToMapping(ZapMenuItem menuItem) {
KeyStroke ks = this.getKeyboardParam().getShortcut(menuItem.getIdenfifier());
if (ks != null) {
if (ks.getKeyCode() == 0) {
// Used to indicate no accelerator should be used
logger.debug("Cleaning menu " + menuItem.getIdenfifier() + " accelerator");
menuItem.setAccelerator(null);
} else {
logger.debug("Setting menu " + menuItem.getIdenfifier() + " accelerator to " + ks.toString());
menuItem.setAccelerator(ks);
}
}
return new KeyboardMapping(menuItem);
}
public List<KeyboardShortcut> getShortcuts() {
return this.getShortcuts(false);
}
public List<KeyboardShortcut> getShortcuts(boolean reset) {
if (View.isInitialised()) {
List<KeyboardShortcut> kss = new ArrayList<KeyboardShortcut>();
addAllMenuItems(kss, View.getSingleton().getMainFrame().getMainMenuBar().getMenuFile(), reset);
addAllMenuItems(kss, View.getSingleton().getMainFrame().getMainMenuBar().getMenuEdit(), reset);
addAllMenuItems(kss, View.getSingleton().getMainFrame().getMainMenuBar().getMenuAnalyse(), reset);
addAllMenuItems(kss, View.getSingleton().getMainFrame().getMainMenuBar().getMenuReport(), reset);
addAllMenuItems(kss, View.getSingleton().getMainFrame().getMainMenuBar().getMenuTools(), reset);
addAllMenuItems(kss, View.getSingleton().getMainFrame().getMainMenuBar().getMenuView(), reset);
addAllMenuItems(kss, View.getSingleton().getMainFrame().getMainMenuBar().getMenuHelp(), reset);
return kss;
}
return null;
}
private void addAllMenuItems(List<KeyboardShortcut> kss, JMenu menu, boolean reset) {
for (Component c: menu.getMenuComponents()) {
if (c instanceof ZapMenuItem) {
kss.add(menuToShortcut((ZapMenuItem)c, reset));
} else if (c instanceof JMenu) {
addAllMenuItems(kss, (JMenu)c, reset);
} else if (c instanceof JMenuItem) {
JMenuItem menuItem = (JMenuItem) c;
logger.debug("Unable to set accelerators on menu " + menuItem.getText());
}
}
}
private KeyboardShortcut menuToShortcut(ZapMenuItem menuItem, boolean reset) {
if (reset) {
return new KeyboardShortcut(menuItem.getIdenfifier(), menuItem.getText(), menuItem.getDefaultAccelerator());
}
KeyStroke ks = this.getKeyboardParam().getShortcut(menuItem.getIdenfifier());
if (ks != null) {
if (ks.getKeyCode() == 0) {
// Used to indicate no accelerator should be used
logger.debug("Cleaning menu " + menuItem.getIdenfifier() + " accelerator");
menuItem.setAccelerator(null);
} else {
logger.debug("Setting menu " + menuItem.getIdenfifier() + " accelerator to " + ks.toString());
menuItem.setAccelerator(ks);
}
}
return new KeyboardShortcut(menuItem.getIdenfifier(), menuItem.getText(), menuItem.getAccelerator());
}
public KeyStroke getShortcut(String identifier) {
KeyboardMapping mapping = (KeyboardMapping) this.map.get(identifier);
if (mapping == null) {
return null;
}
return mapping.getKeyStroke();
}
public void setShortcut(String identifier, KeyStroke ks) {
KeyboardMapping mapping = (KeyboardMapping) this.map.get(identifier);
if (mapping == null) {
logger.error("No mapping found for keyboard shortcut: " + identifier);
return;
}
mapping.setKeyStroke(ks);
this.getKeyboardParam().setShortcut(identifier, ks);
}
private OptionsKeyboardShortcutPanel getOptionsKeyboardPanel() {
if (optionsKeyboardPanel == null) {
optionsKeyboardPanel = new OptionsKeyboardShortcutPanel(this);
}
return optionsKeyboardPanel;
}
public void displayCheatsheetSortedByAction() {
try {
DesktopUtils.openUrlInBrowser(api.getCheatSheetActionURI());
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
public void displayCheatsheetSortedByKey() {
try {
DesktopUtils.openUrlInBrowser(api.getCheatSheetKeyURI());
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
@Override
public String getAuthor() {
return Constant.ZAP_TEAM;
}
@Override
public String getDescription() {
return Constant.messages.getString("keyboard.desc");
}
@Override
public URL getURL() {
try {
return new URL(Constant.ZAP_HOMEPAGE);
} catch (MalformedURLException e) {
return null;
}
}
/**
* No database tables used, so all supported
*/
@Override
public boolean supportsDb(String type) {
return true;
}
}