Skip to content

Commit

Permalink
Added option to create Rules from the context menu of Proxy History i…
Browse files Browse the repository at this point in the history
…tems. Fixed file saving when using the default encoding.
  • Loading branch information
ddwightx committed Feb 18, 2022
1 parent 6356290 commit b69069e
Show file tree
Hide file tree
Showing 21 changed files with 680 additions and 12 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
}

group 'com.synfron.reshaper.burp'
version '1.6.1'
version '1.6.2'

targetCompatibility = '15'
sourceCompatibility = '15'
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/burp/BurpExtender.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import synfron.reshaper.burp.core.settings.GeneralSettings;
import synfron.reshaper.burp.core.utils.Log;
import synfron.reshaper.burp.ui.components.ReshaperComponent;
import synfron.reshaper.burp.ui.utils.ContextMenuHandler;
import synfron.reshaper.burp.ui.utils.UiMessageHandler;

public class BurpExtender implements IBurpExtender {
Expand All @@ -20,7 +21,8 @@ public class BurpExtender implements IBurpExtender {
private static final GeneralSettings generalSettings = new GeneralSettings();
@Getter
private static final MessageEvent messageEvent = new MessageEvent();
private static UiMessageHandler uiMessageHandler = new UiMessageHandler(messageEvent);
private static final UiMessageHandler uiMessageHandler = new UiMessageHandler(messageEvent);
private static final ContextMenuHandler contextMenuHandler = new ContextMenuHandler();

@Override
public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
Expand All @@ -34,6 +36,8 @@ public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
callbacks.registerProxyListener(connector);
callbacks.registerHttpListener(connector);
callbacks.registerExtensionStateListener(connector);
callbacks.registerContextMenuFactory(contextMenuHandler);

Log.get().withMessage("Reshaper started").log();
}
}
10 changes: 8 additions & 2 deletions src/main/java/synfron/reshaper/burp/core/events/Event.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@
public class Event<A> {
private List<WeakReference<IEventListener<A>>> listeners;

public synchronized void clearListeners() {
if (listeners != null) {
listeners.clear();
}
}

public synchronized void remove(IEventListener<A> listener) {
if (listeners != null) {
listeners.remove(listener);
listeners.removeIf(listenerReference -> listenerReference.get() == null || listenerReference.get().equals(listener));
if (listeners.size() == 0) {
listeners = null;
}
}
}

public synchronized void add(IEventListener<A> listener) {
getListeners().add(new WeakReference(listener));
getListeners().add(new WeakReference<>(listener));
}

public synchronized void invoke(A args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
import synfron.reshaper.burp.core.utils.TextUtils;
import synfron.reshaper.burp.core.vars.VariableString;

import java.util.Collections;
import java.util.List;

public class MessageValueHandler {

public static String getValue(IEventInfo eventInfo, MessageValue messageValue, VariableString identifier, GetItemPlacement itemPlacement)
Expand Down Expand Up @@ -109,4 +112,15 @@ public static void setResponseValue(IEventInfo eventInfo, HttpResponseMessage re
case HttpResponseStatusMessage -> responseMessage.getStatusLine().setMessage(StringUtils.defaultString(replacementText));
}
}

public static List<String> getIdentifier(IEventInfo eventInfo, MessageValue messageValue) {
return switch (messageValue) {
case HttpRequestHeader -> eventInfo.getHttpRequestMessage().getHeaders().getHeaderNames();
case HttpResponseHeader -> eventInfo.getHttpResponseMessage().getHeaders().getHeaderNames();
case HttpRequestCookie -> eventInfo.getHttpRequestMessage().getHeaders().getCookies().getCookiesNames();
case HttpResponseCookie -> eventInfo.getHttpResponseMessage().getHeaders().getCookies().getCookiesNames();
case HttpRequestUriQueryParameter -> eventInfo.getHttpRequestMessage().getStatusLine().getUrl().getQueryParams().getParamNames();
default -> Collections.emptyList();
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;

public class HttpCookies extends HttpEntity {
private ListMap<CaseInsensitiveString, String> cookies;
Expand Down Expand Up @@ -44,6 +45,10 @@ public String getCookie(String name, GetItemPlacement itemPlacement) {
return getCookies().get(new CaseInsensitiveString(name), itemPlacement);
}

public List<String> getCookiesNames() {
return getCookies().keys().stream().map(CaseInsensitiveString::toString).sorted().collect(Collectors.toList());
}

public boolean contains(String name)
{
return getCount() > 0 && getCookies().containsKey(new CaseInsensitiveString(name));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public abstract class HttpHeaders extends HttpEntity {
protected final List<String> headerLines;
Expand Down Expand Up @@ -62,6 +63,10 @@ public HttpCookies getCookies() {
});
}

public List<String> getHeaderNames() {
return getHeaders().keys().stream().map(CaseInsensitiveString::toString).sorted().collect(Collectors.toList());
}

private ListMap<CaseInsensitiveString, IValue<String>> getHeaders() {
if (headers == null) {
headers = new ListMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import synfron.reshaper.burp.core.utils.*;

import java.util.List;
import java.util.stream.Collectors;

public class HttpRequestQueryParams extends HttpEntity {
@Getter
Expand All @@ -26,6 +27,11 @@ public void prepare() {
}
}

public List<String> getParamNames() {
prepare();
return params.keys().stream().sorted().collect(Collectors.toList());
}

public boolean hasQueryParameter(String name) {
prepare();
return params.containsKey(name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ private void prepare() {
String[] lineParts = statusLine.split(" ", 3);
method = CollectionUtils.elementAtOrDefault(lineParts, 0, "");
url = new HttpRequestUri(CollectionUtils.elementAtOrDefault(lineParts, 1, ""));
version = CollectionUtils.elementAtOrDefault(lineParts, 2, "");;
version = CollectionUtils.elementAtOrDefault(lineParts, 2, "");
parsed = true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public RuleResponse perform(IEventInfo eventInfo) {
encodingValue = VariableString.getTextOrDefault(eventInfo, encoding, Charset.defaultCharset().name());
Encoder encoder = new Encoder(encodingValue);
if (encoder.isUseDefault()) {
byte[] fileBytes = encoder.encode(encodingValue);
byte[] fileBytes = encoder.encode(textValue);
FileUtils.writeByteArrayToFile(path.toFile(), fileBytes, fileExistsAction == FileExistsAction.Append);
} else {
FileUtils.write(path.toFile(), textValue, encoder.isUseAutoDetect() ? StandardCharsets.UTF_8.toString() : encodingValue, fileExistsAction == FileExistsAction.Append);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public void open(String method, String url, boolean async) throws URISyntaxExcep
uriBuilder.setPath(StringUtils.defaultIfBlank(inputUriBuilder.getPath(), "/"));
uriBuilder.setParameters(inputUriBuilder.getQueryParams());
uriBuilder.setFragment(inputUriBuilder.getFragment());
String request = String.format(requestTemplate, method, uriBuilder.toString(), requestUrl.getAuthority());
String request = String.format(requestTemplate, method, uriBuilder, requestUrl.getAuthority());
Encoder encoder = ((IEventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo")).getEncoder();
requestMessage = new HttpRequestMessage(encoder.encode(request), encoder);
setReadyState(OPENED);
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/synfron/reshaper/burp/core/utils/ListMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ public boolean containsKey(K key) {
return backingMap.containsKey(key);
}

public Set<K> keys() {
return backingMap.keySet();
}

public int size() {
return nodeCount;
}
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/synfron/reshaper/burp/core/utils/Select.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package synfron.reshaper.burp.core.utils;

import lombok.Getter;
import lombok.Setter;

import java.util.Collections;
import java.util.List;

public class Select<T> {

@Getter
private final List<T> options;
@Getter @Setter
private T selectedOption;

public Select(List<T> options, T selectedOption) {
this.options = Collections.unmodifiableList(options);
this.selectedOption = selectedOption != null ? selectedOption : options.stream().findFirst().orElse(null);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ private Component getRuleNameBox() {

ruleName.getDocument().addDocumentListener(new DocumentActionListener(this::onRuleNameChanged));

container.add(new JLabel("Rule Name"));
container.add(new JLabel("Rule Name *"));
container.add(ruleName);
return container;
}
Expand All @@ -83,7 +83,7 @@ private Component getGitHubLink() {
githubLink.setFont(font.deriveFont(attributes));

githubLink.addMouseListener(new MouseListener() {
private Color originalColor = githubLink.getForeground();
private final Color originalColor = githubLink.getForeground();

@SneakyThrows
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package synfron.reshaper.burp.ui.components.rules.wizard;

import net.miginfocom.swing.MigLayout;
import synfron.reshaper.burp.core.messages.MessageValue;
import synfron.reshaper.burp.ui.components.IFormComponent;
import synfron.reshaper.burp.ui.models.rules.wizard.WhenWizardItemModel;
import synfron.reshaper.burp.ui.models.rules.wizard.WizardMatchType;
import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager;
import synfron.reshaper.burp.ui.utils.DocumentActionListener;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.List;

public class WhenWizardItemComponent extends JPanel implements IFormComponent {
private final WhenWizardItemModel model;
private final boolean deletable;
private JComboBox<MessageValue> messageValue;
private JComboBox<String> identifier;
private JComboBox<WizardMatchType> matchType;
private JTextField text;

public WhenWizardItemComponent(WhenWizardItemModel model, boolean deletable) {
this.model = model;
this.deletable = deletable;
initComponent();
}

private void initComponent() {
setLayout(new BorderLayout());
JPanel container = new JPanel(new MigLayout());

messageValue = new JComboBox<>(MessageValue.values());
identifier = new JComboBox<>(model.getIdentifiers().getOptions().toArray(new String[0]));
matchType = new JComboBox<>(WizardMatchType.values());
text = createTextField();
text.setColumns(20);
text.setMaximumSize(new Dimension(text.getPreferredSize().width, text.getPreferredSize().height));
text.setAlignmentX(Component.LEFT_ALIGNMENT);

messageValue.setSelectedItem(model.getMessageValue());
identifier.setSelectedItem(model.getIdentifiers().getSelectedOption());
matchType.setSelectedItem(model.getMatchType());
text.setText(model.getText());

messageValue.addActionListener(this::onMessageValueChanged);
identifier.addActionListener(this::onIdentifierChanged);
matchType.addActionListener(this::onMatchTypeChanged);
text.getDocument().addDocumentListener(new DocumentActionListener(this::onTextChanged));

container.add(text, "wrap");
container.add(messageValue, "wrap");
container.add(ComponentVisibilityManager.withVisibilityFieldChangeDependency(
identifier,
List.of(messageValue, identifier),
() -> ((MessageValue) messageValue.getSelectedItem()).isIdentifierRequired() && identifier.getItemCount() != 0
), "wrap");
container.add(ComponentVisibilityManager.withVisibilityFieldChangeDependency(
new JLabel("Not Applicable"),
List.of(messageValue, identifier),
() -> ((MessageValue) messageValue.getSelectedItem()).isIdentifierRequired() && identifier.getItemCount() == 0
), "wrap");
container.add(ComponentVisibilityManager.withVisibilityFieldChangeDependency(
matchType,
List.of(messageValue, identifier),
() -> !((MessageValue) messageValue.getSelectedItem()).isIdentifierRequired() || identifier.getItemCount() != 0
), "wrap");
container.add(ComponentVisibilityManager.withVisibilityFieldChangeDependency(
text,
List.of(matchType, messageValue, identifier),
() -> (!((MessageValue) messageValue.getSelectedItem()).isIdentifierRequired() || identifier.getItemCount() != 0) && ((WizardMatchType) matchType.getSelectedItem()).isMatcher()
), "wrap");

add(new JSeparator(), BorderLayout.PAGE_START);
add(container, BorderLayout.CENTER);
if (deletable) {
JButton delete = new JButton("Delete");
delete.addActionListener(this::onDelete);
add(getRightJustifiedButton(delete), BorderLayout.PAGE_END);
}
}

private void resetIdentifiers() {
identifier.removeAllItems();
model.getIdentifiers().getOptions().forEach(option -> identifier.addItem(option));
identifier.setSelectedItem(model.getIdentifiers().getSelectedOption());
}

private void resetText() {
text.setText(model.getText());
}

private void onMessageValueChanged(ActionEvent actionEvent) {
model.setMessageValue((MessageValue) messageValue.getSelectedItem());
resetIdentifiers();
resetText();
}

private void onIdentifierChanged(ActionEvent actionEvent) {
model.setIdentifier((String) identifier.getSelectedItem());
resetText();
}

private void onMatchTypeChanged(ActionEvent actionEvent) {
model.setMatchType((WizardMatchType) matchType.getSelectedItem());
}

private void onTextChanged(ActionEvent actionEvent) {
model.setText(text.getText());
}

private void onDelete(ActionEvent actionEvent) {
model.setDeleted(true);
}

protected Component getRightJustifiedButton(JButton button) {
JPanel outerContainer = new JPanel(new FlowLayout(FlowLayout.RIGHT));
outerContainer.setAlignmentX(LEFT_ALIGNMENT);
outerContainer.setAlignmentY(TOP_ALIGNMENT);
outerContainer.add(button);
return outerContainer;
}
}
Loading

0 comments on commit b69069e

Please sign in to comment.