Skip to content

Commit

Permalink
Rework for v2024.11
Browse files Browse the repository at this point in the history
  • Loading branch information
CoreyD97 committed Dec 17, 2024
1 parent ab91b7d commit de6078a
Show file tree
Hide file tree
Showing 8 changed files with 302 additions and 321 deletions.
12 changes: 12 additions & 0 deletions .run/TestPlugin.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="TestPlugin" type="Application" factoryName="Application" nameIsGenerated="true">
<option name="ALTERNATIVE_JRE_PATH" value="corretto-17" />
<option name="MAIN_CLASS_NAME" value="TestPlugin" />
<module name="BurpCustomizer.test" />
<option name="PROGRAM_PARAMETERS" value="--project-file=/tmp/tmp.burp" />
<option name="VM_PARAMETERS" value="--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/javax.crypto=ALL-UNNAMED --add-opens java.desktop/javax.swing=ALL-UNNAMED --add-opens java.desktop/java.awt=ALL-UNNAMED --add-opens java.desktop/java.awt.color=ALL-UNNAMED --add-opens jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED -XX:MaxRAMPercentage=50" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
36 changes: 17 additions & 19 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
apply plugin: 'java'
apply plugin: 'maven'
plugins {
id("java")
id("io.freefair.lombok") version "8.6"
}

sourceCompatibility = 1.8
targetCompatibility = 1.8
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21

repositories {
mavenCentral()
Expand All @@ -12,31 +14,27 @@ repositories {
}

dependencies {
compile 'net.portswigger.burp.extender:burp-extender-api:1.7.22'
compile 'com.github.CoreyD97:BurpExtenderUtilities:c03544e3'
compileOnly 'com.formdev:flatlaf:2.4'
compile 'com.formdev:flatlaf-intellij-themes:2.4'
compile 'com.formdev:flatlaf-extras:2.4'
// runtimeOnly files('/home/corey/BurpSuitePro/burpsuite_pro.jar')
compileOnly 'net.portswigger.burp.extensions:montoya-api:2023.12.1'
implementation 'com.rover12421.opensource:JFontChooser:1.0.5-3'
implementation 'com.github.CoreyD97:Burp-Montoya-Utilities:2993e293'
implementation 'com.formdev:flatlaf-intellij-themes:2.4'
compileOnly 'com.formdev:flatlaf:2.4' //Already shipped in burp
compileOnly 'com.formdev:flatlaf-extras:2.4' //Already implemented in burp
implementation files('/home/corey/BurpSuitePro/burpsuite_pro.jar')
// testCompile files('/home/corey/BurpSuiteCommunity/burpsuite_community.jar')
}

jar {
baseName = project.name
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
archiveBaseName = project.name
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
}

task testJar(type: Jar) {
baseName = project.name + "-TEST"
archiveBaseName = project.name + "-TEST"
from { configurations.testCompile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}


configurations.all {
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
}

tasks.withType(Jar) {
destinationDir = file("$rootDir/releases")
destinationDirectory = file("$rootDir/releases")
}
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
178 changes: 83 additions & 95 deletions src/main/java/com/coreyd97/burpcustomizer/BurpCustomizer.java
Original file line number Diff line number Diff line change
@@ -1,85 +1,78 @@
package com.coreyd97.burpcustomizer;

import burp.IBurpExtender;
import burp.IBurpExtenderCallbacks;
import burp.IExtensionStateListener;
import burp.ITab;
import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.IntelliJTheme;
import com.formdev.flatlaf.extras.FlatInspector;
import com.formdev.flatlaf.extras.FlatUIDefaultsInspector;
import com.formdev.flatlaf.intellijthemes.FlatAllIJThemes;
import lombok.Getter;
import lombok.SneakyThrows;

import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Optional;
import java.util.stream.Collectors;

public class BurpCustomizer implements ITab, IBurpExtender, IExtensionStateListener {
public class BurpCustomizer implements BurpExtension {

enum ThemeSource {BUILTIN, FILE}
private boolean compatible;

private LookAndFeel originalBurpTheme;
@Getter
private ArrayList<UIManager.LookAndFeelInfo> themes;
@Getter
private UIManager.LookAndFeelInfo selectedBuiltIn;
@Getter
private File selectedThemeFile;
@Getter
private ThemeSource themeSource;
private CustomizerPanel ui;
public static IBurpExtenderCallbacks callbacks;
public static MontoyaApi montoya;
JMenuBar menuBar;
JMenu menuItem;

public BurpCustomizer(){
themes = new ArrayList<>(Arrays.asList(FlatAllIJThemes.INFOS));
public BurpCustomizer() {
themes = (ArrayList<UIManager.LookAndFeelInfo>) Arrays.asList(FlatAllIJThemes.INFOS).stream()
.filter(lookAndFeelInfo -> !lookAndFeelInfo.getName().equalsIgnoreCase("Xcode-Dark"))
.map(flatIJLookAndFeelInfo -> (UIManager.LookAndFeelInfo) flatIJLookAndFeelInfo)
.collect(Collectors.toList());
themes.sort(Comparator.comparing(UIManager.LookAndFeelInfo::getName));
}

@SneakyThrows
@Override
public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
BurpCustomizer.callbacks = callbacks;
public void initialize(MontoyaApi montoyaApi) {
BurpCustomizer.montoya = montoyaApi;
originalBurpTheme = UIManager.getLookAndFeel();

String sourceEnum = callbacks.loadExtensionSetting("source");
if(sourceEnum == null || sourceEnum.equalsIgnoreCase("")){
String sourceEnum = montoya.persistence().preferences().getString("source");
if (sourceEnum == null || sourceEnum.equalsIgnoreCase("")) {
themeSource = ThemeSource.BUILTIN;
}else {
} else {
themeSource = ThemeSource.valueOf(sourceEnum);
}

String builtIn = callbacks.loadExtensionSetting("theme");
String builtIn = montoya.persistence().preferences().getString("theme");
Optional<UIManager.LookAndFeelInfo> previousTheme =
themes.stream().filter(lookAndFeelInfo -> lookAndFeelInfo.getClassName().equalsIgnoreCase(builtIn)).findFirst();
if(previousTheme.isPresent()) selectedBuiltIn = previousTheme.get();
previousTheme.ifPresent(lookAndFeelInfo -> selectedBuiltIn = lookAndFeelInfo);

String themeFilePref = callbacks.loadExtensionSetting("themeFile");
if(themeFilePref != null && !themeFilePref.equalsIgnoreCase("")){
String themeFilePref = montoya.persistence().preferences().getString("themeFile");
if (themeFilePref != null && !themeFilePref.equalsIgnoreCase("")) {
selectedThemeFile = new File(themeFilePref);
if(!selectedThemeFile.exists()) selectedThemeFile = null;
if (!selectedThemeFile.exists()) selectedThemeFile = null;
}


try{
ClassLoader.getSystemClassLoader().loadClass("burp.theme.BurpDarkLaf");
compatible = true;
} catch (ClassNotFoundException e) {
compatible = false;
}

FlatInspector.install("ctrl shift alt U");
FlatUIDefaultsInspector.install("ctrl shift alt Y");

SwingUtilities.invokeLater(() -> {
if(themeSource == ThemeSource.BUILTIN && selectedBuiltIn != null){
setTheme(selectedBuiltIn);
}else if(themeSource == ThemeSource.FILE && selectedThemeFile != null){
setTheme(selectedThemeFile);
}
this.ui = new CustomizerPanel(this);
FlatInspector.install("ctrl shift alt U");
patchPopupFactoryForFlatInspector();

// Arrays.stream(Frame.getFrames()).filter(frame -> frame.getTitle().startsWith("Burp Suite") && frame.isVisible() && frame.getMenuBar() != null).findFirst().ifPresent(frame -> {
// menuItem = new JMenu("Customize");
Expand All @@ -95,111 +88,106 @@ public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
// }
// });

callbacks.registerExtensionStateListener(this::extensionUnloaded);
callbacks.addSuiteTab(this);
});
}

@Override
public String getTabCaption() {
return "Customizer";
}

@Override
public Component getUiComponent() {
return this.ui;
}

public UIManager.LookAndFeelInfo getSelectedBuiltIn() {
return selectedBuiltIn;
}
this.ui = new CustomizerPanel(this);
montoya.extension().registerUnloadingHandler(this::extensionUnloaded);

public File getSelectedThemeFile() {
return selectedThemeFile;
}

public ThemeSource getThemeSource(){
return this.themeSource;
}
SwingUtilities.invokeLater(() -> {
if (themeSource == ThemeSource.BUILTIN && selectedBuiltIn != null) {
setTheme(selectedBuiltIn);
} else if (themeSource == ThemeSource.FILE && selectedThemeFile != null) {
setTheme(selectedThemeFile);
}

public ArrayList<UIManager.LookAndFeelInfo> getThemes(){
return this.themes;
montoya.userInterface().registerSuiteTab("Customizer", this.ui);
});
}

public boolean isCompatible() {
return compatible;
//Since Burp explicitly disables HTML in components we need to manually re-enable HTML for the inspector tooltip.
//Shouldn't reintroduce any vulnerabilities unless somehow a malicious value is used in a tooltip somewhere which is unlikely
private void patchPopupFactoryForFlatInspector() {
PopupFactory.setSharedInstance(new PopupFactory() {
@Override
public Popup getPopup(Component owner, Component contents, int x, int y) throws IllegalArgumentException {
if (contents instanceof JToolTip) {
((JToolTip) contents).putClientProperty("html.disable", false);
}
return super.getPopup(owner, contents, x, y);
}
});
}

public void setTheme(UIManager.LookAndFeelInfo lookAndFeelInfo){
if(!compatible) return;
public void setTheme(UIManager.LookAndFeelInfo lookAndFeelInfo) {
try {
LookAndFeel laf = createThemeFromDefaults(lookAndFeelInfo);

LookAndFeel laf = createThemeFromDefaults(lookAndFeelInfo, false);
UIManager.setLookAndFeel(laf);
FlatLaf.updateUI();
patchPopupFactoryForFlatInspector();
selectedBuiltIn = lookAndFeelInfo;
callbacks.saveExtensionSetting("theme", lookAndFeelInfo.getClassName());
callbacks.saveExtensionSetting("source", ThemeSource.BUILTIN.toString());
montoya.persistence().preferences().setString("theme", lookAndFeelInfo.getClassName());
montoya.persistence().preferences().setString("source", ThemeSource.BUILTIN.toString());

// ui.reloadPreview();
} catch (Exception ex) {
StringWriter sw = new StringWriter();
ex.printStackTrace(new PrintWriter(sw));
callbacks.printError("Could not load theme.");
callbacks.printError(sw.toString());
JOptionPane.showMessageDialog(getUiComponent(), "Could not load the specified theme.\n" + ex.getMessage(), "Burp Customizer", JOptionPane.ERROR_MESSAGE);
try{ //Fall back to built in theme if we encounter an issue.
montoya.logging().logToError("Could not load theme.");
montoya.logging().logToError(sw.toString());
JOptionPane.showMessageDialog(ui, "Could not load the specified theme.\n" + ex.getMessage(), "Burp Customizer", JOptionPane.ERROR_MESSAGE);
try { //Fall back to built in theme if we encounter an issue.
UIManager.setLookAndFeel(originalBurpTheme);
}catch (Exception ignored){}
} catch (Exception ignored) {
}
}
}

public LookAndFeel createThemeFromDefaults(UIManager.LookAndFeelInfo lookAndFeelInfo) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
public LookAndFeel createThemeFromDefaults(UIManager.LookAndFeelInfo lookAndFeelInfo, boolean isPreview) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class themeClass = Class.forName(lookAndFeelInfo.getClassName());
IntelliJTheme.ThemeLaf theme = (IntelliJTheme.ThemeLaf) themeClass.getDeclaredConstructor().newInstance();
return new CustomTheme(theme);
return new CustomTheme(theme, isPreview);
}

public void setTheme(File themeJsonFile){
public void setTheme(File themeJsonFile) {
try {
LookAndFeel lookAndFeel = createThemeFromFile(themeJsonFile);

UIManager.setLookAndFeel(lookAndFeel);
FlatLaf.updateUI();

selectedThemeFile = themeJsonFile;
callbacks.saveExtensionSetting("themeFile", themeJsonFile.getAbsolutePath());
callbacks.saveExtensionSetting("source", ThemeSource.FILE.toString());
montoya.persistence().preferences().setString("themeFile", themeJsonFile.getAbsolutePath());
montoya.persistence().preferences().setString("source", ThemeSource.FILE.toString());
} catch (IOException | UnsupportedLookAndFeelException ex) {
StringWriter sw = new StringWriter();
ex.printStackTrace(new PrintWriter(sw));
callbacks.printError("Could not load theme.");
callbacks.printError(sw.toString());
JOptionPane.showMessageDialog(getUiComponent(), "Could not load the specified theme:\n" + ex.getMessage(), "Burp Customizer", JOptionPane.ERROR_MESSAGE);
try{ //Fall back to built in theme if we encounter an issue.
montoya.logging().logToError("Could not load theme.");
montoya.logging().logToError(sw.toString());
JOptionPane.showMessageDialog(ui, "Could not load the specified theme:\n" + ex.getMessage(), "Burp Customizer", JOptionPane.ERROR_MESSAGE);
try { //Fall back to built in theme if we encounter an issue.
UIManager.setLookAndFeel(originalBurpTheme);
}catch (Exception ignored){}
} catch (Exception ignored) {
}
}
}

public LookAndFeel createThemeFromFile(File themeJsonFile) throws IOException, UnsupportedLookAndFeelException {
IntelliJTheme intelliJTheme = new IntelliJTheme(new FileInputStream(themeJsonFile));
IntelliJTheme.ThemeLaf fileTheme = new IntelliJTheme.ThemeLaf(intelliJTheme);
if(intelliJTheme.name == null && intelliJTheme.author == null){
if (intelliJTheme.name == null && intelliJTheme.author == null) {
throw new UnsupportedLookAndFeelException(themeJsonFile.getName() + " does not appear to be a valid theme file.\n" +
"If it is, make sure it has a json attribute \"name\".");
"If it is, make sure it has json attributes \"name\" and \"author\".");
}

return new CustomTheme(fileTheme);
return new CustomTheme(fileTheme, false);
}

@Override
public void extensionUnloaded() {
BurpCustomizer.callbacks = null;
if(menuBar != null && menuItem != null) menuBar.remove(menuItem);
BurpCustomizer.montoya = null;
if (menuBar != null && menuItem != null) menuBar.remove(menuItem);
SwingUtilities.invokeLater(() -> {
try {
UIManager.setLookAndFeel(originalBurpTheme);
FlatLaf.updateUI();
} catch (UnsupportedLookAndFeelException e) {}
} catch (UnsupportedLookAndFeelException e) {
}
});
}
}
Loading

0 comments on commit de6078a

Please sign in to comment.