From 611c16f533031ad1a9575ebc7292d58909651ce0 Mon Sep 17 00:00:00 2001 From: ddwightx Date: Sun, 20 Mar 2022 18:24:26 -0400 Subject: [PATCH] Added new Then action: Then Evaluate. Changed Then Run Rule to use a dropdown to select a Rule to run. Added URL setter in Then Send Request and Then Build Http Message. Added right-click menu with Copy & Paste and an option to insert variable tags into text fields. Improved the default sizing of the When Wizard dialog. --- build.gradle | 2 +- docs/Readme.md | 2 + docs/Rules.md | 22 +++- docs/Variables.md | 4 +- .../reshaper/burp/core/messages/Encoder.java | 9 ++ .../burp/core/messages/EventInfo.java | 19 ++- .../burp/core/messages/MessageValue.java | 27 +++- .../core/messages/MessageValueHandler.java | 13 +- .../messages/entities/HttpRequestMessage.java | 18 +++ .../reshaper/burp/core/rules/Rule.java | 4 +- .../reshaper/burp/core/rules/RulesEngine.java | 6 +- .../burp/core/rules/RulesRegistry.java | 39 +++--- .../reshaper/burp/core/rules/thens/Then.java | 1 + .../rules/thens/ThenBuildHttpMessage.java | 3 +- .../burp/core/rules/thens/ThenEvaluate.java | 98 ++++++++++++++ .../burp/core/rules/thens/ThenRunRules.java | 4 +- .../core/rules/thens/ThenSendRequest.java | 51 ++++++-- .../burp/core/rules/thens/ThenType.java | 2 + .../thens/entities/evaluate/Operation.java | 37 ++++++ .../thens/entities/script/ReshaperObj.java | 1 + .../burp/core/utils/CollectionUtils.java | 37 ++++++ .../synfron/reshaper/burp/core/utils/Log.java | 1 + .../reshaper/burp/core/utils/TextUtils.java | 29 +++++ .../burp/core/vars/VariableSource.java | 16 ++- .../burp/core/vars/VariableSourceEntry.java | 27 +++- .../burp/core/vars/VariableString.java | 34 +++-- .../burp/ui/components/IFormComponent.java | 104 +++++++++++++-- .../ui/components/rules/RuleComponent.java | 2 +- .../components/rules/RuleListComponent.java | 9 +- .../rules/RuleOperationComponent.java | 9 -- .../rules/RuleOperationListComponent.java | 5 +- .../rules/thens/ThenBreakComponent.java | 2 +- .../thens/ThenBuildHttpMessageComponent.java | 8 +- .../rules/thens/ThenCommentComponent.java | 2 +- .../rules/thens/ThenContainerComponent.java | 2 + .../rules/thens/ThenDelayComponent.java | 2 +- .../rules/thens/ThenDeleteValueComponent.java | 7 +- .../thens/ThenDeleteVariableComponent.java | 4 +- .../rules/thens/ThenEvaluateComponent.java | 75 +++++++++++ .../rules/thens/ThenHighlightComponent.java | 2 +- .../rules/thens/ThenLogComponent.java | 2 +- .../thens/ThenParseHttpMessageComponent.java | 4 +- .../rules/thens/ThenPromptComponent.java | 10 +- .../rules/thens/ThenRunProcessComponent.java | 10 +- .../rules/thens/ThenRunRulesComponent.java | 19 ++- .../rules/thens/ThenRunScriptComponent.java | 2 +- .../rules/thens/ThenSaveFileComponent.java | 12 +- .../rules/thens/ThenSendRequestComponent.java | 31 +++-- .../rules/thens/ThenSendToComponent.java | 14 +- .../rules/thens/ThenSetComponent.java | 21 ++- .../rules/thens/ThenSetEncodingComponent.java | 2 +- .../thens/ThenSetEventDirectionComponent.java | 2 +- .../rules/thens/ThenSetValueComponent.java | 6 +- .../rules/thens/ThenSetVariableComponent.java | 4 +- .../MessageValueSetterComponent.java | 19 +-- .../MessageValueGetterComponent.java | 24 ++-- .../whens/WhenEventDirectionComponent.java | 2 +- .../rules/whens/WhenFromToolComponent.java | 2 +- .../rules/whens/WhenHasEntityComponent.java | 4 +- .../rules/whens/WhenInScopeComponent.java | 2 +- .../rules/whens/WhenMatchesTextComponent.java | 16 +-- .../rules/whens/WhenProxyNameComponent.java | 2 +- .../CookieJarVariableTagWizardComponent.java | 74 +++++++++++ .../vars/EventVariableTagWizardComponent.java | 34 +++++ .../vars/FileVariableTagWizardComponent.java | 79 ++++++++++++ .../GlobalVariableTagWizardComponent.java | 34 +++++ .../MessageVariableTagWizardComponent.java | 50 ++++++++ .../SpecialVariableTagWizardComponent.java | 49 +++++++ .../VariableTagWizardContainerComponent.java | 34 +++++ .../vars/VariableTagWizardOptionPane.java | 96 ++++++++++++++ .../{ => whens}/WhenWizardItemComponent.java | 20 +-- .../{ => whens}/WhenWizardOptionPane.java | 21 ++- .../settings/SettingsTabComponent.java | 6 +- .../ui/components/vars/VariableComponent.java | 2 +- .../burp/ui/models/rules/RuleModel.java | 15 +-- .../models/rules/thens/IVariableCreator.java | 9 ++ .../thens/ThenBuildHttpMessageModel.java | 24 +++- .../models/rules/thens/ThenEvaluateModel.java | 112 ++++++++++++++++ .../ui/models/rules/thens/ThenModelType.java | 2 + .../thens/ThenParseHttpMessageModel.java | 13 +- .../models/rules/thens/ThenPromptModel.java | 12 +- .../rules/thens/ThenRunProcessModel.java | 12 +- .../rules/thens/ThenSendRequestModel.java | 39 ++++-- .../rules/thens/ThenSetVariableModel.java | 12 +- .../rules/thens/VariableCreatorRegistry.java | 31 +++++ .../vars/CookieJarVariableTagWizardModel.java | 121 ++++++++++++++++++ .../vars/EventVariableTagWizardModel.java | 65 ++++++++++ .../vars/FileVariableTagWizardModel.java | 62 +++++++++ .../vars/GlobalVariableTagWizardModel.java | 67 ++++++++++ .../wizard/vars/IVariableTagWizardModel.java | 13 ++ .../vars/MessageVariableTagWizardModel.java | 63 +++++++++ .../vars/SpecialVariableTagWizardModel.java | 102 +++++++++++++++ .../wizard/vars/VariableTagWizardModel.java | 99 ++++++++++++++ .../{ => whens}/WhenWizardItemModel.java | 6 +- .../WhenWizardMatchType.java} | 6 +- .../wizard/{ => whens}/WhenWizardModel.java | 19 ++- .../burp/ui/utils/ContextMenuHandler.java | 26 +--- .../reshaper/burp/ui/utils/IPrompter.java | 5 + .../burp/ui/utils/IPrompterModel.java | 21 +++ ...essagePrompter.java => ModalPrompter.java} | 39 +++++- .../burp/ui/utils/UiMessageHandler.java | 4 +- 101 files changed, 2129 insertions(+), 318 deletions(-) create mode 100644 src/main/java/synfron/reshaper/burp/core/rules/thens/ThenEvaluate.java create mode 100644 src/main/java/synfron/reshaper/burp/core/rules/thens/entities/evaluate/Operation.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenEvaluateComponent.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/CookieJarVariableTagWizardComponent.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/EventVariableTagWizardComponent.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/FileVariableTagWizardComponent.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/GlobalVariableTagWizardComponent.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/MessageVariableTagWizardComponent.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/SpecialVariableTagWizardComponent.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardContainerComponent.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardOptionPane.java rename src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/{ => whens}/WhenWizardItemComponent.java (87%) rename src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/{ => whens}/WhenWizardOptionPane.java (88%) create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/thens/IVariableCreator.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenEvaluateModel.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/thens/VariableCreatorRegistry.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CookieJarVariableTagWizardModel.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/EventVariableTagWizardModel.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/FileVariableTagWizardModel.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GlobalVariableTagWizardModel.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/IVariableTagWizardModel.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MessageVariableTagWizardModel.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SpecialVariableTagWizardModel.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/VariableTagWizardModel.java rename src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/{ => whens}/WhenWizardItemModel.java (95%) rename src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/{WizardMatchType.java => whens/WhenWizardMatchType.java} (74%) rename src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/{ => whens}/WhenWizardModel.java (89%) create mode 100644 src/main/java/synfron/reshaper/burp/ui/utils/IPrompter.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/utils/IPrompterModel.java rename src/main/java/synfron/reshaper/burp/ui/utils/{MessagePrompter.java => ModalPrompter.java} (56%) diff --git a/build.gradle b/build.gradle index e5d7a0c..65c49e6 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ plugins { } group 'com.synfron.reshaper.burp' -version '1.7.0' +version '1.8.0' targetCompatibility = '15' sourceCompatibility = '15' diff --git a/docs/Readme.md b/docs/Readme.md index af797e8..3b9984e 100644 --- a/docs/Readme.md +++ b/docs/Readme.md @@ -50,6 +50,8 @@ Run Rules - Run a specific rule or all auto-run rules Run Script - Execute a JavaScript script +Evaluate - Perform operations on values + Set Event Direction - Change whether to send a request or to send a response at the end of processing Set Encoding - Set the encoding used to read and write bytes of the HTTP request or response body diff --git a/docs/Rules.md b/docs/Rules.md index 46fb6b5..c4d393a 100644 --- a/docs/Rules.md +++ b/docs/Rules.md @@ -173,6 +173,18 @@ Script - The text of the JavaScript script to run. Max Execution (secs) - Terminate long-running scripts after this time. +### Evaluate + +Perform operations on values + +#### Fields + +X - First value. Supports variable tags. + +Operation - `Add`, `Subtract`, `Multiply`, `Divide By`, `Increment`, `Decrement`, `Mod`, `Abs`, `Round`, `Equals`, `Greater Than`, `Greater Than Or Equals`, `Less Than`, or `Less Than Or Equals` + +Y - Second value. Only available for certain operations. Supports variable tags. + ### Set Event Direction Change whether to send a request or to send a response at the end of processing @@ -398,13 +410,15 @@ Send a separate HTTP request. #### Fields -Protocol - `http` or `https`. Supports variable tags. +Request - The HTTP request message to send. Uses the value from the current event if left blank. Supports variable tags. + +URL - The URL of the request. If this is set, it overrides the Host request header, the request message URI, protocol, address, and port. Supports variable tags. -Address - Host name without port. Example: `www.example.com`. Supports variable tags. +Protocol - `http` or `https`. If this is set, it overrides the values from the URL (if set) or the current event. Supports variable tags. -Port - Example: `80`. Supports variable tags. +Address - Hostname without port. If this is set, it overrides the values from the URL (if set) or the current event. Example: `www.example.com`. Supports variable tags. -Request - The HTTP request message to send. Supports variable tags. +Port - Example: `80`. If this is set, it overrides the values from the URL (if set) or the current event. Supports variable tags. Wait for Completion - Wait for a response before continuing. diff --git a/docs/Variables.md b/docs/Variables.md index 5a52086..60cdd90 100644 --- a/docs/Variables.md +++ b/docs/Variables.md @@ -20,7 +20,7 @@ Special character variables provide access to special characters which typically ## Variable Tags -Variables can be read by Whens and Thens when a variable tag is specified in supporting text fields. +Variables can be read by Whens and Thens when a variable tag is specified in supporting text fields. Variable tags can be typed in manually or inserted via the right-click menu for those text fields. {% raw %} **Event Variable Tag (event, e):** `{{event:MyVariableName}}` @@ -35,7 +35,7 @@ For example, if Global variable named `firstName` has the value `John` and varia **Special Character Tag (special, s):** `{{s:specialCharacterSequences}}`. Examples: `{{s:n}}` (new line), `{{s:rn}}` (carriage return + new line), `{{s:u00A9}}` (Copyright symbol) -**Cookie Jar Tag (cookiejar, cj):** `{{cookiejar:domain}}` or `{{cookiejar:domain:path}}`. Example: `{{cookiejar:example.com:/}}` +**Cookie Jar Tag (cookiejar, cj):** `{{cookiejar:domain:name}}` or `{{cookiejar:domain:name:path}}`. Example: `{{cookiejar:example.com:tracker:/}}` {% endraw %} diff --git a/src/main/java/synfron/reshaper/burp/core/messages/Encoder.java b/src/main/java/synfron/reshaper/burp/core/messages/Encoder.java index 22c5cec..c3957f3 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/Encoder.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/Encoder.java @@ -30,6 +30,15 @@ public Encoder(String encoding) { setEncoding(encoding, true); } + public String getEncoding() { + if (useAutoDetect) { + return autoDetectEncoderName; + } else if (useDefault) { + return defaultEncoderName; + } + return charset.displayName(); + } + public void setEncoding(String encoding, boolean autoSet) { useDefault = false; useAutoDetect = false; diff --git a/src/main/java/synfron/reshaper/burp/core/messages/EventInfo.java b/src/main/java/synfron/reshaper/burp/core/messages/EventInfo.java index 2b8bac2..e05b9e3 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/EventInfo.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/EventInfo.java @@ -3,6 +3,7 @@ import burp.BurpExtender; import burp.IHttpRequestResponse; import burp.IInterceptedProxyMessage; +import lombok.Data; import lombok.Getter; import synfron.reshaper.burp.core.BurpTool; import synfron.reshaper.burp.core.exceptions.WrappedException; @@ -74,6 +75,20 @@ public EventInfo(DataDirection dataDirection, BurpTool burpTool, IHttpRequestRes proxyName = null; } + public EventInfo(IEventInfo sourceEventInfo) { + this.burpTool = sourceEventInfo.getBurpTool(); + this.dataDirection = sourceEventInfo.getDataDirection(); + this.requestResponse = null; + this.encoder.setEncoding(sourceEventInfo.getEncoder().getEncoding(), sourceEventInfo.getEncoder().isAutoSet()); + httpRequestMessage = new HttpRequestMessage(sourceEventInfo.getHttpRequestMessage().getValue(), encoder); + httpResponseMessage = new HttpResponseMessage(sourceEventInfo.getHttpResponseMessage().getValue(), encoder); + httpProtocol = sourceEventInfo.getHttpProtocol(); + sourceAddress = sourceEventInfo.getSourceAddress(); + destinationPort = sourceEventInfo.getDestinationPort(); + destinationAddress = sourceEventInfo.getDestinationAddress(); + proxyName = sourceEventInfo.getProxyName(); + } + @Override public void setDataDirection(DataDirection dataDirection) { this.dataDirection = dataDirection; @@ -123,8 +138,7 @@ public void setUrl(String urlStr) { setHttpProtocol(url.getProtocol()); setDestinationAddress(url.getHost()); setDestinationPort(url.getPort() > 0 ? url.getPort() : url.getDefaultPort()); - getHttpRequestMessage().getStatusLine().setUrl(url.getFile().startsWith("/") ? url.getFile() : "/" + url.getFile()); - getHttpRequestMessage().getHeaders().setHeader("Host", url.getAuthority(), SetItemPlacement.Only); + getHttpRequestMessage().setUrl(url); } catch (MalformedURLException e) { throw new WrappedException(e); } @@ -162,4 +176,5 @@ public String getUrl() { } return url; } + } diff --git a/src/main/java/synfron/reshaper/burp/core/messages/MessageValue.java b/src/main/java/synfron/reshaper/burp/core/messages/MessageValue.java index 11918b2..b9fc711 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/MessageValue.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/MessageValue.java @@ -4,11 +4,11 @@ public enum MessageValue { SourceAddress("Source Address", null, true, false), - DestinationAddress("Destination Address", null, true, false), - DestinationPort("Destination Port", null, true, false), - HttpProtocol("Protocol", null, true, false), - Url("URL", null, true, false), - HttpRequestMessage("Request Message", DataDirection.Request, true, false), + DestinationAddress("Destination Address", DataDirection.Request, true, false), + DestinationPort("Destination Port", DataDirection.Request, true, false), + HttpProtocol("Protocol", DataDirection.Request, true, false), + Url("URL", DataDirection.Request, true, false, true, false), + HttpRequestMessage("Request Message", DataDirection.Request, true, true, false, false), HttpRequestStatusLine("Request Status Line", DataDirection.Request, false, false), HttpRequestMethod("Request Method", DataDirection.Request, false, false), HttpRequestUri("Request URI", DataDirection.Request, false, false), @@ -19,7 +19,7 @@ public enum MessageValue { HttpRequestHeader("Request Header", DataDirection.Request, false, true), HttpRequestCookie("Request Cookie", DataDirection.Request, false, true), HttpRequestBody("Request Body", DataDirection.Request, false, false), - HttpResponseMessage("Response Message", DataDirection.Response, true, false), + HttpResponseMessage("Response Message", DataDirection.Response, true, true, false, false), HttpResponseStatusLine("Response Status Line", DataDirection.Response, false, false), HttpResponseStatusCode("Response Status Code", DataDirection.Response, false, false), HttpResponseStatusMessage("Response Status Message", DataDirection.Response, false, false), @@ -35,12 +35,27 @@ public enum MessageValue { @Getter private final boolean topLevel; @Getter + private final boolean messageGettable; + @Getter + private final boolean messageSettable; + @Getter private final boolean identifierRequired; MessageValue(String name, DataDirection dataDirection, boolean topLevel, boolean identifierRequired) { this.name = name; this.dataDirection = dataDirection; this.topLevel = topLevel; + this.messageGettable = !topLevel; + this.messageSettable = !topLevel; + this.identifierRequired = identifierRequired; + } + + MessageValue(String name, DataDirection dataDirection, boolean topLevel, boolean messageGettable, boolean messageSettable, boolean identifierRequired) { + this.name = name; + this.dataDirection = dataDirection; + this.topLevel = topLevel; + this.messageGettable = messageGettable; + this.messageSettable = messageSettable; this.identifierRequired = identifierRequired; } diff --git a/src/main/java/synfron/reshaper/burp/core/messages/MessageValueHandler.java b/src/main/java/synfron/reshaper/burp/core/messages/MessageValueHandler.java index 2f54153..09b86bd 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/MessageValueHandler.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/MessageValueHandler.java @@ -16,9 +16,9 @@ public class MessageValueHandler { public static String getValue(IEventInfo eventInfo, MessageValue messageValue, VariableString identifier, GetItemPlacement itemPlacement) { String value; - if (messageValue.getDataDirection() == DataDirection.Request) { + if (!messageValue.isTopLevel() && messageValue.getDataDirection() == DataDirection.Request) { value = getRequestValue(eventInfo, eventInfo.getHttpRequestMessage(), messageValue, identifier, itemPlacement); - } else if (messageValue.getDataDirection() == DataDirection.Response) { + } else if (!messageValue.isTopLevel() && messageValue.getDataDirection() == DataDirection.Response) { value = getResponseValue(eventInfo, eventInfo.getHttpResponseMessage(), messageValue, identifier, itemPlacement); } else { value = switch (messageValue) { @@ -27,6 +27,8 @@ public static String getValue(IEventInfo eventInfo, MessageValue messageValue, V case SourceAddress -> eventInfo.getSourceAddress(); case DestinationPort -> Integer.toString(eventInfo.getDestinationPort()); case DestinationAddress -> eventInfo.getDestinationAddress(); + case HttpRequestMessage -> eventInfo.getHttpRequestMessage().getText(); + case HttpResponseMessage -> eventInfo.getHttpResponseMessage().getText(); default -> throw new UnsupportedOperationException(String.format("Cannot get message value '%s'", messageValue)); }; } @@ -67,9 +69,9 @@ public static String getResponseValue(IEventInfo eventInfo, HttpResponseMessage public static void setValue(IEventInfo eventInfo, MessageValue messageValue, VariableString identifier, SetItemPlacement itemPlacement, String replacementText) { - if (messageValue.getDataDirection() == DataDirection.Request && !messageValue.isTopLevel()) { + if (!messageValue.isTopLevel() && messageValue.getDataDirection() == DataDirection.Request) { setRequestValue(eventInfo, eventInfo.getHttpRequestMessage(), messageValue, identifier,itemPlacement, replacementText); - } else if (messageValue.getDataDirection() == DataDirection.Response && !messageValue.isTopLevel()) { + } else if (!messageValue.isTopLevel() && messageValue.getDataDirection() == DataDirection.Response) { setResponseValue(eventInfo, eventInfo.getHttpResponseMessage(), messageValue, identifier, itemPlacement, replacementText); } else { switch (messageValue) { @@ -92,11 +94,11 @@ public static void setRequestValue(IEventInfo eventInfo, HttpRequestMessage requ case HttpRequestStatusLine -> requestMessage.setStatusLine(replacementText); case HttpRequestCookie -> requestMessage.getHeaders().getCookies().setCookie(identifier.getText(eventInfo), replacementText, itemPlacement); case HttpRequestUri -> requestMessage.getStatusLine().setUrl(replacementText); - case HttpRequestMessage -> eventInfo.setHttpRequestMessage(eventInfo.getEncoder().encode(replacementText)); case HttpRequestMethod -> requestMessage.getStatusLine().setMethod(replacementText); case HttpRequestUriPath -> requestMessage.getStatusLine().getUrl().setPath(StringUtils.defaultString(replacementText)); case HttpRequestUriQueryParameter -> requestMessage.getStatusLine().getUrl().getQueryParams().setQueryParameter(identifier.getText(eventInfo), replacementText, itemPlacement); case HttpRequestUriQueryParameters -> requestMessage.getStatusLine().getUrl().setQueryParametersText(StringUtils.defaultString(replacementText)); + case Url -> requestMessage.setUrl(StringUtils.defaultString(replacementText)); } } @@ -107,7 +109,6 @@ public static void setResponseValue(IEventInfo eventInfo, HttpResponseMessage re case HttpResponseBody -> responseMessage.setBody(StringUtils.defaultString(replacementText)); case HttpResponseStatusLine -> responseMessage.setStatusLine(replacementText); case HttpResponseCookie -> responseMessage.getHeaders().getCookies().setCookie(identifier.getText(eventInfo), replacementText, itemPlacement); - case HttpResponseMessage -> eventInfo.setHttpResponseMessage(eventInfo.getEncoder().encode(replacementText)); case HttpResponseStatusCode -> responseMessage.getStatusLine().setCode(replacementText); case HttpResponseStatusMessage -> responseMessage.getStatusLine().setMessage(StringUtils.defaultString(replacementText)); } diff --git a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestMessage.java b/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestMessage.java index c9a1399..ad30afe 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestMessage.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestMessage.java @@ -3,10 +3,14 @@ import burp.BurpExtender; import burp.IRequestInfo; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.exceptions.WrappedException; import synfron.reshaper.burp.core.messages.ContentType; import synfron.reshaper.burp.core.messages.Encoder; import synfron.reshaper.burp.core.utils.CollectionUtils; +import synfron.reshaper.burp.core.utils.SetItemPlacement; +import java.net.MalformedURLException; +import java.net.URL; import java.util.Arrays; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -87,6 +91,20 @@ public void setBody(String body) { changed = true; } + public void setUrl(String urlStr) { + try { + URL url = new URL(urlStr); + setUrl(url); + } catch (MalformedURLException e) { + throw new WrappedException(e); + } + } + + public void setUrl(URL url) { + getStatusLine().setUrl(url.getFile().startsWith("/") ? url.getFile() : "/" + url.getFile()); + getHeaders().setHeader("Host", url.getAuthority(), SetItemPlacement.Only); + } + public byte[] getValue() { return !isChanged() ? getAdjustedRequest(request) : diff --git a/src/main/java/synfron/reshaper/burp/core/rules/Rule.java b/src/main/java/synfron/reshaper/burp/core/rules/Rule.java index a934b8e..9f37943 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/Rule.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/Rule.java @@ -19,9 +19,9 @@ public class Rule implements Serializable { @Getter private final transient PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); @Getter @Setter - private List> whens = new ArrayList<>(); + private When[] whens = new When[0]; @Getter @Setter - private List> thens = new ArrayList<>(); + private Then[] thens = new Then[0]; @Getter private boolean enabled = true; @Getter diff --git a/src/main/java/synfron/reshaper/burp/core/rules/RulesEngine.java b/src/main/java/synfron/reshaper/burp/core/rules/RulesEngine.java index 7e0b8f1..cd4bcd6 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/RulesEngine.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/RulesEngine.java @@ -14,7 +14,7 @@ public class RulesEngine { @Getter private final RulesRegistry rulesRegistry = new RulesRegistry(); - private boolean match(List> whens, IEventInfo eventInfo) + private boolean match(When[] whens, IEventInfo eventInfo) { boolean isMatch = true; boolean first = true; @@ -37,7 +37,7 @@ private boolean match(List> whens, IEventInfo eventInfo) return isMatch; } - private RuleResponse perform(List> thens, IEventInfo eventInfo) + private RuleResponse perform(Then[] thens, IEventInfo eventInfo) { RuleResponse thenResult = RuleResponse.Continue; for (Then then : thens) @@ -54,7 +54,7 @@ private RuleResponse perform(List> thens, IEventInfo eventInfo) public RuleResponse run(IEventInfo eventInfo) { - List rules = rulesRegistry.getRules(); + Rule[] rules = rulesRegistry.getRules(); try { if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logStart(eventInfo); for (Rule rule : rules) { diff --git a/src/main/java/synfron/reshaper/burp/core/rules/RulesRegistry.java b/src/main/java/synfron/reshaper/burp/core/rules/RulesRegistry.java index 00802b7..d437f8e 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/RulesRegistry.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/RulesRegistry.java @@ -1,9 +1,11 @@ package synfron.reshaper.burp.core.rules; import lombok.Getter; +import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import synfron.reshaper.burp.core.events.*; +import synfron.reshaper.burp.core.utils.CollectionUtils; import java.util.ArrayList; import java.util.Collections; @@ -18,34 +20,34 @@ public class RulesRegistry { private final IEventListener rulePropertyChangedListener = this::onRulePropertyChanged; - private List rules = new ArrayList<>(); + private Rule[] rules = new Rule[0]; - public List getRules() { - return new ArrayList<>(rules); + public Rule[] getRules() { + return rules; } @Getter private final CollectionChangedEvent collectionChangedEvent = new CollectionChangedEvent(); public synchronized void deleteRule(Rule rule) { - int index = rules.indexOf(rule); + int index = ArrayUtils.indexOf(rules, rule); if (index >= 0) { - rules.remove(index); + rules = ArrayUtils.remove(rules, index); version++; collectionChangedEvent.invoke(new CollectionChangedArgs(this, CollectionChangedAction.Remove, index, rule)); } } public synchronized void addRule(Rule rule) { - rules.add(rule); + rules = ArrayUtils.add(rules, rule); version++; - collectionChangedEvent.invoke(new CollectionChangedArgs(this, CollectionChangedAction.Add, rules.size() - 1, rule)); + collectionChangedEvent.invoke(new CollectionChangedArgs(this, CollectionChangedAction.Add, rules.length - 1, rule)); rule.getPropertyChangedEvent().add(rulePropertyChangedListener); } private void onRulePropertyChanged(PropertyChangedArgs propertyChangedArgs) { Rule rule = (Rule)propertyChangedArgs.getSource(); - int index = rules.indexOf(rule); + int index = ArrayUtils.indexOf(rules, rule); if (index >= 0) { version++; collectionChangedEvent.invoke(new CollectionChangedArgs(this, CollectionChangedAction.Update, index, rule)); @@ -55,11 +57,9 @@ private void onRulePropertyChanged(PropertyChangedArgs propertyChangedArgs) { public synchronized void movePrevious(Rule rule) { if (rule != null) { - int currentIndex = rules.indexOf(rule); + int currentIndex = ArrayUtils.indexOf(rules, rule); if (currentIndex > 0) { - - rules.remove(currentIndex); - rules.add(--currentIndex, rule); + rules = CollectionUtils.move(rules, rule, currentIndex, --currentIndex); version++; collectionChangedEvent.invoke(new CollectionChangedArgs(this, CollectionChangedAction.Move, currentIndex + 1, currentIndex, rule)); } @@ -70,11 +70,10 @@ public synchronized void moveNext(Rule rule) { if (rule != null) { - int currentIndex = rules.indexOf(rule); - if (currentIndex < rules.size() - 1) + int currentIndex = ArrayUtils.indexOf(rules, rule); + if (currentIndex < rules.length - 1) { - rules.remove(currentIndex); - rules.add(++currentIndex, rule); + rules = CollectionUtils.move(rules, rule, currentIndex, ++currentIndex); version++; collectionChangedEvent.invoke(new CollectionChangedArgs(this, CollectionChangedAction.Move, currentIndex - 1, currentIndex, rule)); } @@ -83,20 +82,20 @@ public synchronized void moveNext(Rule rule) public void importRules(List rules, boolean overwriteDuplicates) { rules = ObjectUtils.defaultIfNull(rules, Collections.emptyList()); - Set existingRules = this.rules.stream().map(Rule::toString).collect(Collectors.toSet()); + Set existingRules = Stream.of(this.rules).map(Rule::toString).collect(Collectors.toSet()); Set newRules = rules.stream().map(Rule::toString).collect(Collectors.toSet()); this.rules = Stream.concat( - this.rules.stream() + Stream.of(this.rules) .filter(rule -> !overwriteDuplicates || !newRules.contains(rule.getName())), rules.stream() .filter(rule -> overwriteDuplicates || !existingRules.contains(rule.getName())) .map(rule -> rule.withListener(rulePropertyChangedListener)) - ).collect(Collectors.toList()); + ).toArray(Rule[]::new); version++; collectionChangedEvent.invoke(new CollectionChangedArgs(this, CollectionChangedAction.Reset)); } public List exportRules() { - return rules.stream().filter(rule -> StringUtils.isNotEmpty(rule.getName())).collect(Collectors.toList()); + return Stream.of(this.rules).filter(rule -> StringUtils.isNotEmpty(rule.getName())).collect(Collectors.toList()); } } diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/Then.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/Then.java index 6ea1dad..590401d 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/Then.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/Then.java @@ -19,6 +19,7 @@ @JsonSubTypes.Type(value = ThenLog.class), @JsonSubTypes.Type(value = ThenRunRules.class), @JsonSubTypes.Type(value = ThenRunScript.class), + @JsonSubTypes.Type(value = ThenEvaluate.class), @JsonSubTypes.Type(value = ThenSendTo.class), @JsonSubTypes.Type(value = ThenSetEventDirection.class), @JsonSubTypes.Type(value = ThenSetValue.class), diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenBuildHttpMessage.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenBuildHttpMessage.java index 840a875..a0edc72 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenBuildHttpMessage.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenBuildHttpMessage.java @@ -1,6 +1,5 @@ package synfron.reshaper.burp.core.rules.thens; -import burp.BurpExtender; import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.tuple.Pair; @@ -52,7 +51,7 @@ public RuleResponse perform(IEventInfo eventInfo) { ), messageValueSetters.stream().map(messageValueSetter -> Pair.of( VariableSourceEntry.getTag( - VariableSource.Message.name().toLowerCase(), + VariableSource.Message, messageValueSetter.getDestinationMessageValue().name().toLowerCase(), messageValueSetter.getDestinationMessageValue().isIdentifierRequired() ? VariableString.getTextOrDefault( eventInfo, messageValueSetter.getDestinationIdentifier(), null diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenEvaluate.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenEvaluate.java new file mode 100644 index 0000000..a29af1d --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenEvaluate.java @@ -0,0 +1,98 @@ +package synfron.reshaper.burp.core.rules.thens; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.rules.RuleOperationType; +import synfron.reshaper.burp.core.rules.RuleResponse; +import synfron.reshaper.burp.core.rules.thens.entities.evaluate.Operation; +import synfron.reshaper.burp.core.vars.*; + +import java.util.Arrays; + +public class ThenEvaluate extends Then { + @Getter + @Setter + private VariableString x; + @Getter + @Setter + private Operation operation = Operation.Add; + @Getter + @Setter + private VariableString y; + @Getter @Setter + private VariableSource destinationVariableSource = VariableSource.Global; + @Getter @Setter + private VariableString destinationVariableName; + + @Override + public RuleResponse perform(IEventInfo eventInfo) { + boolean hasError = true; + String result = null; + try { + Variables variables = switch (destinationVariableSource) { + case Event -> eventInfo.getVariables(); + case Global -> GlobalVariables.get(); + default -> null; + }; + if (variables != null) { + Variable variable = variables.add(destinationVariableName.getText(eventInfo)); + result = evaluate(eventInfo); + if (result != null) { + variable.setValue(result); + } + } + hasError = result == null; + } finally { + if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logProperties(this, hasError, Arrays.asList( + Pair.of("X", VariableString.getTextOrDefault(eventInfo, x, null)), + Pair.of("Y", VariableString.getTextOrDefault(eventInfo, y, null)), + Pair.of("destinationVariableSource", destinationVariableSource), + Pair.of("destinationVariableName", VariableString.getTextOrDefault(eventInfo, destinationVariableName, null)), + Pair.of("result", result) + )); + } + return RuleResponse.Continue; + } + + private String evaluate(IEventInfo eventInfo) { + Double value1 = operation.getInputs() > 0 ? VariableString.getDoubleOrDefault(eventInfo, x, null) : null; + Double value2 = operation.getInputs() > 1 ? VariableString.getDoubleOrDefault(eventInfo, y, null) : null; + String result = null; + if ((operation.getInputs() == 1 && value1 != null) + || (operation.getInputs() == 2 && value1 != null && value2 != null)) { + result = switch (operation) { + case Add -> toString(value1 + value2); + case Subtract -> toString(value1 - value2); + case Multiply -> toString(value1 * value2); + case DivideBy -> toString(value1 / value2); + case Increment -> toString(value1 + 1); + case Decrement -> toString(value1 - 1); + case Equals -> toString(value1.equals(value2)); + case GreaterThan -> toString(value1 > value2); + case GreaterThanOrEquals -> toString(value1 >= value2); + case LessThan -> toString(value1 < value2); + case LessThanOrEquals -> toString(value1 <= value2); + case Abs -> toString(Math.abs(value1)); + case Mod -> toString(value1 % value2); + case Round -> toString(Math.round(value1)); + }; + } + return result; + } + + private String toString(double value) { + return StringUtils.removeEnd(String.valueOf(value), ".0"); + } + + private String toString(boolean value) { + return String.valueOf(value); + } + + @Override + public RuleOperationType getType() { + return ThenType.Evaluate; + } +} diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRunRules.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRunRules.java index 5062245..035d604 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRunRules.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRunRules.java @@ -10,6 +10,8 @@ import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.rules.RulesEngine; +import java.util.stream.Stream; + public class ThenRunRules extends Then { private int cacheVersion; private transient Rule ruleCache = null; @@ -42,7 +44,7 @@ public RuleResponse perform(IEventInfo eventInfo) { private Rule getRule(RulesEngine rulesEngine) { if (isRuleCacheExpired(rulesEngine)) { - ruleCache = rulesEngine.getRulesRegistry().getRules().stream() + ruleCache = Stream.of(rulesEngine.getRulesRegistry().getRules()) .filter(rule -> StringUtils.isNotEmpty(rule.getName()) && rule.getName().equals(ruleName)) .findFirst() .get(); diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSendRequest.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSendRequest.java index adfcfc3..0d4a8be 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSendRequest.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSendRequest.java @@ -6,7 +6,10 @@ import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.events.Event; import synfron.reshaper.burp.core.exceptions.WrappedException; +import synfron.reshaper.burp.core.messages.DataDirection; +import synfron.reshaper.burp.core.messages.EventInfo; import synfron.reshaper.burp.core.messages.IEventInfo; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; @@ -20,6 +23,10 @@ import java.util.concurrent.atomic.AtomicReference; public class ThenSendRequest extends Then { + @Getter @Setter + private VariableString request; + @Getter @Setter + private VariableString url; @Getter @Setter private VariableString protocol; @Getter @Setter @@ -27,8 +34,6 @@ public class ThenSendRequest extends Then { @Getter @Setter private VariableString port; @Getter @Setter - private VariableString request; - @Getter @Setter private boolean waitForCompletion; @Getter @Setter private VariableString failAfter; @@ -60,17 +65,36 @@ public RuleResponse perform(IEventInfo eventInfo) { AtomicReference response = new AtomicReference<>(); executor.submit(() -> { try { - boolean useHttps = !StringUtils.equalsIgnoreCase(VariableString.getTextOrDefault(eventInfo, protocol, eventInfo.getHttpProtocol()), "http"); - String address = VariableString.getTextOrDefault(eventInfo, this.address, eventInfo.getDestinationAddress()); - int port = VariableString.getIntOrDefault(eventInfo, this.port, eventInfo.getDestinationPort() == null ? 0 : eventInfo.getDestinationPort()); - byte[] request = this.request != null && !this.request.isEmpty() ? - eventInfo.getEncoder().encode(this.request.getText(eventInfo)) : - eventInfo.getHttpRequestMessage().getValue(); + EventInfo newEventInfo = new EventInfo(eventInfo); + boolean useHttps = !StringUtils.equalsIgnoreCase(newEventInfo.getHttpProtocol(), "http"); + if (!VariableString.isEmpty(request)) { + newEventInfo.setHttpRequestMessage(eventInfo.getEncoder().encode(this.request.getText(eventInfo))); + } + if (!VariableString.isEmpty(url)) { + newEventInfo.setUrl(url.getText(eventInfo)); + useHttps = !StringUtils.equalsIgnoreCase(newEventInfo.getHttpProtocol(), "http"); + } + if (!VariableString.isEmpty(protocol)) { + useHttps = !StringUtils.equalsIgnoreCase(protocol.getText(eventInfo), "http"); + } + if (!VariableString.isEmpty(address)) { + newEventInfo.setDestinationAddress(address.getText(eventInfo)); + } + if (!VariableString.isEmpty(port)) { + newEventInfo.setDestinationPort(VariableString.getIntOrDefault( + eventInfo, + this.port, + (newEventInfo.getDestinationPort() == null || newEventInfo.getDestinationPort() == 0) ? + (useHttps ? 443 : 80) : + newEventInfo.getDestinationPort() + )); + } + byte[] responseBytes = BurpExtender.getCallbacks().makeHttpRequest( - address, - port > 0 ? port : (useHttps ? 443 : 80), + newEventInfo.getDestinationAddress(), + newEventInfo.getDestinationPort(), useHttps, - request + newEventInfo.getHttpRequestMessage().getValue() ); response.set(responseBytes); } catch (Exception e) { @@ -90,7 +114,7 @@ public RuleResponse perform(IEventInfo eventInfo) { 0; failed = !complete || (failOnErrorStatusCode && (exitCode == 0 || (exitCode >= 400 && exitCode < 600))); if (captureOutput && (!failed || captureAfterFailure)) { - output = BurpExtender.getCallbacks().getHelpers().bytesToString(response.get()); + output = response.get() != null ? BurpExtender.getCallbacks().getHelpers().bytesToString(response.get()) : ""; setVariable(eventInfo, captureVariableName, output); } } @@ -105,10 +129,11 @@ public RuleResponse perform(IEventInfo eventInfo) { } finally { if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logProperties(this, hasError, Arrays.asList( + Pair.of("url", VariableString.getTextOrDefault(eventInfo, url, null)), + Pair.of("request", VariableString.getTextOrDefault(eventInfo, request, null)), Pair.of("protocol", VariableString.getTextOrDefault(eventInfo, protocol, null)), Pair.of("address", VariableString.getTextOrDefault(eventInfo, address, null)), Pair.of("port", VariableString.getTextOrDefault(eventInfo, port, null)), - Pair.of("request", VariableString.getTextOrDefault(eventInfo, request, null)), Pair.of("output", output), Pair.of("captureVariableSource", waitForCompletion && captureOutput ? captureVariableSource : null), Pair.of("captureVariableName", waitForCompletion && captureOutput ? captureVariableName : null), diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenType.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenType.java index 7059b43..32d134a 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenType.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenType.java @@ -15,6 +15,7 @@ public class ThenType> extends RuleOperationType { public static final ThenType Prompt = new ThenType<>("Prompt", ThenPrompt.class); public static final ThenType RunRules = new ThenType<>("Run Rules", ThenRunRules.class); public static final ThenType RunScript = new ThenType<>("Run Script", ThenRunScript.class); + public static final ThenType Evaluate = new ThenType<>("Evaluate", ThenEvaluate.class); public static final ThenType SetEventDirection = new ThenType<>("Set Event Direction", ThenSetEventDirection.class); public static final ThenType SetEncoding = new ThenType<>("Set Encoding", ThenSetEncoding.class); public static final ThenType SetValue = new ThenType<>("Set Value", ThenSetValue.class); @@ -47,6 +48,7 @@ public static List> getTypes() { Prompt, RunRules, RunScript, + Evaluate, SetEventDirection, SetEncoding, SetValue, diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/evaluate/Operation.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/evaluate/Operation.java new file mode 100644 index 0000000..e5f0b2a --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/evaluate/Operation.java @@ -0,0 +1,37 @@ +package synfron.reshaper.burp.core.rules.thens.entities.evaluate; + +import lombok.Getter; + +public enum Operation { + Add("Add", 2), + Subtract("Subtract", 2), + Multiply("Multiply", 2), + DivideBy("Divide By", 2), + Increment("Increment", 1), + Decrement("Decrement", 1), + Mod("Mod", 2), + Abs("Abs", 1), + Round("Round", 1), + Equals("Equals", 2), + GreaterThan("Greater Than", 2), + GreaterThanOrEquals("Greater Than Or Equals", 2), + LessThan("Less Than", 2), + LessThanOrEquals("Less Than Or Equals", 2); + + @Getter + private final String name; + @Getter + private final int inputs; + + Operation(String name, int inputs) { + this.name = name; + this.inputs = inputs; + } + + @Override + public String toString() { + return name; + } + + +} diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/ReshaperObj.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/ReshaperObj.java index 4d31080..2478375 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/ReshaperObj.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/ReshaperObj.java @@ -107,6 +107,7 @@ public String runThen(String thenType, NativeObject thenData) { Stream> supportedThenTypes = Stream.of( ThenType.Highlight, ThenType.Comment, + ThenType.Evaluate, ThenType.BuildHttpMessage, ThenType.DeleteValue, ThenType.DeleteVariable, diff --git a/src/main/java/synfron/reshaper/burp/core/utils/CollectionUtils.java b/src/main/java/synfron/reshaper/burp/core/utils/CollectionUtils.java index 46fb576..91c7321 100644 --- a/src/main/java/synfron/reshaper/burp/core/utils/CollectionUtils.java +++ b/src/main/java/synfron/reshaper/burp/core/utils/CollectionUtils.java @@ -1,7 +1,10 @@ package synfron.reshaper.burp.core.utils; +import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.rules.Rule; +import java.lang.reflect.Array; import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -32,4 +35,38 @@ public static Stream splitNewLines(Stream values) { public static List splitNewLines(List values) { return splitNewLines(values.stream()).collect(Collectors.toList()); } + + @SuppressWarnings("unchecked") + public static T[] move(T[] array, T item, int currentIndex, int newIndex) { + if (currentIndex - newIndex == 1 || currentIndex - newIndex == -1) { + T[] newArray = ArrayUtils.clone(array); + ArrayUtils.swap(newArray, currentIndex, newIndex); + return newArray; + } + + if (currentIndex < 0 || currentIndex >= array.length) { + throw new IndexOutOfBoundsException(String.format("Index: %s, Size: %s", currentIndex, array.length)); + } + if (newIndex < 0 || newIndex >= array.length) { + throw new IndexOutOfBoundsException(String.format("Index: %s, Size: %s", newIndex, array.length)); + } + + final T[] result = (T[])Array.newInstance(array.getClass().getComponentType(), array.length - 1); + + if (currentIndex < newIndex) { + System.arraycopy(array, 0, result, 0, currentIndex); + System.arraycopy(array, currentIndex + 1, result, currentIndex, newIndex - currentIndex); + if (newIndex + 1 < array.length) { + System.arraycopy(array, newIndex + 1, result, newIndex + 1, array.length - (newIndex + 1)); + } + } else { + System.arraycopy(array, 0, result, 0, newIndex); + System.arraycopy(array, newIndex, result, newIndex + 1, currentIndex - newIndex); + if (currentIndex + 1 < array.length) { + System.arraycopy(array, currentIndex + 1, result, currentIndex + 1, array.length - (currentIndex + 1)); + } + } + result[newIndex] = array[currentIndex]; + return result; + } } diff --git a/src/main/java/synfron/reshaper/burp/core/utils/Log.java b/src/main/java/synfron/reshaper/burp/core/utils/Log.java index 39b536a..5610c07 100644 --- a/src/main/java/synfron/reshaper/burp/core/utils/Log.java +++ b/src/main/java/synfron/reshaper/burp/core/utils/Log.java @@ -36,6 +36,7 @@ public Log withException(Exception exception) { StringUtils.defaultString(exception.getMessage(), ""), ExceptionUtils.getStackTrace(exception) ); + exception.printStackTrace(); return this; } diff --git a/src/main/java/synfron/reshaper/burp/core/utils/TextUtils.java b/src/main/java/synfron/reshaper/burp/core/utils/TextUtils.java index 03197e0..6799101 100644 --- a/src/main/java/synfron/reshaper/burp/core/utils/TextUtils.java +++ b/src/main/java/synfron/reshaper/burp/core/utils/TextUtils.java @@ -100,6 +100,35 @@ public static boolean isInt(String text) { } } + public static Integer asInt(String text) { + Integer nullableValue = null; + try { + nullableValue = Integer.parseInt(text); + } catch (NumberFormatException ignored) { + + } + return nullableValue; + } + + public static boolean isDouble(String text) { + try { + Double.parseDouble(text); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + public static Double asDouble(String text) { + Double nullableValue = null; + try { + nullableValue = Double.parseDouble(text); + } catch (NumberFormatException ignored) { + + } + return nullableValue; + } + public static String toString(Object value) { return value != null ? value.toString() : null; } diff --git a/src/main/java/synfron/reshaper/burp/core/vars/VariableSource.java b/src/main/java/synfron/reshaper/burp/core/vars/VariableSource.java index 96bde70..4bd32a6 100644 --- a/src/main/java/synfron/reshaper/burp/core/vars/VariableSource.java +++ b/src/main/java/synfron/reshaper/burp/core/vars/VariableSource.java @@ -14,12 +14,20 @@ public enum VariableSource { Message("m", true), File("f", true), Special("s", true), - CookieJar("cj", true); + CookieJar("Cookie Jar", "cj", true); + private final String displayName; private final String shortName; private final boolean accessor; + VariableSource(String displayName, String shortName, boolean accessor) { + this.displayName = displayName; + this.shortName = shortName; + this.accessor = accessor; + } + VariableSource(String shortName, boolean accessor) { + this.displayName = this.name(); this.shortName = shortName; this.accessor = accessor; } @@ -37,4 +45,10 @@ public static VariableSource get(String name) { .findFirst() .orElse(null); } + + + @Override + public String toString() { + return displayName; + } } diff --git a/src/main/java/synfron/reshaper/burp/core/vars/VariableSourceEntry.java b/src/main/java/synfron/reshaper/burp/core/vars/VariableSourceEntry.java index 51ad0c2..1196805 100644 --- a/src/main/java/synfron/reshaper/burp/core/vars/VariableSourceEntry.java +++ b/src/main/java/synfron/reshaper/burp/core/vars/VariableSourceEntry.java @@ -4,6 +4,7 @@ import org.apache.commons.lang3.StringUtils; import java.io.Serializable; +import java.util.Arrays; import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -24,6 +25,12 @@ public VariableSourceEntry(VariableSource variableSource, String name, String ta this.tag = tag; } + public VariableSourceEntry(VariableSource variableSource, String name) { + this.variableSource = variableSource; + this.name = name; + this.tag = getTag(); + } + public String getTag() { return StringUtils.isNotEmpty(tag) ? tag : getTag(variableSource, name); } @@ -32,11 +39,21 @@ public static String getTag(VariableSource variableSource, String name) { return String.format("{{%s:%s}}", variableSource.toString().toLowerCase(), name); } - public static String getTag(String source, String name, String identifier) { - return String.format("{{%s}}", Stream.of( - StringUtils.defaultString(source), - StringUtils.defaultString(name), - StringUtils.defaultIfEmpty(identifier, null) + public static String getTag(VariableSource variableSource, String... names) { + return String.format("{{%s}}", Stream.concat( + Stream.of(StringUtils.defaultString(variableSource.toString().toLowerCase())), + Arrays.stream(names).map(name -> StringUtils.defaultIfEmpty(name, null)) + ).filter(Objects::nonNull).collect(Collectors.joining(":"))); + } + + public static String getShortTag(VariableSource variableSource, String name) { + return String.format("{{%s:%s}}", variableSource.getShortName(), name); + } + + public static String getShortTag(VariableSource variableSource, String... names) { + return String.format("{{%s}}", Stream.concat( + Stream.of(StringUtils.defaultString(variableSource.getShortName())), + Arrays.stream(names).map(name -> StringUtils.defaultIfEmpty(name, null)) ).filter(Objects::nonNull).collect(Collectors.joining(":"))); } } diff --git a/src/main/java/synfron/reshaper/burp/core/vars/VariableString.java b/src/main/java/synfron/reshaper/burp/core/vars/VariableString.java index a0861b9..24243eb 100644 --- a/src/main/java/synfron/reshaper/burp/core/vars/VariableString.java +++ b/src/main/java/synfron/reshaper/burp/core/vars/VariableString.java @@ -8,6 +8,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import synfron.reshaper.burp.core.messages.Encoder; import synfron.reshaper.burp.core.messages.IEventInfo; import synfron.reshaper.burp.core.messages.MessageValue; @@ -18,7 +19,6 @@ import synfron.reshaper.burp.core.utils.TextUtils; import java.io.File; -import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; @@ -55,6 +55,10 @@ public boolean isEmpty() { return StringUtils.isEmpty(text); } + public static boolean isEmpty(VariableString variableString) { + return variableString == null || variableString.isEmpty(); + } + public String toString() { return String.format(text, variables.stream().map(VariableSourceEntry::getTag).toArray()); @@ -63,10 +67,18 @@ public String toString() public static String toString(VariableString variableString, String defaultValue) { return variableString != null ? variableString.toString() : defaultValue; } + public static VariableString getAsVariableString(String str) { return getAsVariableString(str, true); } + public static List> getVariableTagPositions(String str) { + Pattern pattern = Pattern.compile(String.format("\\{\\{(%s):(.+?)\\}\\}", String.join("|", VariableSource.getSupportedNames()))); + return pattern.matcher(str).results() + .map(result -> Pair.of(result.start(), result.end())) + .collect(Collectors.toList()); + } + public static VariableString getAsVariableString(String str, boolean requiresParsing) { if (str == null) { @@ -97,14 +109,12 @@ public static VariableString getAsVariableString(String str, boolean requiresPar public Integer getInt(IEventInfo eventInfo) { - String text = getText(eventInfo); - Integer nullableValue = null; - try { - nullableValue = Integer.parseInt(text); - } catch (NumberFormatException ignored) { + return TextUtils.asInt(getText(eventInfo)); + } - } - return nullableValue; + public Double getDouble(IEventInfo eventInfo) + { + return TextUtils.asDouble(getText(eventInfo)); } public String getText(IEventInfo eventInfo) @@ -223,12 +233,18 @@ public static String getText(IEventInfo eventInfo, VariableString variableString return variableString != null ? variableString.getText(eventInfo) : null; } - public static int getIntOrDefault(IEventInfo eventInfo, VariableString variableString, int defaultValue) { + public static Integer getIntOrDefault(IEventInfo eventInfo, VariableString variableString, Integer defaultValue) { return variableString != null && !variableString.isEmpty() ? variableString.getInt(eventInfo) : defaultValue; } + public static Double getDoubleOrDefault(IEventInfo eventInfo, VariableString variableString, Double defaultValue) { + return variableString != null && !variableString.isEmpty() ? + variableString.getDouble(eventInfo) : + defaultValue; + } + public static boolean isPotentialInt(String formattedString) { if (StringUtils.isEmpty(formattedString)) { return false; diff --git a/src/main/java/synfron/reshaper/burp/ui/components/IFormComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/IFormComponent.java index 6282b69..461ea4f 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/IFormComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/IFormComponent.java @@ -1,15 +1,23 @@ package synfron.reshaper.burp.ui.components; import net.miginfocom.swing.MigLayout; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.vars.VariableString; +import synfron.reshaper.burp.ui.components.rules.wizard.vars.VariableTagWizardOptionPane; +import synfron.reshaper.burp.ui.models.rules.wizard.vars.VariableTagWizardModel; import synfron.reshaper.burp.ui.utils.ActionPerformedListener; +import synfron.reshaper.burp.ui.utils.ModalPrompter; import javax.swing.*; +import javax.swing.text.DefaultEditorKit; import javax.swing.text.JTextComponent; import javax.swing.undo.UndoManager; import java.awt.*; -import java.awt.event.InputEvent; import java.awt.event.KeyEvent; +import static java.awt.Component.LEFT_ALIGNMENT; +import static java.awt.Component.TOP_ALIGNMENT; + public interface IFormComponent { default Component getLabeledField(String label, Component innerComponent) { @@ -17,13 +25,7 @@ default Component getLabeledField(String label, Component innerComponent) { container.setLayout(new MigLayout()); container.setBorder(null); - if (innerComponent instanceof JTextField) { - JTextField textField = (JTextField) innerComponent; - textField.setColumns(20); - textField.setMaximumSize(new Dimension(textField.getPreferredSize().width, textField.getPreferredSize().height)); - textField.setAlignmentX(Component.LEFT_ALIGNMENT); - container.setBorder(BorderFactory.createEmptyBorder(0, -3, 0, 0)); - } else if (innerComponent instanceof JComboBox) { + if (innerComponent instanceof JTextField || innerComponent instanceof JComboBox) { container.setBorder(BorderFactory.createEmptyBorder(0, -3, 0, 0)); } @@ -32,14 +34,92 @@ default Component getLabeledField(String label, Component innerComponent) { return container; } - default JTextField createTextField() { - return addUndo(new JTextField()); + default JComboBox createComboBox(T[] array) { + return createComboBox(array, false); + } + + default JComboBox createComboBox(T[] array, boolean isEditable) { + JComboBox comboBox = new JComboBox<>(array); + if (isEditable) { + comboBox.setEditable(true); + int columnSize = comboBox.getFontMetrics(comboBox.getFont()).charWidth('m') * 20; + comboBox.setPreferredSize(new Dimension(columnSize, comboBox.getPreferredSize().height)); + } + return comboBox; + } + + default JTextField createTextField(boolean supportsVariableTags) { + JTextField textField = new JTextField(); + textField.setColumns(20); + textField.setMaximumSize(new Dimension(textField.getPreferredSize().width, textField.getPreferredSize().height)); + textField.setAlignmentX(LEFT_ALIGNMENT); + return addContextMenu(addUndo(textField), supportsVariableTags); + } + + default Component getPaddedButton(JButton button) { + JPanel outerContainer = new JPanel(new FlowLayout(FlowLayout.LEFT)); + outerContainer.setAlignmentX(LEFT_ALIGNMENT); + outerContainer.setAlignmentY(TOP_ALIGNMENT); + outerContainer.add(button); + return outerContainer; } default JTextPane createTextPane() { - return addUndo(new JTextPane()); + return addContextMenu(addUndo(new JTextPane()), false); + } + + private static T addContextMenu(T textComponent, boolean supportsVariableTags) { + JPopupMenu popupMenu = new JPopupMenu(); + + Action cut = new DefaultEditorKit.CutAction(); + Action copy = new DefaultEditorKit.CopyAction(); + Action paste = new DefaultEditorKit.PasteAction(); + Action selectAll = new ActionPerformedListener(event -> textComponent.selectAll()); + + cut.putValue(Action.NAME, "Cut"); + copy.putValue(Action.NAME, "Copy"); + paste.putValue(Action.NAME, "Paste"); + selectAll.putValue(Action.NAME, "Select All"); + + popupMenu.add(cut); + popupMenu.add(copy); + popupMenu.add(paste); + popupMenu.add(selectAll); + + if (supportsVariableTags) { + Action addVariableTag = new ActionPerformedListener(event -> insertVariableTag(textComponent)); + addVariableTag.putValue(Action.NAME, "Insert Variable Tag"); + popupMenu.addSeparator(); + popupMenu.add(addVariableTag); + } + + textComponent.setComponentPopupMenu(popupMenu); + + return textComponent; + } + + private static void insertVariableTag(T textComponent) { + VariableTagWizardModel model = new VariableTagWizardModel(); + do { + ModalPrompter.open(model, ignored -> VariableTagWizardOptionPane.showDialog(model), false); + } while (model.isInvalidated() && !model.isDismissed()); + if (!model.isDismissed()) { + String tag = model.getTag(); + if (StringUtils.isNotEmpty(tag)) { + int cursorPosition = textComponent.getCaretPosition(); + int insertPosition = VariableString.getVariableTagPositions(textComponent.getText()).stream() + .noneMatch(position -> position.getLeft() < cursorPosition && cursorPosition < position.getRight()) ? + cursorPosition : + textComponent.getText().length(); + StringBuilder text = new StringBuilder(textComponent.getText()); + text.insert(insertPosition, tag); + textComponent.setText(text.toString()); + textComponent.setCaretPosition(insertPosition + tag.length()); + } + } + textComponent.requestFocus(); } - + static T addUndo(T textComponent) { UndoManager undoManager = new UndoManager(); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleComponent.java index 0379728..6d5a7cd 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleComponent.java @@ -59,7 +59,7 @@ private Component getRuleNameBox() { container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS)); container.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5)); - ruleName = createTextField(); + ruleName = createTextField(false); ruleName.setText(model.getName()); ruleName.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY)); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleListComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleListComponent.java index 70ef7cb..c76349f 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleListComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleListComponent.java @@ -5,6 +5,7 @@ import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.rules.Rule; +import synfron.reshaper.burp.core.rules.whens.When; import synfron.reshaper.burp.core.rules.whens.WhenEventDirection; import synfron.reshaper.burp.ui.models.rules.RuleModel; import synfron.reshaper.burp.ui.utils.ForegroundColorListCellRenderer; @@ -14,10 +15,12 @@ import javax.swing.event.ListSelectionEvent; import java.awt.*; import java.awt.event.ActionEvent; +import java.util.Arrays; import java.util.Collections; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; public class RuleListComponent extends JPanel { private JList rulesList; @@ -34,7 +37,7 @@ private void initComponent() { setLayout(new BorderLayout()); ruleListModel = new DefaultListModel<>(); - ruleListModel.addAll(BurpExtender.getConnector().getRulesEngine().getRulesRegistry().getRules().stream() + ruleListModel.addAll(Stream.of(BurpExtender.getConnector().getRulesEngine().getRulesRegistry().getRules()) .map(rule -> new RuleModel(rule).withListener(ruleModelChangeListener)) .collect(Collectors.toList())); @@ -119,7 +122,7 @@ private void onRulesCollectionChanged(CollectionChangedArgs collectionChangedArg ruleListModel.elements()).stream().collect(Collectors.toMap(RuleModel::getRule, Function.identity()) ); ruleListModel.clear(); - ruleListModel.addAll(BurpExtender.getConnector().getRulesEngine().getRulesRegistry().getRules().stream() + ruleListModel.addAll(Stream.of(BurpExtender.getConnector().getRulesEngine().getRulesRegistry().getRules()) .map(rule -> ruleModelMap.containsKey(rule) ? ruleModelMap.get(rule) : new RuleModel(rule).withListener(ruleModelChangeListener) @@ -205,7 +208,7 @@ public void setSelectionContainer(RuleContainerComponent ruleContainer) { private Rule createNewRule() { Rule rule = new Rule(); rule.setEnabled(false); - rule.getWhens().add(new WhenEventDirection()); + rule.setWhens(new When[]{ new WhenEventDirection() }); return rule; } } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationComponent.java index 49da285..b780745 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationComponent.java @@ -9,7 +9,6 @@ import synfron.reshaper.burp.ui.models.rules.RuleOperationModel; import javax.swing.*; -import java.awt.*; import java.awt.event.ActionEvent; public abstract class RuleOperationComponent

, T extends IRuleOperation> extends JScrollPane implements IFormComponent { @@ -38,14 +37,6 @@ private void onModelPropertyChanged(PropertyChangedArgs propertyChangedArgs) { } } - protected Component getPaddedButton(JButton button) { - JPanel outerContainer = new JPanel(new FlowLayout(FlowLayout.LEFT)); - outerContainer.setAlignmentX(LEFT_ALIGNMENT); - outerContainer.setAlignmentY(TOP_ALIGNMENT); - outerContainer.add(button); - return outerContainer; - } - private void setValidateButtonState() { if (model.isValidated()) { validate.setEnabled(false); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationListComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationListComponent.java index 0116098..ac69b56 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationListComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationListComponent.java @@ -4,6 +4,7 @@ import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.rules.IRuleOperation; +import synfron.reshaper.burp.ui.components.IFormComponent; import synfron.reshaper.burp.ui.models.rules.RuleModel; import synfron.reshaper.burp.ui.models.rules.RuleOperationModel; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; @@ -15,7 +16,7 @@ import java.awt.event.ActionEvent; import java.util.List; -public abstract class RuleOperationListComponent> extends JPanel { +public abstract class RuleOperationListComponent> extends JPanel implements IFormComponent { protected final RuleModel model; protected JList operationsList; protected DefaultListModel operationsListModel; @@ -117,7 +118,7 @@ private Component getActionBar() { private Component getAddOperation() { JPanel container = new JPanel(); - operationSelector = new JComboBox<>(getRuleOperationModelTypes().toArray(new RuleOperationModelType[0])); + operationSelector = createComboBox(getRuleOperationModelTypes().toArray(new RuleOperationModelType[0])); JButton add = new JButton("Add"); add.addActionListener(this::onAdd); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenBreakComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenBreakComponent.java index 904c654..7a2afb5 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenBreakComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenBreakComponent.java @@ -16,7 +16,7 @@ public ThenBreakComponent(ThenBreakModel then) { } private void initComponent() { - breakType = new JComboBox<>(RuleResponse.getValues().stream().skip(1).toArray(RuleResponse[]::new)); + breakType = createComboBox(RuleResponse.getValues().stream().skip(1).toArray(RuleResponse[]::new)); breakType.setSelectedItem(model.getBreakType()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenBuildHttpMessageComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenBuildHttpMessageComponent.java index 91465a0..ee7b427 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenBuildHttpMessageComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenBuildHttpMessageComponent.java @@ -29,10 +29,10 @@ public ThenBuildHttpMessageComponent(ThenBuildHttpMessageModel then) { } private void initComponent() { - dataDirection = new JComboBox<>(DataDirection.values()); - starterHttpMessage = createTextField(); - destinationVariableSource = new JComboBox<>(new VariableSource[] { VariableSource.Event, VariableSource.Global }); - destinationVariableName = createTextField(); + dataDirection = createComboBox(DataDirection.values()); + starterHttpMessage = createTextField(true); + destinationVariableSource = createComboBox(new VariableSource[] { VariableSource.Event, VariableSource.Global }); + destinationVariableName = createTextField(true); JButton addSetter = new JButton("Add Setter"); dataDirection.setSelectedItem(model.getDataDirection()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenCommentComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenCommentComponent.java index 65fe4f0..d0b6261 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenCommentComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenCommentComponent.java @@ -16,7 +16,7 @@ public ThenCommentComponent(ThenCommentModel then) { } private void initComponent() { - text = createTextField(); + text = createTextField(true); text.setText(model.getText()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenContainerComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenContainerComponent.java index c66de5d..6fd93fc 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenContainerComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenContainerComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.rules.thens.ThenEvaluate; import synfron.reshaper.burp.ui.components.rules.RuleOperationContainerComponent; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; import synfron.reshaper.burp.ui.models.rules.thens.ThenModelType; @@ -21,6 +22,7 @@ public class ThenContainerComponent extends RuleOperationContainerComponent { componentMap.put(ThenModelType.Prompt, ThenPromptComponent.class); componentMap.put(ThenModelType.RunRules, ThenRunRulesComponent.class); componentMap.put(ThenModelType.RunScript, ThenRunScriptComponent.class); + componentMap.put(ThenModelType.Evaluate, ThenEvaluateComponent.class); componentMap.put(ThenModelType.SetEventDirection, ThenSetEventDirectionComponent.class); componentMap.put(ThenModelType.SetEncoding, ThenSetEncodingComponent.class); componentMap.put(ThenModelType.SetValue, ThenSetValueComponent.class); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDelayComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDelayComponent.java index 49fc49a..c204a75 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDelayComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDelayComponent.java @@ -16,7 +16,7 @@ public ThenDelayComponent(ThenDelayModel then) { } private void initComponent() { - delay = createTextField(); + delay = createTextField(true); delay.setText(model.getDelay()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDeleteValueComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDeleteValueComponent.java index 4f3c6e0..ba2873b 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDeleteValueComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDeleteValueComponent.java @@ -3,7 +3,6 @@ import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.rules.thens.ThenDeleteValue; import synfron.reshaper.burp.core.utils.DeleteItemPlacement; -import synfron.reshaper.burp.core.utils.GetItemPlacement; import synfron.reshaper.burp.ui.models.rules.thens.ThenDeleteValueModel; import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; import synfron.reshaper.burp.ui.utils.DocumentActionListener; @@ -40,12 +39,12 @@ public ThenDeleteValueComponent(ThenDeleteValueModel then) { } private void initComponent() { - messageValue = new JComboBox<>(Arrays.stream(MessageValue.values()) + messageValue = createComboBox(Arrays.stream(MessageValue.values()) .filter(value -> !excludedMessageValues.contains(value)) .toArray(MessageValue[]::new) ); - identifier = createTextField(); - identifierPlacement = new JComboBox<>(DeleteItemPlacement.values()); + identifier = createTextField(true); + identifierPlacement = createComboBox(DeleteItemPlacement.values()); messageValue.setSelectedItem(model.getMessageValue()); identifier.setText(model.getIdentifier()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDeleteVariableComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDeleteVariableComponent.java index 1ccc499..b3bd760 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDeleteVariableComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDeleteVariableComponent.java @@ -18,8 +18,8 @@ public ThenDeleteVariableComponent(ThenDeleteVariableModel then) { } private void initComponent() { - targetSource = new JComboBox<>(new VariableSource[] { VariableSource.Event, VariableSource.Global }); - variableName = createTextField(); + targetSource = createComboBox(new VariableSource[] { VariableSource.Event, VariableSource.Global }); + variableName = createTextField(true); targetSource.setSelectedItem(model.getTargetSource()); variableName.setText(model.getVariableName()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenEvaluateComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenEvaluateComponent.java new file mode 100644 index 0000000..972cf62 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenEvaluateComponent.java @@ -0,0 +1,75 @@ +package synfron.reshaper.burp.ui.components.rules.thens; + +import synfron.reshaper.burp.core.rules.thens.ThenEvaluate; +import synfron.reshaper.burp.core.rules.thens.entities.evaluate.Operation; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.ui.models.rules.thens.ThenEvaluateModel; +import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class ThenEvaluateComponent extends ThenComponent { + private JTextField x; + private JComboBox operation; + private JTextField y; + private JComboBox destinationVariableSource; + private JTextField destinationVariableName; + + public ThenEvaluateComponent(ThenEvaluateModel then) { + super(then); + initComponent(); + } + + private void initComponent() { + x = createTextField(true); + operation = createComboBox(Operation.values()); + y = createTextField(true); + destinationVariableSource = createComboBox(new VariableSource[] { VariableSource.Event, VariableSource.Global }); + destinationVariableName = createTextField(true); + + x.setText(model.getX()); + operation.setSelectedItem(model.getOperation()); + y.setText(model.getY()); + destinationVariableSource.setSelectedItem(model.getDestinationVariableSource()); + destinationVariableName.setText(model.getDestinationVariableName()); + + x.getDocument().addDocumentListener(new DocumentActionListener(this::onXChanged)); + operation.addActionListener(this::onOperationChanged); + y.getDocument().addDocumentListener(new DocumentActionListener(this::onYChanged)); + destinationVariableSource.addActionListener(this::onDestinationVariableSourceChanged); + destinationVariableName.getDocument().addDocumentListener(new DocumentActionListener(this::onDestinationVariableNameChanged)); + + mainContainer.add(getLabeledField("X *", x), "wrap"); + mainContainer.add(getLabeledField("Operation", operation), "wrap"); + mainContainer.add(ComponentVisibilityManager.withVisibilityFieldChangeDependency( + getLabeledField("Y *", y), + operation, + () -> ((Operation)operation.getSelectedItem()).getInputs() == 2 + ), "wrap"); + mainContainer.add(getLabeledField("Destination Variable Source", destinationVariableSource), "wrap"); + mainContainer.add(getLabeledField("Destination Variable Name *", destinationVariableName), "wrap"); + mainContainer.add(getPaddedButton(validate)); + } + + private void onXChanged(ActionEvent actionEvent) { + model.setX(x.getText()); + } + + private void onOperationChanged(ActionEvent actionEvent) { + model.setOperation((Operation) operation.getSelectedItem()); + } + + private void onYChanged(ActionEvent actionEvent) { + model.setY(y.getText()); + } + + private void onDestinationVariableSourceChanged(ActionEvent actionEvent) { + model.setDestinationVariableSource((VariableSource) destinationVariableSource.getSelectedItem()); + } + + private void onDestinationVariableNameChanged(ActionEvent actionEvent) { + model.setDestinationVariableName(destinationVariableName.getText()); + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenHighlightComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenHighlightComponent.java index cc3d797..d4c9c27 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenHighlightComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenHighlightComponent.java @@ -15,7 +15,7 @@ public ThenHighlightComponent(ThenHighlightModel then) { } private void initComponent() { - color = new JComboBox<>(ThenHighlight.HighlightColor.values()); + color = createComboBox(ThenHighlight.HighlightColor.values()); color.setSelectedItem(model.getColor()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenLogComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenLogComponent.java index 7adb1c8..3593ae2 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenLogComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenLogComponent.java @@ -16,7 +16,7 @@ public ThenLogComponent(ThenLogModel then) { } private void initComponent() { - text = createTextField(); + text = createTextField(true); text.setText(model.getText()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenParseHttpMessageComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenParseHttpMessageComponent.java index f5571f9..83cb5fb 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenParseHttpMessageComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenParseHttpMessageComponent.java @@ -26,8 +26,8 @@ public ThenParseHttpMessageComponent(ThenParseHttpMessageModel then) { } private void initComponent() { - dataDirection = new JComboBox<>(DataDirection.values()); - httpMessage = createTextField(); + dataDirection = createComboBox(DataDirection.values()); + httpMessage = createTextField(true); JButton addGetter = new JButton("Add Getter"); dataDirection.setSelectedItem(model.getDataDirection()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenPromptComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenPromptComponent.java index 1c9efb8..41000f7 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenPromptComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenPromptComponent.java @@ -22,12 +22,12 @@ public ThenPromptComponent(ThenPromptModel then) { } private void initComponent() { - description = createTextField(); - starterText = createTextField(); - failAfter = createTextField(); + description = createTextField(true); + starterText = createTextField(true); + failAfter = createTextField(true); breakAfterFailure = new JCheckBox("Break After Failure"); - captureVariableSource = new JComboBox<>(new VariableSource[] { VariableSource.Event, VariableSource.Global }); - captureVariableName = createTextField(); + captureVariableSource = createComboBox(new VariableSource[] { VariableSource.Event, VariableSource.Global }); + captureVariableName = createTextField(true); description.setText(model.getDescription()); starterText.setText(model.getStarterText()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunProcessComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunProcessComponent.java index 4947615..f54c117 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunProcessComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunProcessComponent.java @@ -29,17 +29,17 @@ public ThenRunProcessComponent(ThenRunProcessModel then) { } private void initComponent() { - command = createTextField(); - input = createTextField(); + command = createTextField(true); + input = createTextField(true); waitForCompletion = new JCheckBox("Wait for Completion"); - failAfter = createTextField(); + failAfter = createTextField(true); killAfterFailure = new JCheckBox("Kill After Failure"); failOnNonZeroExitCode = new JCheckBox("Fail on Non-Zero Exit Code"); breakAfterFailure = new JCheckBox("Break After Failure"); captureOutput = new JCheckBox("Capture Output"); captureAfterFailure = new JCheckBox("Capture After Failure"); - captureVariableSource = new JComboBox<>(new VariableSource[] { VariableSource.Event, VariableSource.Global }); - captureVariableName = createTextField(); + captureVariableSource = createComboBox(new VariableSource[] { VariableSource.Event, VariableSource.Global }); + captureVariableName = createTextField(true); command.setText(model.getCommand()); input.setText(model.getInput()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunRulesComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunRulesComponent.java index 5f701f0..dde4ff4 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunRulesComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunRulesComponent.java @@ -1,5 +1,8 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import burp.BurpExtender; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.rules.RulesRegistry; import synfron.reshaper.burp.core.rules.thens.ThenRunRules; import synfron.reshaper.burp.ui.models.rules.thens.ThenRunRulesModel; import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; @@ -7,9 +10,12 @@ import javax.swing.*; import java.awt.event.ActionEvent; +import java.util.Arrays; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class ThenRunRulesComponent extends ThenComponent { - private JTextField ruleName; + private JComboBox ruleName; private JCheckBox runSingle; public ThenRunRulesComponent(ThenRunRulesModel then) { @@ -19,13 +25,16 @@ public ThenRunRulesComponent(ThenRunRulesModel then) { private void initComponent() { runSingle = new JCheckBox("Run Single"); - ruleName = createTextField(); + ruleName = createComboBox(Stream.concat( + Arrays.stream(BurpExtender.getConnector().getRulesEngine().getRulesRegistry().getRules()).map(rule -> rule.getName()), + Stream.of(model.getRuleName()) + ).filter(StringUtils::isNotEmpty).sorted().distinct().toArray(String[]::new)); runSingle.setSelected(model.isRunSingle()); - ruleName.setText(model.getRuleName()); + ruleName.setSelectedItem(model.getRuleName()); runSingle.addActionListener(this::onRunSingleChanged); - ruleName.getDocument().addDocumentListener(new DocumentActionListener(this::onRuleNameChanged)); + ruleName.addActionListener(this::onRuleNameChanged); mainContainer.add(runSingle, "wrap"); mainContainer.add(ComponentVisibilityManager.withVisibilityFieldChangeDependency( @@ -41,6 +50,6 @@ private void onRunSingleChanged(ActionEvent actionEvent) { } private void onRuleNameChanged(ActionEvent actionEvent) { - model.setRuleName(ruleName.getText()); + model.setRuleName((String) ruleName.getSelectedItem()); } } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunScriptComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunScriptComponent.java index 1a87cf5..a0be265 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunScriptComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunScriptComponent.java @@ -36,7 +36,7 @@ private void initComponent() { private Component getOtherFields() { JPanel container = new JPanel(new MigLayout()); - maxExecutionSeconds = createTextField(); + maxExecutionSeconds = createTextField(false); maxExecutionSeconds.setText(model.getMaxExecutionSeconds()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSaveFileComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSaveFileComponent.java index f56d237..bf1e29b 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSaveFileComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSaveFileComponent.java @@ -1,9 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; -import lombok.Getter; import synfron.reshaper.burp.core.messages.Encoder; -import synfron.reshaper.burp.core.rules.RuleResponse; -import synfron.reshaper.burp.core.rules.thens.ThenHighlight; import synfron.reshaper.burp.core.rules.thens.ThenSaveFile; import synfron.reshaper.burp.core.rules.thens.entities.savefile.FileExistsAction; import synfron.reshaper.burp.ui.models.rules.thens.ThenSaveFileModel; @@ -24,15 +21,14 @@ public ThenSaveFileComponent(ThenSaveFileModel then) { } private void initComponent() { - filePath = createTextField(); - text = createTextField(); - encoding = new JComboBox<>(Encoder.getEncodings().toArray(new String[0])); - fileExistsAction = new JComboBox<>(FileExistsAction.values()); + filePath = createTextField(true); + text = createTextField(true); + encoding = createComboBox(Encoder.getEncodings().toArray(new String[0]), true); + fileExistsAction = createComboBox(FileExistsAction.values()); filePath.setText(model.getFilePath()); text.setText(model.getText()); encoding.setSelectedItem(model.getEncoding()); - encoding.setEditable(true); fileExistsAction.setSelectedItem(model.getFileExistsAction()); filePath.getDocument().addDocumentListener(new DocumentActionListener(this::onFilePathChanged)); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendRequestComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendRequestComponent.java index b23d07d..1ab10b8 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendRequestComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendRequestComponent.java @@ -11,10 +11,11 @@ import java.util.List; public class ThenSendRequestComponent extends ThenComponent { + private JTextField request; + private JTextField url; private JTextField protocol; private JTextField address; private JTextField port; - private JTextField request; private JCheckBox waitForCompletion; private JTextField failAfter; private JCheckBox failOnErrorStatusCode; @@ -30,23 +31,25 @@ public ThenSendRequestComponent(ThenSendRequestModel then) { } private void initComponent() { - protocol = createTextField(); - address = createTextField(); - port = createTextField(); - request = createTextField(); + request = createTextField(true); + url = createTextField(true); + protocol = createTextField(true); + address = createTextField(true); + port = createTextField(true); waitForCompletion = new JCheckBox("Wait for Completion"); - failAfter = createTextField(); + failAfter = createTextField(true); failOnErrorStatusCode = new JCheckBox("Fail on Error Status Code"); breakAfterFailure = new JCheckBox("Break After Failure"); captureOutput = new JCheckBox("Capture Output"); captureAfterFailure = new JCheckBox("Capture After Failure"); - captureVariableSource = new JComboBox<>(new VariableSource[] { VariableSource.Event, VariableSource.Global }); - captureVariableName = createTextField(); + captureVariableSource = createComboBox(new VariableSource[] { VariableSource.Event, VariableSource.Global }); + captureVariableName = createTextField(true); + request.setText(model.getRequest()); + url.setText(model.getUrl()); protocol.setText(model.getProtocol()); address.setText(model.getAddress()); port.setText(model.getPort()); - request.setText(model.getRequest()); waitForCompletion.setSelected(model.isWaitForCompletion()); failAfter.setText(model.getFailAfter()); failOnErrorStatusCode.setSelected(model.isFailOnErrorStatusCode()); @@ -56,10 +59,11 @@ private void initComponent() { captureVariableSource.setSelectedItem(model.getCaptureVariableSource()); captureVariableName.setText(model.getCaptureVariableName()); + request.getDocument().addDocumentListener(new DocumentActionListener(this::onRequestChanged)); + url.getDocument().addDocumentListener(new DocumentActionListener(this::onUrlChanged)); protocol.getDocument().addDocumentListener(new DocumentActionListener(this::onProtocolChanged)); address.getDocument().addDocumentListener(new DocumentActionListener(this::onAddressChanged)); port.getDocument().addDocumentListener(new DocumentActionListener(this::onPortChanged)); - request.getDocument().addDocumentListener(new DocumentActionListener(this::onRequestChanged)); waitForCompletion.addActionListener(this::onWaitForCompletionChanged); failAfter.getDocument().addDocumentListener(new DocumentActionListener(this::onFailAfterChanged)); failOnErrorStatusCode.addActionListener(this::onFailOnErrorStatusCodeChanged); @@ -69,10 +73,11 @@ private void initComponent() { captureVariableSource.addActionListener(this::onCaptureVariableSourceChanged); captureVariableName.getDocument().addDocumentListener(new DocumentActionListener(this::onCaptureVariableNameChanged)); + mainContainer.add(getLabeledField("Request", request), "wrap"); + mainContainer.add(getLabeledField("URL", url), "wrap"); mainContainer.add(getLabeledField("Protocol", protocol), "wrap"); mainContainer.add(getLabeledField("Address", address), "wrap"); mainContainer.add(getLabeledField("Port", port), "wrap"); - mainContainer.add(getLabeledField("Request", request), "wrap"); mainContainer.add(waitForCompletion, "wrap"); mainContainer.add(ComponentVisibilityManager.withVisibilityFieldChangeDependency( getLabeledField("Fail After (milliseconds) *", failAfter), @@ -116,6 +121,10 @@ private void onRequestChanged(ActionEvent actionEvent) { model.setRequest(request.getText()); } + private void onUrlChanged(ActionEvent actionEvent) { + model.setUrl(url.getText()); + } + private void onPortChanged(ActionEvent actionEvent) { model.setPort(port.getText()); } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendToComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendToComponent.java index f6751e7..6912b10 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendToComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendToComponent.java @@ -26,14 +26,14 @@ public ThenSendToComponent(ThenSendToModel then) { } private void initComponent() { - sendTo = new JComboBox<>(SendToOption.values()); + sendTo = createComboBox(SendToOption.values()); overrideDefaults = new JCheckBox("Override Defaults"); - host = createTextField(); - port = createTextField(); - protocol = createTextField(); - request = createTextField(); - value = createTextField(); - url = createTextField(); + host = createTextField(true); + port = createTextField(true); + protocol = createTextField(true); + request = createTextField(true); + value = createTextField(true); + url = createTextField(true); sendTo.setSelectedItem(model.getSendTo()); overrideDefaults.setSelected(model.isOverrideDefaults()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetComponent.java index 570d6cb..36c4553 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetComponent.java @@ -4,7 +4,6 @@ import synfron.reshaper.burp.core.messages.MessageValueType; import synfron.reshaper.burp.core.rules.thens.ThenSet; import synfron.reshaper.burp.core.utils.GetItemPlacement; -import synfron.reshaper.burp.core.utils.SetItemPlacement; import synfron.reshaper.burp.ui.models.rules.thens.ThenSetModel; import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; import synfron.reshaper.burp.ui.utils.DocumentActionListener; @@ -35,17 +34,17 @@ public ThenSetComponent(P then) { private void initComponent() { useMessageValue = new JCheckBox("Use Message Value"); - sourceMessageValue = new JComboBox<>(MessageValue.values()); - sourceIdentifier = createTextField(); - sourceIdentifierPlacement = new JComboBox<>(GetItemPlacement.values()); - sourceMessageValueType = new JComboBox<>(MessageValueType.values()); - sourceMessageValuePath = createTextField(); + sourceMessageValue = createComboBox(MessageValue.values()); + sourceIdentifier = createTextField(true); + sourceIdentifierPlacement = createComboBox(GetItemPlacement.values()); + sourceMessageValueType = createComboBox(MessageValueType.values()); + sourceMessageValuePath = createTextField(true); useReplace = new JCheckBox("Use Regex Replace"); - regexPattern = createTextField(); - text = createTextField(); - replacementText = createTextField(); - destinationMessageValueType = new JComboBox<>(MessageValueType.values()); - destinationMessageValuePath = createTextField(); + regexPattern = createTextField(true); + text = createTextField(true); + replacementText = createTextField(true); + destinationMessageValueType = createComboBox(MessageValueType.values()); + destinationMessageValuePath = createTextField(true); useMessageValue.setSelected(model.isUseMessageValue()); sourceMessageValue.setSelectedItem(model.getSourceMessageValue()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetEncodingComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetEncodingComponent.java index e888c47..1d1f49a 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetEncodingComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetEncodingComponent.java @@ -16,7 +16,7 @@ public ThenSetEncodingComponent(ThenSetEncodingModel then) { } private void initComponent() { - encoding = new JComboBox<>(Encoder.getEncodings().toArray(new String[0])); + encoding = createComboBox(Encoder.getEncodings().toArray(new String[0])); encoding.setSelectedItem(model.getEncoding()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetEventDirectionComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetEventDirectionComponent.java index 7b55d90..4c869e2 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetEventDirectionComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetEventDirectionComponent.java @@ -16,7 +16,7 @@ public ThenSetEventDirectionComponent(ThenSetEventDirectionModel then) { } private void initComponent() { - dataDirection = new JComboBox<>(DataDirection.values()); + dataDirection = createComboBox(DataDirection.values()); dataDirection.setSelectedItem(model.getDataDirection()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetValueComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetValueComponent.java index ff03594..55e5603 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetValueComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetValueComponent.java @@ -24,9 +24,9 @@ public ThenSetValueComponent(ThenSetValueModel then) { @Override protected List getExtendedComponents() { - destinationMessageValue = new JComboBox<>(MessageValue.values()); - destinationIdentifier = createTextField(); - destinationIdentifierPlacement = new JComboBox<>(SetItemPlacement.values()); + destinationMessageValue = createComboBox(MessageValue.values()); + destinationIdentifier = createTextField(true); + destinationIdentifierPlacement = createComboBox(SetItemPlacement.values()); destinationMessageValue.setSelectedItem(model.getDestinationMessageValue()); destinationIdentifier.setText(model.getDestinationIdentifier()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetVariableComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetVariableComponent.java index 2911cd6..4c39030 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetVariableComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetVariableComponent.java @@ -21,8 +21,8 @@ public ThenSetVariableComponent(ThenSetVariableModel then) { @Override protected List getExtendedComponents() { - targetSource = new JComboBox<>(new VariableSource[] { VariableSource.Event, VariableSource.Global }); - variableName = createTextField(); + targetSource = createComboBox(new VariableSource[] { VariableSource.Event, VariableSource.Global }); + variableName = createTextField(true); targetSource.setSelectedItem(model.getTargetSource()); variableName.setText(model.getVariableName()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/buildhttpmessage/MessageValueSetterComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/buildhttpmessage/MessageValueSetterComponent.java index 45c603e..32f1ddf 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/buildhttpmessage/MessageValueSetterComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/buildhttpmessage/MessageValueSetterComponent.java @@ -11,7 +11,6 @@ import javax.swing.*; import javax.swing.border.CompoundBorder; -import java.awt.*; import java.awt.event.ActionEvent; import java.util.List; import java.util.stream.Stream; @@ -40,14 +39,14 @@ public MessageValueSetterComponent(MessageValueSetterModel model, DataDirection private void initComponent() { setLayout(new MigLayout()); - sourceText = createTextField(); - destinationMessageValue = new JComboBox<>( + sourceText = createTextField(true); + destinationMessageValue = createComboBox( Stream.of(MessageValue.values()) - .filter(messageValue -> messageValue.getDataDirection() == dataDirection && !messageValue.isTopLevel()) + .filter(messageValue -> messageValue.getDataDirection() == dataDirection && messageValue.isMessageSettable()) .toArray(MessageValue[]::new) ); - destinationIdentifier = createTextField(); - destinationIdentifierPlacement = new JComboBox<>(SetItemPlacement.values()); + destinationIdentifier = createTextField(true); + destinationIdentifierPlacement = createComboBox(SetItemPlacement.values()); sourceText.setText(model.getSourceText()); destinationMessageValue.setSelectedItem(model.getDestinationMessageValue()); @@ -97,12 +96,4 @@ private void onTextChanged(ActionEvent actionEvent) { private void onDelete(ActionEvent actionEvent) { model.setDeleted(true); } - - protected Component getPaddedButton(JButton button) { - JPanel outerContainer = new JPanel(new FlowLayout(FlowLayout.LEFT)); - outerContainer.setAlignmentX(LEFT_ALIGNMENT); - outerContainer.setAlignmentY(TOP_ALIGNMENT); - outerContainer.add(button); - return outerContainer; - } } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/parsehttpmessage/MessageValueGetterComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/parsehttpmessage/MessageValueGetterComponent.java index b569390..bbf6636 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/parsehttpmessage/MessageValueGetterComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/parsehttpmessage/MessageValueGetterComponent.java @@ -4,7 +4,6 @@ import synfron.reshaper.burp.core.messages.DataDirection; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.utils.GetItemPlacement; -import synfron.reshaper.burp.core.utils.SetItemPlacement; import synfron.reshaper.burp.core.vars.VariableSource; import synfron.reshaper.burp.ui.components.IFormComponent; import synfron.reshaper.burp.ui.models.rules.thens.parsehttpmessage.MessageValueGetterModel; @@ -13,7 +12,6 @@ import javax.swing.*; import javax.swing.border.CompoundBorder; -import java.awt.*; import java.awt.event.ActionEvent; import java.util.List; import java.util.stream.Stream; @@ -43,13 +41,15 @@ public MessageValueGetterComponent(MessageValueGetterModel model, DataDirection private void initComponent() { setLayout(new MigLayout()); - sourceMessageValue = new JComboBox<>( - Stream.of(MessageValue.values()).filter(messageValue -> messageValue.getDataDirection() == dataDirection).toArray(MessageValue[]::new) + sourceMessageValue = createComboBox( + Stream.of(MessageValue.values()) + .filter(messageValue -> messageValue.getDataDirection() == dataDirection && messageValue.isMessageGettable()) + .toArray(MessageValue[]::new) ); - sourceIdentifier = createTextField(); - sourceIdentifierPlacement = new JComboBox<>(GetItemPlacement.values()); - destinationVariableSource = new JComboBox<>(new VariableSource[] { VariableSource.Event, VariableSource.Global }); - destinationVariableName = createTextField(); + sourceIdentifier = createTextField(true); + sourceIdentifierPlacement = createComboBox(GetItemPlacement.values()); + destinationVariableSource = createComboBox(new VariableSource[] { VariableSource.Event, VariableSource.Global }); + destinationVariableName = createTextField(true); sourceMessageValue.setSelectedItem(model.getSourceMessageValue()); sourceIdentifier.setText(model.getSourceIdentifier()); @@ -106,12 +106,4 @@ private void onDestinationVariableNameChanged(ActionEvent actionEvent) { private void onDelete(ActionEvent actionEvent) { model.setDeleted(true); } - - protected Component getPaddedButton(JButton button) { - JPanel outerContainer = new JPanel(new FlowLayout(FlowLayout.LEFT)); - outerContainer.setAlignmentX(LEFT_ALIGNMENT); - outerContainer.setAlignmentY(TOP_ALIGNMENT); - outerContainer.add(button); - return outerContainer; - } } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenEventDirectionComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenEventDirectionComponent.java index 58dc3df..fd4832c 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenEventDirectionComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenEventDirectionComponent.java @@ -16,7 +16,7 @@ public WhenEventDirectionComponent(WhenEventDirectionModel when) { } private void initComponent() { - dataDirection = new JComboBox<>(DataDirection.values()); + dataDirection = createComboBox(DataDirection.values()); dataDirection.setSelectedItem(model.getDataDirection()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenFromToolComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenFromToolComponent.java index 60d6af6..cd063f1 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenFromToolComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenFromToolComponent.java @@ -16,7 +16,7 @@ public WhenFromToolComponent(WhenFromToolModel when) { } private void initComponent() { - tool = new JComboBox<>(BurpTool.values()); + tool = createComboBox(BurpTool.values()); tool.setSelectedItem(model.getTool()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenHasEntityComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenHasEntityComponent.java index 3781513..0c2080c 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenHasEntityComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenHasEntityComponent.java @@ -19,8 +19,8 @@ public WhenHasEntityComponent(WhenHasEntityModel when) { } private void initComponent() { - identifier = createTextField(); - messageValue = new JComboBox<>(MessageValue.values()); + identifier = createTextField(true); + messageValue = createComboBox(MessageValue.values()); messageValue.setSelectedItem(model.getMessageValue()); identifier.setText(model.getIdentifier()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenInScopeComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenInScopeComponent.java index 4ceca67..6b7987d 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenInScopeComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenInScopeComponent.java @@ -16,7 +16,7 @@ public WhenInScopeComponent(WhenInScopeModel when) { } private void initComponent() { - url = createTextField(); + url = createTextField(true); url.setText(model.getUrl()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenMatchesTextComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenMatchesTextComponent.java index a044f5d..bb964b3 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenMatchesTextComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenMatchesTextComponent.java @@ -31,14 +31,14 @@ public WhenMatchesTextComponent(WhenMatchesTextModel when) { private void initComponent() { useMessageValue = new JCheckBox("Use Message Value"); - messageValue = new JComboBox<>(MessageValue.values()); - identifier = createTextField(); - identifierPlacement = new JComboBox<>(GetItemPlacement.values()); - sourceText = createTextField(); - messageValueType = new JComboBox<>(MessageValueType.values()); - messageValuePath = createTextField(); - matchType = new JComboBox<>(MatchType.values()); - matchText = createTextField(); + messageValue = createComboBox(MessageValue.values()); + identifier = createTextField(true); + identifierPlacement = createComboBox(GetItemPlacement.values()); + sourceText = createTextField(true); + messageValueType = createComboBox(MessageValueType.values()); + messageValuePath = createTextField(true); + matchType = createComboBox(MatchType.values()); + matchText = createTextField(true); useMessageValue.setSelected(model.isUseMessageValue()); messageValue.setSelectedItem(model.getMessageValue()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenProxyNameComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenProxyNameComponent.java index 8b9dec9..6bf0b97 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenProxyNameComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenProxyNameComponent.java @@ -16,7 +16,7 @@ public WhenProxyNameComponent(WhenProxyNameModel when) { } private void initComponent() { - proxyName = createTextField(); + proxyName = createTextField(false); proxyName.setText(model.getProxyName()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/CookieJarVariableTagWizardComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/CookieJarVariableTagWizardComponent.java new file mode 100644 index 0000000..5122e51 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/CookieJarVariableTagWizardComponent.java @@ -0,0 +1,74 @@ +package synfron.reshaper.burp.ui.components.rules.wizard.vars; + +import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.models.rules.wizard.vars.CookieJarVariableTagWizardModel; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class CookieJarVariableTagWizardComponent extends JPanel implements IFormComponent { + private final CookieJarVariableTagWizardModel model; + private JComboBox domain; + private JComboBox name; + private JComboBox path; + + public CookieJarVariableTagWizardComponent(CookieJarVariableTagWizardModel model) { + this.model = model; + initComponent(); + + model.withListener(this::onModelChanged); + } + + private void initComponent() { + setLayout(new MigLayout()); + + domain = createComboBox(model.getDomains().getOptions().toArray(new String[0]), true); + name = createComboBox(model.getNames().getOptions().toArray(new String[0]), true); + path = createComboBox(model.getPaths().getOptions().toArray(new String[0]), true); + + domain.setSelectedItem(model.getDomains().getSelectedOption()); + name.setSelectedItem(model.getNames().getSelectedOption()); + path.setSelectedItem(model.getPaths().getSelectedOption()); + + domain.addActionListener(this::onDomainChanged); + name.addActionListener(this::onNameChanged); + path.addActionListener(this::onPathChanged); + + add(getLabeledField("Domain *", domain), "wrap"); + add(getLabeledField("Name *", name), "wrap"); + add(getLabeledField("Path", path)); + } + + private void onModelChanged(PropertyChangedArgs propertyChangedArgs) { + switch (propertyChangedArgs.getName()) { + case "names" -> resetNames(); + case "paths" -> resetPaths(); + } + } + + private void onDomainChanged(ActionEvent actionEvent) { + model.setDomain((String) domain.getSelectedItem()); + } + + private void onNameChanged(ActionEvent actionEvent) { + model.setName((String) name.getSelectedItem()); + } + + private void onPathChanged(ActionEvent actionEvent) { + model.setPath((String) path.getSelectedItem()); + } + + private void resetPaths() { + path.removeAllItems(); + model.getPaths().getOptions().forEach(option -> path.addItem(option)); + path.setSelectedItem(model.getPaths().getSelectedOption()); + } + + private void resetNames() { + name.removeAllItems(); + model.getNames().getOptions().forEach(option -> name.addItem(option)); + name.setSelectedItem(model.getNames().getSelectedOption()); + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/EventVariableTagWizardComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/EventVariableTagWizardComponent.java new file mode 100644 index 0000000..90ad8af --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/EventVariableTagWizardComponent.java @@ -0,0 +1,34 @@ +package synfron.reshaper.burp.ui.components.rules.wizard.vars; + +import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.models.rules.wizard.vars.EventVariableTagWizardModel; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class EventVariableTagWizardComponent extends JPanel implements IFormComponent { + private final EventVariableTagWizardModel model; + private JComboBox variableName; + + public EventVariableTagWizardComponent(EventVariableTagWizardModel model) { + this.model = model; + initComponent(); + } + + private void initComponent() { + setLayout(new MigLayout()); + + variableName = createComboBox(model.getVariableNames().toArray(new String[0]), true); + + variableName.setSelectedItem(model.getVariableNames().stream().findFirst().orElse("")); + + variableName.addActionListener(this::onVariableNameChanged); + + add(getLabeledField("Variable Name *", variableName)); + } + + private void onVariableNameChanged(ActionEvent actionEvent) { + model.setVariableName((String)variableName.getSelectedItem()); + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/FileVariableTagWizardComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/FileVariableTagWizardComponent.java new file mode 100644 index 0000000..96d50f8 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/FileVariableTagWizardComponent.java @@ -0,0 +1,79 @@ +package synfron.reshaper.burp.ui.components.rules.wizard.vars; + +import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.messages.Encoder; +import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.models.rules.wizard.vars.FileVariableTagWizardModel; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class FileVariableTagWizardComponent extends JPanel implements IFormComponent { + private final FileVariableTagWizardModel model; + private JComboBox encoding; + private JTextField filePath; + + public FileVariableTagWizardComponent(FileVariableTagWizardModel model) { + this.model = model; + initComponent(); + } + + private void initComponent() { + setLayout(new MigLayout()); + + encoding = createComboBox(Encoder.getEncodings().toArray(new String[0]), true); + JPanel fileBrowser = getFileBrowser(); + + encoding.setSelectedItem(model.getEncoding()); + + encoding.addActionListener(this::onEncodingChanged); + + add(getLabeledField("Encoding *", encoding), "wrap"); + add(getLabeledField("File Path *", fileBrowser)); + } + + private JPanel getFileBrowser() { + JPanel container = new JPanel(new MigLayout()); + + filePath = createTextField(true); + JButton browse = new JButton("Browse"); + + filePath.setText(model.getFilePath()); + + filePath.getDocument().addDocumentListener(new DocumentActionListener(this::onFilePathChanged)); + browse.addActionListener(this::onBrowse); + + container.add(filePath); + container.add(getPaddedButton(browse)); + + return container; + } + + private void onEncodingChanged(ActionEvent actionEvent) { + model.setEncoding((String) encoding.getSelectedItem()); + } + + private void onFilePathChanged(ActionEvent actionEvent) { + model.setFilePath(filePath.getText()); + } + + private void onBrowse(ActionEvent actionEvent) { + try { + JFileChooser fileChooser = createFileChooser("Select File"); + int result = fileChooser.showOpenDialog(this); + if (result == JFileChooser.APPROVE_OPTION) { + filePath.setText(fileChooser.getSelectedFile().getAbsolutePath()); + } + } catch (Exception ignored) { + } + } + + private JFileChooser createFileChooser(String title) { + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setDialogTitle(title); + fileChooser.setAcceptAllFileFilterUsed(false); + fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + return fileChooser; + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/GlobalVariableTagWizardComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/GlobalVariableTagWizardComponent.java new file mode 100644 index 0000000..896d33a --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/GlobalVariableTagWizardComponent.java @@ -0,0 +1,34 @@ +package synfron.reshaper.burp.ui.components.rules.wizard.vars; + +import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.models.rules.wizard.vars.GlobalVariableTagWizardModel; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class GlobalVariableTagWizardComponent extends JPanel implements IFormComponent { + private final GlobalVariableTagWizardModel model; + private JComboBox variableName; + + public GlobalVariableTagWizardComponent(GlobalVariableTagWizardModel model) { + this.model = model; + initComponent(); + } + + private void initComponent() { + setLayout(new MigLayout()); + + variableName = createComboBox(model.getVariableNames().toArray(new String[0]), true); + + variableName.setSelectedItem(model.getVariableNames().stream().findFirst().orElse("")); + + variableName.addActionListener(this::onVariableNameChanged); + + add(getLabeledField("Variable Name *", variableName)); + } + + private void onVariableNameChanged(ActionEvent actionEvent) { + model.setVariableName((String)variableName.getSelectedItem()); + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/MessageVariableTagWizardComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/MessageVariableTagWizardComponent.java new file mode 100644 index 0000000..7c7650c --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/MessageVariableTagWizardComponent.java @@ -0,0 +1,50 @@ +package synfron.reshaper.burp.ui.components.rules.wizard.vars; + +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.vars.MessageVariableTagWizardModel; +import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class MessageVariableTagWizardComponent extends JPanel implements IFormComponent { + private final MessageVariableTagWizardModel model; + private JComboBox messageValue; + private JTextField identifier; + + public MessageVariableTagWizardComponent(MessageVariableTagWizardModel model) { + this.model = model; + initComponent(); + } + + private void initComponent() { + setLayout(new MigLayout()); + + messageValue = createComboBox(MessageValue.values()); + identifier = createTextField(true); + + messageValue.setSelectedItem(model.getMessageValue()); + identifier.setText(model.getIdentifier()); + + messageValue.addActionListener(this::onMessageValueChanged); + identifier.getDocument().addDocumentListener(new DocumentActionListener(this::onIdentifierChanged)); + + add(getLabeledField("Message Value", messageValue), "wrap"); + add(ComponentVisibilityManager.withVisibilityFieldChangeDependency( + getLabeledField("Identifier *", identifier), + messageValue, + () -> ((MessageValue)messageValue.getSelectedItem()).isIdentifierRequired() + ), "wrap"); + } + + private void onMessageValueChanged(ActionEvent actionEvent) { + model.setMessageValue((MessageValue)messageValue.getSelectedItem()); + } + + private void onIdentifierChanged(ActionEvent actionEvent) { + model.setIdentifier(identifier.getText()); + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/SpecialVariableTagWizardComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/SpecialVariableTagWizardComponent.java new file mode 100644 index 0000000..610fbdb --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/SpecialVariableTagWizardComponent.java @@ -0,0 +1,49 @@ +package synfron.reshaper.burp.ui.components.rules.wizard.vars; + +import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.models.rules.wizard.vars.SpecialVariableTagWizardModel; +import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class SpecialVariableTagWizardComponent extends JPanel implements IFormComponent { + private final SpecialVariableTagWizardModel model; + private JComboBox specialChar; + private JTextField value; + + public SpecialVariableTagWizardComponent(SpecialVariableTagWizardModel model) { + this.model = model; + initComponent(); + } + + private void initComponent() { + setLayout(new MigLayout()); + + specialChar = createComboBox(model.getSpecialChars().toArray(new SpecialVariableTagWizardModel.SpecialChar[0])); + value = createTextField(true); + + specialChar.setSelectedItem(model.getSpecialChar()); + value.setText(model.getValue()); + + specialChar.addActionListener(this::onSpecialCharChanged); + value.getDocument().addDocumentListener(new DocumentActionListener(this::onValueChanged)); + + add(getLabeledField("Type", specialChar), "wrap"); + add(ComponentVisibilityManager.withVisibilityFieldChangeDependency( + getLabeledField("Value *", value), + specialChar, + () -> ((SpecialVariableTagWizardModel.SpecialChar)specialChar.getSelectedItem()).isValueRequired() + )); + } + + private void onSpecialCharChanged(ActionEvent actionEvent) { + model.setSpecialChar((SpecialVariableTagWizardModel.SpecialChar) specialChar.getSelectedItem()); + } + + private void onValueChanged(ActionEvent actionEvent) { + model.setValue(value.getText()); + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardContainerComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardContainerComponent.java new file mode 100644 index 0000000..158715d --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardContainerComponent.java @@ -0,0 +1,34 @@ +package synfron.reshaper.burp.ui.components.rules.wizard.vars; + +import synfron.reshaper.burp.ui.models.rules.wizard.vars.*; + +import javax.swing.*; +import java.awt.*; + +public class VariableTagWizardContainerComponent extends JPanel { + + public VariableTagWizardContainerComponent() { + initComponent(); + } + + private void initComponent() { + setLayout(new BorderLayout()); + } + + public void setModel(IVariableTagWizardModel model) { + removeAll(); + if (model != null) { + JPanel component = switch (model.getVariableSource()) { + case Event -> new EventVariableTagWizardComponent((EventVariableTagWizardModel) model); + case Global -> new GlobalVariableTagWizardComponent((GlobalVariableTagWizardModel) model); + case Message -> new MessageVariableTagWizardComponent((MessageVariableTagWizardModel) model); + case File -> new FileVariableTagWizardComponent((FileVariableTagWizardModel) model); + case Special -> new SpecialVariableTagWizardComponent((SpecialVariableTagWizardModel) model); + case CookieJar -> new CookieJarVariableTagWizardComponent((CookieJarVariableTagWizardModel) model); + }; + add(component); + } + revalidate(); + repaint(); + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardOptionPane.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardOptionPane.java new file mode 100644 index 0000000..a3c59f0 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardOptionPane.java @@ -0,0 +1,96 @@ +package synfron.reshaper.burp.ui.components.rules.wizard.vars; + +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.models.rules.wizard.vars.VariableTagWizardModel; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.beans.PropertyChangeEvent; + +public class VariableTagWizardOptionPane extends JOptionPane implements IFormComponent { + + private final JPanel outerContainer; + private final VariableTagWizardModel model; + private JComboBox variableSource; + private final VariableTagWizardContainerComponent container = new VariableTagWizardContainerComponent(); + private JDialog currentDialog; + + private VariableTagWizardOptionPane(VariableTagWizardModel model) { + super(new JPanel(new BorderLayout()), JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION); + outerContainer = (JPanel)message; + this.model = model; + addPropertyChangeListener(JOptionPane.VALUE_PROPERTY, this::onPropertyChanged); + initComponent(); + + model.withListener(this::onModelChanged); + } + + private void initComponent() { + variableSource = createComboBox(VariableSource.values()); + + variableSource.setSelectedItem(model.getVariableSource()); + + variableSource.addActionListener(this::onVariableSourceChanged); + + outerContainer.add(getLabeledField("Tag Type", variableSource), BorderLayout.PAGE_START); + outerContainer.add(container, BorderLayout.CENTER); + + container.setModel(model.getTagModel()); + + container.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + resize(); + } + }); + } + + private void onModelChanged(PropertyChangedArgs propertyChangedArgs) { + switch (propertyChangedArgs.getName()) { + case "tagModel" -> { + container.setModel(model.getTagModel()); + resize(); + + } + } + } + + private void resize() { + if (currentDialog != null) { + currentDialog.pack(); + } + } + + private void onVariableSourceChanged(ActionEvent actionEvent) { + model.setVariableSource((VariableSource)variableSource.getSelectedItem()); + } + + private void onPropertyChanged(PropertyChangeEvent event) { + if (getValue() != null && (int)getValue() == JOptionPane.OK_OPTION) { + if (!model.validate().isEmpty()) { + JOptionPane.showMessageDialog(this, + String.join("\n", model.validate()), + "Validation Error", + JOptionPane.ERROR_MESSAGE); + } + } else { + model.setDismissed(true); + } + } + + public static void showDialog(VariableTagWizardModel model) { + VariableTagWizardOptionPane optionPane = new VariableTagWizardOptionPane(model); + JDialog dialog = optionPane.createDialog("Variable Tag"); + optionPane.setCurrentDialog(dialog); + dialog.setVisible(true); + } + + private void setCurrentDialog(JDialog dialog) { + this.currentDialog = dialog; + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/WhenWizardItemComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardItemComponent.java similarity index 87% rename from src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/WhenWizardItemComponent.java rename to src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardItemComponent.java index 0ad0034..8298e33 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/WhenWizardItemComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardItemComponent.java @@ -1,10 +1,10 @@ -package synfron.reshaper.burp.ui.components.rules.wizard; +package synfron.reshaper.burp.ui.components.rules.wizard.whens; 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.models.rules.wizard.whens.WhenWizardItemModel; +import synfron.reshaper.burp.ui.models.rules.wizard.whens.WhenWizardMatchType; import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; import synfron.reshaper.burp.ui.utils.DocumentActionListener; @@ -18,7 +18,7 @@ public class WhenWizardItemComponent extends JPanel implements IFormComponent { private final boolean deletable; private JComboBox messageValue; private JComboBox identifier; - private JComboBox matchType; + private JComboBox matchType; private JTextField text; public WhenWizardItemComponent(WhenWizardItemModel model, boolean deletable) { @@ -31,10 +31,10 @@ 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(); + messageValue = createComboBox(MessageValue.values()); + identifier = createComboBox(model.getIdentifiers().getOptions().toArray(new String[0])); + matchType = createComboBox(WhenWizardMatchType.values()); + text = createTextField(true); text.setColumns(20); text.setMaximumSize(new Dimension(text.getPreferredSize().width, text.getPreferredSize().height)); text.setAlignmentX(Component.LEFT_ALIGNMENT); @@ -69,7 +69,7 @@ private void initComponent() { container.add(ComponentVisibilityManager.withVisibilityFieldChangeDependency( text, List.of(matchType, messageValue, identifier), - () -> (!((MessageValue) messageValue.getSelectedItem()).isIdentifierRequired() || identifier.getItemCount() != 0) && ((WizardMatchType) matchType.getSelectedItem()).isMatcher() + () -> (!((MessageValue) messageValue.getSelectedItem()).isIdentifierRequired() || identifier.getItemCount() != 0) && ((WhenWizardMatchType) matchType.getSelectedItem()).isMatcher() ), "wrap"); add(new JSeparator(), BorderLayout.PAGE_START); @@ -103,7 +103,7 @@ private void onIdentifierChanged(ActionEvent actionEvent) { } private void onMatchTypeChanged(ActionEvent actionEvent) { - model.setMatchType((WizardMatchType) matchType.getSelectedItem()); + model.setMatchType((WhenWizardMatchType) matchType.getSelectedItem()); } private void onTextChanged(ActionEvent actionEvent) { diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/WhenWizardOptionPane.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardOptionPane.java similarity index 88% rename from src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/WhenWizardOptionPane.java rename to src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardOptionPane.java index d342631..3083a9b 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/WhenWizardOptionPane.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardOptionPane.java @@ -1,11 +1,11 @@ -package synfron.reshaper.burp.ui.components.rules.wizard; +package synfron.reshaper.burp.ui.components.rules.wizard.whens; import net.miginfocom.swing.MigLayout; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.ui.components.IFormComponent; -import synfron.reshaper.burp.ui.models.rules.wizard.WhenWizardItemModel; -import synfron.reshaper.burp.ui.models.rules.wizard.WhenWizardModel; +import synfron.reshaper.burp.ui.models.rules.wizard.whens.WhenWizardItemModel; +import synfron.reshaper.burp.ui.models.rules.wizard.whens.WhenWizardModel; import synfron.reshaper.burp.ui.utils.DocumentActionListener; import javax.swing.*; @@ -43,6 +43,8 @@ private void onPropertyChanged(PropertyChangeEvent event) { "Validation Error", JOptionPane.ERROR_MESSAGE); } + } else { + model.setDismissed(true); } } @@ -62,11 +64,10 @@ private void initComponent() { private Component getBody() { JPanel container = new JPanel(new MigLayout()); - ruleName = createTextField(); + ruleName = createTextField(false); JScrollPane scrollPane = new JScrollPane(); scrollPane.setBorder(new EmptyBorder(0,0,0,0)); scrollPane.setViewportView(container); - scrollPane.setPreferredSize(new Dimension(300, 300)); JButton addItem = new JButton("Add"); @@ -77,6 +78,8 @@ private Component getBody() { container.add(getWhenWizardItemList(), "wrap"); container.add(getPaddedButton(addItem), "wrap"); + scrollPane.setPreferredSize(container.getPreferredSize()); + return scrollPane; } @@ -84,14 +87,6 @@ private void onRuleNameChanged(ActionEvent actionEvent) { model.setRuleName(ruleName.getText()); } - protected Component getPaddedButton(JButton button) { - JPanel outerContainer = new JPanel(new FlowLayout(FlowLayout.LEFT)); - outerContainer.setAlignmentX(LEFT_ALIGNMENT); - outerContainer.setAlignmentY(TOP_ALIGNMENT); - outerContainer.add(button); - return outerContainer; - } - private void onAddItem(ActionEvent actionEvent) { onAddItem(); } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/settings/SettingsTabComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/settings/SettingsTabComponent.java index 0890fc0..2d9bfca 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/settings/SettingsTabComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/settings/SettingsTabComponent.java @@ -75,11 +75,11 @@ private Component getMiscOptions() { JPanel container = new JPanel(new MigLayout()); enableEventDiagnostics = new JCheckBox("Enable Event Diagnostics"); - diagnosticValueMaxLength = createTextField(); + diagnosticValueMaxLength = createTextField(false); enableSanityCheckWarnings = new JCheckBox("Enable Sanity Check Warnings"); logInExtenderOutput = new JCheckBox("Replicate Logs in Extender Output"); - logTabCharacterLimit = createTextField(); - defaultEncoding = new JComboBox<>(Encoder.getEncodings().toArray(new String[0])); + logTabCharacterLimit = createTextField(false); + defaultEncoding = createComboBox(Encoder.getEncodings().toArray(new String[0])); enableEventDiagnostics.setSelected(generalSettings.isEnableEventDiagnostics()); diagnosticValueMaxLength.setText(Objects.toString(generalSettings.getDiagnosticValueMaxLength())); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/vars/VariableComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/vars/VariableComponent.java index c51da1d..bb90ad7 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/vars/VariableComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/vars/VariableComponent.java @@ -62,7 +62,7 @@ private Component getVariableNameBox() { container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS)); container.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5)); - variableName = createTextField(); + variableName = createTextField(false); variableName.setText(model.getName()); variableName.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY)); variableName.setAlignmentX(Component.LEFT_ALIGNMENT); diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleModel.java index 8aa6a5a..f5b6eaf 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleModel.java @@ -14,6 +14,7 @@ import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.Stream; public class RuleModel { @Getter @@ -40,10 +41,10 @@ public RuleModel(Rule rule) { public RuleModel(Rule rule, boolean isNew) { this.rule = rule; - this.whens = rule.getWhens().stream() + this.whens = Stream.of(rule.getWhens()) .map(when -> WhenModel.getModel(when).withListener(ruleOperationChangedListener)) .collect(Collectors.toList()); - this.thens = rule.getThens().stream() + this.thens = Stream.of(rule.getThens()) .map(then -> ThenModel.getModel(then).withListener(ruleOperationChangedListener)) .collect(Collectors.toList()); this.name = rule.getName(); @@ -123,16 +124,14 @@ public boolean persist() { whens.forEach(WhenModel::persist); thens.forEach(RuleOperationModel::persist); - rule.getWhens().clear(); - rule.getWhens().addAll(whens.stream() + rule.setWhens(whens.stream() .map(model -> (When)model.getRuleOperation()) - .collect(Collectors.toList()) + .toArray(When[]::new) ); - rule.getThens().clear(); - rule.getThens().addAll(thens.stream() + rule.setThens(thens.stream() .map(model -> (Then)model.getRuleOperation()) - .collect(Collectors.toList()) + .toArray(Then[]::new) ); rule.setName(name); diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/IVariableCreator.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/IVariableCreator.java new file mode 100644 index 0000000..4cd26ad --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/IVariableCreator.java @@ -0,0 +1,9 @@ +package synfron.reshaper.burp.ui.models.rules.thens; + +import synfron.reshaper.burp.core.vars.VariableSourceEntry; + +import java.util.List; + +public interface IVariableCreator { + List getVariableEntries(); +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBuildHttpMessageModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBuildHttpMessageModel.java index d99f3c4..3f63b43 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBuildHttpMessageModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBuildHttpMessageModel.java @@ -8,14 +8,16 @@ import synfron.reshaper.burp.core.rules.thens.ThenBuildHttpMessage; import synfron.reshaper.burp.core.rules.thens.entities.buildhttpmessage.MessageValueSetter; import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; import synfron.reshaper.burp.ui.models.rules.thens.buildhttpmessage.MessageValueSetterModel; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; -public class ThenBuildHttpMessageModel extends ThenModel { +public class ThenBuildHttpMessageModel extends ThenModel implements IVariableCreator { @Getter private DataDirection dataDirection; @@ -26,7 +28,7 @@ public class ThenBuildHttpMessageModel extends ThenModel messageValueSetterChangedListener = this::onMessageValueSetterChanged; @@ -38,7 +40,8 @@ public ThenBuildHttpMessageModel(ThenBuildHttpMessage then, Boolean isNew) { .map(messageValueSetter -> new MessageValueSetterModel(messageValueSetter).withListener(messageValueSetterChangedListener)) .collect(Collectors.toList()); this.destinationVariableSource = then.getDestinationVariableSource(); - this.DestinationVariableName = VariableString.toString(then.getDestinationVariableName(), DestinationVariableName); + this.destinationVariableName = VariableString.toString(then.getDestinationVariableName(), destinationVariableName); + VariableCreatorRegistry.register(this); } public MessageValueSetterModel addMessageValueSetter() { @@ -76,15 +79,15 @@ public void setDestinationVariableSource(VariableSource destinationVariableSourc } public void setDestinationVariableName(String destinationVariableName) { - this.DestinationVariableName = destinationVariableName; + this.destinationVariableName = destinationVariableName; propertyChanged("destinationVariableName", destinationVariableName); } public List validate() { List errors = super.validate(); - if (StringUtils.isEmpty(DestinationVariableName)) { + if (StringUtils.isEmpty(destinationVariableName)) { errors.add("Destination Variable Name is required"); - } else if (!VariableString.isValidVariableName(DestinationVariableName)) { + } else if (!VariableString.isValidVariableName(destinationVariableName)) { errors.add("Destination Variable Name is invalid"); } messageValueSetters.forEach(messageValueSetter -> errors.addAll(messageValueSetter.validate())); @@ -106,7 +109,7 @@ public boolean persist() { ); ruleOperation.setDestinationVariableSource(destinationVariableSource); - ruleOperation.setDestinationVariableName(VariableString.getAsVariableString(DestinationVariableName)); + ruleOperation.setDestinationVariableName(VariableString.getAsVariableString(destinationVariableName)); setValidated(true); return true; } @@ -124,4 +127,11 @@ public boolean record() { public RuleOperationModelType getType() { return ThenModelType.BuildHttpMessage; } + + @Override + public List getVariableEntries() { + return StringUtils.isNotEmpty(destinationVariableName) ? + List.of(new VariableSourceEntry(destinationVariableSource, destinationVariableName)) : + Collections.emptyList(); + } } diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenEvaluateModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenEvaluateModel.java new file mode 100644 index 0000000..36d2361 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenEvaluateModel.java @@ -0,0 +1,112 @@ +package synfron.reshaper.burp.ui.models.rules.thens; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.rules.thens.ThenEvaluate; +import synfron.reshaper.burp.core.rules.thens.entities.evaluate.Operation; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; +import synfron.reshaper.burp.core.vars.VariableString; +import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; + +import java.util.Collections; +import java.util.List; + +public class ThenEvaluateModel extends ThenModel implements IVariableCreator { + + @Getter + private String x; + @Getter + private Operation operation; + @Getter + private String y; + @Getter + private VariableSource destinationVariableSource; + @Getter + private String destinationVariableName; + + public ThenEvaluateModel(ThenEvaluate then, Boolean isNew) { + super(then, isNew); + this.x = VariableString.toString(then.getX(), x); + this.operation = then.getOperation(); + this.y = VariableString.toString(then.getY(), y); + this.destinationVariableSource = then.getDestinationVariableSource(); + this.destinationVariableName = VariableString.toString(then.getDestinationVariableName(), destinationVariableName); + VariableCreatorRegistry.register(this); + } + + public void setX(String x) { + this.x = x; + propertyChanged("x", x); + } + + public void setOperation(Operation operation) { + this.operation = operation; + propertyChanged("operation", operation); + } + + public void setY(String y) { + this.y = y; + propertyChanged("y", y); + } + + public void setDestinationVariableSource(VariableSource destinationVariableSource) { + this.destinationVariableSource = destinationVariableSource; + propertyChanged("destinationVariableSource", destinationVariableSource); + } + + public void setDestinationVariableName(String destinationVariableName) { + this.destinationVariableName = destinationVariableName; + propertyChanged("destinationVariableName", destinationVariableName); + } + + public List validate() { + List errors = super.validate(); + if (StringUtils.isEmpty(x)) { + errors.add("X is required"); + } + if (operation.getInputs() > 1 && StringUtils.isEmpty(y)) { + errors.add("Y is required"); + } + if (StringUtils.isEmpty(destinationVariableName)) { + errors.add("Destination Variable Name is required"); + } else if (!VariableString.isValidVariableName(destinationVariableName)) { + errors.add("Destination Variable Name is invalid"); + } + return errors; + } + + public boolean persist() { + if (validate().size() != 0) { + return false; + } + ruleOperation.setX(VariableString.getAsVariableString(x)); + ruleOperation.setOperation(operation); + ruleOperation.setY(VariableString.getAsVariableString(y)); + ruleOperation.setDestinationVariableSource(destinationVariableSource); + ruleOperation.setDestinationVariableName(VariableString.getAsVariableString(destinationVariableName)); + setValidated(true); + return true; + } + + @Override + public boolean record() { + if (validate().size() != 0) { + return false; + } + setValidated(true); + return true; + } + + @Override + public RuleOperationModelType getType() { + return ThenModelType.Evaluate; + } + + @Override + public List getVariableEntries() { + return StringUtils.isNotEmpty(destinationVariableName) ? + List.of(new VariableSourceEntry(destinationVariableSource, destinationVariableName)) : + Collections.emptyList(); + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenModelType.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenModelType.java index c93bdc4..43c796e 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenModelType.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenModelType.java @@ -15,6 +15,7 @@ public class ThenModelType

, T extends Then> extends public static final ThenModelType Prompt = new ThenModelType<>("Prompt", ThenPromptModel.class, ThenType.Prompt); public static final ThenModelType RunRules = new ThenModelType<>("Run Rules", ThenRunRulesModel.class, ThenType.RunRules); public static final ThenModelType RunScript = new ThenModelType<>("Run Script", ThenRunScriptModel.class, ThenType.RunScript); + public static final ThenModelType Evaluate = new ThenModelType<>("Evaluate", ThenEvaluateModel.class, ThenType.Evaluate); public static final ThenModelType SetEventDirection = new ThenModelType<>("Set Event Direction", ThenSetEventDirectionModel.class, ThenType.SetEventDirection); public static final ThenModelType SetEncoding = new ThenModelType<>("Set Encoding", ThenSetEncodingModel.class, ThenType.SetEncoding); public static final ThenModelType SetValue = new ThenModelType<>("Set Value", ThenSetValueModel.class, ThenType.SetValue); @@ -43,6 +44,7 @@ public static List> getTypes() { Prompt, RunRules, RunScript, + Evaluate, SetEventDirection, SetEncoding, SetValue, diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenParseHttpMessageModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenParseHttpMessageModel.java index d47988b..40dc89e 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenParseHttpMessageModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenParseHttpMessageModel.java @@ -1,11 +1,13 @@ package synfron.reshaper.burp.ui.models.rules.thens; import lombok.Getter; +import org.apache.commons.lang3.StringUtils; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.messages.DataDirection; import synfron.reshaper.burp.core.rules.thens.ThenParseHttpMessage; import synfron.reshaper.burp.core.rules.thens.entities.parsehttpmessage.MessageValueGetter; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; import synfron.reshaper.burp.ui.models.rules.thens.parsehttpmessage.MessageValueGetterModel; @@ -13,7 +15,7 @@ import java.util.List; import java.util.stream.Collectors; -public class ThenParseHttpMessageModel extends ThenModel { +public class ThenParseHttpMessageModel extends ThenModel implements IVariableCreator { @Getter private DataDirection dataDirection; @@ -31,6 +33,7 @@ public ThenParseHttpMessageModel(ThenParseHttpMessage then, Boolean isNew) { this.messageValueGetters = then.getMessageValueGetters().stream() .map(messageValueGetter -> new MessageValueGetterModel(messageValueGetter).withListener(messageValueGetterChangedListener)) .collect(Collectors.toList()); + VariableCreatorRegistry.register(this); } public MessageValueGetterModel addMessageValueGetter() { @@ -99,4 +102,12 @@ public boolean record() { public RuleOperationModelType getType() { return ThenModelType.ParseHttpMessage; } + + @Override + public List getVariableEntries() { + return messageValueGetters.stream() + .filter(getter -> StringUtils.isNotEmpty(getter.getDestinationVariableName())) + .map(getter -> new VariableSourceEntry(getter.getDestinationVariableSource(), getter.getDestinationVariableName())) + .collect(Collectors.toList()); + } } diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenPromptModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenPromptModel.java index 50934d1..c7b1282 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenPromptModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenPromptModel.java @@ -4,12 +4,14 @@ import org.apache.commons.lang3.StringUtils; import synfron.reshaper.burp.core.rules.thens.ThenPrompt; import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; +import java.util.Collections; import java.util.List; -public class ThenPromptModel extends ThenModel { +public class ThenPromptModel extends ThenModel implements IVariableCreator { @Getter private String description; @@ -32,6 +34,7 @@ public ThenPromptModel(ThenPrompt then, Boolean isNew) { breakAfterFailure = then.isBreakAfterFailure(); captureVariableSource = then.getCaptureVariableSource(); captureVariableName = VariableString.toString(then.getCaptureVariableName(), captureVariableName); + VariableCreatorRegistry.register(this); } public void setDescription(String description) { @@ -109,4 +112,11 @@ public boolean record() { public RuleOperationModelType getType() { return ThenModelType.Prompt; } + + @Override + public List getVariableEntries() { + return StringUtils.isNotEmpty(captureVariableName) ? + List.of(new VariableSourceEntry(captureVariableSource, captureVariableName)) : + Collections.emptyList(); + } } diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunProcessModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunProcessModel.java index 4d5be4b..b8c4179 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunProcessModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunProcessModel.java @@ -4,12 +4,14 @@ import org.apache.commons.lang3.StringUtils; import synfron.reshaper.burp.core.rules.thens.ThenRunProcess; import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; +import java.util.Collections; import java.util.List; -public class ThenRunProcessModel extends ThenModel { +public class ThenRunProcessModel extends ThenModel implements IVariableCreator { @Getter private String command; @@ -47,6 +49,7 @@ public ThenRunProcessModel(ThenRunProcess then, Boolean isNew) { captureAfterFailure = then.isCaptureAfterFailure(); captureVariableSource = then.getCaptureVariableSource(); captureVariableName = VariableString.toString(then.getCaptureVariableName(), captureVariableName); + VariableCreatorRegistry.register(this); } public void setCommand(String command) { @@ -154,4 +157,11 @@ public boolean record() { public RuleOperationModelType getType() { return ThenModelType.RunProcess; } + + @Override + public List getVariableEntries() { + return captureOutput && StringUtils.isNotEmpty(captureVariableName) ? + List.of(new VariableSourceEntry(captureVariableSource, captureVariableName)) : + Collections.emptyList(); + } } diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendRequestModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendRequestModel.java index 81e0776..00a76d7 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendRequestModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendRequestModel.java @@ -4,13 +4,19 @@ import org.apache.commons.lang3.StringUtils; import synfron.reshaper.burp.core.rules.thens.ThenSendRequest; import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; +import java.util.Collections; import java.util.List; -public class ThenSendRequestModel extends ThenModel { +public class ThenSendRequestModel extends ThenModel implements IVariableCreator { + @Getter + private String request; + @Getter + private String url; @Getter private String protocol; @Getter @@ -18,8 +24,6 @@ public class ThenSendRequestModel extends ThenModel getType() { return ThenModelType.SendRequest; } + + @Override + public List getVariableEntries() { + return captureOutput && StringUtils.isNotEmpty(captureVariableName) ? + List.of(new VariableSourceEntry(captureVariableSource, captureVariableName)) : + Collections.emptyList(); + } } diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetVariableModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetVariableModel.java index 94268d3..189cbdb 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetVariableModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetVariableModel.java @@ -4,12 +4,14 @@ import org.apache.commons.lang3.StringUtils; import synfron.reshaper.burp.core.rules.thens.ThenSetVariable; import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; +import java.util.Collections; import java.util.List; -public class ThenSetVariableModel extends ThenSetModel { +public class ThenSetVariableModel extends ThenSetModel implements IVariableCreator { @Getter private VariableSource targetSource; @@ -20,6 +22,7 @@ public ThenSetVariableModel(ThenSetVariable then, Boolean isNew) { super(then, isNew); targetSource = then.getTargetSource(); variableName = VariableString.toString(then.getVariableName(), variableName); + VariableCreatorRegistry.register(this); } public void setTargetSource(VariableSource targetSource) { @@ -64,4 +67,11 @@ public boolean record() { public RuleOperationModelType getType() { return ThenModelType.SetVariable; } + + @Override + public List getVariableEntries() { + return StringUtils.isNotEmpty(variableName) ? + List.of(new VariableSourceEntry(targetSource, variableName)) : + Collections.emptyList(); + } } diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/VariableCreatorRegistry.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/VariableCreatorRegistry.java new file mode 100644 index 0000000..0c776a1 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/VariableCreatorRegistry.java @@ -0,0 +1,31 @@ +package synfron.reshaper.burp.ui.models.rules.thens; + +import synfron.reshaper.burp.core.vars.VariableSourceEntry; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class VariableCreatorRegistry { + + private static final List> creators = new ArrayList<>(); + + public static synchronized void register(IVariableCreator variableCreator) { + creators.add(new WeakReference<>(variableCreator)); + } + + public static synchronized List getVariableEntries() { + List entries = new ArrayList<>(creators.size() + 5); + Iterator> iterator = creators.iterator(); + while (iterator.hasNext()) { + WeakReference listenerReference = iterator.next(); + if (listenerReference.get() != null) { + entries.addAll(listenerReference.get().getVariableEntries()); + } else { + iterator.remove(); + } + } + return entries; + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CookieJarVariableTagWizardModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CookieJarVariableTagWizardModel.java new file mode 100644 index 0000000..fc35fb8 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CookieJarVariableTagWizardModel.java @@ -0,0 +1,121 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars; + +import burp.BurpExtender; +import burp.ICookie; +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.events.IEventListener; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.core.events.PropertyChangedEvent; +import synfron.reshaper.burp.core.utils.Select; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; + +import java.util.*; +import java.util.stream.Collectors; + +public class CookieJarVariableTagWizardModel implements IVariableTagWizardModel { + + @Getter + private final Select domains; + @Getter + private Select names; + @Getter + private Select paths; + + @Getter + private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); + + public CookieJarVariableTagWizardModel() { + List domains = BurpExtender.getCallbacks().getCookieJarContents().stream() + .map(ICookie::getDomain) + .filter(StringUtils::isNotEmpty) + .distinct() + .collect(Collectors.toList()); + this.domains = new Select<>(domains, domains.stream().findFirst().orElse("")); + resetNames(); + resetPaths(); + } + + public CookieJarVariableTagWizardModel withListener(IEventListener listener) { + getPropertyChangedEvent().add(listener); + return this; + } + + private void resetNames() { + List names = BurpExtender.getCallbacks().getCookieJarContents().stream() + .filter(cookie -> cookie.getDomain().equals(this.domains.getSelectedOption())) + .map(ICookie::getName) + .filter(StringUtils::isNotEmpty) + .distinct() + .collect(Collectors.toList()); + this.names = new Select<>(names, names.stream().findFirst().orElse("")); + propertyChanged("names", names); + resetPaths(); + } + + private void resetPaths() { + List paths = BurpExtender.getCallbacks().getCookieJarContents().stream() + .filter(cookie -> cookie.getDomain().equals(this.domains.getSelectedOption()) && cookie.getDomain().equals(this.names.getSelectedOption())) + .map(ICookie::getPath) + .filter(StringUtils::isNotEmpty) + .distinct() + .collect(Collectors.toList()); + this.paths = new Select<>(paths, paths.stream().findFirst().orElse("")); + propertyChanged("paths", paths); + } + + private void propertyChanged(String name, Object value) { + propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); + } + + public void setDomain(String domain) { + domains.setSelectedOption(domain); + resetNames(); + propertyChanged("domain", domains); + } + + public void setName(String name) { + names.setSelectedOption(name); + resetPaths(); + propertyChanged("name", names); + } + + public void setPath(String path) { + paths.setSelectedOption(path); + propertyChanged("path", paths); + } + + @Override + public List validate() { + List errors = new ArrayList<>(); + if (StringUtils.isEmpty(domains.getSelectedOption())) { + errors.add("Domain is required"); + } + if (StringUtils.isEmpty(names.getSelectedOption())) { + errors.add("Name is required"); + } + return errors; + } + + @Override + public VariableSource getVariableSource() { + return VariableSource.CookieJar; + } + + @Override + public String getTag() { + return validate().isEmpty() ? + VariableSourceEntry.getShortTag( + VariableSource.CookieJar, + getTagSafe(domains.getSelectedOption()), + getTagSafe(names.getSelectedOption()), + StringUtils.defaultIfEmpty(paths.getSelectedOption(), null) + ) : + null; + } + + private String getTagSafe(String value) { + return value.contains(":") ? "\"" + StringUtils.strip(value, "\"").replace("\"", "\\\"") + "\"" : value; + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/EventVariableTagWizardModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/EventVariableTagWizardModel.java new file mode 100644 index 0000000..98d63a6 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/EventVariableTagWizardModel.java @@ -0,0 +1,65 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.core.events.PropertyChangedEvent; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class EventVariableTagWizardModel implements IVariableTagWizardModel { + + @Getter + private final List variableNames; + + @Getter + private String variableName; + + @Getter + private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); + + public EventVariableTagWizardModel(List entries) { + variableNames = entries.stream() + .filter(entry -> entry.getVariableSource() == VariableSource.Event) + .map(VariableSourceEntry::getName) + .filter(VariableString::isValidVariableName) + .distinct() + .sorted(String::compareToIgnoreCase) + .collect(Collectors.toList()); + } + + private void propertyChanged(String name, Object value) { + propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); + } + + public void setVariableName(String variableName) { + this.variableName = variableName; + propertyChanged("variableName", variableName); + } + + @Override + public List validate() { + List errors = new ArrayList<>(); + if (StringUtils.isEmpty(variableName)) { + errors.add("Variable Name is required"); + } + return errors; + } + + @Override + public VariableSource getVariableSource() { + return VariableSource.Event; + } + + @Override + public String getTag() { + return validate().isEmpty() ? + VariableSourceEntry.getShortTag(VariableSource.Event, variableName) : + null; + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/FileVariableTagWizardModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/FileVariableTagWizardModel.java new file mode 100644 index 0000000..35932fb --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/FileVariableTagWizardModel.java @@ -0,0 +1,62 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.core.events.PropertyChangedEvent; +import synfron.reshaper.burp.core.messages.Encoder; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; + +import java.util.ArrayList; +import java.util.List; + +public class FileVariableTagWizardModel implements IVariableTagWizardModel { + + @Getter + private String encoding = Encoder.getDefaultEncoderName(); + + @Getter + private String filePath; + + @Getter + private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); + + private void propertyChanged(String name, Object value) { + propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + propertyChanged("encoding", encoding); + } + + public void setFilePath(String filePath) { + this.filePath = filePath; + propertyChanged("filePath", filePath); + } + + @Override + public List validate() { + List errors = new ArrayList<>(); + if (StringUtils.isEmpty(encoding)) { + errors.add("Encoding is required"); + } + if (StringUtils.isEmpty(filePath)) { + errors.add("File Path is required"); + } + return errors; + } + + @Override + public VariableSource getVariableSource() { + return VariableSource.File; + } + + @Override + public String getTag() { + return validate().isEmpty() ? + VariableSourceEntry.getShortTag(VariableSource.File, encoding, filePath) : + null; + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GlobalVariableTagWizardModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GlobalVariableTagWizardModel.java new file mode 100644 index 0000000..8d165ef --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GlobalVariableTagWizardModel.java @@ -0,0 +1,67 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.core.events.PropertyChangedEvent; +import synfron.reshaper.burp.core.vars.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class GlobalVariableTagWizardModel implements IVariableTagWizardModel { + + @Getter + private final List variableNames; + + @Getter + private String variableName; + + @Getter + private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); + + public GlobalVariableTagWizardModel(List entries) { + variableNames = Stream.concat( + GlobalVariables.get().getValues().stream().map(Variable::getName), + entries.stream() + .filter(entry -> entry.getVariableSource() == VariableSource.Global) + .map(VariableSourceEntry::getName) + ) + .filter(VariableString::isValidVariableName) + .distinct() + .sorted(String::compareToIgnoreCase) + .collect(Collectors.toList()); + } + + private void propertyChanged(String name, Object value) { + propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); + } + + public void setVariableName(String variableName) { + this.variableName = variableName; + propertyChanged("variableName", variableName); + } + + @Override + public List validate() { + List errors = new ArrayList<>(); + if (StringUtils.isEmpty(variableName)) { + errors.add("Variable Name is required"); + } + return errors; + } + + @Override + public VariableSource getVariableSource() { + return VariableSource.Global; + } + + @Override + public String getTag() { + return validate().isEmpty() ? + VariableSourceEntry.getShortTag(VariableSource.Global, variableName) : + null; + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/IVariableTagWizardModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/IVariableTagWizardModel.java new file mode 100644 index 0000000..04924b9 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/IVariableTagWizardModel.java @@ -0,0 +1,13 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars; + +import synfron.reshaper.burp.core.events.PropertyChangedEvent; +import synfron.reshaper.burp.core.vars.VariableSource; + +import java.util.List; + +public interface IVariableTagWizardModel { + String getTag(); + List validate(); + VariableSource getVariableSource(); + PropertyChangedEvent getPropertyChangedEvent(); +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MessageVariableTagWizardModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MessageVariableTagWizardModel.java new file mode 100644 index 0000000..28ca84e --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MessageVariableTagWizardModel.java @@ -0,0 +1,63 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.core.events.PropertyChangedEvent; +import synfron.reshaper.burp.core.messages.MessageValue; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; + +import java.util.ArrayList; +import java.util.List; + +public class MessageVariableTagWizardModel implements IVariableTagWizardModel { + + @Getter + private MessageValue messageValue = MessageValue.HttpRequestBody; + + @Getter + private String identifier; + + @Getter + private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); + + private void propertyChanged(String name, Object value) { + propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); + } + + public void setMessageValue(MessageValue messageValue) { + this.messageValue = messageValue; + propertyChanged("messageValue", messageValue); + } + + public void setIdentifier(String identifier) { + this.identifier = identifier; + propertyChanged("identifier", identifier); + } + + @Override + public List validate() { + List errors = new ArrayList<>(); + if (messageValue.isIdentifierRequired() && StringUtils.isEmpty(identifier)) { + errors.add("Identifier is required"); + } + return errors; + } + + @Override + public VariableSource getVariableSource() { + return VariableSource.Message; + } + + @Override + public String getTag() { + return validate().isEmpty() ? + VariableSourceEntry.getShortTag( + VariableSource.Message, + messageValue.name().toLowerCase(), + messageValue.isIdentifierRequired() ? identifier : null + ) : + null; + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SpecialVariableTagWizardModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SpecialVariableTagWizardModel.java new file mode 100644 index 0000000..eab1471 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SpecialVariableTagWizardModel.java @@ -0,0 +1,102 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars; + +import lombok.*; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.core.events.PropertyChangedEvent; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +public class SpecialVariableTagWizardModel implements IVariableTagWizardModel { + + @Getter + private final List specialChars = List.of( + new SpecialChar("New Line", "n"), + new SpecialChar("Carriage Return", "r"), + new SpecialChar("Carriage Return + New Line", "rn"), + new SpecialChar("Tab", "t"), + new SpecialChar("Form Feed", "f"), + new SpecialChar("Backspace", "b"), + new SpecialChar("ASCII Code", "x", "^[0-9a-fA-F]+$", 2), + new SpecialChar("Unicode Code", "u", "^[0-9a-fA-F]+$", 4), + new SpecialChar("Other Character", "", "^[^\\}xu]$", 1) + ); + + @Getter + private SpecialChar specialChar = specialChars.get(0); + + @Getter + private String value; + + @Getter + private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); + + private void propertyChanged(String name, Object value) { + propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); + } + + public void setSpecialChar(SpecialChar specialChar) { + this.specialChar = specialChar; + propertyChanged("specialChar", specialChar); + } + + public void setValue(String value) { + this.value = value; + propertyChanged("value", value); + } + + @Override + public List validate() { + List errors = new ArrayList<>(); + if (specialChar.isValueRequired()) { + if (StringUtils.isEmpty(value)) { + errors.add("Value is required"); + } else if (specialChar.valueLength != null && value.length() != specialChar.valueLength) { + errors.add(String.format("Value does not have the expect length (%s)", specialChar.valueLength)); + } else if (specialChar.valuePattern != null && !Pattern.matches(specialChar.valuePattern, value)) { + errors.add("Value has invalid text"); + } + } + return errors; + } + + @Override + public VariableSource getVariableSource() { + return VariableSource.Special; + } + + @Override + public String getTag() { + return validate().isEmpty() ? + VariableSourceEntry.getShortTag( + VariableSource.Special, + specialChar.code + (specialChar.isValueRequired() ? value : "") + ) : + null; + } + + @Data + @AllArgsConstructor + @RequiredArgsConstructor + public static class SpecialChar { + @NonNull + private String displayName; + @NonNull + private String code; + private String valuePattern; + private Integer valueLength; + + public boolean isValueRequired() { + return valuePattern != null || (valueLength != null && valueLength > 0); + } + + @Override + public String toString() { + return displayName; + } + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/VariableTagWizardModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/VariableTagWizardModel.java new file mode 100644 index 0000000..73eafe5 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/VariableTagWizardModel.java @@ -0,0 +1,99 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars; + +import lombok.Getter; +import lombok.Setter; +import synfron.reshaper.burp.core.events.IEventListener; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.core.events.PropertyChangedEvent; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; +import synfron.reshaper.burp.ui.models.rules.thens.VariableCreatorRegistry; +import synfron.reshaper.burp.ui.utils.IPrompterModel; +import synfron.reshaper.burp.ui.utils.ModalPrompter; + +import java.util.List; +import java.util.Map; + +public class VariableTagWizardModel implements IVariableTagWizardModel, IPrompterModel { + + @Getter + private VariableSource variableSource = VariableSource.Event; + + private final Map tagModelMap; + + @Getter + private IVariableTagWizardModel tagModel; + + @Getter + private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); + + @Getter + private boolean invalidated; + @Getter + private boolean dismissed; + + @Setter @Getter + private ModalPrompter modalPrompter; + + public VariableTagWizardModel() { + List variableSourceEntries = VariableCreatorRegistry.getVariableEntries(); + + tagModelMap = Map.of( + VariableSource.Event, new EventVariableTagWizardModel(variableSourceEntries), + VariableSource.Global, new GlobalVariableTagWizardModel(variableSourceEntries), + VariableSource.Message, new MessageVariableTagWizardModel(), + VariableSource.File, new FileVariableTagWizardModel(), + VariableSource.Special, new SpecialVariableTagWizardModel(), + VariableSource.CookieJar, new CookieJarVariableTagWizardModel() + ); + + tagModel = tagModelMap.get(variableSource); + } + + public VariableTagWizardModel withListener(IEventListener listener) { + getPropertyChangedEvent().add(listener); + return this; + } + + @Override + public void resetPropertyChangedListener() { + propertyChangedEvent.clearListeners(); + tagModelMap.values().forEach(item -> item.getPropertyChangedEvent().clearListeners()); + } + + private void propertyChanged(String name, Object value) { + propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); + } + + public void setVariableSource(VariableSource variableSource) { + this.variableSource = variableSource; + this.tagModel = tagModelMap.get(variableSource); + propertyChanged("variableSource", variableSource); + propertyChanged("tagModel", tagModel); + } + + public void setInvalidated(boolean invalidated) { + this.invalidated = invalidated; + propertyChanged("invalidated", invalidated); + } + + public void setDismissed(boolean dismissed) { + this.dismissed = dismissed; + propertyChanged("dismissed", dismissed); + } + + @Override + public String getTag() { + String tag = validate().isEmpty() ? + tagModel.getTag() : + null; + return tag; + } + + @Override + public List validate() { + List errors = tagModel.validate(); + setInvalidated(!errors.isEmpty()); + return errors; + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/WhenWizardItemModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardItemModel.java similarity index 95% rename from src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/WhenWizardItemModel.java rename to src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardItemModel.java index f9f6005..216e35a 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/WhenWizardItemModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardItemModel.java @@ -1,4 +1,4 @@ -package synfron.reshaper.burp.ui.models.rules.wizard; +package synfron.reshaper.burp.ui.models.rules.wizard.whens; import lombok.Getter; import org.apache.commons.lang3.StringUtils; @@ -26,7 +26,7 @@ public class WhenWizardItemModel { @Getter private Select identifiers = new Select<>(Collections.emptyList(), null); @Getter - private WizardMatchType matchType = WizardMatchType.Equals; + private WhenWizardMatchType matchType = WhenWizardMatchType.Equals; @Getter private String text; @Getter @@ -92,7 +92,7 @@ public void setIdentifier(String identifier) { resetText(); } - public void setMatchType(WizardMatchType matchType) { + public void setMatchType(WhenWizardMatchType matchType) { this.matchType = matchType; propertyChanged("matchType", matchType); } diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/WizardMatchType.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardMatchType.java similarity index 74% rename from src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/WizardMatchType.java rename to src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardMatchType.java index cbd5896..aa1138b 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/WizardMatchType.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardMatchType.java @@ -1,8 +1,8 @@ -package synfron.reshaper.burp.ui.models.rules.wizard; +package synfron.reshaper.burp.ui.models.rules.wizard.whens; import lombok.Getter; -public enum WizardMatchType { +public enum WhenWizardMatchType { Exists("Exists", false), Equals("Equals", true), Contains("Contains", true), @@ -15,7 +15,7 @@ public enum WizardMatchType { @Getter private final boolean matcher; - WizardMatchType(String name, boolean matcher) { + WhenWizardMatchType(String name, boolean matcher) { this.name = name; this.matcher = matcher; } diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/WhenWizardModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardModel.java similarity index 89% rename from src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/WhenWizardModel.java rename to src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardModel.java index a41580e..c784863 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/WhenWizardModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardModel.java @@ -1,7 +1,8 @@ -package synfron.reshaper.burp.ui.models.rules.wizard; +package synfron.reshaper.burp.ui.models.rules.wizard.whens; import burp.BurpExtender; import lombok.Getter; +import lombok.Setter; import org.apache.commons.lang3.StringUtils; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; @@ -17,13 +18,15 @@ import synfron.reshaper.burp.core.rules.whens.WhenMatchesText; import synfron.reshaper.burp.core.utils.GetItemPlacement; import synfron.reshaper.burp.core.vars.VariableString; +import synfron.reshaper.burp.ui.utils.IPrompterModel; +import synfron.reshaper.burp.ui.utils.ModalPrompter; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; -public class WhenWizardModel { +public class WhenWizardModel implements IPrompterModel { @Getter private final IEventInfo eventInfo; @Getter @@ -35,6 +38,11 @@ public class WhenWizardModel { private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); @Getter private boolean invalidated; + @Getter + private boolean dismissed; + + @Setter @Getter + private ModalPrompter modalPrompter; public WhenWizardModel(IEventInfo eventInfo) { this.eventInfo = eventInfo; @@ -105,6 +113,11 @@ public void setInvalidated(boolean invalidated) { propertyChanged("invalidated", invalidated); } + public void setDismissed(boolean dismissed) { + this.dismissed = dismissed; + propertyChanged("dismissed", dismissed); + } + public boolean createRule() { if (validate().isEmpty()) { Rule rule = new Rule(); @@ -126,7 +139,7 @@ public boolean createRule() { rule.setName(ruleName); rule.setEnabled(false); rule.setAutoRun(true); - rule.setWhens(new ArrayList<>(whens)); + rule.setWhens(whens.toArray(When[]::new)); BurpExtender.getConnector().getRulesEngine().getRulesRegistry().addRule(rule); setInvalidated(false); return true; diff --git a/src/main/java/synfron/reshaper/burp/ui/utils/ContextMenuHandler.java b/src/main/java/synfron/reshaper/burp/ui/utils/ContextMenuHandler.java index 07acb59..7c7a867 100644 --- a/src/main/java/synfron/reshaper/burp/ui/utils/ContextMenuHandler.java +++ b/src/main/java/synfron/reshaper/burp/ui/utils/ContextMenuHandler.java @@ -2,14 +2,10 @@ import burp.IContextMenuFactory; import burp.IContextMenuInvocation; -import burp.IHttpRequestResponse; -import synfron.reshaper.burp.core.events.IEventListener; -import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.messages.EventInfo; -import synfron.reshaper.burp.core.messages.IEventInfo; import synfron.reshaper.burp.core.utils.Log; -import synfron.reshaper.burp.ui.components.rules.wizard.WhenWizardOptionPane; -import synfron.reshaper.burp.ui.models.rules.wizard.WhenWizardModel; +import synfron.reshaper.burp.ui.components.rules.wizard.whens.WhenWizardOptionPane; +import synfron.reshaper.burp.ui.models.rules.wizard.whens.WhenWizardModel; import javax.swing.*; import java.awt.event.ActionEvent; @@ -18,15 +14,6 @@ public class ContextMenuHandler implements IContextMenuFactory { - private final IEventListener whenWizardChangedListener = this::onWhenWizardChanged; - - private void onWhenWizardChanged(PropertyChangedArgs propertyChangedArgs) { - if (propertyChangedArgs.getName().equals("invalidated") && (boolean)propertyChangedArgs.getValue()) { - WhenWizardModel whenWizardModel = (WhenWizardModel)propertyChangedArgs.getSource(); - openWhenWizard(whenWizardModel); - } - } - @Override public List createMenuItems(IContextMenuInvocation invocation) { JMenuItem menuItem = new JMenuItem("Create Rule"); @@ -35,17 +22,12 @@ public List createMenuItems(IContextMenuInvocation invocation) { } private void onCreateRule(IContextMenuInvocation invocation, ActionEvent actionEvent) { - IHttpRequestResponse requestResponse = invocation.getSelectedMessages()[0]; - IEventInfo eventInfo = new EventInfo(null, null, requestResponse); - WhenWizardModel model = new WhenWizardModel(eventInfo); - openWhenWizard(model); + openWhenWizard(new WhenWizardModel(new EventInfo(null, null, invocation.getSelectedMessages()[0]))); } private void openWhenWizard(WhenWizardModel model) { try { - model.resetPropertyChangedListener(); - model.withListener(whenWizardChangedListener); - WhenWizardOptionPane.showDialog(model); + ModalPrompter.open(model, ignored -> WhenWizardOptionPane.showDialog(model), true); } catch (Exception e) { Log.get().withMessage("Failed to create rule from content menu").withException(e).logErr(); } diff --git a/src/main/java/synfron/reshaper/burp/ui/utils/IPrompter.java b/src/main/java/synfron/reshaper/burp/ui/utils/IPrompter.java new file mode 100644 index 0000000..53d49e4 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/utils/IPrompter.java @@ -0,0 +1,5 @@ +package synfron.reshaper.burp.ui.utils; + +public interface IPrompter { + void open(T model); +} diff --git a/src/main/java/synfron/reshaper/burp/ui/utils/IPrompterModel.java b/src/main/java/synfron/reshaper/burp/ui/utils/IPrompterModel.java new file mode 100644 index 0000000..437fbcd --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/utils/IPrompterModel.java @@ -0,0 +1,21 @@ +package synfron.reshaper.burp.ui.utils; + +import synfron.reshaper.burp.core.events.IEventListener; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; + +public interface IPrompterModel> { + + T withListener(IEventListener listener); + + void resetPropertyChangedListener(); + + void setModalPrompter(ModalPrompter modalPrompter); + + ModalPrompter getModalPrompter(); + + boolean isInvalidated(); + + boolean isDismissed(); + + void setDismissed(boolean dismissed); +} diff --git a/src/main/java/synfron/reshaper/burp/ui/utils/MessagePrompter.java b/src/main/java/synfron/reshaper/burp/ui/utils/ModalPrompter.java similarity index 56% rename from src/main/java/synfron/reshaper/burp/ui/utils/MessagePrompter.java rename to src/main/java/synfron/reshaper/burp/ui/utils/ModalPrompter.java index 4f01add..cd39803 100644 --- a/src/main/java/synfron/reshaper/burp/ui/utils/MessagePrompter.java +++ b/src/main/java/synfron/reshaper/burp/ui/utils/ModalPrompter.java @@ -1,19 +1,48 @@ package synfron.reshaper.burp.ui.utils; -import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.events.IEventListener; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.ui.components.IFormComponent; import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; -import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; -import java.util.function.Supplier; -public class MessagePrompter implements IFormComponent { +public class ModalPrompter> implements IFormComponent { private static final Map dialogMap = new ConcurrentHashMap<>(); + private final T model; + private final IPrompter prompter; + private final boolean reopenOnError; + + private final IEventListener modelChangedListener = this::onModelChanged; + + public ModalPrompter(T model, IPrompter prompter, boolean reopenOnError) { + this.model = model; + this.prompter = prompter; + this.reopenOnError = reopenOnError; + + model.setModalPrompter(this); + } + + private void open() { + model.resetPropertyChangedListener(); + model.withListener(modelChangedListener); + prompter.open(model); + } + + public static > void open(T model, IPrompter prompter, boolean reopenOnError) { + ModalPrompter modalPrompter = new ModalPrompter<>(model, prompter, reopenOnError); + modalPrompter.open(); + } + + private void onModelChanged(PropertyChangedArgs propertyChangedArgs) { + if (reopenOnError && !model.isDismissed() && propertyChangedArgs.getName().equals("invalidated") && (boolean)propertyChangedArgs.getValue()) { + ModalPrompter.open(model, prompter, reopenOnError); + } + } public static void createTextAreaDialog(String id, String title, String description, String text, Consumer valueHandler) { JPanel container = new JPanel(new BorderLayout()); @@ -39,6 +68,7 @@ public static void createTextAreaDialog(String id, String title, String descript } else { valueHandler.accept(null); } + dismiss(id); }); dialog.setModal(false); @@ -49,6 +79,7 @@ public static void dismiss(String id) { JDialog dialog = dialogMap.get(id); if (dialog != null) { dialog.dispose(); + dialogMap.remove(id); } } } diff --git a/src/main/java/synfron/reshaper/burp/ui/utils/UiMessageHandler.java b/src/main/java/synfron/reshaper/burp/ui/utils/UiMessageHandler.java index dfa16ee..f6a070f 100644 --- a/src/main/java/synfron/reshaper/burp/ui/utils/UiMessageHandler.java +++ b/src/main/java/synfron/reshaper/burp/ui/utils/UiMessageHandler.java @@ -19,7 +19,7 @@ private void onMessage(MessageArgs messageArgs) { switch (messageArgs.getData().getMessageType()) { case PromptRequest -> { PromptRequestMessage message = (PromptRequestMessage)messageArgs.getData(); - MessagePrompter.createTextAreaDialog( + ModalPrompter.createTextAreaDialog( message.getMessageId(), "Prompt", message.getDescription(), @@ -30,7 +30,7 @@ private void onMessage(MessageArgs messageArgs) { ))) ); } - case PromptCancel -> MessagePrompter.dismiss(messageArgs.getData().getMessageId()); + case PromptCancel -> ModalPrompter.dismiss(messageArgs.getData().getMessageId()); } } }