GP-4433 Preliminary GhidraGo support for accepting GhidraURL locating a

DomainFolder.
This commit is contained in:
ghidraffe 2024-03-14 18:37:02 +00:00 committed by ghidra1
parent c131adc670
commit 146c177343
4 changed files with 97 additions and 29 deletions

View file

@ -22,23 +22,26 @@ import ghidra.app.CorePluginPackage;
import ghidra.app.plugin.PluginCategoryNames; import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.core.go.ipc.GhidraGoListener; import ghidra.app.plugin.core.go.ipc.GhidraGoListener;
import ghidra.framework.main.*; import ghidra.framework.main.*;
import ghidra.framework.model.ToolServices;
import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus; import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.framework.protocol.ghidra.GhidraURL; import ghidra.framework.protocol.ghidra.GhidraURL;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.Swing;
//@formatter:off //@formatter:off
@PluginInfo( @PluginInfo(
category = PluginCategoryNames.COMMON, category = PluginCategoryNames.COMMON,
status = PluginStatus.UNSTABLE, status = PluginStatus.UNSTABLE,
packageName = CorePluginPackage.NAME, packageName = CorePluginPackage.NAME,
shortDescription = "Listens for new GhidraURL's to launch using ToolServices", shortDescription = "Listens for new GhidraURL's to launch using FrontEndTool's" +
description = "Polls the ghidraGo directory for any url files written by the GhidraGoClient and " + " accept method",
"processes them in Ghidra", description = "Polls the ghidraGo directory for any url files written by the " +
"GhidraGoSender and processes them in Ghidra",
eventsConsumed = {ProjectPluginEvent.class}) eventsConsumed = {ProjectPluginEvent.class})
//@formatter:on //@formatter:on
/**
* Polls the ghidraGo directory located in the user's temporary directory for any url files written
* by the {@link GhidraGoSender} and processes them in Ghidra.
*/
public class GhidraGoPlugin extends Plugin implements ApplicationLevelOnlyPlugin { public class GhidraGoPlugin extends Plugin implements ApplicationLevelOnlyPlugin {
private GhidraGoListener listener; private GhidraGoListener listener;
@ -69,7 +72,7 @@ public class GhidraGoPlugin extends Plugin implements ApplicationLevelOnlyPlugin
else { else {
try { try {
listener = new GhidraGoListener((url) -> { listener = new GhidraGoListener((url) -> {
processGhidraURL(url); accept(url);
}); });
} }
catch (IOException e) { catch (IOException e) {
@ -81,26 +84,14 @@ public class GhidraGoPlugin extends Plugin implements ApplicationLevelOnlyPlugin
} }
/** /**
* If the active project is null, do nothing. * Accept the given url, which is then passed to the FrontEndTool to process.
* Otherwise, try and open the url using {@link ToolServices} launchDefaultToolWithURL function. * @param url a {@link GhidraURL}
* @param ghidraURL the GhidraURL to open. * @return true if handled successfully, false otherwise.
*/ */
private void processGhidraURL(URL ghidraURL) { public boolean accept(URL url) {
Msg.info(this, "GhidraGo accepting the resource at " + GhidraURL.getProjectURL(url));
Msg.info(this, "GhidraGo processing " + ghidraURL); FrontEndTool frontEndTool = AppInfo.getFrontEndTool();
frontEndTool.toFront();
try { return frontEndTool.accept(url);
Msg.info(this,
"Accepting the resource at " + GhidraURL.getProjectURL(ghidraURL));
Swing.runNow(() -> {
FrontEndTool frontEnd = AppInfo.getFrontEndTool();
frontEnd.toFront();
frontEnd.getToolServices().launchDefaultToolWithURL(ghidraURL);
});
}
catch (IllegalArgumentException e) {
Msg.showError(this, null, "GhidraGo Unable to process GhidraURL",
"GhidraGo could not process " + ghidraURL, e);
}
} }
} }

View file

@ -0,0 +1,68 @@
/* ###
* IP: GHIDRA
*
* 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 ghidra.framework.main;
import java.io.IOException;
import java.net.URL;
import ghidra.framework.data.FolderLinkContentHandler;
import ghidra.framework.main.datatree.ProjectDataTreePanel;
import ghidra.framework.model.DomainFile;
import ghidra.framework.model.DomainFolder;
import ghidra.framework.protocol.ghidra.GhidraURL;
import ghidra.framework.protocol.ghidra.GhidraURLQueryTask;
import ghidra.util.Swing;
import ghidra.util.task.TaskMonitor;
public class AcceptUrlContentTask extends GhidraURLQueryTask {
private FrontEndPlugin plugin;
public AcceptUrlContentTask(URL url, FrontEndPlugin plugin) {
super("Accepting URL", url);
this.plugin = plugin;
}
@Override
public void processResult(DomainFile domainFile, URL url, TaskMonitor monitor)
throws IOException {
Swing.runNow(() -> {
if (FolderLinkContentHandler.FOLDER_LINK_CONTENT_TYPE
.equals(domainFile.getContentType())) {
plugin.showLinkedFolder(domainFile);
return;
}
AppInfo.getFrontEndTool().getToolServices().launchDefaultToolWithURL(url);
});
}
@Override
public void processResult(DomainFolder domainFolder, URL url, TaskMonitor monitor)
throws IOException {
ProjectDataPanel projectDataPanel = plugin.getProjectDataPanel();
Swing.runNow(() -> {
ProjectDataTreePanel dtp = projectDataPanel.openView(GhidraURL.getProjectURL(url));
if (dtp == null) {
return;
}
dtp.selectDomainFolder(domainFolder);
});
}
}

View file

@ -1109,11 +1109,11 @@ public class FrontEndPlugin extends Plugin
"opens this type of file"); "opens this type of file");
} }
private void showLinkedFolder(DomainFile domainFile) { void showLinkedFolder(DomainFile domainFile) {
try { try {
LinkedGhidraFolder linkedFolder = LinkedGhidraFolder linkedFolder =
FolderLinkContentHandler.getReadOnlyLinkedFolder(domainFile); FolderLinkContentHandler.getReadOnlyLinkedFolder(domainFile);
if (linkedFolder == null) { if (linkedFolder == null) {
return; // unsupported use return; // unsupported use
} }
@ -1133,7 +1133,6 @@ public class FrontEndPlugin extends Plugin
Msg.showError(this, projectDataPanel, "Linked-folder failure: " + domainFile.getName(), Msg.showError(this, projectDataPanel, "Linked-folder failure: " + domainFile.getName(),
e); e);
} }
} }
private class MyToolChestChangeListener implements ToolChestChangeListener { private class MyToolChestChangeListener implements ToolChestChangeListener {

View file

@ -64,6 +64,7 @@ import ghidra.framework.plugintool.util.*;
import ghidra.framework.preferences.Preferences; import ghidra.framework.preferences.Preferences;
import ghidra.framework.project.tool.GhidraTool; import ghidra.framework.project.tool.GhidraTool;
import ghidra.framework.project.tool.GhidraToolTemplate; import ghidra.framework.project.tool.GhidraToolTemplate;
import ghidra.framework.protocol.ghidra.GhidraURL;
import ghidra.util.*; import ghidra.util.*;
import ghidra.util.bean.GGlassPane; import ghidra.util.bean.GGlassPane;
import ghidra.util.classfinder.ClassSearcher; import ghidra.util.classfinder.ClassSearcher;
@ -176,6 +177,15 @@ public class FrontEndTool extends PluginTool implements OptionsChangeListener {
System.exit(0); System.exit(0);
} }
@Override
public boolean accept(URL url) {
if (!GhidraURL.isLocalProjectURL(url) && !GhidraURL.isServerRepositoryURL(url)) {
return false;
}
Swing.runLater(() -> execute(new AcceptUrlContentTask(url, plugin)));
return true;
}
private void ensureSize() { private void ensureSize() {
JFrame frame = getToolFrame(); JFrame frame = getToolFrame();
Dimension size = frame.getSize(); Dimension size = frame.getSize();