diff --git a/Readme.md b/Readme.md index 4811840..82d0b89 100644 --- a/Readme.md +++ b/Readme.md @@ -34,7 +34,7 @@ Proxy Name - If received by a certain Burp proxy listener Repeat - Repeat a group of When constraints for each item in a list -[More](https://synfron.github.io/ReshaperForBurp/Rules.html#whens) +[More](https://synfron.github.io/ReshaperForBurp/Whens.html) ### Thens @@ -54,6 +54,10 @@ Drop - Have Burp drop the connection Evaluate - Perform operations on values +Extract - Extract values into lists + +Generate - Generate a value + Highlight - Highlight the line item in the HTTP/WebSocket history Intercept - Intercept the message in the Proxy interceptor @@ -76,7 +80,13 @@ Run Script - Execute a JavaScript script Save File - Save text to a file -Set Encoding - Set the encoding used to read and write bytes of the HTTP request or response body, or WebSocket message +Send Message - Send a separate WebSocket message + +Send Request - Send a separate HTTP request + +Send To - Send data to other Burp tools or the system's default browser + +Set Encoding - Set the encoding used to read and write bytes of the HTTP request or response body, or WebSocket message Set Event Direction - Change whether to send a request or to send a response at the end of processing @@ -84,13 +94,9 @@ Set Value - Set the value of an HTTP/WebSocket event using another value (text, Set Variable - Set a variable using another value (text, variable, or HTTP/WebSocket event entity) -Send Message - Send a separate WebSocket message - -Send Request - Send a separate HTTP request - -Send To - Send data to other Burp tools or the system's default browser +Transform - Transform/convert a value -[More](https://synfron.github.io/ReshaperForBurp/Rules.html#thens) +[More](https://synfron.github.io/ReshaperForBurp/Thens.html) ## Variables @@ -109,8 +115,8 @@ Share values across different Rules while processing the same event or all event ### Build JAR with CLI -1. Install Java 18. -2. Install Gradle v8.5. +1. Install Java 21. +2. Install Gradle v8.6. 3. Open a terminal into the `extension` directory of the project. 4. Run the `gradle --refresh-dependencies build jar` command. 5. The JAR will be placed in the `extension/build/libs` directory. diff --git a/docs b/docs index 8b4c359..6166e08 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 8b4c359de90804abfa4673e0772c41797805564d +Subproject commit 6166e08512159ee3317fafbe3b6961701261ff03 diff --git a/extension/build.gradle b/extension/build.gradle index 6e35db9..bf35276 100644 --- a/extension/build.gradle +++ b/extension/build.gradle @@ -4,7 +4,7 @@ plugins { group 'com.synfron.reshaper.burp' archivesBaseName = 'reshaper-for-burp' -version '2.3.3' +version '2.4.0' targetCompatibility = '21' sourceCompatibility = '21' @@ -35,7 +35,8 @@ dependencies { 'org.jsoup:jsoup:1.15.3', 'com.fasterxml.jackson.core:jackson-databind:2.14.0', 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.14.0', - 'org.apache.commons:commons-text:1.10.0' + 'org.apache.commons:commons-text:1.10.0', + 'com.fasterxml.uuid:java-uuid-generator:5.0.0' ) compileOnly ( diff --git a/extension/src/main/java/synfron/reshaper/burp/core/Tab.java b/extension/src/main/java/synfron/reshaper/burp/core/Tab.java new file mode 100644 index 0000000..6844c5b --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/Tab.java @@ -0,0 +1,32 @@ +package synfron.reshaper.burp.core; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +@Getter +@AllArgsConstructor +public enum Tab { + HttpRules("HTTP Rules"), + WebSocketRules ("WebSocket Rules"), + GlobalVariables("Global Variables"), + Logs("Logs"), + Settings("Settings", false); + + private String name; + private boolean hideable = true; + + Tab(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + + public static Tab byName(String name) { + return Arrays.stream(Tab.values()).filter(tab -> tab.name.equals(name)).findFirst().orElse(null); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/events/Event.java b/extension/src/main/java/synfron/reshaper/burp/core/events/Event.java index eb88b92..816739e 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/events/Event.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/events/Event.java @@ -17,7 +17,7 @@ public synchronized void clearListeners() { public synchronized void remove(IEventListener listener) { if (listeners != null) { listeners.removeIf(listenerReference -> listenerReference.get() == null || listenerReference.get().equals(listener)); - if (listeners.size() == 0) { + if (listeners.isEmpty()) { listeners = null; } } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/messages/ContentType.java b/extension/src/main/java/synfron/reshaper/burp/core/messages/ContentType.java index 9402bbe..83d5590 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/messages/ContentType.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/messages/ContentType.java @@ -8,14 +8,15 @@ @EqualsAndHashCode public class ContentType { - public static final ContentType None = new ContentType("None", 0, 1); - public static final ContentType UrlEncoded = new ContentType("URL Encoded", 1, 2); - public static final ContentType MultiPart = new ContentType("Multi-Part", 2, 4); - public static final ContentType Xml = new ContentType("XML", 3, 8); - public static final ContentType Json = new ContentType("JSON", 4, 16); - public static final ContentType Amf = new ContentType("AMF", 5, 32); - public static final ContentType Unknown = new ContentType("Unknown", -1, 64); + public static final ContentType None = new ContentType("None", 1); + public static final ContentType UrlEncoded = new ContentType("URL Encoded", 2); + public static final ContentType MultiPart = new ContentType("Multi-Part", 4); + public static final ContentType Xml = new ContentType("XML", 8); + public static final ContentType Json = new ContentType("JSON", 16); + public static final ContentType Amf = new ContentType("AMF", 32); + public static final ContentType Unknown = new ContentType("Unknown", 64); + @Getter private static final List values = List.of( None, UrlEncoded, @@ -28,26 +29,23 @@ public class ContentType { @Getter private final String[] names; - private final int[] ids; private final int flags; private ContentType() { - this(None.names[0], None.ids[0], None.flags); + this(None.names[0], None.flags); } - private ContentType(String name, int id, int flags) { + private ContentType(String name, int flags) { this.names = new String[] { name }; - this.ids = new int[] { id }; this.flags = flags; } private ContentType(int flags) { List contentTypes = getValues().stream() .filter(contentType -> contentType.hasFlags(flags)) - .collect(Collectors.toList()); + .toList(); this.names = contentTypes.stream() .map(ContentType::getName).toArray(String[]::new); - this.ids = contentTypes.stream().mapToInt(ContentType::getId).toArray(); this.flags = flags; } @@ -55,10 +53,6 @@ public String getName() { return String.join(", ", names); } - private int getId() { - return ids.length == 1 ? ids[0] : Unknown.getId(); - } - public static ContentType get(burp.api.montoya.http.message.ContentType contentType) { return switch (contentType) { case AMF -> Amf; @@ -71,21 +65,10 @@ public static ContentType get(burp.api.montoya.http.message.ContentType contentT }; } - public static ContentType get(int id) { - return getValues().stream() - .filter(contentType -> contentType.getId() == id) - .findFirst() - .orElse(Unknown); - } - public boolean isTextBased() { return flags != 0 && (flags & ~(Json.flags | UrlEncoded.flags | Xml.flags)) == 0; } - public static List getValues() { - return values; - } - public boolean hasFlags(ContentType contentType) { return hasFlags(contentType.flags); } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/messages/MessageValueHandler.java b/extension/src/main/java/synfron/reshaper/burp/core/messages/MessageValueHandler.java index 4d740bb..e9d7bd0 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/messages/MessageValueHandler.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/messages/MessageValueHandler.java @@ -69,11 +69,9 @@ public static String getResponseValue(EventInfo eventInfo, HttpResponseMessage r public static void setValue(EventInfo eventInfo, MessageValue messageValue, VariableString identifier, SetItemPlacement itemPlacement, String replacementText) { - if (eventInfo instanceof HttpEventInfo) { - HttpEventInfo httpEventInfo = (HttpEventInfo)eventInfo; + if (eventInfo instanceof HttpEventInfo httpEventInfo) { setValue(httpEventInfo, messageValue, identifier, itemPlacement, replacementText); - } else if (eventInfo instanceof WebSocketEventInfo) { - WebSocketEventInfo webSocketEventInfo = (WebSocketEventInfo)eventInfo; + } else if (eventInfo instanceof WebSocketEventInfo webSocketEventInfo) { setValue(webSocketEventInfo, messageValue, replacementText); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/MatchType.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/MatchType.java index 92e7edb..248ac6e 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/MatchType.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/MatchType.java @@ -7,7 +7,11 @@ public enum MatchType { Contains("Contains"), BeginsWith("Begins With"), EndsWith("Ends With"), - Regex("Regex"); + Regex("Regex"), + LessThan("Less Than"), + LessThanOrEqual("Less Than Or Equal"), + GreaterThan("Greater Than"), + GreaterThanOrEqual("Greater Than Or Equal"); @Getter private final String name; diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/diagnostics/Diagnostics.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/diagnostics/Diagnostics.java index c26f1a4..5a2dcfb 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/diagnostics/Diagnostics.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/diagnostics/Diagnostics.java @@ -103,7 +103,7 @@ public void logProperties(When when, boolean result, List records = getRecords(); - return records.size() > 0 && records.get(records.size() - 1).getEntityType() == entityType; + return !records.isEmpty() && records.get(records.size() - 1).getEntityType() == entityType; } @Override @@ -167,22 +167,18 @@ public void logGroupEnd(String name) { @Override public void logStart(EventInfo eventInfo) { - if (eventInfo instanceof HttpEventInfo) { - HttpEventInfo httpEventInfo = (HttpEventInfo)eventInfo; + if (eventInfo instanceof HttpEventInfo httpEventInfo) { logStart(httpEventInfo); - } else if (eventInfo instanceof WebSocketEventInfo) { - WebSocketEventInfo webSocketEventInfo = (WebSocketEventInfo)eventInfo; + } else if (eventInfo instanceof WebSocketEventInfo webSocketEventInfo) { logStart(webSocketEventInfo); } } @Override public void logEnd(EventInfo eventInfo) { - if (eventInfo instanceof HttpEventInfo) { - HttpEventInfo httpEventInfo = (HttpEventInfo)eventInfo; + if (eventInfo instanceof HttpEventInfo httpEventInfo) { logEnd(httpEventInfo); - } else if (eventInfo instanceof WebSocketEventInfo) { - WebSocketEventInfo webSocketEventInfo = (WebSocketEventInfo)eventInfo; + } else if (eventInfo instanceof WebSocketEventInfo webSocketEventInfo) { logEnd(webSocketEventInfo); } } @@ -268,6 +264,10 @@ private String toMatchPhrase(MatchType matchType, boolean negated) { case EndsWith -> "ends with"; case BeginsWith -> "begins with"; case Regex -> "is matched by"; + case LessThan -> "is less than"; + case GreaterThan -> "is greater than"; + case LessThanOrEqual -> "is less than or equals"; + case GreaterThanOrEqual -> "is greater than or equals"; }; } else { return switch (matchType) { @@ -276,6 +276,10 @@ private String toMatchPhrase(MatchType matchType, boolean negated) { case EndsWith -> "does not end with"; case BeginsWith -> "does not begin with"; case Regex -> "is not matched by"; + case LessThan -> "is not less than"; + case GreaterThan -> "is not greater than"; + case LessThanOrEqual -> "is not less than or equal to"; + case GreaterThanOrEqual -> "is not greater than or equal to"; }; } } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/Then.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/Then.java index 5d767a4..7b4d9e3 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/Then.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/Then.java @@ -35,7 +35,10 @@ @JsonSubTypes.Type(value = ThenSendRequest.class), @JsonSubTypes.Type(value = ThenSendMessage.class), @JsonSubTypes.Type(value = ThenRepeat.class), - @JsonSubTypes.Type(value = ThenReadFile.class) + @JsonSubTypes.Type(value = ThenReadFile.class), + @JsonSubTypes.Type(value = ThenExtract.class), + @JsonSubTypes.Type(value = ThenGenerate.class), + @JsonSubTypes.Type(value = ThenTransform.class) }) public abstract class Then> implements IRuleOperation { diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenBuildHttpMessage.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenBuildHttpMessage.java index 62a01fa..5455eb1 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenBuildHttpMessage.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenBuildHttpMessage.java @@ -58,7 +58,7 @@ public RuleResponse perform(EventInfo eventInfo) { Pair.of("index", destinationVariableSource.isList() && itemPlacement.isHasIndexSetter() ? VariableString.getTextOrDefault(eventInfo, index, null) : null) ), messageValueSetters.stream().map(messageValueSetter -> Pair.of( - VariableSourceEntry.getTag( + VariableTag.getTag( VariableSource.Message, messageValueSetter.getDestinationMessageValue().name().toLowerCase(), messageValueSetter.getDestinationMessageValue().isIdentifierRequired() ? VariableString.getTextOrDefault( diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDelay.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDelay.java index cd233c4..277fbb9 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDelay.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDelay.java @@ -14,6 +14,7 @@ import synfron.reshaper.burp.core.vars.VariableString; import java.util.Arrays; +import java.util.List; public class ThenDelay extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @@ -33,7 +34,7 @@ public RuleResponse perform(EventInfo eventInfo) { hasError = true; throw e; } finally { - if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logProperties(this, hasError, Arrays.asList(Pair.of("millis", VariableString.getTextOrDefault(eventInfo, delay, "0")))); + if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logProperties(this, hasError, List.of(Pair.of("millis", VariableString.getTextOrDefault(eventInfo, delay, "0")))); } return RuleResponse.Continue; } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDeleteVariable.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDeleteVariable.java index ee676b8..3291be9 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDeleteVariable.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDeleteVariable.java @@ -41,7 +41,7 @@ public RuleResponse perform(EventInfo eventInfo) { if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logValue( this, hasError, - VariableSourceEntry.getTag( + VariableTag.getTag( targetSource, variableName.getText(eventInfo), IListItemPlacement.toGet(itemPlacement), diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenExtract.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenExtract.java new file mode 100644 index 0000000..eebbbec --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenExtract.java @@ -0,0 +1,81 @@ +package synfron.reshaper.burp.core.rules.thens; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; +import synfron.reshaper.burp.core.rules.RuleOperationType; +import synfron.reshaper.burp.core.rules.RuleResponse; +import synfron.reshaper.burp.core.rules.thens.entities.extract.ExtractorType; +import synfron.reshaper.burp.core.utils.TextUtils; +import synfron.reshaper.burp.core.vars.*; + +import java.util.List; + +@Setter @Getter +public class ThenExtract extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { + + private VariableString text; + private ExtractorType extractorType = ExtractorType.Regex; + private VariableString extractor; + private VariableSource listVariableSource = VariableSource.GlobalList; + private VariableString listVariableName; + private VariableString delimiter; + private SetListItemsPlacement itemsPlacement = SetListItemsPlacement.Overwrite; + + @Override + public RuleResponse perform(EventInfo eventInfo) { + String valueText = null; + String extractorText = null; + String listVariableNameText = null; + String delimiterText = null; + ListVariable variable = null; + + boolean hasError = false; + try { + valueText = text.getText(eventInfo); + extractorText = extractor.getText(eventInfo); + listVariableNameText = listVariableName.getText(eventInfo); + delimiterText = delimiter.getText(eventInfo); + VariableSourceEntry variableSource = new VariableSourceEntry(listVariableSource, List.of(listVariableNameText)); + variable = switch (variableSource.getVariableSource()) { + case GlobalList -> (ListVariable) GlobalVariables.get().add(Variables.asKey(variableSource.getParams().getFirst(), true)); + case EventList -> (ListVariable) eventInfo.getVariables().add(Variables.asKey(variableSource.getParams().getFirst(), true)); + case SessionList -> (ListVariable) eventInfo.getSessionVariables().add(Variables.asKey(variableSource.getParams().getFirst(), true)); + default -> null; + }; + + List values = switch (extractorType) { + case Regex -> TextUtils.getRegexValues(valueText, extractorText); + case Json -> TextUtils.getJsonPathValues(valueText, extractorText); + case CssSelector -> TextUtils.getCssSelectorValues(valueText, extractorText); + case XPath -> TextUtils.getXPathValues(valueText, extractorText); + case Chunk -> TextUtils.getChunks(valueText, TextUtils.asInt(extractorText)); + }; + + variable.setValues(values.toArray(), delimiterText, itemsPlacement); + } catch (Exception e) { + hasError = true; + throw e; + } finally { + if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logProperties(this, hasError, List.of( + Pair.of("text", valueText), + Pair.of("extractorType", extractorType), + Pair.of("extractor", extractorText), + Pair.of("listVariableSource", listVariableSource), + Pair.of("listVariableName", listVariableNameText), + Pair.of("delimiter", delimiterText), + Pair.of("itemsPlacement", itemsPlacement), + Pair.of("value", variable != null && variable.hasValue() ? variable.getValue().toString() : null) + )); + } + return RuleResponse.Continue; + } + + @Override + public RuleOperationType getType() { + return ThenType.Extract; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenGenerate.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenGenerate.java new file mode 100644 index 0000000..46f833a --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenGenerate.java @@ -0,0 +1,72 @@ +package synfron.reshaper.burp.core.rules.thens; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; +import synfron.reshaper.burp.core.rules.RuleOperationType; +import synfron.reshaper.burp.core.rules.RuleResponse; +import synfron.reshaper.burp.core.rules.thens.entities.generate.GenerateOption; +import synfron.reshaper.burp.core.rules.thens.entities.generate.IGenerator; +import synfron.reshaper.burp.core.rules.thens.entities.generate.UuidGenerator; +import synfron.reshaper.burp.core.vars.SetListItemPlacement; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Setter +@Getter +public class ThenGenerate extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { + private GenerateOption generateOption = GenerateOption.Uuid; + private IGenerator generator = new UuidGenerator(); + private VariableSource destinationVariableSource = VariableSource.Global; + private VariableString destinationVariableName; + private SetListItemPlacement itemPlacement = SetListItemPlacement.Index; + private VariableString delimiter; + private VariableString index; + + @Override + public RuleResponse perform(EventInfo eventInfo) { + boolean hasError = true; + List> diagnosticProperties = eventInfo.getDiagnostics().isEnabled() ? + new ArrayList<>() : + null; + try { + String value = generator.generate(eventInfo, diagnosticProperties); + setVariable( + destinationVariableSource, eventInfo, + destinationVariableName.getText(eventInfo), + itemPlacement, + VariableString.getTextOrDefault(eventInfo, delimiter, "\n"), + VariableString.getIntOrDefault(eventInfo, index, 0), + value + ); + hasError = false; + } finally { + if (diagnosticProperties != null) { + diagnosticProperties.addAll( + Arrays.asList( + Pair.of("destinationVariableSource", destinationVariableSource), + Pair.of("destinationVariableName", VariableString.getTextOrDefault(eventInfo, destinationVariableName, null)), + Pair.of("itemPlacement", destinationVariableSource.isList() ? itemPlacement : null), + Pair.of("delimiter", destinationVariableSource.isList() && itemPlacement.isHasDelimiterSetter() ? delimiter : null), + Pair.of("index", destinationVariableSource.isList() && itemPlacement.isHasIndexSetter() ? VariableString.getTextOrDefault(eventInfo, index, null) : null) + ) + ); + eventInfo.getDiagnostics().logProperties(this, hasError, diagnosticProperties); + } + } + return RuleResponse.Continue; + } + + @Override + public RuleOperationType getType() { + return ThenType.Generate; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenLog.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenLog.java index 63ce1ac..de05555 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenLog.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenLog.java @@ -19,6 +19,7 @@ public class ThenLog extends Then implements IHttpRuleOperation, IWebSo public RuleResponse perform(EventInfo eventInfo) { boolean hasError = true; try { + Log.get().withMessage(text.getText(eventInfo)).log(); hasError = false; } finally { diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenParseHttpMessage.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenParseHttpMessage.java index c0a1f73..6748c23 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenParseHttpMessage.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenParseHttpMessage.java @@ -114,14 +114,14 @@ private List> parseResponseMessage(EventInfo eventInfo) { private Pair setVariable(EventInfo eventInfo, VariableSource variableSource, String variableName, SetListItemPlacement itemPlacement, String delimiter, Integer index, String value) { super.setVariable(variableSource, eventInfo, variableName, itemPlacement, delimiter, index, value); return variableSource.isList() ? - Pair.of(VariableSourceEntry.getTag( + Pair.of(VariableTag.getTag( variableSource, variableName, itemPlacement.toString(), itemPlacement.isHasIndexSetter() ? TextUtils.toString(index) : null ), value) : - Pair.of(VariableSourceEntry.getTag(variableSource, variableName), value); + Pair.of(VariableTag.getTag(variableSource, variableName), value); } @Override diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRepeat.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRepeat.java index ff00c0a..afa98d3 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRepeat.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRepeat.java @@ -152,19 +152,19 @@ private Iterator getHasNextItemIterator(EventInfo eventInfo, List (ListVariable) GlobalVariables.get().getOrDefault(Variables.asKey(variable1.getName(), true)); - case EventList -> (ListVariable) eventInfo.getVariables().getOrDefault(Variables.asKey(variable1.getName(), true)); - case SessionList -> (ListVariable) eventInfo.getSessionVariables().getOrDefault(Variables.asKey(variable1.getName(), true)); + case GlobalList -> (ListVariable) GlobalVariables.get().getOrDefault(Variables.asKey(variable1.getParams().getFirst(), true)); + case EventList -> (ListVariable) eventInfo.getVariables().getOrDefault(Variables.asKey(variable1.getParams().getFirst(), true)); + case SessionList -> (ListVariable) eventInfo.getSessionVariables().getOrDefault(Variables.asKey(variable1.getParams().getFirst(), true)); default -> null; }; listSize = variable != null ? variable.size() : null; conditionData.setValue(entryVariableNameText); if (diagnosticProperties != null) { - diagnosticProperties.add(Pair.of("listVariable", VariableSourceEntry.getTag(listVariableSource, listVariableNameText))); + diagnosticProperties.add(Pair.of("listVariable", VariableTag.getTag(listVariableSource, listVariableNameText))); diagnosticProperties.add(Pair.of("listSize", listSize != null ? listSize.toString() : "null")); - diagnosticProperties.add(Pair.of("entryVariable", VariableSourceEntry.getTag(VariableSource.Event, entryVariableNameText))); + diagnosticProperties.add(Pair.of("entryVariable", VariableTag.getTag(VariableSource.Event, entryVariableNameText))); } return variable != null ? variable.getIterator() : null; } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSet.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSet.java index 071f985..a213295 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSet.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSet.java @@ -51,8 +51,8 @@ protected String getReplacementValue(EventInfo eventInfo) if (sourceMessageValueType != MessageValueType.Text && sourceMessageValuePath != null) { text = switch (sourceMessageValueType) { - case Json -> StringUtils.defaultString(TextUtils.getJsonValue(text, sourceMessageValuePath.getText(eventInfo))); - case Html -> StringUtils.defaultString(TextUtils.getHtmlValue(text, sourceMessageValuePath.getText(eventInfo))); + case Json -> StringUtils.defaultString(TextUtils.getJsonPathValue(text, sourceMessageValuePath.getText(eventInfo))); + case Html -> StringUtils.defaultString(TextUtils.getCssSelectorValue(text, sourceMessageValuePath.getText(eventInfo))); case Params -> StringUtils.defaultString(TextUtils.getParamValue(text, sourceMessageValuePath.getText(eventInfo))); default -> text; }; diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetValue.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetValue.java index 8f469c6..82fbc5d 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetValue.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetValue.java @@ -50,8 +50,8 @@ private void setValue(EventInfo eventInfo, String replacementText) IItemPlacement.toGet(destinationIdentifierPlacement) ); switch (destinationMessageValueType) { - case Json -> replacementText = TextUtils.setJsonValue(fullText, destinationMessageValuePath.getText(eventInfo), replacementText); - case Html -> replacementText = TextUtils.setHtmlValue(fullText, destinationMessageValuePath.getText(eventInfo), replacementText); + case Json -> replacementText = TextUtils.setJsonPathValue(fullText, destinationMessageValuePath.getText(eventInfo), replacementText); + case Html -> replacementText = TextUtils.setCssSelectorValue(fullText, destinationMessageValuePath.getText(eventInfo), replacementText); case Params -> replacementText = TextUtils.setParamValue(fullText, destinationMessageValuePath.getText(eventInfo), replacementText); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetVariable.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetVariable.java index 2ecdd4f..d66ea6e 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetVariable.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetVariable.java @@ -53,8 +53,8 @@ private void setValue(EventInfo eventInfo, String replacementText) { String value = StringUtils.defaultString(TextUtils.toString(variable.getValue(IListItemPlacement.toGet(itemPlacement), VariableString.getIntOrDefault(eventInfo, index, null)))); switch (destinationMessageValueType) { - case Json -> replacementText = TextUtils.setJsonValue(value, destinationMessageValuePath.getText(eventInfo), replacementText); - case Html -> replacementText = TextUtils.setHtmlValue(value, destinationMessageValuePath.getText(eventInfo), replacementText); + case Json -> replacementText = TextUtils.setJsonPathValue(value, destinationMessageValuePath.getText(eventInfo), replacementText); + case Html -> replacementText = TextUtils.setCssSelectorValue(value, destinationMessageValuePath.getText(eventInfo), replacementText); case Params -> replacementText = TextUtils.setParamValue(value, destinationMessageValuePath.getText(eventInfo), replacementText); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenTransform.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenTransform.java new file mode 100644 index 0000000..585a28d --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenTransform.java @@ -0,0 +1,77 @@ +package synfron.reshaper.burp.core.rules.thens; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; +import synfron.reshaper.burp.core.rules.RuleOperationType; +import synfron.reshaper.burp.core.rules.RuleResponse; +import synfron.reshaper.burp.core.rules.thens.entities.transform.ITransformer; +import synfron.reshaper.burp.core.rules.thens.entities.transform.TransformOption; +import synfron.reshaper.burp.core.vars.SetListItemPlacement; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ThenTransform extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { + @Getter @Setter + private TransformOption transformOption = TransformOption.Base64; + @Getter @Setter + private ITransformer transformer; + @Getter @Setter + private VariableSource destinationVariableSource = VariableSource.Global; + @Getter @Setter + private VariableString destinationVariableName; + @Getter @Setter + private SetListItemPlacement itemPlacement = SetListItemPlacement.Index; + @Getter @Setter + private VariableString delimiter; + @Getter @Setter + private VariableString index; + + @Override + public RuleResponse perform(EventInfo eventInfo) { + boolean hasError = true; + List> diagnosticProperties = eventInfo.getDiagnostics().isEnabled() ? + new ArrayList<>() : + null; + try { + String value = transformer.transform(eventInfo, diagnosticProperties); + setVariable( + destinationVariableSource, eventInfo, + destinationVariableName.getText(eventInfo), + itemPlacement, + VariableString.getTextOrDefault(eventInfo, delimiter, "\n"), + VariableString.getIntOrDefault(eventInfo, index, 0), + value + ); + hasError = false; + } finally { + if (diagnosticProperties != null) { + diagnosticProperties.addAll( + Arrays.asList( + Pair.of("transformOption", transformOption), + Pair.of("destinationVariableSource", destinationVariableSource), + Pair.of("destinationVariableName", VariableString.getTextOrDefault(eventInfo, destinationVariableName, null)), + Pair.of("itemPlacement", destinationVariableSource.isList() ? itemPlacement : null), + Pair.of("delimiter", destinationVariableSource.isList() && itemPlacement.isHasDelimiterSetter() ? delimiter : null), + Pair.of("index", destinationVariableSource.isList() && itemPlacement.isHasIndexSetter() ? VariableString.getTextOrDefault(eventInfo, index, null) : null) + ) + ); + eventInfo.getDiagnostics().logProperties(this, hasError, diagnosticProperties); + } + } + return RuleResponse.Continue; + } + + @Override + public RuleOperationType getType() { + return ThenType.Transform; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenType.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenType.java index 9f58654..964b8bb 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenType.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenType.java @@ -33,6 +33,9 @@ public class ThenType> extends RuleOperationType { public static final ThenType Intercept = new ThenType<>("Intercept", ThenIntercept.class); public static final ThenType Repeat = new ThenType<>("Repeat", ThenRepeat.class); public static final ThenType ReadFile = new ThenType<>("Read File", ThenReadFile.class); + public static final ThenType Generate = new ThenType<>("Generate", ThenGenerate.class); + public static final ThenType Transform = new ThenType<>("Transform", ThenTransform.class); + public static final ThenType Extract = new ThenType<>("Extract", ThenExtract.class); private ThenType() { this(null, null); @@ -69,7 +72,10 @@ public static List> getTypes() { Drop, Intercept, Repeat, - ReadFile + ReadFile, + Extract, + Generate, + Transform ); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/extract/ExtractorType.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/extract/ExtractorType.java new file mode 100644 index 0000000..a232d24 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/extract/ExtractorType.java @@ -0,0 +1,27 @@ +package synfron.reshaper.burp.core.rules.thens.entities.extract; + +import lombok.Getter; + +public enum ExtractorType { + Regex("Regex", "Pattern"), + Json("JSONPath", "Path"), + CssSelector("CSS Selector", "Selector"), + XPath("XPath", "Path"), + Chunk("Chunk", "Size"); + + @Getter + private final String name; + @Getter + private final String syntax; + + ExtractorType(String name, String syntax) { + this.name = name; + this.syntax = syntax; + } + + + @Override + public String toString() { + return name; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/BytesGenerator.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/BytesGenerator.java new file mode 100644 index 0000000..cb37431 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/BytesGenerator.java @@ -0,0 +1,34 @@ +package synfron.reshaper.burp.core.rules.thens.entities.generate; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.Encoder; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.utils.ValueGenerator; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.io.Serializable; +import java.nio.charset.StandardCharsets; +import java.util.List; + +@Setter +@Getter +public class BytesGenerator implements IGenerator { + + private VariableString length; + private VariableString encoding; + + @Override + public String generate(EventInfo eventInfo, List> diagnosticProperties) { + int length = this.length.getInt(eventInfo); + String encodingValue = VariableString.getTextOrDefault(eventInfo, encoding, StandardCharsets.ISO_8859_1.displayName()); + Encoder encoder = new Encoder(encodingValue); + String value = ValueGenerator.bytes(length, encoder); + if (diagnosticProperties != null) { + diagnosticProperties.add(Pair.of("length", length)); + diagnosticProperties.add(Pair.of("value", value)); + } + return value; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/GenerateOption.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/GenerateOption.java new file mode 100644 index 0000000..a1d838b --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/GenerateOption.java @@ -0,0 +1,32 @@ +package synfron.reshaper.burp.core.rules.thens.entities.generate; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +@RequiredArgsConstructor +@AllArgsConstructor +public enum GenerateOption { + Uuid("UUID", UuidGenerator.class), + Words(WordGenerator.class), + Password(PasswordGenerator.class), + Bytes(BytesGenerator.class), + Integer(IntegerGenerator.class), + IpAddress("IP Address", IpAddressGenerator.class), + Timestamp(TimestampGenerator.class), + UnixTimestamp("UNIX Timestamp", UnixTimestampGenerator.class); + + private String name; + @Getter + private final Class generatorClass; + + public String getName() { + return StringUtils.defaultString(name, name()); + } + + @Override + public String toString() { + return getName(); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/IGenerator.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/IGenerator.java new file mode 100644 index 0000000..8029d73 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/IGenerator.java @@ -0,0 +1,24 @@ +package synfron.reshaper.burp.core.rules.thens.entities.generate; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; + +import java.io.Serializable; +import java.util.List; + +@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, property = "@class") +@JsonSubTypes({ + @JsonSubTypes.Type(value = BytesGenerator.class), + @JsonSubTypes.Type(value = IntegerGenerator.class), + @JsonSubTypes.Type(value = IpAddressGenerator.class), + @JsonSubTypes.Type(value = PasswordGenerator.class), + @JsonSubTypes.Type(value = TimestampGenerator.class), + @JsonSubTypes.Type(value = UnixTimestampGenerator.class), + @JsonSubTypes.Type(value = UuidGenerator.class), + @JsonSubTypes.Type(value = WordGenerator.class) +}) +public interface IGenerator { + String generate(EventInfo eventInfo, List> diagnosticProperties); +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/IntegerGenerator.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/IntegerGenerator.java new file mode 100644 index 0000000..05b8c9c --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/IntegerGenerator.java @@ -0,0 +1,37 @@ +package synfron.reshaper.burp.core.rules.thens.entities.generate; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.utils.ValueGenerator; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.io.Serializable; +import java.util.List; + +@Setter +@Getter +public class IntegerGenerator implements IGenerator { + + private VariableString minValue; + + private VariableString maxValue; + + private VariableString base; + + @Override + public String generate(EventInfo eventInfo, List> diagnosticProperties) { + long minValue = this.minValue.getLong(eventInfo); + long maxValue = this.maxValue.getLong(eventInfo); + int base = VariableString.getIntOrDefault(eventInfo, this.base, 10); + String value = ValueGenerator.integer(minValue, maxValue, base); + if (diagnosticProperties != null) { + diagnosticProperties.add(Pair.of("minValue", minValue)); + diagnosticProperties.add(Pair.of("maxValue", maxValue)); + diagnosticProperties.add(Pair.of("base", base)); + diagnosticProperties.add(Pair.of("value", value)); + } + return value; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/IpAddressGenerator.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/IpAddressGenerator.java new file mode 100644 index 0000000..6b06a75 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/IpAddressGenerator.java @@ -0,0 +1,28 @@ +package synfron.reshaper.burp.core.rules.thens.entities.generate; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.utils.ValueGenerator; + +import java.io.Serializable; +import java.util.List; + +@Setter +@Getter +public class IpAddressGenerator implements IGenerator { + + private ValueGenerator.IpVersion version = ValueGenerator.IpVersion.V4; + + @Override + public String generate(EventInfo eventInfo, List> diagnosticProperties) { + String value = ValueGenerator.ipAddress(version); + if (diagnosticProperties != null) { + diagnosticProperties.add(Pair.of("version", version)); + diagnosticProperties.add(Pair.of("value", value)); + } + return value; + } + +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/PasswordGenerator.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/PasswordGenerator.java new file mode 100644 index 0000000..660d144 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/PasswordGenerator.java @@ -0,0 +1,39 @@ +package synfron.reshaper.burp.core.rules.thens.entities.generate; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.utils.PasswordCharacterGroup; +import synfron.reshaper.burp.core.utils.ValueGenerator; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; + +@Setter +@Getter +public class PasswordGenerator implements IGenerator { + + private VariableString minLength; + + private VariableString maxLength; + + EnumSet characterGroups = EnumSet.allOf(PasswordCharacterGroup.class); + + @Override + public String generate(EventInfo eventInfo, List> diagnosticProperties) { + int minLength = this.minLength.getInt(eventInfo); + int maxLength = this.maxLength.getInt(eventInfo); + String value = ValueGenerator.password(minLength, maxLength, new ArrayList<>(characterGroups)); + if (diagnosticProperties != null) { + diagnosticProperties.add(Pair.of("minLength", minLength)); + diagnosticProperties.add(Pair.of("maxLength", maxLength)); + diagnosticProperties.add(Pair.of("characterGroups", characterGroups)); + diagnosticProperties.add(Pair.of("value", value)); + } + return value; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/TimestampGenerator.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/TimestampGenerator.java new file mode 100644 index 0000000..c0bbc63 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/TimestampGenerator.java @@ -0,0 +1,38 @@ +package synfron.reshaper.burp.core.rules.thens.entities.generate; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.utils.ValueGenerator; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.io.Serializable; +import java.util.List; + +@Setter +@Getter +public class TimestampGenerator implements IGenerator { + + private VariableString format; + + private VariableString minTimestamp; + + private VariableString maxTimestamp; + + @Override + public String generate(EventInfo eventInfo, List> diagnosticProperties) { + String format = VariableString.getTextOrDefault(eventInfo, this.format, null); + String minTimestamp = VariableString.getTextOrDefault(eventInfo, this.minTimestamp, null); + String maxTimestamp = VariableString.getTextOrDefault(eventInfo, this.maxTimestamp, null); + String value = ValueGenerator.dateOrNow(format, minTimestamp, maxTimestamp); + if (diagnosticProperties != null) { + diagnosticProperties.add(Pair.of("format", format)); + diagnosticProperties.add(Pair.of("minTimestamp", minTimestamp)); + diagnosticProperties.add(Pair.of("maxTimestamp", maxTimestamp)); + diagnosticProperties.add(Pair.of("value", value)); + } + return value; + } + +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/UnixTimestampGenerator.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/UnixTimestampGenerator.java new file mode 100644 index 0000000..96e2725 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/UnixTimestampGenerator.java @@ -0,0 +1,38 @@ +package synfron.reshaper.burp.core.rules.thens.entities.generate; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.utils.ValueGenerator; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.io.Serializable; +import java.util.List; + +@Setter +@Getter +public class UnixTimestampGenerator implements IGenerator { + + private VariableString format; + + private VariableString minTimestamp; + + private VariableString maxTimestamp; + + @Override + public String generate(EventInfo eventInfo, List> diagnosticProperties) { + String format = VariableString.getTextOrDefault(eventInfo, this.format, null); + String minTimestamp = VariableString.getTextOrDefault(eventInfo, this.minTimestamp, null); + String maxTimestamp = VariableString.getTextOrDefault(eventInfo, this.maxTimestamp, null); + String value = ValueGenerator.timestampOrNow(format, minTimestamp, maxTimestamp); + if (diagnosticProperties != null) { + diagnosticProperties.add(Pair.of("format", format)); + diagnosticProperties.add(Pair.of("minTimestamp", minTimestamp)); + diagnosticProperties.add(Pair.of("maxTimestamp", maxTimestamp)); + diagnosticProperties.add(Pair.of("value", value)); + } + return value; + } + +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/UuidGenerator.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/UuidGenerator.java new file mode 100644 index 0000000..a775896 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/UuidGenerator.java @@ -0,0 +1,37 @@ +package synfron.reshaper.burp.core.rules.thens.entities.generate; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.utils.ValueGenerator; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.io.Serializable; +import java.util.List; + +@Setter +@Getter +public class UuidGenerator implements IGenerator { + + private ValueGenerator.UuidVersion version = ValueGenerator.UuidVersion.V4; + + private VariableString namespace; + + private VariableString name; + + @Override + public String generate(EventInfo eventInfo, List> diagnosticProperties) { + String namespace = VariableString.getTextOrDefault(eventInfo, this.namespace, null); + String name = VariableString.getTextOrDefault(eventInfo, this.name, null); + String value = ValueGenerator.uuid(version, namespace, name); + if (diagnosticProperties != null) { + diagnosticProperties.add(Pair.of("version", version)); + diagnosticProperties.add(Pair.of("namespace", namespace)); + diagnosticProperties.add(Pair.of("name", name)); + diagnosticProperties.add(Pair.of("value", value)); + } + return value; + } + +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/WordGenerator.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/WordGenerator.java new file mode 100644 index 0000000..aecf024 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/generate/WordGenerator.java @@ -0,0 +1,37 @@ +package synfron.reshaper.burp.core.rules.thens.entities.generate; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.utils.ValueGenerator; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.io.Serializable; +import java.util.List; + +@Setter +@Getter +public class WordGenerator implements IGenerator { + + private ValueGenerator.WordGeneratorType generatorType = ValueGenerator.WordGeneratorType.Paragraph; + + private VariableString count; + + private VariableString separator; + + @Override + public String generate(EventInfo eventInfo, List> diagnosticProperties) { + int count = VariableString.getIntOrDefault(eventInfo, this.count, 1); + String separator = VariableString.getTextOrDefault(eventInfo, this.separator, "\n"); + String value = ValueGenerator.words(generatorType, count, separator); + if (diagnosticProperties != null) { + diagnosticProperties.add(Pair.of("generatorType", generatorType)); + diagnosticProperties.add(Pair.of("count", count)); + diagnosticProperties.add(Pair.of("separator", separator)); + diagnosticProperties.add(Pair.of("value", value)); + } + return value; + } + +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/ConsoleObj.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/ConsoleObj.java index 3570514..7bf7941 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/ConsoleObj.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/ConsoleObj.java @@ -11,12 +11,12 @@ public class ConsoleObj { public void log(Object... args) { List values = getConsoleWritable(args); - Log.get().withMessage("Script Log").withPayload(values.size() == 1 ? values.get(0) : values).log(); + Log.get().withMessage("Script Log").withPayload(values.size() == 1 ? values.getFirst() : values).log(); } public void error(Object... args) { List values = getConsoleWritable(args); - Log.get().withMessage("Script Log").withPayload(values.size() == 1 ? values.get(0) : values).logErr(); + Log.get().withMessage("Script Log").withPayload(values.size() == 1 ? values.getFirst() : values).logErr(); } private List getConsoleWritable(Object[] values) { diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/ReshaperObj.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/ReshaperObj.java index e9ff1d1..83dbf4e 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/ReshaperObj.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/ReshaperObj.java @@ -99,7 +99,7 @@ public void setGlobalListVariable(String name, Object[] values, String delimiter throw new IllegalArgumentException(String.format("Invalid variable name '%s'", name)); } ListVariable variable = (ListVariable) GlobalVariables.get().add(Variables.asKey(name, true)); - variable.setValues(values, delimiter); + variable.setValues(values, delimiter, SetListItemsPlacement.Overwrite); } public void setEventListVariable(String name, Object[] values, String delimiter) { @@ -107,7 +107,7 @@ public void setEventListVariable(String name, Object[] values, String delimiter) throw new IllegalArgumentException(String.format("Invalid variable name '%s'", name)); } ListVariable variable = (ListVariable) ((EventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo")).getVariables().add(Variables.asKey(name, true)); - variable.setValues(values, delimiter); + variable.setValues(values, delimiter, SetListItemsPlacement.Overwrite); } public void setSessionListVariable(String name, Object[] values, String delimiter) { @@ -115,7 +115,7 @@ public void setSessionListVariable(String name, Object[] values, String delimite throw new IllegalArgumentException(String.format("Invalid variable name '%s'", name)); } ListVariable variable = (ListVariable) ((EventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo")).getSessionVariables().add(Variables.asKey(name, true)); - variable.setValues(values, delimiter); + variable.setValues(values, delimiter, SetListItemsPlacement.Overwrite); } public void deleteGlobalVariable(String name) { @@ -187,25 +187,28 @@ public String runThen(String thenType, NativeObject thenData) { EventInfo eventInfo = (EventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo"); String adjustedThenTypeName = StringUtils.prependIfMissing(thenType, "Then"); Stream> supportedThenTypes = Stream.of( - ThenType.Highlight, - ThenType.Comment, - ThenType.Evaluate, ThenType.BuildHttpMessage, + ThenType.Comment, ThenType.DeleteValue, ThenType.DeleteVariable, ThenType.Drop, + ThenType.Evaluate, + ThenType.Extract, + ThenType.Generate, + ThenType.Highlight, ThenType.Intercept, ThenType.Log, ThenType.ParseHttpMessage, - ThenType.SendRequest, + ThenType.ReadFile, + ThenType.SaveFile, ThenType.SendMessage, + ThenType.SendRequest, ThenType.SendTo, - ThenType.SetEventDirection, ThenType.SetEncoding, + ThenType.SetEventDirection, ThenType.SetValue, ThenType.SetVariable, - ThenType.SaveFile, - ThenType.ReadFile + ThenType.Transform ); Class thenClass = supportedThenTypes .filter(type -> eventInfo.getProtocolType().accepts(ProtocolType.fromRuleOperationType(type.getType()))) diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/sendto/SendToOption.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/sendto/SendToOption.java index c185e02..c1448aa 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/sendto/SendToOption.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/sendto/SendToOption.java @@ -12,7 +12,7 @@ public enum SendToOption { Decoder, SiteMap("Site Map"); - private String name; + private final String name; SendToOption() { name = name(); diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/Base64Transformer.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/Base64Transformer.java new file mode 100644 index 0000000..71787fe --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/Base64Transformer.java @@ -0,0 +1,47 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.Encoder; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.utils.TextUtils; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.io.Serializable; +import java.nio.charset.StandardCharsets; +import java.util.List; + +@Setter +@Getter +public class Base64Transformer extends Transformer { + + private EncodeTransform action = EncodeTransform.Encode; + private Base64Variant variant = Base64Variant.Standard; + private VariableString encoding; + + @Override + public String transform(EventInfo eventInfo, List> diagnosticProperties) { + String input = this.input.getText(eventInfo); + String encodingValue = VariableString.getTextOrDefault(eventInfo, encoding, StandardCharsets.ISO_8859_1.displayName()); + Encoder encoder = new Encoder(encodingValue); + String value = switch (variant) { + case Standard -> switch (action) { + case Encode -> TextUtils.base64Encode(input, encoder); + case Decode -> TextUtils.base64Decode(input, encoder); + }; + case Url -> switch (action) { + case Encode -> TextUtils.base64UrlEncode(input, encoder); + case Decode -> TextUtils.base64UrlDecode(input, encoder); + }; + }; + if (diagnosticProperties != null) { + diagnosticProperties.add(Pair.of("action", action)); + diagnosticProperties.add(Pair.of("variant", variant)); + diagnosticProperties.add(Pair.of("input", input)); + diagnosticProperties.add(Pair.of("encoder", encoder.getEncoding())); + diagnosticProperties.add(Pair.of("value", value)); + } + return value; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/Base64Variant.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/Base64Variant.java new file mode 100644 index 0000000..8a81f1a --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/Base64Variant.java @@ -0,0 +1,23 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +@NoArgsConstructor +@AllArgsConstructor +public enum Base64Variant { + Standard, + Url("URL"); + + private String name; + + public String getName() { + return StringUtils.defaultString(name, name()); + } + + @Override + public String toString() { + return getName(); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/CaseTransformer.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/CaseTransformer.java new file mode 100644 index 0000000..8dc1a92 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/CaseTransformer.java @@ -0,0 +1,30 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.utils.PhraseCase; +import synfron.reshaper.burp.core.utils.TextUtils; + +import java.io.Serializable; +import java.util.List; + +@Setter +@Getter +public class CaseTransformer extends Transformer { + + private PhraseCase phraseCase = PhraseCase.UpperCase; + + @Override + public String transform(EventInfo eventInfo, List> diagnosticProperties) { + String input = this.input.getText(eventInfo); + String value = TextUtils.changeCase(input, phraseCase); + if (diagnosticProperties != null) { + diagnosticProperties.add(Pair.of("phraseCase", phraseCase)); + diagnosticProperties.add(Pair.of("input", input)); + diagnosticProperties.add(Pair.of("value", value)); + } + return value; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/EncodeTransform.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/EncodeTransform.java new file mode 100644 index 0000000..962f2af --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/EncodeTransform.java @@ -0,0 +1,6 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +public enum EncodeTransform { + Encode, + Decode +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/EntityType.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/EntityType.java new file mode 100644 index 0000000..dc2d174 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/EntityType.java @@ -0,0 +1,19 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public enum EntityType { + Html("HTML"), + Xml("XML"), + Json("JSON"), + Url("URL"); + + private final String name; + + + @Override + public String toString() { + return name; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/EscapeTransform.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/EscapeTransform.java new file mode 100644 index 0000000..78c7645 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/EscapeTransform.java @@ -0,0 +1,6 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +public enum EscapeTransform { + Escape, + Unescape +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/EscapeTransformer.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/EscapeTransformer.java new file mode 100644 index 0000000..251a8ad --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/EscapeTransformer.java @@ -0,0 +1,37 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.utils.TextUtils; +import synfron.reshaper.burp.core.utils.UrlUtils; + +import java.io.Serializable; +import java.util.List; + +@Setter +@Getter +public class EscapeTransformer extends Transformer { + + private EntityType entityType = EntityType.Html; + private EscapeTransform action = EscapeTransform.Escape; + + @Override + public String transform(EventInfo eventInfo, List> diagnosticProperties) { + String input = this.input.getText(eventInfo); + String value = switch (entityType) { + case Html -> action == EscapeTransform.Escape ? TextUtils.htmlEncode(input) : TextUtils.htmlDecode(input); + case Xml -> action == EscapeTransform.Escape ? TextUtils.xmlEncode(input) : TextUtils.xmlDecode(input); + case Json -> action == EscapeTransform.Escape ? TextUtils.jsonEscape(input) : TextUtils.jsonUnescape(input); + case Url -> action == EscapeTransform.Escape ? UrlUtils.urlEncode(input) : UrlUtils.urlDecode(input); + }; + if (diagnosticProperties != null) { + diagnosticProperties.add(Pair.of("input", input)); + diagnosticProperties.add(Pair.of("entityType", entityType)); + diagnosticProperties.add(Pair.of("action", action)); + diagnosticProperties.add(Pair.of("value", value)); + } + return value; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/HashTransformer.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/HashTransformer.java new file mode 100644 index 0000000..423eca0 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/HashTransformer.java @@ -0,0 +1,37 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.utils.PhraseCase; +import synfron.reshaper.burp.core.utils.TextUtils; + +import java.io.Serializable; +import java.util.List; + +@Setter +@Getter +public class HashTransformer extends Transformer { + + private HashType hashType = HashType.Sha1; + + @Override + public String transform(EventInfo eventInfo, List> diagnosticProperties) { + String input = this.input.getText(eventInfo); + String value = switch (hashType) { + case Sha1 -> TextUtils.sha1(input); + case Sha256 -> TextUtils.sha256(input); + case Sha512 -> TextUtils.sha512(input); + case Sha256V3 -> TextUtils.sha256V3(input); + case Sha512V3 -> TextUtils.sha512V3(input); + case Md5 -> TextUtils.md5(input); + }; + if (diagnosticProperties != null) { + diagnosticProperties.add(Pair.of("hashType", hashType)); + diagnosticProperties.add(Pair.of("input", input)); + diagnosticProperties.add(Pair.of("value", value)); + } + return value; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/HashType.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/HashType.java new file mode 100644 index 0000000..ca68160 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/HashType.java @@ -0,0 +1,21 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +public enum HashType { + Sha1("SHA-1"), + Sha256("SHA-256"), + Sha512("SHA-512"), + Sha256V3("SHA3-256"), + Sha512V3("SHA3-512"), + Md5("MD5"); + + HashType(String name) { + this.name = name; + } + + private final String name; + + @Override + public String toString() { + return name; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/HexTransformer.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/HexTransformer.java new file mode 100644 index 0000000..32dae20 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/HexTransformer.java @@ -0,0 +1,40 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.Encoder; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.utils.TextUtils; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.io.Serializable; +import java.nio.charset.StandardCharsets; +import java.util.HexFormat; +import java.util.List; + +@Setter +@Getter +public class HexTransformer extends Transformer { + + private TextTransform action = TextTransform.FromText; + private VariableString encoding; + + @Override + public String transform(EventInfo eventInfo, List> diagnosticProperties) { + String input = this.input.getText(eventInfo); + String encodingValue = VariableString.getTextOrDefault(eventInfo, encoding, StandardCharsets.ISO_8859_1.displayName()); + Encoder encoder = new Encoder(encodingValue); + String value = switch (action) { + case FromText -> TextUtils.toHex(input, encoder); + case ToText -> TextUtils.fromHex(input, encoder); + }; + if (diagnosticProperties != null) { + diagnosticProperties.add(Pair.of("action", action)); + diagnosticProperties.add(Pair.of("input", input)); + diagnosticProperties.add(Pair.of("encoder", encoder.getEncoding())); + diagnosticProperties.add(Pair.of("value", value)); + } + return value; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/ITransformer.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/ITransformer.java new file mode 100644 index 0000000..cdac457 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/ITransformer.java @@ -0,0 +1,30 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.thens.entities.generate.*; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.io.Serializable; +import java.util.List; + +@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, property = "@class") +@JsonSubTypes({ + @JsonSubTypes.Type(value = Base64Transformer.class), + @JsonSubTypes.Type(value = CaseTransformer.class), + @JsonSubTypes.Type(value = EscapeTransform.class), + @JsonSubTypes.Type(value = HashTransformer.class), + @JsonSubTypes.Type(value = HexTransformer.class), + @JsonSubTypes.Type(value = IntegerGenerator.class), + @JsonSubTypes.Type(value = JwtDecodeTransformer.class), + @JsonSubTypes.Type(value = TrimTransformer.class) +}) +public interface ITransformer { + String transform(EventInfo eventInfo, List> diagnosticProperties); + + VariableString getInput(); + + void setInput(VariableString input); +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/IntegerTransformer.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/IntegerTransformer.java new file mode 100644 index 0000000..0eb2aa3 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/IntegerTransformer.java @@ -0,0 +1,34 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.utils.TextUtils; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.io.Serializable; +import java.util.List; + +@Setter +@Getter +public class IntegerTransformer extends Transformer { + + private VariableString sourceBase; + private VariableString targetBase; + + @Override + public String transform(EventInfo eventInfo, List> diagnosticProperties) { + String input = this.input.getText(eventInfo); + int sourceBase = VariableString.getIntOrDefault(eventInfo, this.sourceBase, 10); + int targetBase = VariableString.getIntOrDefault(eventInfo, this.targetBase, 10); + String value = TextUtils.changeBase(input, sourceBase, targetBase); + if (diagnosticProperties != null) { + diagnosticProperties.add(Pair.of("sourceBase", sourceBase)); + diagnosticProperties.add(Pair.of("targetBase", targetBase)); + diagnosticProperties.add(Pair.of("input", input)); + diagnosticProperties.add(Pair.of("value", value)); + } + return value; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/JwtDecodeTransformer.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/JwtDecodeTransformer.java new file mode 100644 index 0000000..66874ba --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/JwtDecodeTransformer.java @@ -0,0 +1,37 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +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.Encoder; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.utils.CollectionUtils; +import synfron.reshaper.burp.core.utils.TextUtils; + +import java.io.Serializable; +import java.nio.charset.StandardCharsets; +import java.util.List; + +@Setter +@Getter +public class JwtDecodeTransformer extends Transformer { + + private JwtSegment segment = JwtSegment.Header; + + @Override + public String transform(EventInfo eventInfo, List> diagnosticProperties) { + String input = this.input.getText(eventInfo); + String value = StringUtils.isNotEmpty(input) ? switch (segment) { + case Header -> TextUtils.base64UrlDecode(input.split("\\.", 3)[0], new Encoder(StandardCharsets.UTF_8.displayName())); + case Payload -> TextUtils.base64UrlDecode(CollectionUtils.elementAtOrDefault(input.split("\\.", 3), 1), new Encoder(StandardCharsets.UTF_8.displayName())); + case Signature -> TextUtils.base64UrlDecode(CollectionUtils.elementAtOrDefault(input.split("\\.", 3), 2), new Encoder(StandardCharsets.ISO_8859_1.displayName())); + } : ""; + if (diagnosticProperties != null) { + diagnosticProperties.add(Pair.of("segment", segment)); + diagnosticProperties.add(Pair.of("input", input)); + diagnosticProperties.add(Pair.of("value", value)); + } + return value; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/JwtSegment.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/JwtSegment.java new file mode 100644 index 0000000..6ee9fdd --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/JwtSegment.java @@ -0,0 +1,9 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +import java.security.Signature; + +public enum JwtSegment { + Header, + Payload, + Signature +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/TextTransform.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/TextTransform.java new file mode 100644 index 0000000..30a3a77 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/TextTransform.java @@ -0,0 +1,17 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +public enum TextTransform { + FromText("From Text"), + ToText("To Text"); + + TextTransform(String name) { + this.name = name; + } + + private final String name; + + @Override + public String toString() { + return name; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/TransformOption.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/TransformOption.java new file mode 100644 index 0000000..9b0723d --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/TransformOption.java @@ -0,0 +1,33 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +@Getter +@RequiredArgsConstructor +@AllArgsConstructor +public enum TransformOption { + Base64(Base64Transformer.class), + Escape(EscapeTransformer.class), + JwtDecode("JWT Decode", JwtDecodeTransformer.class), + Case(CaseTransformer.class), + Hash(HashTransformer.class), + Hex(HexTransformer.class), + Integer(IntegerTransformer.class), + Trim(TrimTransformer.class); + + private String name; + + private final Class transformerClass; + + public String getName() { + return StringUtils.defaultString(name, name()); + } + + @Override + public String toString() { + return getName(); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/Transformer.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/Transformer.java new file mode 100644 index 0000000..5599a6e --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/Transformer.java @@ -0,0 +1,18 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.io.Serializable; +import java.util.List; + +@Setter +@Getter +public abstract class Transformer implements ITransformer { + public VariableString input; + + public abstract String transform(EventInfo eventInfo, List> diagnosticProperties); +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/TrimOption.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/TrimOption.java new file mode 100644 index 0000000..16427d7 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/TrimOption.java @@ -0,0 +1,24 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +@NoArgsConstructor +@AllArgsConstructor +public enum TrimOption { + Start, + End, + StartAndEnd("Start And End"); + + private String name; + + public String getName() { + return StringUtils.defaultString(name, name()); + } + + @Override + public String toString() { + return getName(); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/TrimTransformer.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/TrimTransformer.java new file mode 100644 index 0000000..06b332d --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/transform/TrimTransformer.java @@ -0,0 +1,38 @@ +package synfron.reshaper.burp.core.rules.thens.entities.transform; + +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.EventInfo; +import synfron.reshaper.burp.core.utils.TextUtils; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.io.Serializable; +import java.util.List; + +@Setter +@Getter +public class TrimTransformer extends Transformer { + + private TrimOption trimOption = TrimOption.StartAndEnd; + private VariableString characters; + + @Override + public String transform(EventInfo eventInfo, List> diagnosticProperties) { + String input = this.input.getText(eventInfo); + String characters = VariableString.getTextOrDefault(eventInfo, this.characters, null); + String value = switch (trimOption) { + case Start -> StringUtils.stripStart(input, characters); + case End -> StringUtils.stripEnd(input, characters); + case StartAndEnd -> StringUtils.strip(input, characters); + }; + if (diagnosticProperties != null) { + diagnosticProperties.add(Pair.of("trimOption", trimOption)); + diagnosticProperties.add(Pair.of("input", input)); + diagnosticProperties.add(Pair.of("characters", characters)); + diagnosticProperties.add(Pair.of("value", value)); + } + return value; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenMatchesText.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenMatchesText.java index 7d0a9cb..608c27a 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenMatchesText.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenMatchesText.java @@ -65,6 +65,10 @@ public boolean isMatch(EventInfo eventInfo) { case Contains -> ignoreCase ? StringUtils.containsIgnoreCase(sourceText, matchText) : StringUtils.contains(sourceText, matchText); case Equals -> ignoreCase ? StringUtils.equalsIgnoreCase(sourceText, matchText) : StringUtils.equals(sourceText, matchText); case Regex -> TextUtils.isMatch(sourceText, matchText, ignoreCase); + case LessThan -> TextUtils.lessThan(sourceText, matchText); + case GreaterThan -> TextUtils.greaterThan(sourceText, matchText); + case LessThanOrEqual -> TextUtils.lessThan(sourceText, matchText) || TextUtils.textOrNumberEquals(sourceText, matchText, ignoreCase); + case GreaterThanOrEqual -> TextUtils.greaterThan(sourceText, matchText) || TextUtils.textOrNumberEquals(sourceText, matchText, ignoreCase); }; } catch (Exception ignored) { } @@ -83,8 +87,8 @@ private String getPathValue(String value, EventInfo eventInfo) { if (messageValueType != MessageValueType.Text && messageValuePath != null) { switch (messageValueType) { - case Json -> value = TextUtils.getJsonValue(value, messageValuePath.getText(eventInfo)); - case Html -> value = TextUtils.getHtmlValue(value, messageValuePath.getText(eventInfo)); + case Json -> value = TextUtils.getJsonPathValue(value, messageValuePath.getText(eventInfo)); + case Html -> value = TextUtils.getCssSelectorValue(value, messageValuePath.getText(eventInfo)); case Params -> value = TextUtils.getParamValue(value, messageValuePath.getText(eventInfo)); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenRepeat.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenRepeat.java index 61100af..153ddd4 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenRepeat.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenRepeat.java @@ -42,11 +42,11 @@ public boolean isMatch(List> whensSubList, EventInfo eventInfo try { listVariableNameText = listVariableName.getText(eventInfo); entryVariableNameText = entryVariableName.getText(eventInfo); - VariableSourceEntry variable1 = new VariableSourceEntry(listVariableSource, listVariableNameText); + VariableSourceEntry variable1 = new VariableSourceEntry(listVariableSource, List.of(listVariableNameText)); ListVariable variable = switch (variable1.getVariableSource()) { - case GlobalList -> (ListVariable) GlobalVariables.get().getOrDefault(Variables.asKey(variable1.getName(), true)); - case EventList -> (ListVariable) eventInfo.getVariables().getOrDefault(Variables.asKey(variable1.getName(), true)); - case SessionList -> (ListVariable) eventInfo.getSessionVariables().getOrDefault(Variables.asKey(variable1.getName(), true)); + case GlobalList -> (ListVariable) GlobalVariables.get().getOrDefault(Variables.asKey(variable1.getParams().getFirst(), true)); + case EventList -> (ListVariable) eventInfo.getVariables().getOrDefault(Variables.asKey(variable1.getParams().getFirst(), true)); + case SessionList -> (ListVariable) eventInfo.getSessionVariables().getOrDefault(Variables.asKey(variable1.getParams().getFirst(), true)); default -> null; }; @@ -81,11 +81,11 @@ public boolean isMatch(List> whensSubList, EventInfo eventInfo finally { if (eventInfo.getDiagnostics().isEnabled()) { eventInfo.getDiagnostics().logProperties(this, isMatch, Arrays.asList( - Pair.of("listVariable", VariableSourceEntry.getTag(listVariableSource, listVariableNameText)), + Pair.of("listVariable", VariableTag.getTag(listVariableSource, listVariableNameText)), Pair.of("listSize", listSize != null ? listSize.toString() : "null"), Pair.of("subGroupCount", subGroupCount), Pair.of("successCriteria", successCriteria), - Pair.of("entryVariable", VariableSourceEntry.getTag(VariableSource.Event, entryVariableNameText)) + Pair.of("entryVariable", VariableTag.getTag(VariableSource.Event, entryVariableNameText)) )); if (diagnosticsPosition != -1) { eventInfo.getDiagnostics().moveLast(diagnosticsPosition); diff --git a/extension/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenType.java b/extension/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenType.java index 3e718a7..711279f 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenType.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenType.java @@ -38,7 +38,8 @@ public static List> getTypes() { MessageType, ProxyName, FromTool, - InScope + InScope, + Repeat ); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/settings/GeneralSettings.java b/extension/src/main/java/synfron/reshaper/burp/core/settings/GeneralSettings.java index 1eeb453..efd736f 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/settings/GeneralSettings.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/settings/GeneralSettings.java @@ -1,9 +1,17 @@ package synfron.reshaper.burp.core.settings; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; +import lombok.Getter; import synfron.reshaper.burp.core.BurpTool; +import synfron.reshaper.burp.core.Tab; +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.messages.Encoder; +import java.util.HashSet; + @Data public class GeneralSettings { private boolean captureProxy = true; @@ -24,6 +32,13 @@ public class GeneralSettings { private String importUrl; private String lastExportPath; private String lastExportFileName = "ReshaperBackup.json"; + private HashSet hiddenThenTypes = new HashSet<>(); + private HashSet hiddenWhenTypes = new HashSet<>(); + private HashSet hiddenTabs = new HashSet<>(); + + @Getter @JsonIgnore + private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); + public void importSettings(GeneralSettings other) { if (other != null) { @@ -44,6 +59,9 @@ public void importSettings(GeneralSettings other) { this.importUrl = other.importUrl; this.lastExportPath = other.lastExportPath; this.lastExportFileName = other.lastExportFileName; + this.hiddenThenTypes = other.hiddenThenTypes; + this.hiddenWhenTypes = other.hiddenWhenTypes; + this.hiddenTabs = other.hiddenTabs; } } @@ -60,6 +78,120 @@ public boolean isCapture(BurpTool burpTool) { }; } + private void propertyChanged(String name, Object value) { + propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); + } + + public void setLogInExtenderOutput(boolean logInExtenderOutput) { + this.logInExtenderOutput = logInExtenderOutput; + propertyChanged("logInExtenderOutput", logInExtenderOutput); + } + + public void setCaptureProxy(boolean captureProxy) { + this.captureProxy = captureProxy; + propertyChanged("captureProxy", captureProxy); + } + + public void setCaptureTarget(boolean captureTarget) { + this.captureTarget = captureTarget; + propertyChanged("captureTarget", captureTarget); + } + + public void setCaptureScanner(boolean captureScanner) { + this.captureScanner = captureScanner; + propertyChanged("captureScanner", captureScanner); + } + + public void setCaptureRepeater(boolean captureRepeater) { + this.captureRepeater = captureRepeater; + propertyChanged("captureRepeater", captureRepeater); + } + + public void setCaptureIntruder(boolean captureIntruder) { + this.captureIntruder = captureIntruder; + propertyChanged("captureIntruder", captureIntruder); + } + + public void setCaptureExtender(boolean captureExtender) { + this.captureExtender = captureExtender; + propertyChanged("captureExtender", captureExtender); + } + + public void setCaptureWebSockets(boolean captureWebSockets) { + this.captureWebSockets = captureWebSockets; + propertyChanged("captureWebSockets", captureWebSockets); + } + + public void setEnableEventDiagnostics(boolean enableEventDiagnostics) { + this.enableEventDiagnostics = enableEventDiagnostics; + propertyChanged("enableEventDiagnostics", enableEventDiagnostics); + } + + public void setDiagnosticValueMaxLength(int diagnosticValueMaxLength) { + this.diagnosticValueMaxLength = diagnosticValueMaxLength; + propertyChanged("diagnosticValueMaxLength", diagnosticValueMaxLength); + } + + public void setEnableSanityCheckWarnings(boolean enableSanityCheckWarnings) { + this.enableSanityCheckWarnings = enableSanityCheckWarnings; + propertyChanged("enableSanityCheckWarnings", enableSanityCheckWarnings); + } + + public void setLogTabCharacterLimit(int logTabCharacterLimit) { + this.logTabCharacterLimit = logTabCharacterLimit; + propertyChanged("logTabCharacterLimit", logTabCharacterLimit); + } + + public void setDefaultEncoding(String defaultEncoding) { + this.defaultEncoding = defaultEncoding; + propertyChanged("defaultEncoding", defaultEncoding); + } + + public void setImportMethod(ImportMethod importMethod) { + this.importMethod = importMethod; + propertyChanged("importMethod", importMethod); + } + + public void setExportMethod(ExportMethod exportMethod) { + this.exportMethod = exportMethod; + propertyChanged("exportMethod", exportMethod); + } + + public void setImportUrl(String importUrl) { + this.importUrl = importUrl; + propertyChanged("importUrl", importUrl); + } + + public void setLastExportPath(String lastExportPath) { + this.lastExportPath = lastExportPath; + propertyChanged("lastExportPath", lastExportPath); + } + + public void setLastExportFileName(String lastExportFileName) { + this.lastExportFileName = lastExportFileName; + propertyChanged("lastExportFileName", lastExportFileName); + } + + public void setHiddenThenTypes(HashSet hiddenThenTypes) { + this.hiddenThenTypes = hiddenThenTypes; + propertyChanged("hiddenThenTypes", hiddenThenTypes); + } + + public void setHiddenWhenTypes(HashSet hiddenWhenTypes) { + this.hiddenWhenTypes = hiddenWhenTypes; + propertyChanged("hiddenWhenTypes", hiddenWhenTypes); + } + + public void setHiddenTabs(HashSet hiddenTabs) { + this.hiddenTabs = hiddenTabs; + propertyChanged("hiddenTabs", hiddenTabs); + } + + public GeneralSettings withListener(IEventListener listener) { + propertyChangedEvent.add(listener); + return this; + } + public enum ImportMethod { File, Url diff --git a/extension/src/main/java/synfron/reshaper/burp/core/utils/CollectionUtils.java b/extension/src/main/java/synfron/reshaper/burp/core/utils/CollectionUtils.java index e64cdcf..38a31e7 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/utils/CollectionUtils.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/utils/CollectionUtils.java @@ -87,6 +87,10 @@ public static byte[] defaultIfEmpty(byte[] array, byte[] defaultArray) { return (array != null && array.length > 0) ? array : defaultArray; } + public static List defaultIfEmpty(List list, List defaultList) { + return (list != null && !list.isEmpty()) ? list : defaultList; + } + public static List defaultIfNull(List list) { return list != null ? list : List.of(); } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/utils/CustomProbabilityRandomizer.java b/extension/src/main/java/synfron/reshaper/burp/core/utils/CustomProbabilityRandomizer.java new file mode 100644 index 0000000..4965106 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/utils/CustomProbabilityRandomizer.java @@ -0,0 +1,38 @@ +package synfron.reshaper.burp.core.utils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Random; + +public class CustomProbabilityRandomizer { + private final List values; + private final List progressiveSums; + private final int sum; + private final Random random; + + public CustomProbabilityRandomizer(Random random, Map probabilityMap) { + this.random = random; + values = new ArrayList<>(probabilityMap.size()); + progressiveSums = new ArrayList<>(probabilityMap.size()); + int sum = 0; + for (Map.Entry entry : probabilityMap.entrySet()) { + int probability = entry.getValue(); + values.add(entry.getKey()); + sum += probability; + progressiveSums.add(sum); + } + this.sum = sum; + } + + public T next() { + int randValue = random.nextInt(0, sum); + for (int i = 0; i + 1 < progressiveSums.size(); i++) { + if (randValue < progressiveSums.get(i)) { + return values.get(i); + } + } + return values.get(values.size() - 1); + } + +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/utils/ListMap.java b/extension/src/main/java/synfron/reshaper/burp/core/utils/ListMap.java index f47aa66..c87ded0 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/utils/ListMap.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/utils/ListMap.java @@ -78,7 +78,7 @@ public void computeFirstWhereOrAdd(K key, Predicate predicate, Function if (values.isEmpty()) { values.add(createNode(key, compute.apply(null))); } else { - OrderedNode node = values.get(0); + OrderedNode node = values.getFirst(); V value = node.getValue(); V newValue = compute.apply(value); if (value != newValue) { @@ -92,7 +92,7 @@ public V getFirstWhere(K key, Predicate predicate) { .filter(node -> predicate.test(node.getValue())) .toList(); if (!values.isEmpty()) { - OrderedNode node = values.get(0); + OrderedNode node = values.getFirst(); return node.getValue(); } return null; @@ -124,7 +124,7 @@ public void computeOnlyWhereOrAdd(K key, Predicate predicate, Function } else { List nodesToRemove = CollectionUtils.subList(values, 1, values.size() - 1); backingMap.get(key).removeAll(nodesToRemove); - OrderedNode node = values.get(0); + OrderedNode node = values.getFirst(); V value = node.getValue(); V newValue = compute.apply(value); if (value != newValue) { @@ -150,7 +150,7 @@ public void setFirstOrAdd(K key, V value) { if (values.isEmpty()) { values.add(createNode(key, value)); } else { - values.get(0).set(key, value); + values.getFirst().set(key, value); } } @@ -160,7 +160,7 @@ public void setOnly(K key, V value) { if (values.isEmpty()) { node = createNode(key, value); } else { - node = values.get(0); + node = values.getFirst(); node.set(key, value); nodeCount -= values.size(); values.clear(); @@ -186,7 +186,7 @@ public void setOrAdd(K key, V value, SetItemPlacement itemPlacement) { public V getFirst(K key) { List nodes = backingMap.get(key); - return CollectionUtils.hasAny(nodes) ? nodes.get(0).getValue() : null; + return CollectionUtils.hasAny(nodes) ? nodes.getFirst().getValue() : null; } public V getLast(K key) { @@ -266,8 +266,8 @@ public void removeFirstWhere(K key, Predicate predicate) { List removeNodes = nodes.stream().filter(node -> predicate.test(node.getValue())).toList(); if (!removeNodes.isEmpty()) { nodeCount -= 1; - nodes.remove(removeNodes.get(0)); - if (nodes.size() == 0) { + nodes.remove(removeNodes.getFirst()); + if (nodes.isEmpty()) { backingMap.remove(key); } } @@ -293,7 +293,7 @@ public void removeLastWhere(K key, Predicate predicate) { if (!removeNodes.isEmpty()) { nodeCount -= 1; nodes.remove(removeNodes.get(removeNodes.size() - 1)); - if (nodes.size() == 0) { + if (nodes.isEmpty()) { backingMap.remove(key); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/utils/PasswordCharacterGroup.java b/extension/src/main/java/synfron/reshaper/burp/core/utils/PasswordCharacterGroup.java new file mode 100644 index 0000000..55fa1aa --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/utils/PasswordCharacterGroup.java @@ -0,0 +1,28 @@ +package synfron.reshaper.burp.core.utils; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +@Getter +@AllArgsConstructor +@RequiredArgsConstructor +public enum PasswordCharacterGroup { + LowercaseLetters("Lowercase Letters", "abcdefghijklmnopqrstuvwxyz"), + UppercaseLetters("Uppercase Letters", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"), + Numbers("1234567890"), + Symbols("}<[{~;)-=%(|/,:!*>&_\\@#$+].?^`\"'"); + + private String name; + private final String characters; + + public String getName() { + return StringUtils.defaultString(name, name()); + } + + @Override + public String toString() { + return getName(); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/utils/PhraseCase.java b/extension/src/main/java/synfron/reshaper/burp/core/utils/PhraseCase.java new file mode 100644 index 0000000..dd4bce2 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/utils/PhraseCase.java @@ -0,0 +1,28 @@ +package synfron.reshaper.burp.core.utils; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public enum PhraseCase { + LowerCase("lower case"), + UpperCase("UPPER CASE"), + FlatCase("flatcase"), + CamelCase("camelCase"), + PascalCase("PascalCase"), + SnakeCase("snake_case"), + ConstantCase("CONSTANT_CASE"), + DashCase("dash-case"), + CobolCase("COBOL-CASE"), + TitleCase("Title Case"), + SentenceCase("Sentence case"); + + private final String name; + + + @Override + public String toString() { + return name; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/utils/Serializer.java b/extension/src/main/java/synfron/reshaper/burp/core/utils/Serializer.java index 3169b49..32d1270 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/utils/Serializer.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/utils/Serializer.java @@ -7,7 +7,6 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonTokenId; -import com.fasterxml.jackson.core.json.JsonWriteFeature; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.json.JsonMapper; @@ -25,7 +24,7 @@ public class Serializer { @Getter private static ObjectMapper objectMapper; - private static JsonFactory jsonFactory = new JsonFactory(); + private static final JsonFactory jsonFactory = new JsonFactory(); static { VariableStringSerializer variableStringSerializer = new VariableStringSerializer(); @@ -64,7 +63,7 @@ private static ObjectMapper configureMapper(JsonSerializer[] serializers, Jso builder.visibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE); builder.visibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE); builder.visibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE); - builder.visibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.NONE); + builder.visibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.ANY); if (serializers.length > 0 || deserializers.length > 0) { SimpleModule module = new SimpleModule(); Stream.of(serializers).forEach(module::addSerializer); diff --git a/extension/src/main/java/synfron/reshaper/burp/core/utils/TextUtils.java b/extension/src/main/java/synfron/reshaper/burp/core/utils/TextUtils.java index 1678bbd..0f7502e 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/utils/TextUtils.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/utils/TextUtils.java @@ -1,22 +1,37 @@ package synfron.reshaper.burp.core.utils; +import burp.BurpExtender; +import burp.api.montoya.core.ByteArray; +import burp.api.montoya.utilities.DigestAlgorithm; import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.Option; import com.jayway.jsonpath.ParseContext; +import net.minidev.json.JSONArray; import net.minidev.json.JSONValue; +import org.apache.commons.codec.binary.Hex; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.StringEscapeUtils; import org.apache.http.NameValuePair; import org.apache.http.client.utils.URLEncodedUtils; import org.apache.http.message.BasicNameValuePair; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.nodes.Node; import org.jsoup.select.Elements; +import synfron.reshaper.burp.core.messages.Encoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Base64; +import java.util.HexFormat; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.MatchResult; +import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; public class TextUtils { @@ -29,15 +44,15 @@ private static ParseContext getJsonPathContext() { return jsonPathContext; } - public static String getJsonValue(String text, String jsonPath) { + public static String getJsonPathValue(String text, String jsonPath) { return stripQuotes(JSONValue.toJSONString(getJsonPathContext().parse(text).read(jsonPath))); } - public static String setJsonValue(String text, String jsonPath, String value) { + public static String setJsonPathValue(String text, String jsonPath, String value) { return stripQuotes(getJsonPathContext().parse(text).set(jsonPath, JSONValue.parse(value)).jsonString()); } - private static String stripQuotes(String text) { + public static String stripQuotes(String text) { if (text.startsWith("\"") && text.endsWith("\"")) { text = StringUtils.removeStart(text, "\""); text = StringUtils.removeEnd(text, "\""); @@ -45,17 +60,61 @@ private static String stripQuotes(String text) { return text; } - public static String getHtmlValue(String text, String selector) { + public static String getCssSelectorValue(String text, String selector) { Document doc = Jsoup.parse(text); + boolean hasInnerHTML = selector.endsWith("::innerHTML"); + selector = hasInnerHTML ? StringUtils.removeEnd(selector, "::innerHTML") : selector; Elements elements = doc.select(selector); - return elements.toString(); + if (hasInnerHTML) { + return elements.html(); + } else { + return elements.toString(); + } } - public static String setHtmlValue(String text, String selector, String value) { + public static List getJsonPathValues(String text, String jsonPath) { + Object value = getJsonPathContext().parse(text).read(jsonPath); + if (value instanceof JSONArray array) { + return array.stream().map(item -> stripQuotes(JSONValue.toJSONString(item))).toList(); + } + return List.of(stripQuotes(JSONValue.toJSONString(value))); + } + + public static List getCssSelectorValues(String text, String selector) { Document doc = Jsoup.parse(text); + boolean hasInnerHTML = selector.endsWith("::innerHTML"); + selector = hasInnerHTML ? StringUtils.removeEnd(selector, "::innerHTML") : selector; Elements elements = doc.select(selector); - elements.before(value); - elements.remove(); + if (hasInnerHTML) { + return elements.stream().map(Element::html).toList(); + } else { + return elements.stream().map(Element::toString).toList(); + } + } + + public static List getXPathValues(String text, String xpath) { + Document doc = Jsoup.parse(text); + List nodes = doc.selectXpath(xpath, Node.class); + return nodes.stream().map(Node::toString).toList(); + } + + public static List getRegexValues(String text, String regex) { + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(text); + return matcher.results().map(MatchResult::group).toList(); + } + + public static String setCssSelectorValue(String text, String selector, String value) { + Document doc = Jsoup.parse(text); + boolean hasInnerHTML = selector.endsWith("::innerHTML"); + selector = hasInnerHTML ? StringUtils.removeEnd(selector, "::innerHTML") : selector; + Elements elements = doc.select(selector); + if (hasInnerHTML) { + elements.html(value); + } else { + elements.before(value); + elements.remove(); + } return doc.toString(); } @@ -110,6 +169,25 @@ public static Integer asInt(String text) { return nullableValue; } + public static Long asLong(String text) { + Long nullableValue = null; + try { + nullableValue = Long.parseLong(text); + } catch (NumberFormatException ignored) { + + } + return nullableValue; + } + + public static boolean isLong(String text) { + try { + Long.parseLong(text); + return true; + } catch (NumberFormatException e) { + return false; + } + } + public static boolean isDouble(String text) { try { Double.parseDouble(text); @@ -167,4 +245,210 @@ public static String parseSpecialChars(String text) { } return stringBuilder.toString(); } + + public static List getChunks(String text, int size) { + List chunks = new ArrayList<>(); + for (int startIndex = 0; startIndex < text.length(); startIndex += size) { + chunks.add(text.substring(startIndex, Math.min(startIndex + size, text.length()))); + } + return chunks; + } + + public static String changeCase(String text, PhraseCase phraseCase) { + return switch (phraseCase) { + case LowerCase -> text.toLowerCase(); + case UpperCase -> text.toUpperCase(); + case FlatCase -> splitPhrases(text).stream().map(token -> token.toString().toLowerCase()).collect(Collectors.joining()); + case PascalCase -> splitPhrases(text).stream().map(token -> uppercaseFirst(token.toString().toLowerCase())).collect(Collectors.joining()); + case CamelCase -> { + AtomicBoolean isFirst = new AtomicBoolean(true); + yield splitPhrases(text).stream().map(token -> { + if (!isFirst.get()) { + return uppercaseFirst(token.toString().toLowerCase()); + } else { + isFirst.set(false); + } + return token.toString().toLowerCase(); + }).collect(Collectors.joining()); + } + case SnakeCase -> splitPhrases(text).stream().map(token -> token.toString().toLowerCase()).collect(Collectors.joining("_")); + case ConstantCase -> splitPhrases(text).stream().map(token -> token.toString().toUpperCase()).collect(Collectors.joining("_")); + case DashCase -> splitPhrases(text).stream().map(token -> token.toString().toLowerCase()).collect(Collectors.joining("-")); + case CobolCase -> splitPhrases(text).stream().map(token -> token.toString().toUpperCase()).collect(Collectors.joining("-")); + case TitleCase -> splitPhrases(text).stream().map(token -> uppercaseFirst(token.toString().toLowerCase())).collect(Collectors.joining(" ")); + case SentenceCase -> uppercaseFirst(splitPhrases(text).stream().map(token -> token.toString().toLowerCase()).collect(Collectors.joining(" "))); + }; + } + + private static List splitPhrases(String text) { + if (text.isEmpty()) { + return List.of(new StringBuilder()); + } + char character = text.charAt(0); + StringBuilder lastToken = new StringBuilder(); + lastToken.append(character); + boolean isLastUppercase = Character.isUpperCase(character); + boolean isLastDigit = Character.isDigit(character); + boolean isLastLetter = Character.isLetter(character); + boolean newToken = true; + List tokens = new ArrayList<>(); + tokens.add(lastToken); + for (int i = 1; i < text.length(); i++) { + character = text.charAt(i); + if (Character.isLetter(character)) { + boolean isCurrentUppercase = Character.isUpperCase(character); + if (!isLastLetter) { + newToken = true; + lastToken = new StringBuilder(); + lastToken.append(character); + tokens.add(lastToken); + } else if (isLastUppercase == isCurrentUppercase) { + lastToken.append(character); + newToken = false; + } else { + if (newToken) { + lastToken.append(character); + newToken = false; + } else { + newToken = true; + lastToken = new StringBuilder(); + lastToken.append(character); + tokens.add(lastToken); + } + } + isLastUppercase = isCurrentUppercase; + isLastLetter = true; + isLastDigit = false; + } else if (Character.isDigit(character)) { + if (isLastDigit) { + lastToken.append(character); + newToken = false; + } else { + newToken = true; + lastToken = new StringBuilder(); + lastToken.append(character); + tokens.add(lastToken); + } + isLastLetter = false; + isLastDigit = true; + } else { + isLastLetter = false; + isLastDigit = false; + } + } + return tokens; + } + + private static String uppercaseFirst(String text) { + if (text.isEmpty()) { + return text; + } else if (text.length() == 1) { + return text.toUpperCase(); + } else { + return Character.toUpperCase(text.charAt(0)) + text.substring(1); + } + } + + public static String base64Decode(String value, Encoder encoder) { + return encoder.decode(Base64.getDecoder().decode(value)); + } + + public static String base64Encode(String value, Encoder encoder) { + return Base64.getEncoder().encodeToString(encoder.encode(value)); + } + + public static String base64UrlDecode(String value, Encoder encoder) { + return encoder.decode(Base64.getUrlDecoder().decode(value)); + } + + public static String base64UrlEncode(String value, Encoder encoder) { + return Base64.getUrlEncoder().encodeToString(encoder.encode(value)); + } + + public static String toHex(String value, Encoder encoder) { + return HexFormat.of().formatHex(encoder.encode(value)); + } + + public static String fromHex(String value, Encoder encoder) { + return encoder.decode(HexFormat.of().parseHex(value)); + } + + public static String htmlEncode(String value) { + return BurpExtender.getApi().utilities().htmlUtils().encode(value); + } + + public static String htmlDecode(String value) { + return BurpExtender.getApi().utilities().htmlUtils().decode(value); + } + + public static String xmlEncode(String value) { + return StringEscapeUtils.escapeXml11(value); + } + + public static String xmlDecode(String value) { + return StringEscapeUtils.unescapeXml(value); + } + + public static String jsonEscape(String value) { + return StringEscapeUtils.escapeJson(value); + } + + public static String jsonUnescape(String value) { + return StringEscapeUtils.unescapeJson(value); + } + + public static String sha1(String value) { + return Hex.encodeHexString(BurpExtender.getApi().utilities().cryptoUtils().generateDigest(ByteArray.byteArray(value), DigestAlgorithm.SHA_1).getBytes()); + } + + public static String sha256(String value) { + return Hex.encodeHexString(BurpExtender.getApi().utilities().cryptoUtils().generateDigest(ByteArray.byteArray(value), DigestAlgorithm.SHA_256).getBytes()); + } + + public static String sha512(String value) { + return Hex.encodeHexString(BurpExtender.getApi().utilities().cryptoUtils().generateDigest(ByteArray.byteArray(value), DigestAlgorithm.SHA_512).getBytes()); + } + + public static String sha256V3(String value) { + return Hex.encodeHexString(BurpExtender.getApi().utilities().cryptoUtils().generateDigest(ByteArray.byteArray(value), DigestAlgorithm.SHA3_256).getBytes()); + } + + public static String sha512V3(String value) { + return Hex.encodeHexString(BurpExtender.getApi().utilities().cryptoUtils().generateDigest(ByteArray.byteArray(value), DigestAlgorithm.SHA3_512).getBytes()); + } + + public static String md5(String value) { + return Hex.encodeHexString(BurpExtender.getApi().utilities().cryptoUtils().generateDigest(ByteArray.byteArray(value), DigestAlgorithm.MD5).getBytes()); + } + + public static String changeBase(String value, int sourceBase, int targetBase) { + return Long.toString(Long.parseLong(value, sourceBase), targetBase); + } + + public static boolean textOrNumberEquals(String item1, String item2, boolean ignoreCase) { + if (TextUtils.isLong(item1) && TextUtils.isLong(item2)) { + return Long.parseLong(item1) == Long.parseLong(item2); + } else if (TextUtils.isDouble(item1) && TextUtils.isDouble(item2)) { + return Double.parseDouble(item1) == Double.parseDouble(item2); + } + return ignoreCase ? StringUtils.equalsIgnoreCase(item1, item2) : StringUtils.equals(item1, item2); + } + + public static boolean lessThan(String item1, String item2) { + if (TextUtils.isLong(item1) && TextUtils.isLong(item2)) { + return Long.parseLong(item1) < Long.parseLong(item2); + } else if (TextUtils.isDouble(item1) && TextUtils.isDouble(item2)) { + return Double.parseDouble(item1) < Double.parseDouble(item2); + } + return false; + } + + public static boolean greaterThan(String item1, String item2) { + if (TextUtils.isLong(item1) && TextUtils.isLong(item2)) { + return Long.parseLong(item1) > Long.parseLong(item2); + } else if (TextUtils.isDouble(item1) && TextUtils.isDouble(item2)) { + return Double.parseDouble(item1) > Double.parseDouble(item2); + } + return false; + } } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/utils/UrlUtils.java b/extension/src/main/java/synfron/reshaper/burp/core/utils/UrlUtils.java index e173dfb..7180555 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/utils/UrlUtils.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/utils/UrlUtils.java @@ -1,5 +1,7 @@ package synfron.reshaper.burp.core.utils; +import burp.BurpExtender; + public class UrlUtils { public static Url getUrl(String protocol, String host, Integer port, String path) { @@ -10,4 +12,12 @@ public static Url getUrl(String protocol, String host, Integer port, String path path ); } + + public static String urlEncode(String value) { + return BurpExtender.getApi().utilities().urlUtils().encode(value); + } + + public static String urlDecode(String value) { + return BurpExtender.getApi().utilities().urlUtils().decode(value); + } } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/utils/ValueGenerator.java b/extension/src/main/java/synfron/reshaper/burp/core/utils/ValueGenerator.java new file mode 100644 index 0000000..5142ae5 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/utils/ValueGenerator.java @@ -0,0 +1,395 @@ +package synfron.reshaper.burp.core.utils; + +import com.fasterxml.uuid.Generators; +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.exceptions.WrappedException; +import synfron.reshaper.burp.core.messages.Encoder; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAccessor; +import java.util.*; +import java.util.stream.Collectors; + +public class ValueGenerator { + private static final SecureRandom random = new SecureRandom(); + private static CustomProbabilityRandomizer letterCountRandomizer; + private static CustomProbabilityRandomizer consonantPopularityRandomizer; + private static CustomProbabilityRandomizer vowelPopularityRandomizer; + + public static String uuidV3(String namespace, String name) { + try { + return Generators.nameBasedGenerator(StringUtils.isNotEmpty(namespace) ? UUID.fromString(namespace) : null, MessageDigest.getInstance("MD5")).generate(name).toString(); + } catch (NoSuchAlgorithmException e) { + throw new WrappedException(e); + } + } + + public static String uuidV5(String namespace, String name) { + try { + return Generators.nameBasedGenerator(StringUtils.isNotEmpty(namespace) ? UUID.fromString(namespace) : null, MessageDigest.getInstance("SHA-1")).generate(name).toString(); + } catch (NoSuchAlgorithmException e) { + throw new WrappedException(e); + } + } + + public static String uuidV4() { + return Generators.randomBasedGenerator().generate().toString(); + } + + public static String ipAddressV4() { + int[] ipParts = new int[4]; + Random random = new Random(); + + ipParts[0] = random.nextInt(256); + ipParts[1] = random.nextInt(256); + ipParts[2] = random.nextInt(256); + ipParts[3] = random.nextInt(256); + + if ( + (ipParts[0] == 10) || + (ipParts[0] == 127) || + (ipParts[0] == 192 && ipParts[1] == 168) || + (ipParts[0] == 169 && ipParts[1] == 254) || + (ipParts[0] == 172 && (ipParts[1] >= 16 && ipParts[1] <= 31)) || + (ipParts[0] == 0 && ipParts[1] == 0 && ipParts[2] == 0 && ipParts[3] == 0) || + (ipParts[0] == 255 && ipParts[1] == 255 && ipParts[2] == 255 && ipParts[3] == 255) + ) { + return ipAddressV4(); + } + return String.format("%s.%s.%s.%s", ipParts[0], ipParts[1], ipParts[2], ipParts[3]); + } + + public static String ipAddressV6() { + byte[] bytes = new byte[16]; + try { + random.nextBytes(bytes); + return InetAddress.getByAddress(bytes).getHostAddress(); + } catch (UnknownHostException e) { + throw new WrappedException(e); + } + } + + public static String currentDate(String format) { + format = StringUtils.defaultString(format, "yyyy-MM-dd"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format); + return ZonedDateTime.now().format(formatter); + } + + public static String currentTimestamp() { + return Long.toString(ZonedDateTime.now().toInstant().toEpochMilli()); + } + + public static String timestamp(String format, String minDate, String maxDate) { + format = StringUtils.defaultString(format, "yyyy-MM-dd"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format); + ZonedDateTime now = ZonedDateTime.now(); + TemporalAccessor min = StringUtils.isNotEmpty(minDate) ? formatter.parseBest(minDate, ZonedDateTime::from, LocalDateTime::from, LocalDate::from) : now; + TemporalAccessor max = StringUtils.isNotEmpty(maxDate) ? formatter.parseBest(maxDate, ZonedDateTime::from, LocalDateTime::from, LocalDate::from) : now; + if (min instanceof ZonedDateTime) { + return Long.toString(date((ZonedDateTime) min, (ZonedDateTime) max).toInstant().toEpochMilli()); + } + if (min instanceof LocalDateTime) { + return Long.toString(date((LocalDateTime) min, (LocalDateTime) max).toInstant(now.getOffset()).toEpochMilli()); + } + return Long.toString(date((LocalDate) min, (LocalDate) max).toInstant(now.getOffset()).toEpochMilli()); + } + + public static String date(String format, String minDate, String maxDate) { + format = StringUtils.defaultString(format, "yyyy-MM-dd"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format); + ZonedDateTime now = ZonedDateTime.now(); + TemporalAccessor min = StringUtils.isNotEmpty(minDate) ? formatter.parseBest(minDate, ZonedDateTime::from, LocalDateTime::from, LocalDate::from) : now; + TemporalAccessor max = StringUtils.isNotEmpty(maxDate) ? formatter.parseBest(maxDate, ZonedDateTime::from, LocalDateTime::from, LocalDate::from) : now; + if (min instanceof ZonedDateTime) { + return date((ZonedDateTime) min, (ZonedDateTime) max).format(formatter); + } + if (min instanceof LocalDateTime) { + return date((LocalDateTime) min, (LocalDateTime) max).format(formatter); + } + return date((LocalDate) min, (LocalDate) max).format(formatter); + } + + private static ZonedDateTime date(ZonedDateTime min, ZonedDateTime max) { + return min.plus(random.nextLong(0L, max.toInstant().toEpochMilli() - min.toInstant().toEpochMilli()), ChronoUnit.MILLIS); + } + + private static LocalDateTime date(LocalDateTime min, LocalDateTime max) { + return min.plus(random.nextLong(0L, max.toInstant(ZoneOffset.UTC).toEpochMilli() - min.toInstant(ZoneOffset.UTC).toEpochMilli()), ChronoUnit.MILLIS); + } + + private static LocalDateTime date(LocalDate min, LocalDate max) { + return date(min.atStartOfDay(), max.atStartOfDay()); + } + + public static String password(int minLength, int maxLength, List characterGroups) { + String characters = characterGroups.stream().map(PasswordCharacterGroup::getCharacters).collect(Collectors.joining()); + List password = new ArrayList<>(); + int length = random.nextInt(minLength, maxLength + 1); + for (int i = 0; i < length; i++) { + if (i < characterGroups.size()) { + String groupCharacters = characterGroups.get(i).getCharacters(); + password.add(groupCharacters.charAt(random.nextInt(0, groupCharacters.length()))); + } else { + password.add(characters.charAt(random.nextInt(0, characters.length()))); + } + } + Collections.shuffle(password); + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < password.size(); i++) { + builder.append(password.get(i).charValue()); + } + return builder.toString(); + } + + public static String paragraphs(int count, String separator) { + return paragraphsFragment(count, separator, new StringBuilder()).toString(); + } + + private static StringBuilder paragraphsFragment(int count, String separator, StringBuilder builder) { + for (int i = 0; i < count; i++) { + paragraphFragment(builder); + if (i + 1 < count) { + builder.append(separator); + } + } + return builder; + } + + public static String paragraph() { + return paragraphFragment(new StringBuilder()).toString(); + } + + private static StringBuilder paragraphFragment(StringBuilder builder) { + Random random = new Random(); + int sentenceCount = random.nextInt(4, 8); + for (int i = 0; i < sentenceCount; i++) { + sentenceFragment(builder); + if (i + 1 < sentenceCount) { + builder.append(' '); + } + } + return builder; + } + + public static String sentences(int count, String separator) { + return sentencesFragment(count, separator, new StringBuilder()).toString(); + } + + private static StringBuilder sentencesFragment(int count, String separator, StringBuilder builder) { + for (int i = 0; i < count; i++) { + sentenceFragment(builder); + if (i + 1 < count) { + builder.append(separator); + } + } + return builder; + } + + public static String sentence() { + return sentenceFragment(new StringBuilder()).toString(); + } + + private static StringBuilder sentenceFragment(StringBuilder builder) { + Random random = new Random(); + int wordCount = random.nextInt(4, 20); + int commaPlacement = random.nextInt(5, 10); + for (int i = 0; i < wordCount; i++) { + wordFragment(i == 0, builder); + if (i + 1 < wordCount) { + if (i == commaPlacement) { + builder.append(','); + commaPlacement += random.nextInt(5, 10); + } + builder.append(' '); + } else { + builder.append('.'); + } + } + return builder; + } + + public static String words(int count, String separator, boolean uppercaseFirst) { + return wordsFragment(count, separator, uppercaseFirst, new StringBuilder()).toString(); + } + + private static StringBuilder wordsFragment(int count, String separator, boolean uppercaseFirst, StringBuilder builder) { + for (int i = 0; i < count; i++) { + wordFragment(uppercaseFirst, builder); + if (i + 1 < count) { + builder.append(separator); + } + } + return builder; + } + + public static String word(boolean uppercaseFirst) { + return wordFragment(uppercaseFirst, new StringBuilder()).toString(); + } + + private static StringBuilder wordFragment(boolean uppercaseFirst, StringBuilder builder) { + initLetterCountRandomizer(); + int count = letterCountRandomizer.next(); + if (count == 1) { + builder.append(uppercase(vowelPopularityRandomizer.next(), uppercaseFirst)); + } else { + boolean switchCharType = false; + boolean isLastVowel = random.nextBoolean(); + for (int i = 0; i < count; i ++) { + if (switchCharType) { + if (isLastVowel) { + builder.append(uppercase(consonantPopularityRandomizer.next(), false)); + } else { + builder.append(uppercase(vowelPopularityRandomizer.next(), false)); + } + isLastVowel = !isLastVowel; + switchCharType = false; + } else { + boolean isVowel = random.nextBoolean(); + if (isVowel) { + builder.append(uppercase(vowelPopularityRandomizer.next(), uppercaseFirst && i == 0)); + } else { + builder.append(uppercase(consonantPopularityRandomizer.next(), uppercaseFirst && i == 0)); + } + if (isLastVowel == isVowel) { + switchCharType = true; + } + isLastVowel = isVowel; + } + if (i == 0) { + switchCharType = true; + } + } + } + return builder; + } + + private static char uppercase(char character, boolean shouldUppercase) { + return shouldUppercase ? Character.toUpperCase(character) : character; + } + + public static String bytes(int length, Encoder encoder) { + byte[] bytesArr = new byte[length]; + random.nextBytes(bytesArr); + return encoder.decode(bytesArr); + } + + public static String integer(long minValue, long maxValue, int base) { + return Long.toString(random.nextLong(minValue, maxValue), base); + } + + private static void initLetterCountRandomizer() { + if (letterCountRandomizer == null) { + letterCountRandomizer = new CustomProbabilityRandomizer<>(random, Map.ofEntries( + Map.entry(1, 3), + Map.entry(2, 18), + Map.entry(3, 18), + Map.entry(4, 7), + Map.entry(5, 10), + Map.entry(6, 8), + Map.entry(7, 7), + Map.entry(8, 8), + Map.entry(9, 11), + Map.entry(10, 5), + Map.entry(11, 4), + Map.entry(12, 2), + Map.entry(13, 1) + )); + consonantPopularityRandomizer = new CustomProbabilityRandomizer<>(random, Map.ofEntries( + Map.entry('r', 758), + Map.entry('t', 695), + Map.entry('n', 665), + Map.entry('s', 573), + Map.entry('l', 549), + Map.entry('c', 454), + Map.entry('d', 338), + Map.entry('m', 300), + Map.entry('p', 190), + Map.entry('h', 300), + Map.entry('g', 247), + Map.entry('b', 207), + Map.entry('y', 178), + Map.entry('v', 101), + Map.entry('k', 110), + Map.entry('j', 20), + Map.entry('x', 29), + Map.entry('q', 20), + Map.entry('z', 27) + )); + vowelPopularityRandomizer = new CustomProbabilityRandomizer<>(random, Map.ofEntries( + Map.entry('e', 1116), + Map.entry('a', 850), + Map.entry('i', 754), + Map.entry('o', 716), + Map.entry('u', 363) + )); + } + } + + public static String uuid(UuidVersion version, String namespace, String name) { + return switch (version) { + case V3 -> uuidV3(namespace, name); + case V4 -> uuidV4(); + case V5 -> uuidV5(namespace, name); + }; + } + + public static String words(WordGeneratorType generatorType, int count, String separator) { + String value = switch (generatorType) { + case Word -> words(count, separator, false); + case Sentence -> sentences(count, separator); + case Paragraph -> paragraphs(count, separator); + }; + return value; + } + + public static String ipAddress(IpVersion version) { + return switch (version) { + case V4 -> ipAddressV4(); + case V6 -> ipAddressV6(); + }; + } + + public static String dateOrNow(String format, String minTimestamp, String maxTimestamp) { + return !StringUtils.isAllEmpty(minTimestamp, maxTimestamp) ? date(format, minTimestamp, maxTimestamp) : currentDate(format); + } + + public static String timestampOrNow(String format, String minTimestamp, String maxTimestamp) { + String value = !StringUtils.isAllEmpty(minTimestamp, maxTimestamp) ? timestamp(format, minTimestamp, maxTimestamp) : currentTimestamp(); + return value; + } + + @Getter + public enum UuidVersion { + V3(true), + V4(false), + V5(true); + + private final boolean hasInputs; + + UuidVersion(boolean hasInputs) { + this.hasInputs = hasInputs; + } + } + + public enum IpVersion { + V4, + V6 + } + + public enum WordGeneratorType { + Word, + Sentence, + Paragraph + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/vars/ListVariable.java b/extension/src/main/java/synfron/reshaper/burp/core/vars/ListVariable.java index 35252d1..17e1ab8 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/vars/ListVariable.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/vars/ListVariable.java @@ -9,6 +9,7 @@ import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; public class ListVariable extends Variable { @@ -53,11 +54,18 @@ public void setValue(Object value) { propertyChangedEvent.invoke(new PropertyChangedArgs(this, "value", value)); } - public void setValues(Object[] values, String delimiter) { + public void setValues(Object[] values, String delimiter, SetListItemsPlacement itemsPlacement) { this.delimiter = StringUtils.defaultString(delimiter, this.delimiter); - this.values = values == null ? - new ArrayList<>() : - Arrays.stream(values).map(TextUtils::toString).map(value -> (Object)value).collect(Collectors.toCollection(ArrayList::new)); + List newValues = Arrays.stream(values).map(TextUtils::toString).map(value -> (Object)value).collect(Collectors.toCollection(ArrayList::new)); + if (hasValue()) { + switch (itemsPlacement) { + case AddFirst -> this.values = Stream.concat(newValues.stream(), this.values.stream()).toList(); + case AddLast -> this.values = Stream.concat(this.values.stream(), newValues.stream()).toList(); + case Overwrite -> this.values = newValues; + } + } else { + this.values = newValues; + } propertyChangedEvent.invoke(new PropertyChangedArgs(this, "value", getValue())); } @@ -106,7 +114,7 @@ public String toString() { @Override public boolean hasValue() { - return values != null && values.size() > 0; + return values != null && !values.isEmpty(); } @Override diff --git a/extension/src/main/java/synfron/reshaper/burp/core/vars/SetListItemsPlacement.java b/extension/src/main/java/synfron/reshaper/burp/core/vars/SetListItemsPlacement.java new file mode 100644 index 0000000..174847e --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/vars/SetListItemsPlacement.java @@ -0,0 +1,21 @@ +package synfron.reshaper.burp.core.vars; + +import lombok.Getter; + +public enum SetListItemsPlacement { + AddFirst("Add First"), + AddLast("Add Last"), + Overwrite("Overwrite"); + + @Getter + private final String name; + + SetListItemsPlacement(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/vars/VariableSource.java b/extension/src/main/java/synfron/reshaper/burp/core/vars/VariableSource.java index 40f6271..8703464 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/vars/VariableSource.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/vars/VariableSource.java @@ -17,11 +17,12 @@ public enum VariableSource { GlobalList("Global List", "gl", false, ProtocolType.Any, true), SessionList("Session List", "sl", false, ProtocolType.Any, true), Message("m", true, ProtocolType.Any, false), + CookieJar("Cookie Jar", "cj", true, ProtocolType.Any, false), Macro("mc", true, ProtocolType.Http, false), Annotation("a", true, ProtocolType.Any, false), File("f", true, ProtocolType.Any, false), - Special("s", true, ProtocolType.Any, false), - CookieJar("Cookie Jar", "cj", true, ProtocolType.Any, false); + Generator("gr", true, ProtocolType.Any, false), + Special("s", true, ProtocolType.Any, false); private final String displayName; private final String shortName; diff --git a/extension/src/main/java/synfron/reshaper/burp/core/vars/VariableSourceEntry.java b/extension/src/main/java/synfron/reshaper/burp/core/vars/VariableSourceEntry.java index 9e2d026..03bd18f 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/vars/VariableSourceEntry.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/vars/VariableSourceEntry.java @@ -1,83 +1,45 @@ package synfron.reshaper.burp.core.vars; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import org.apache.commons.lang3.StringUtils; -import synfron.reshaper.burp.core.utils.TextUtils; +import synfron.reshaper.burp.core.utils.CollectionUtils; import java.io.Serializable; -import java.util.Arrays; -import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import java.util.ArrayList; +import java.util.List; @Getter public class VariableSourceEntry implements Serializable { private final VariableSource variableSource; - private final String name; - private final String tag; - - private VariableSourceEntry() { - this(null, null, null); - } - - public VariableSourceEntry(VariableSource variableSource, String name, String tag) { + private String tag; + private final List params = new ArrayList<>(); + + public VariableSourceEntry( + @JsonProperty("variableSource") VariableSource variableSource, + @JsonProperty("name") String name, + @JsonProperty("params") List params, + @JsonProperty("tag") String tag + ) { this.variableSource = variableSource; - this.name = name; + this.params.addAll(CollectionUtils.hasAny(params) ? params : VariableTag.parseParams(":" + StringUtils.defaultString(name))); 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); + public VariableSourceEntry(VariableSource variableSource, List params, String tag) { + this(variableSource, null, params, tag); } - public static String getTag(VariableSource variableSource, String name, GetListItemPlacement itemPlacement, Integer index) { - return getTag( - variableSource, - name, - itemPlacement.toString(), - itemPlacement.isHasIndexSetter() ? TextUtils.toString(index) : null - ); + public VariableSourceEntry(VariableSource variableSource, List params) { + this(variableSource, null, params, null); } - public static String getTag(VariableSource variableSource, String name, SetListItemPlacement itemPlacement, Integer index) { - return getTag( - variableSource, - name, - itemPlacement != null ? itemPlacement.toString() : null, - itemPlacement != null && itemPlacement.isHasIndexSetter() ? TextUtils.toString(index) : null - ); - } - - public static String getTag(VariableSource variableSource, String... names) { - return String.format("{{%s}}", Stream.concat( - Stream.of(StringUtils.defaultString(variableSource.name().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(":"))); + @JsonProperty + public String getTag() { + if (StringUtils.isEmpty(tag)) { + tag = VariableTag.getTag(variableSource, false, params.toArray(String[]::new)); + } + return tag; } - public static String getShortTag(VariableSource variableSource, String name, GetListItemPlacement itemPlacement, Integer index) { - return getShortTag( - variableSource, - name, - itemPlacement != null ? itemPlacement.toString() : null, - itemPlacement != null && itemPlacement.isHasIndexSetter() ? TextUtils.toString(index) : null - ); - } } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/vars/VariableString.java b/extension/src/main/java/synfron/reshaper/burp/core/vars/VariableString.java index f1b5dea..5d0cc38 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/vars/VariableString.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/vars/VariableString.java @@ -1,10 +1,7 @@ package synfron.reshaper.burp.core.vars; -import burp.BurpExtender; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.Pair; import synfron.reshaper.burp.core.messages.EventInfo; -import synfron.reshaper.burp.core.utils.Log; import synfron.reshaper.burp.core.utils.TextUtils; import synfron.reshaper.burp.core.vars.getters.VariableGetterProvider; @@ -13,7 +10,6 @@ import java.util.Collections; import java.util.List; import java.util.regex.Pattern; -import java.util.stream.Collectors; public class VariableString implements Serializable { private final String text; @@ -57,13 +53,6 @@ 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) { return null; @@ -71,17 +60,7 @@ public static VariableString getAsVariableString(String str, boolean requiresPar str = str.replace("%", "%%"); if (requiresParsing) { List variableSourceEntries = new ArrayList<>(); - Pattern pattern = Pattern.compile(String.format("\\{\\{(%s):(.+?)\\}\\}", String.join("|", VariableSource.getSupportedNames()))); - str = pattern.matcher(str).replaceAll(match -> { - VariableSource variableSource = VariableSource.get(match.group(1)); - String entryName = variableSource == VariableSource.Special ? - getSpecialChar(match.group(2)) : - match.group(2); - variableSourceEntries.add( - new VariableSourceEntry(VariableSource.get(match.group(1)), entryName, match.group(0)) - ); - return "%s"; - }); + str = VariableTag.replaceTags(str, variableSourceEntries, "%s"); return new VariableString(str, variableSourceEntries); } else { return new VariableString(str, Collections.emptyList()); @@ -92,6 +71,10 @@ public Integer getInt(EventInfo eventInfo) { return TextUtils.asInt(getText(eventInfo)); } + public Long getLong(EventInfo eventInfo) { + return TextUtils.asLong(getText(eventInfo)); + } + public Double getDouble(EventInfo eventInfo) { return TextUtils.asDouble(getText(eventInfo)); } @@ -107,17 +90,6 @@ public String getText(EventInfo eventInfo) { return String.format(text, variableVals.toArray()); } - private static String getSpecialChar(String sequences) { - try { - return TextUtils.parseSpecialChars(sequences); - } catch (Exception e) { - if (BurpExtender.getGeneralSettings().isEnableEventDiagnostics()) { - Log.get().withMessage(String.format("Invalid use of special character variable tag: %s", VariableSourceEntry.getTag(VariableSource.Special, sequences))).withException(e).logErr(); - } - } - return null; - } - public static String getTextOrDefault(EventInfo eventInfo, VariableString variableString, String defaultValue) { return variableString != null && !variableString.isEmpty() ? StringUtils.defaultIfEmpty(variableString.getText(eventInfo), defaultValue) : @@ -135,6 +107,13 @@ public static Integer getIntOrDefault(EventInfo eventInfo, VariableString variab defaultValue; } + public static Long getLongOrDefault(EventInfo eventInfo, VariableString variableString, Integer defaultValue) { + Long value; + return variableString != null && !variableString.isEmpty() && (value = variableString.getLong(eventInfo)) != null ? + value : + defaultValue; + } + public static Double getDoubleOrDefault(EventInfo eventInfo, VariableString variableString, Double defaultValue) { Double value; return variableString != null && !variableString.isEmpty() && (value = variableString.getDouble(eventInfo)) != null ? @@ -146,15 +125,17 @@ public static boolean isPotentialInt(String formattedString) { if (StringUtils.isEmpty(formattedString)) { return false; } - String strippedText = formattedString.replaceAll(String.format("\\{\\{(%s):(.+?)\\}\\}", String.join("|", VariableSource.getSupportedNames())), ""); + String strippedText = VariableTag.replaceTag(formattedString, ""); return TextUtils.isInt(strippedText) || strippedText.isEmpty(); } - public static boolean hasTag(String text) { - if (StringUtils.isEmpty(text)) { + public static boolean isPotentialLong(String formattedString) { + if (StringUtils.isEmpty(formattedString)) { return false; } - Pattern pattern = Pattern.compile(String.format("\\{\\{(%s):(.+?)\\}\\}", String.join("|", VariableSource.getSupportedNames()))); - return pattern.matcher(text).find(); + + String strippedText = VariableTag.replaceTag(formattedString, ""); + return TextUtils.isLong(strippedText) || strippedText.isEmpty(); } + } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/vars/VariableTag.java b/extension/src/main/java/synfron/reshaper/burp/core/vars/VariableTag.java new file mode 100644 index 0000000..f9edeca --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/core/vars/VariableTag.java @@ -0,0 +1,140 @@ +package synfron.reshaper.burp.core.vars; + +import burp.BurpExtender; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import synfron.reshaper.burp.core.utils.Log; +import synfron.reshaper.burp.core.utils.TextUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class VariableTag { + + private final static Pattern tagPattern; + private final static Pattern paramPattern; + + static { + String paramRegex = "(:(?(\\\"(([^\\\"\\\\]+|\\\\.)+?)\\\")|([^:]+))?)"; + String subParamRegex = "(:(?(\\\"(([^\\\"\\\\]+|\\\\.)+?)\\\")|([^:]+?))?)"; + String tagRegex = String.format("\\{\\{(?%s)(?%s*)\\}\\}", String.join("|", VariableSource.getSupportedNames()), subParamRegex); + tagPattern = Pattern.compile(tagRegex); + paramPattern = Pattern.compile(paramRegex); + } + + public static List parseParams(String params) { + List paramsList = new ArrayList<>(); + Matcher paramsMatcher = paramPattern.matcher(params); + while (paramsMatcher.find()) { + String param = StringUtils.defaultString(paramsMatcher.group("param")); + if (param.startsWith("\"")) { + param = TextUtils.jsonUnescape(TextUtils.stripQuotes(param)); + } + paramsList.add(param); + } + return paramsList; + } + + private static String joinParams(String[] params, boolean ignoreEmpty) { + return Stream.of(params) + .filter(param -> !ignoreEmpty || StringUtils.isNotEmpty(param)) + .map(StringUtils::defaultString) + .map(param -> { + String value = TextUtils.jsonEscape(param); + return StringUtils.containsAny(param, '{', '}', '\"', ':') || !param.equals(value) ? + String.format("\"%s\"", value) : + param; + }) + .collect(Collectors.joining(":")); + } + + public static String getTag(VariableSource variableSource, String name, GetListItemPlacement itemPlacement, Integer index) { + return getTag( + variableSource, + name, + itemPlacement.toString(), + itemPlacement.isHasIndexSetter() ? TextUtils.toString(index) : null + ); + } + + public static String getTag(VariableSource variableSource, String name, SetListItemPlacement itemPlacement, Integer index) { + return getTag( + variableSource, + name, + itemPlacement != null ? itemPlacement.toString() : null, + itemPlacement != null && itemPlacement.isHasIndexSetter() ? TextUtils.toString(index) : null + ); + } + + public static String getTag(VariableSource variableSource, String... names) { + return getTag(variableSource, true, names); + } + + public static String getTag(VariableSource variableSource, boolean ignoreEmpty, String... names) { + return String.format("{{%s:%s}}", + StringUtils.defaultString(variableSource.name().toLowerCase()), + joinParams(names, ignoreEmpty) + ); + } + + public static String getShortTag(VariableSource variableSource, String... names) { + return String.format("{{%s:%s}}", + StringUtils.defaultString(variableSource.getShortName()), + joinParams(names, true) + ); + } + + public static String getShortTag(VariableSource variableSource, String name, GetListItemPlacement itemPlacement, Integer index) { + return getShortTag( + variableSource, + name, + itemPlacement != null ? itemPlacement.toString() : null, + itemPlacement != null && itemPlacement.isHasIndexSetter() ? TextUtils.toString(index) : null + ); + } + + public static List> getVariableTagPositions(String str) {; + return tagPattern.matcher(str).results() + .map(result -> Pair.of(result.start(), result.end())) + .collect(Collectors.toList()); + } + + + private static String getSpecialChar(String sequences) { + try { + return TextUtils.parseSpecialChars(sequences); + } catch (Exception e) { + if (BurpExtender.getGeneralSettings().isEnableEventDiagnostics()) { + Log.get().withMessage(String.format("Invalid use of special character variable tag: %s", VariableTag.getTag(VariableSource.Special, sequences))).withException(e).logErr(); + } + } + return null; + } + + static String replaceTags(String str, List variableSourceEntries, String replacement) { + return tagPattern.matcher(str).replaceAll(match -> { + String tag = match.group(0); + String name = match.group("name"); + String params = match.group("params"); + VariableSource variableSource = VariableSource.get(name); + List paramsList = parseParams(params); + if (variableSource == VariableSource.Special) { + paramsList = List.of(StringUtils.defaultString(getSpecialChar(paramsList.getFirst()))); + } + variableSourceEntries.add(new VariableSourceEntry(variableSource, paramsList, tag)); + return replacement; + }); + } + + public static boolean hasTag(String text) { + return !StringUtils.isEmpty(text) && tagPattern.matcher(text).find(); + } + + static String replaceTag(String str, String replacement) { + return str.replaceAll(tagPattern.pattern(), replacement); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/core/vars/getters/AccessorVariableGetter.java b/extension/src/main/java/synfron/reshaper/burp/core/vars/getters/AccessorVariableGetter.java index 607c246..90b5a53 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/vars/getters/AccessorVariableGetter.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/vars/getters/AccessorVariableGetter.java @@ -3,44 +3,74 @@ import burp.BurpExtender; import burp.api.montoya.http.message.Cookie; import burp.api.montoya.http.message.HttpRequestResponse; -import org.apache.commons.csv.CSVFormat; -import org.apache.commons.csv.CSVParser; -import org.apache.commons.csv.CSVRecord; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; import synfron.reshaper.burp.core.messages.*; -import synfron.reshaper.burp.core.utils.CollectionUtils; import synfron.reshaper.burp.core.rules.GetItemPlacement; +import synfron.reshaper.burp.core.rules.thens.entities.generate.GenerateOption; +import synfron.reshaper.burp.core.utils.CollectionUtils; import synfron.reshaper.burp.core.utils.Log; -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.core.vars.Variables; +import synfron.reshaper.burp.core.utils.PasswordCharacterGroup; +import synfron.reshaper.burp.core.utils.ValueGenerator; +import synfron.reshaper.burp.core.vars.*; import java.io.File; import java.util.Arrays; +import java.util.List; public class AccessorVariableGetter extends VariableGetter { @Override public String getText(VariableSourceEntry variable, EventInfo eventInfo) { return switch (variable.getVariableSource()) { - case Message -> getMessageVariable(eventInfo, variable.getName()); - case File -> getFileText(eventInfo, variable.getName()); - case Special -> variable.getName(); - case CookieJar -> getCookie(variable.getName()); - case Annotation -> getAnnotation(eventInfo, variable.getName()); - case Macro -> getMacro(eventInfo, variable.getName()); + case Message -> getMessageVariable(eventInfo, variable.getParams()); + case File -> getFileText(eventInfo, variable.getParams()); + case Special -> variable.getParams().getFirst(); + case CookieJar -> getCookie(variable.getParams()); + case Annotation -> getAnnotation(eventInfo, variable.getParams()); + case Macro -> getMacro(eventInfo, variable.getParams()); + case Generator -> generate(eventInfo, variable.getParams()); default -> null; }; } - private String getMacro(EventInfo eventInfo, String locator) { - String[] variableNameParts = locator.split(":", 3); - if (variableNameParts.length > 1) { - int macroItemIndex = NumberUtils.toInt(variableNameParts[0], 0) - 1; - MessageValue messageValue = EnumUtils.getEnumIgnoreCase(MessageValue.class, variableNameParts[1]); + private String generate(EventInfo eventInfo, List params) { + GenerateOption generateOption = EnumUtils.getEnumIgnoreCase(GenerateOption.class, params.getFirst()); + return switch (generateOption) { + case Uuid -> ValueGenerator.uuid( + EnumUtils.getEnumIgnoreCase(ValueGenerator.UuidVersion.class, params.get(1)), + CollectionUtils.elementAtOrDefault(params, 2), + CollectionUtils.elementAtOrDefault(params, 3) + ); + case Words -> ValueGenerator.words( + EnumUtils.getEnumIgnoreCase(ValueGenerator.WordGeneratorType.class, params.get(1)), + Integer.parseInt(CollectionUtils.elementAtOrDefault(params, 2, "1")), + CollectionUtils.elementAtOrDefault(params, 3, "\n") + ); + case Password -> ValueGenerator.password( + Integer.parseInt(params.get(1)), + Integer.parseInt(params.get(2)), + CollectionUtils.defaultIfEmpty( + Arrays.stream(CollectionUtils.elementAtOrDefault(params, 3, "").split(",")) + .filter(StringUtils::isNotEmpty) + .map(characterGroup -> EnumUtils.getEnumIgnoreCase(PasswordCharacterGroup.class, characterGroup)) + .toList(), + List.of(PasswordCharacterGroup.values()) + ) + ); + case Bytes -> ValueGenerator.bytes(Integer.parseInt(params.get(1)), eventInfo.getEncoder()); + case Integer -> ValueGenerator.integer(Long.parseLong(params.get(1)), Long.parseLong(params.get(2)), Integer.parseInt(CollectionUtils.elementAtOrDefault(params, 3, "10"))); + case IpAddress -> ValueGenerator.ipAddress(EnumUtils.getEnumIgnoreCase(ValueGenerator.IpVersion.class, params.get(1))); + case Timestamp -> ValueGenerator.dateOrNow(CollectionUtils.elementAtOrDefault(params, 1), CollectionUtils.elementAtOrDefault(params, 2), CollectionUtils.elementAtOrDefault(params, 3)); + case UnixTimestamp -> ValueGenerator.timestampOrNow(CollectionUtils.elementAtOrDefault(params, 1), CollectionUtils.elementAtOrDefault(params, 2), CollectionUtils.elementAtOrDefault(params, 3)); + }; + } + + private String getMacro(EventInfo eventInfo, List variableNameParts) { + if (variableNameParts.size() > 1) { + int macroItemIndex = NumberUtils.toInt(variableNameParts.getFirst(), 0) - 1; + MessageValue messageValue = EnumUtils.getEnumIgnoreCase(MessageValue.class, variableNameParts.get(1)); String identifier = CollectionUtils.elementAtOrDefault(variableNameParts, 2, ""); if (macroItemIndex >= 0 && messageValue != null) { HttpRequestResponse requestResponse = CollectionUtils.elementAtOrDefault(eventInfo.getMacros(), macroItemIndex); @@ -63,8 +93,8 @@ private String getMacro(EventInfo eventInfo, String locator) { return null; } - private String getAnnotation(EventInfo eventInfo, String name) { - MessageAnnotation annotation = EnumUtils.getEnumIgnoreCase(MessageAnnotation.class, name); + private String getAnnotation(EventInfo eventInfo, List name) { + MessageAnnotation annotation = EnumUtils.getEnumIgnoreCase(MessageAnnotation.class, name.getFirst()); if (annotation != null && eventInfo.getAnnotations() != null) { return switch (annotation) { case Comment -> eventInfo.getAnnotations().notes(); @@ -74,26 +104,11 @@ private String getAnnotation(EventInfo eventInfo, String name) { return null; } - private String getCookie(String locator) { + private String getCookie(List parts) { try { - String[] parts = locator.split(":", 3); - String domain = parts[0]; - String name = parts[1]; + String domain = parts.getFirst(); + String name = parts.get(1); String path = CollectionUtils.elementAtOrDefault(parts, 2); - if (Arrays.stream(parts).anyMatch(part -> part.startsWith("\""))) { - try (CSVParser csvParser = CSVParser.parse(locator, getParamFormat())) { - CSVRecord record = csvParser.getRecords().get(0); - if (record.size() == 2) { - domain = record.get(0); - name = record.get(1); - path = null; - } else if (record.size() == 3) { - domain = record.get(0); - name = record.get(1); - path = record.get(2); - } - } - } for (Cookie cookie : BurpExtender.getApi().http().cookieJar().cookies()) { if (cookie.domain().equals(domain) && cookie.name().equals(name) @@ -103,17 +118,16 @@ private String getCookie(String locator) { } } catch (Exception e) { if (BurpExtender.getGeneralSettings().isEnableEventDiagnostics()) { - Log.get().withMessage(String.format("Invalid use of cookie jar variable tag: %s", VariableSourceEntry.getTag(VariableSource.CookieJar, locator))).withException(e).logErr(); + Log.get().withMessage(String.format("Invalid use of cookie jar variable tag: %s", VariableTag.getTag(VariableSource.CookieJar, parts.toArray(String[]::new)))).withException(e).logErr(); } } return ""; } - private String getFileText(EventInfo eventInfo, String locator) { + private String getFileText(EventInfo eventInfo, List variableNameParts) { try { - String[] variableNameParts = locator.split(":", 2); - File file = new File(variableNameParts[1]); - String encoding = variableNameParts[0]; + File file = new File(variableNameParts.get(1)); + String encoding = variableNameParts.getFirst(); Encoder encoder = new Encoder(encoding); if (encoder.isUseDefault() || encoder.isUseAutoDetect()) { byte[] fileBytes = FileUtils.readFileToByteArray(file); @@ -122,14 +136,13 @@ private String getFileText(EventInfo eventInfo, String locator) { return FileUtils.readFileToString(file, encoding); } catch (Exception e) { if (eventInfo.getDiagnostics().isEnabled()) { - Log.get().withMessage(String.format("Error reading file with variable tag: %s", VariableSourceEntry.getTag(VariableSource.Special, locator))).withException(e).logErr(); + Log.get().withMessage(String.format("Error reading file with variable tag: %s", VariableTag.getTag(VariableSource.Special, variableNameParts.toArray(String[]::new)))).withException(e).logErr(); } } return null; } - private String getMessageVariable(EventInfo eventInfo, String locator) { - String[] variableNameParts = locator.split(":", 2); + private String getMessageVariable(EventInfo eventInfo, List variableNameParts) { MessageValue messageValue = EnumUtils.getEnumIgnoreCase(MessageValue.class, CollectionUtils.elementAtOrDefault(variableNameParts, 0, "")); String identifier = CollectionUtils.elementAtOrDefault(variableNameParts, 1, ""); if (messageValue != null) { @@ -139,11 +152,4 @@ private String getMessageVariable(EventInfo eventInfo, String locator) { } return null; } - - private CSVFormat getParamFormat() { - return CSVFormat.DEFAULT.builder().setDelimiter(':') - .setAllowMissingColumnNames(true) - .setEscape('\\') - .build(); - } } diff --git a/extension/src/main/java/synfron/reshaper/burp/core/vars/getters/CustomListVariableGetter.java b/extension/src/main/java/synfron/reshaper/burp/core/vars/getters/CustomListVariableGetter.java index 9788a4a..694f248 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/vars/getters/CustomListVariableGetter.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/vars/getters/CustomListVariableGetter.java @@ -7,12 +7,14 @@ import synfron.reshaper.burp.core.utils.TextUtils; import synfron.reshaper.burp.core.vars.*; +import java.util.List; + public class CustomListVariableGetter extends VariableGetter { @Override public String getText(VariableSourceEntry variableSourceEntry, EventInfo eventInfo) { - String[] locatorParts = variableSourceEntry.getName().split(":", 2); - String variableName = locatorParts[0]; + List locatorParts = variableSourceEntry.getParams(); + String variableName = locatorParts.getFirst(); ListVariable variable = getVariable(variableSourceEntry, variableName, eventInfo); String place = CollectionUtils.elementAtOrDefault(locatorParts, 1); if (variable == null) { diff --git a/extension/src/main/java/synfron/reshaper/burp/core/vars/getters/CustomVariableGetter.java b/extension/src/main/java/synfron/reshaper/burp/core/vars/getters/CustomVariableGetter.java index 03f9270..3fb366c 100644 --- a/extension/src/main/java/synfron/reshaper/burp/core/vars/getters/CustomVariableGetter.java +++ b/extension/src/main/java/synfron/reshaper/burp/core/vars/getters/CustomVariableGetter.java @@ -12,9 +12,9 @@ public class CustomVariableGetter extends VariableGetter { @Override public String getText(VariableSourceEntry variable, EventInfo eventInfo) { Variable value = switch (variable.getVariableSource()) { - case Global -> GlobalVariables.get().getOrDefault(Variables.asKey(variable.getName(), false)); - case Event -> eventInfo.getVariables().getOrDefault(Variables.asKey(variable.getName(), false)); - case Session -> eventInfo.getSessionVariables().getOrDefault(Variables.asKey(variable.getName(), false)); + case Global -> GlobalVariables.get().getOrDefault(Variables.asKey(variable.getParams().getFirst(), false)); + case Event -> eventInfo.getVariables().getOrDefault(Variables.asKey(variable.getParams().getFirst(), false)); + case Session -> eventInfo.getSessionVariables().getOrDefault(Variables.asKey(variable.getParams().getFirst(), false)); default -> null; }; return value != null ? TextUtils.toString(value.getValue()) : null; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/IFormComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/IFormComponent.java index c32e6d4..68e31d0 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/IFormComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/IFormComponent.java @@ -3,7 +3,7 @@ import net.miginfocom.swing.MigLayout; import org.apache.commons.lang3.StringUtils; import synfron.reshaper.burp.core.ProtocolType; -import synfron.reshaper.burp.core.vars.VariableString; +import synfron.reshaper.burp.core.vars.VariableTag; import synfron.reshaper.burp.ui.components.rules.RuleOperationComponent; import synfron.reshaper.burp.ui.components.rules.wizard.vars.VariableTagWizardOptionPane; import synfron.reshaper.burp.ui.models.rules.wizard.vars.VariableTagWizardModel; @@ -22,11 +22,11 @@ public interface IFormComponent { - default Component getLabeledField(String label, Component innerComponent) { + default JPanel getLabeledField(String label, Component innerComponent) { return getLabeledField(label, innerComponent, true); } - default Component getLabeledField(String label, Component innerComponent, boolean span) { + default JPanel getLabeledField(String label, Component innerComponent, boolean span) { JPanel container = new JPanel(); container.setLayout(new MigLayout()); container.setBorder(null); @@ -54,6 +54,20 @@ default JComboBox createComboBox(T[] array, boolean isEditable) { return comboBox; } + default JComboBox createComboBox(ComboBoxModel model) { + return createComboBox(model, false); + } + + default JComboBox createComboBox(ComboBoxModel model, boolean isEditable) { + JComboBox comboBox = new JComboBox<>(model); + if (isEditable) { + comboBox.setEditable(true); + int columnSize = comboBox.getFontMetrics(comboBox.getFont()).charWidth('m') * 20; + comboBox.setPreferredSize(new Dimension(columnSize, comboBox.getPreferredSize().height)); + } + return comboBox; + } + private ProtocolType getProtocolType() { return this instanceof RuleOperationComponent ? ((RuleOperationComponent)this).getProtocolType() : ProtocolType.Any; } @@ -121,7 +135,7 @@ private static void insertVariableTag(T textComponent String tag = model.getTag(); if (StringUtils.isNotEmpty(tag)) { int cursorPosition = textComponent.getCaretPosition(); - int insertPosition = VariableString.getVariableTagPositions(textComponent.getText()).stream() + int insertPosition = VariableTag.getVariableTagPositions(textComponent.getText()).stream() .noneMatch(position -> position.getLeft() < cursorPosition && cursorPosition < position.getRight()) ? cursorPosition : textComponent.getText().length(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/ITabActivationListener.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/ITabActivationListener.java deleted file mode 100644 index 48c17ec..0000000 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/ITabActivationListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package synfron.reshaper.burp.ui.components; - -public interface ITabActivationListener { - default void onActivated() { } -} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/ReshaperComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/ReshaperComponent.java index 538b90d..f33862c 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/ReshaperComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/ReshaperComponent.java @@ -5,7 +5,11 @@ */ package synfron.reshaper.burp.ui.components; +import burp.BurpExtender; +import synfron.reshaper.burp.core.Tab; import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.events.IEventListener; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.ui.components.rules.RulesTabComponent; import synfron.reshaper.burp.ui.components.settings.SettingsTabComponent; import synfron.reshaper.burp.ui.components.vars.VariablesTabComponent; @@ -13,9 +17,11 @@ import javax.swing.*; import javax.swing.event.ChangeEvent; import java.awt.*; +import java.util.HashMap; public class ReshaperComponent extends JPanel { + private final IEventListener generalSettingsChangedListener = this::onGeneralSettingsChanged; private JTabbedPane tabs; public ReshaperComponent() { @@ -25,26 +31,48 @@ public ReshaperComponent() { private void initComponents() { setLayout(new BorderLayout()); add(getTabs()); + + BurpExtender.getGeneralSettings().withListener(generalSettingsChangedListener); } private JTabbedPane getTabs() { tabs = new JTabbedPane(); - tabs.addTab("HTTP Rules", new RulesTabComponent(ProtocolType.Http)); - tabs.addTab("WebSocket Rules", new RulesTabComponent(ProtocolType.WebSocket)); - tabs.addTab("Global Variables", new VariablesTabComponent()); - tabs.addTab("Logs", new LogsComponent()); - tabs.addTab("Settings", new SettingsTabComponent()); - - tabs.addChangeListener(this::onTabChanged); + addOrRemoveTabs(); return tabs; } - private void onTabChanged(ChangeEvent e) { - if (tabs.getSelectedIndex() >= 0) { - Component selectedTab = tabs.getComponentAt(tabs.getSelectedIndex()); - if (selectedTab instanceof ITabActivationListener listener) { - listener.onActivated(); + private void onGeneralSettingsChanged(PropertyChangedArgs propertyChangedArgs) { + if (propertyChangedArgs.getName().equals("hiddenTabs")) { + addOrRemoveTabs(); + } + } + + private void addOrRemoveTabs() { + HashMap existingTabs = new HashMap<>(); + for (int tabIndex = 0; tabIndex < tabs.getTabCount(); tabIndex++) { + Tab tab = Tab.byName(tabs.getTitleAt(tabIndex)); + existingTabs.put(tab, tabs.getComponentAt(tabIndex)); + } + Component activeTab = tabs.getSelectedComponent(); + tabs.removeAll(); + + for (Tab tab : Tab.values()) { + if (!tab.isHideable() || !BurpExtender.getGeneralSettings().getHiddenTabs().contains(tab)) { + Component component = existingTabs.get(tab); + if (component == null) { + component = switch (tab) { + case HttpRules -> new RulesTabComponent(ProtocolType.Http); + case WebSocketRules -> new RulesTabComponent(ProtocolType.WebSocket); + case GlobalVariables -> new VariablesTabComponent(); + case Logs -> new LogsComponent(); + case Settings -> new SettingsTabComponent(); + }; + } + tabs.addTab(tab.toString(), component); + if (activeTab == component) { + tabs.setSelectedComponent(component); + } } } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleListComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleListComponent.java index 2cd1885..f2f64ab 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleListComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleListComponent.java @@ -101,8 +101,7 @@ protected void processMouseEvent(MouseEvent e) { private Color ruleListItemColorProvider(Object item, Color defaultColor) { Color newColor = null; - if (item instanceof RuleModel) { - RuleModel model = (RuleModel) item; + if (item instanceof RuleModel model) { if (!model.isEnabled()) { newColor = new Color( rgbScaler(defaultColor.getRed(), 2.6), @@ -128,7 +127,7 @@ private void onSelectionChanged(ListSelectionEvent listSelectionEvent) { } private boolean defaultSelect() { - if (rulesList.getSelectedValue() == null && ruleListModel.size() > 0) { + if (rulesList.getSelectedValue() == null && !ruleListModel.isEmpty()) { rulesList.setSelectedIndex(ruleListModel.size() - 1); return true; } @@ -242,7 +241,7 @@ private void onDuplicate(ActionEvent actionEvent) { public void setSelectionContainer(RuleContainerComponent ruleContainer) { this.ruleContainer = ruleContainer; - if (ruleListModel.size() == 0) { + if (ruleListModel.isEmpty()) { rulesRegistry.addRule(createNewRule()); } defaultSelect(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationContainerComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationContainerComponent.java index 081556e..0dab208 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationContainerComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationContainerComponent.java @@ -36,5 +36,5 @@ private Component getComponent(RuleOperationModel model) { return (Component)ObjectUtils.construct(componentClass, protocolType, model); } - protected abstract Map, Class> getComponentMap(); + protected abstract Map, Class>> getComponentMap(); } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationListComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationListComponent.java index 08a60e5..baa8947 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationListComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationListComponent.java @@ -1,10 +1,12 @@ package synfron.reshaper.burp.ui.components.rules; +import burp.BurpExtender; import lombok.Getter; import synfron.reshaper.burp.core.ProtocolType; 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.core.utils.CollectionUtils; import synfron.reshaper.burp.ui.components.IFormComponent; import synfron.reshaper.burp.ui.models.rules.RuleModel; import synfron.reshaper.burp.ui.models.rules.RuleOperationModel; @@ -24,6 +26,7 @@ public abstract class RuleOperationListComponent operationsList; protected DefaultListModel operationsListModel; protected JComboBox> operationSelector; + protected DefaultComboBoxModel> operatorSelectorListModel = new DefaultComboBoxModel<>(); @Getter private RuleOperationContainerComponent ruleOperationContainer; private final IEventListener ruleOperationChangedListener = this::onRuleOperationChanged; @@ -71,7 +74,7 @@ else if (!defaultSelect()) { } private boolean defaultSelect() { - if (operationsList.getSelectedValue() == null && operationsListModel.size() > 0) { + if (operationsList.getSelectedValue() == null && !operationsListModel.isEmpty()) { operationsList.setSelectedIndex(operationsListModel.size() - 1); return true; } @@ -122,9 +125,10 @@ private Component getActionBar() { private Component getAddOperation() { JPanel container = new JPanel(); - operationSelector = createComboBox(getRuleOperationModelTypes().stream() - .sorted(Comparator.comparing(RuleOperationModelType::getName)) - .toArray(RuleOperationModelType[]::new)); + operationSelector = createComboBox(operatorSelectorListModel); + + syncOperationSelectorList(); + JButton add = new JButton("Add"); add.addActionListener(this::onAdd); @@ -134,6 +138,18 @@ private Component getAddOperation() { return container; } + protected void syncOperationSelectorList() { + operatorSelectorListModel.removeAllElements(); + List> operationTypes = getRuleOperationModelTypes().stream() + .sorted(Comparator.comparing(RuleOperationModelType::getName)) + .toList(); + operatorSelectorListModel.addAll(operationTypes); + + RuleOperationModelType defaultItem = operationTypes.stream().filter(RuleOperationModelType::isDefault) + .findFirst().orElse(CollectionUtils.firstOrDefault(operationTypes)); + operationSelector.setSelectedItem(defaultItem); + } + private void onDelete(ActionEvent actionEvent) { RuleOperationModel model = operationsList.getSelectedValue(); if (model != null) { diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenContainerComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenContainerComponent.java index e94f756..4bd8db1 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenContainerComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenContainerComponent.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.components.rules.thens; import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.ui.components.rules.RuleOperationComponent; 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; @@ -10,7 +11,7 @@ public class ThenContainerComponent extends RuleOperationContainerComponent { - private final static Map, Class> componentMap; + private final static Map, Class>> componentMap; static { componentMap = new HashMap<>(); @@ -40,6 +41,9 @@ public class ThenContainerComponent extends RuleOperationContainerComponent { componentMap.put(ThenModelType.Intercept, ThenInterceptComponent.class); componentMap.put(ThenModelType.Repeat, ThenRepeatComponent.class); componentMap.put(ThenModelType.ReadFile, ThenReadFileComponent.class); + componentMap.put(ThenModelType.Extract, ThenExtractComponent.class); + componentMap.put(ThenModelType.Generate, ThenGenerateComponent.class); + componentMap.put(ThenModelType.Transform, ThenTransformComponent.class); } public ThenContainerComponent(ProtocolType protocolType) { @@ -47,7 +51,7 @@ public ThenContainerComponent(ProtocolType protocolType) { } @Override - protected Map, Class> getComponentMap() { + protected Map, Class>> getComponentMap() { return componentMap; } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenExtractComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenExtractComponent.java new file mode 100644 index 0000000..676dbec --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenExtractComponent.java @@ -0,0 +1,96 @@ +package synfron.reshaper.burp.ui.components.rules.thens; + +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.rules.thens.ThenExtract; +import synfron.reshaper.burp.core.rules.thens.entities.extract.ExtractorType; +import synfron.reshaper.burp.core.vars.SetListItemsPlacement; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.ui.models.rules.thens.ThenExtractModel; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.util.Arrays; + +public class ThenExtractComponent extends ThenComponent { + private JTextField text; + private JComboBox extractorType; + private JTextField extractor; + private JComboBox listVariableSource; + private JTextField listVariableName; + private JTextField delimiter; + private JComboBox itemsPlacement; + private JPanel extractorField; + + public ThenExtractComponent(ProtocolType protocolType, ThenExtractModel then) { + super(protocolType, then); + initComponent(); + } + + private void initComponent() { + text = createTextField(true); + extractorType = createComboBox(ExtractorType.values()); + extractor = createTextField(true); + listVariableSource = createComboBox(Arrays.stream(VariableSource.values()) + .filter(VariableSource::isList) + .toArray(VariableSource[]::new)); + listVariableName = createTextField(true); + delimiter = createTextField(true); + itemsPlacement = createComboBox(SetListItemsPlacement.values()); + + text.setText(model.getText()); + extractorType.setSelectedItem(model.getExtractorType()); + extractor.setText(model.getExtractor()); + listVariableSource.setSelectedItem(model.getListVariableSource()); + listVariableName.setText(model.getListVariableName()); + delimiter.setText(model.getDelimiter()); + itemsPlacement.setSelectedItem(model.getItemsPlacement()); + + text.getDocument().addDocumentListener(new DocumentActionListener(this::onTextChanged)); + extractorType.addActionListener(this::onExtractorTypeChanged); + extractor.getDocument().addDocumentListener(new DocumentActionListener(this::onExtractorChanged)); + listVariableSource.addActionListener(this::onListVariableSourceChanged); + listVariableName.getDocument().addDocumentListener(new DocumentActionListener(this::onListVariableNameChanged)); + delimiter.getDocument().addDocumentListener(new DocumentActionListener(this::onDelimiterChanged)); + itemsPlacement.addActionListener(this::onItemsPlacementChanged); + + extractorField = getLabeledField( model.getExtractorType().getSyntax() + " *", extractor); + + mainContainer.add(getLabeledField("Text *", text), "wrap"); + mainContainer.add(getLabeledField("Extractor Type", extractorType), "wrap"); + mainContainer.add(extractorField, "wrap"); + mainContainer.add(getLabeledField("List Variable Source", listVariableSource), "wrap"); + mainContainer.add(getLabeledField("List Variable Name *", listVariableName), "wrap"); + mainContainer.add(getLabeledField("Delimiter *", delimiter), "wrap"); + mainContainer.add(getLabeledField("Items Placement", itemsPlacement), "wrap"); + } + + private void onTextChanged(ActionEvent actionEvent) { + model.setText(text.getText()); + } + + private void onExtractorTypeChanged(ActionEvent actionEvent) { + model.setExtractorType((ExtractorType) extractorType.getSelectedItem()); + ((JLabel)extractorField.getComponents()[0]).setText(model.getExtractorType().getSyntax() + " *"); + } + + private void onExtractorChanged(ActionEvent actionEvent) { + model.setExtractor(extractor.getText()); + } + + private void onListVariableSourceChanged(ActionEvent actionEvent) { + model.setListVariableSource((VariableSource) listVariableSource.getSelectedItem()); + } + + private void onListVariableNameChanged(ActionEvent actionEvent) { + model.setListVariableName(listVariableName.getText()); + } + + private void onDelimiterChanged(ActionEvent actionEvent) { + model.setDelimiter(delimiter.getText()); + } + + private void onItemsPlacementChanged(ActionEvent actionEvent) { + model.setItemsPlacement((SetListItemsPlacement) itemsPlacement.getSelectedItem()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenGenerateComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenGenerateComponent.java new file mode 100644 index 0000000..5441499 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenGenerateComponent.java @@ -0,0 +1,124 @@ +package synfron.reshaper.burp.ui.components.rules.thens; + +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.rules.thens.ThenGenerate; +import synfron.reshaper.burp.core.rules.thens.entities.generate.GenerateOption; +import synfron.reshaper.burp.core.vars.SetListItemPlacement; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.ui.components.rules.thens.generate.*; +import synfron.reshaper.burp.ui.models.rules.thens.ThenGenerateModel; +import synfron.reshaper.burp.ui.models.rules.thens.generate.*; +import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.util.List; + +public class ThenGenerateComponent extends ThenComponent { + private JComboBox generateOption; + private final JPanel generatorContainer = new JPanel(); + private JComboBox destinationVariableSource; + private JTextField destinationVariableName; + private JComboBox itemPlacement; + private JTextField delimiter; + private JTextField index; + + public ThenGenerateComponent(ProtocolType protocolType, ThenGenerateModel then) { + super(protocolType, then); + initComponent(); + } + + private GeneratorComponent getGenerator() { + return switch (model.getGenerateOption()) { + case Uuid -> new UuidGeneratorComponent((UuidGeneratorModel) model.getGenerator(), true); + case Words -> new WordGeneratorComponent((WordGeneratorModel) model.getGenerator(), true); + case Bytes -> new BytesGeneratorComponent((BytesGeneratorModel) model.getGenerator(), true); + case Integer -> new IntegerGeneratorComponent((IntegerGeneratorModel) model.getGenerator(), true); + case IpAddress -> new IpAddressGeneratorComponent((IpAddressGeneratorModel) model.getGenerator(), true); + case Timestamp -> new TimestampGeneratorComponent((TimestampGeneratorModel) model.getGenerator(), true); + case UnixTimestamp -> new UnixTimestampGeneratorComponent((UnixTimestampGeneratorModel) model.getGenerator(), true); + case Password -> new PasswordGeneratorComponent((PasswordGeneratorModel) model.getGenerator(), true); + }; + } + + private void initComponent() { + generatorContainer.setBorder(BorderFactory.createEmptyBorder(0, -12, 0, 0)); + generateOption = createComboBox(GenerateOption.values()); + destinationVariableSource = createComboBox(VariableSource.getAllSettables(protocolType)); + destinationVariableName = createTextField(true); + itemPlacement = createComboBox(SetListItemPlacement.values()); + delimiter = createTextField(true); + index = createTextField(true); + + generateOption.setSelectedItem(model.getGenerateOption()); + destinationVariableSource.setSelectedItem(model.getDestinationVariableSource()); + destinationVariableName.setText(model.getDestinationVariableName()); + itemPlacement.setSelectedItem(model.getItemPlacement()); + delimiter.setText(model.getDelimiter()); + index.setText(model.getIndex()); + + generateOption.addActionListener(this::onSetGenerateOptionChanged); + destinationVariableSource.addActionListener(this::onDestinationVariableSourceChanged); + destinationVariableName.getDocument().addDocumentListener(new DocumentActionListener(this::onDestinationVariableNameChanged)); + itemPlacement.addActionListener(this::onItemPlacementChanged); + delimiter.getDocument().addDocumentListener(new DocumentActionListener(this::onDelimiterChanged)); + index.getDocument().addDocumentListener(new DocumentActionListener(this::onIndexChanged)); + + mainContainer.add(getLabeledField("Generate Option", generateOption), "wrap"); + mainContainer.add(generatorContainer, "wrap"); + mainContainer.add(getLabeledField("Destination Variable Source", destinationVariableSource), "wrap"); + mainContainer.add(getLabeledField("Destination Variable Name *", destinationVariableName), "wrap"); + mainContainer.add(ComponentVisibilityManager.withVisibilityFieldChangeDependency( + getLabeledField("Item Placement", itemPlacement), + destinationVariableSource, + () -> ((VariableSource)destinationVariableSource.getSelectedItem()).isList() + ), "wrap"); + mainContainer.add(ComponentVisibilityManager.withVisibilityFieldChangeDependency( + getLabeledField("Delimiter *", delimiter), + List.of(destinationVariableSource, itemPlacement), + () -> ((VariableSource)destinationVariableSource.getSelectedItem()).isList() && ((SetListItemPlacement)itemPlacement.getSelectedItem()).isHasDelimiterSetter() + ), "wrap"); + mainContainer.add(ComponentVisibilityManager.withVisibilityFieldChangeDependency( + getLabeledField("Index *", index), + List.of(destinationVariableSource, itemPlacement), + () -> ((VariableSource)destinationVariableSource.getSelectedItem()).isList() && ((SetListItemPlacement)itemPlacement.getSelectedItem()).isHasIndexSetter() + ), "wrap"); + + setGenerator(); + } + + private void setGenerator() { + GeneratorComponent generator = getGenerator(); + + generatorContainer.removeAll(); + generatorContainer.add(generator); + revalidate(); + repaint(); + } + + private void onSetGenerateOptionChanged(ActionEvent actionEvent) { + model.setGenerateOption((GenerateOption) generateOption.getSelectedItem()); + setGenerator(); + } + + private void onDestinationVariableSourceChanged(ActionEvent actionEvent) { + model.setDestinationVariableSource((VariableSource) destinationVariableSource.getSelectedItem()); + } + + private void onDestinationVariableNameChanged(ActionEvent actionEvent) { + model.setDestinationVariableName(destinationVariableName.getText()); + } + + private void onItemPlacementChanged(ActionEvent actionEvent) { + model.setItemPlacement((SetListItemPlacement)itemPlacement.getSelectedItem()); + } + + private void onDelimiterChanged(ActionEvent actionEvent) { + model.setDelimiter(delimiter.getText()); + } + + private void onIndexChanged(ActionEvent actionEvent) { + model.setIndex(index.getText()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenListComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenListComponent.java index f21969c..9c6bb1b 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenListComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenListComponent.java @@ -1,6 +1,9 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import burp.BurpExtender; import synfron.reshaper.burp.core.ProtocolType; +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.core.rules.thens.Then; import synfron.reshaper.burp.ui.components.rules.RuleOperationListComponent; @@ -8,14 +11,19 @@ import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; import synfron.reshaper.burp.ui.models.rules.thens.ThenModel; import synfron.reshaper.burp.ui.models.rules.thens.ThenModelType; +import synfron.reshaper.burp.ui.models.rules.whens.WhenModelType; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; public class ThenListComponent extends RuleOperationListComponent> { + private final IEventListener generalSettingsChangedListener = this::onGeneralSettingsChanged; + public ThenListComponent(ProtocolType protocolType, RuleModel model) { super(protocolType, model); + BurpExtender.getGeneralSettings().withListener(generalSettingsChangedListener); } @Override @@ -23,9 +31,17 @@ public ThenListComponent(ProtocolType protocolType, RuleModel model) { return model.getThens(); } + private void onGeneralSettingsChanged(PropertyChangedArgs propertyChangedArgs) { + if (propertyChangedArgs.getName().equals("hiddenThenTypes")) { + syncOperationSelectorList(); + } + } + @Override protected List> getRuleOperationModelTypes() { - return Collections.unmodifiableList(ThenModelType.getTypes(protocolType)); + return ThenModelType.getTypes(protocolType).stream() + .filter(type -> !BurpExtender.getGeneralSettings().getHiddenThenTypes().contains(type.getName())) + .collect(Collectors.toList()); } @Override diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRepeatComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRepeatComponent.java index 7c5f360..d7c86ec 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRepeatComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRepeatComponent.java @@ -14,11 +14,11 @@ public class ThenRepeatComponent extends ThenComponent { - protected JTextField subGroupCount; - protected JComboBox repeatCondition; - protected JComboBox listVariableSource; - protected JTextField listVariableName; - protected JTextField entryVariableName; + private JTextField subGroupCount; + private JComboBox repeatCondition; + private JComboBox listVariableSource; + private JTextField listVariableName; + private JTextField entryVariableName; private JTextField count; private JTextField booleanValue; protected JTextField maxCount; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendToComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendToComponent.java index bed0961..b01b26b 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendToComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendToComponent.java @@ -153,7 +153,7 @@ private void initComponent() { } private void onSendToChanged(ActionEvent actionEvent) { - model.setSendTo((SendToOption)sendTo.getSelectedItem()); + model.setSendTo((SendToOption) sendTo.getSelectedItem()); } private void onOverrideDefaultsChanged(ActionEvent actionEvent) { diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenTransformComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenTransformComponent.java new file mode 100644 index 0000000..f5c4593 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenTransformComponent.java @@ -0,0 +1,124 @@ +package synfron.reshaper.burp.ui.components.rules.thens; + +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.rules.thens.ThenTransform; +import synfron.reshaper.burp.core.rules.thens.entities.transform.TransformOption; +import synfron.reshaper.burp.core.vars.SetListItemPlacement; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.ui.components.rules.thens.transform.*; +import synfron.reshaper.burp.ui.models.rules.thens.ThenTransformModel; +import synfron.reshaper.burp.ui.models.rules.thens.transform.*; +import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.util.List; + +public class ThenTransformComponent extends ThenComponent { + private JComboBox transformOption; + private final JPanel transformerContainer = new JPanel(); + private JComboBox destinationVariableSource; + private JTextField destinationVariableName; + private JComboBox itemPlacement; + private JTextField delimiter; + private JTextField index; + + public ThenTransformComponent(ProtocolType protocolType, ThenTransformModel then) { + super(protocolType, then); + initComponent(); + } + + private TransformerComponent getTransformer() { + return switch (model.getTransformOption()) { + case Base64 -> new Base64TransformerComponent((Base64TransformerModel) model.getTransformer()); + case Escape -> new EscapeTransformerComponent((EscapeTransformerModel) model.getTransformer()); + case JwtDecode -> new JwtDecodeTransformerComponent((JwtDecodeTransformerModel) model.getTransformer()); + case Case -> new CaseTransformerComponent((CaseTransformerModel) model.getTransformer()); + case Hash -> new HashTransformerComponent((HashTransformerModel) model.getTransformer()); + case Hex -> new HexTransformerComponent((HexTransformerModel) model.getTransformer()); + case Integer -> new IntegerTransformerComponent((IntegerTransformerModel) model.getTransformer()); + case Trim -> new TrimTransformerComponent((TrimTransformerModel) model.getTransformer()); + }; + } + + private void initComponent() { + transformerContainer.setBorder(BorderFactory.createEmptyBorder(0, -12, 0, 0)); + transformOption = createComboBox(TransformOption.values()); + destinationVariableSource = createComboBox(VariableSource.getAllSettables(protocolType)); + destinationVariableName = createTextField(true); + itemPlacement = createComboBox(SetListItemPlacement.values()); + delimiter = createTextField(true); + index = createTextField(true); + + transformOption.setSelectedItem(model.getTransformOption()); + destinationVariableSource.setSelectedItem(model.getDestinationVariableSource()); + destinationVariableName.setText(model.getDestinationVariableName()); + itemPlacement.setSelectedItem(model.getItemPlacement()); + delimiter.setText(model.getDelimiter()); + index.setText(model.getIndex()); + + transformOption.addActionListener(this::onSetTransformOptionChanged); + destinationVariableSource.addActionListener(this::onDestinationVariableSourceChanged); + destinationVariableName.getDocument().addDocumentListener(new DocumentActionListener(this::onDestinationVariableNameChanged)); + itemPlacement.addActionListener(this::onItemPlacementChanged); + delimiter.getDocument().addDocumentListener(new DocumentActionListener(this::onDelimiterChanged)); + index.getDocument().addDocumentListener(new DocumentActionListener(this::onIndexChanged)); + + mainContainer.add(getLabeledField("Transform Option", transformOption), "wrap"); + mainContainer.add(transformerContainer, "wrap"); + mainContainer.add(getLabeledField("Destination Variable Source", destinationVariableSource), "wrap"); + mainContainer.add(getLabeledField("Destination Variable Name *", destinationVariableName), "wrap"); + mainContainer.add(ComponentVisibilityManager.withVisibilityFieldChangeDependency( + getLabeledField("Item Placement", itemPlacement), + destinationVariableSource, + () -> ((VariableSource)destinationVariableSource.getSelectedItem()).isList() + ), "wrap"); + mainContainer.add(ComponentVisibilityManager.withVisibilityFieldChangeDependency( + getLabeledField("Delimiter *", delimiter), + List.of(destinationVariableSource, itemPlacement), + () -> ((VariableSource)destinationVariableSource.getSelectedItem()).isList() && ((SetListItemPlacement)itemPlacement.getSelectedItem()).isHasDelimiterSetter() + ), "wrap"); + mainContainer.add(ComponentVisibilityManager.withVisibilityFieldChangeDependency( + getLabeledField("Index *", index), + List.of(destinationVariableSource, itemPlacement), + () -> ((VariableSource)destinationVariableSource.getSelectedItem()).isList() && ((SetListItemPlacement)itemPlacement.getSelectedItem()).isHasIndexSetter() + ), "wrap"); + + setTransformer(); + } + + private void setTransformer() { + TransformerComponent transformer = getTransformer(); + + transformerContainer.removeAll(); + transformerContainer.add(transformer); + revalidate(); + repaint(); + } + + private void onSetTransformOptionChanged(ActionEvent actionEvent) { + model.setTransformOption((TransformOption) transformOption.getSelectedItem()); + setTransformer(); + } + + private void onDestinationVariableSourceChanged(ActionEvent actionEvent) { + model.setDestinationVariableSource((VariableSource) destinationVariableSource.getSelectedItem()); + } + + private void onDestinationVariableNameChanged(ActionEvent actionEvent) { + model.setDestinationVariableName(destinationVariableName.getText()); + } + + private void onItemPlacementChanged(ActionEvent actionEvent) { + model.setItemPlacement((SetListItemPlacement)itemPlacement.getSelectedItem()); + } + + private void onDelimiterChanged(ActionEvent actionEvent) { + model.setDelimiter(delimiter.getText()); + } + + private void onIndexChanged(ActionEvent actionEvent) { + model.setIndex(index.getText()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/BytesGeneratorComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/BytesGeneratorComponent.java new file mode 100644 index 0000000..3539d80 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/BytesGeneratorComponent.java @@ -0,0 +1,40 @@ +package synfron.reshaper.burp.ui.components.rules.thens.generate; + +import synfron.reshaper.burp.core.messages.Encoder; +import synfron.reshaper.burp.ui.models.rules.thens.generate.IBytesGeneratorModel; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class BytesGeneratorComponent extends GeneratorComponent { + + private JTextField length; + private JComboBox encoding; + + public BytesGeneratorComponent(IBytesGeneratorModel model, boolean allowVariableTags) { + super(model, allowVariableTags); + } + + protected void initComponent() { + length = createTextField(allowVariableTags); + encoding = createComboBox(Encoder.getEncodings().toArray(new String[0]), true); + + length.setText(model.getLength()); + encoding.setSelectedItem(model.getEncoding()); + + length.getDocument().addDocumentListener(new DocumentActionListener(this::onLengthChanged)); + encoding.addActionListener(this::onEncodingChanged); + + add(getLabeledField("Length *", length), "wrap"); + add(getLabeledField("Encoding", encoding), "wrap"); + } + + private void onLengthChanged(ActionEvent actionEvent) { + model.setLength(length.getText()); + } + + private void onEncodingChanged(ActionEvent actionEvent) { + model.setEncoding((String) encoding.getSelectedItem()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/GeneratorComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/GeneratorComponent.java new file mode 100644 index 0000000..b74b858 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/GeneratorComponent.java @@ -0,0 +1,23 @@ +package synfron.reshaper.burp.ui.components.rules.thens.generate; + +import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.models.rules.thens.generate.IGeneratorModel; + +import javax.swing.*; + +public abstract class GeneratorComponent> extends JPanel implements IFormComponent { + + protected final T model; + protected final boolean allowVariableTags; + + public GeneratorComponent(T model, boolean allowVariableTags) { + this.model = model; + this.allowVariableTags = allowVariableTags; + setLayout(new MigLayout()); + setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + initComponent(); + } + + protected abstract void initComponent(); +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/IntegerGeneratorComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/IntegerGeneratorComponent.java new file mode 100644 index 0000000..d84af63 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/IntegerGeneratorComponent.java @@ -0,0 +1,48 @@ +package synfron.reshaper.burp.ui.components.rules.thens.generate; + +import synfron.reshaper.burp.ui.models.rules.thens.generate.IIntegerGeneratorModel; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class IntegerGeneratorComponent extends GeneratorComponent { + + private JTextField minValue; + private JTextField maxValue; + private JTextField base; + + public IntegerGeneratorComponent(IIntegerGeneratorModel model, boolean allowVariableTags) { + super(model, allowVariableTags); + } + + protected void initComponent() { + minValue = createTextField(allowVariableTags); + maxValue = createTextField(allowVariableTags); + base = createTextField(allowVariableTags); + + minValue.setText(model.getMinValue()); + maxValue.setText(model.getMaxValue()); + base.setText(model.getBase()); + + minValue.getDocument().addDocumentListener(new DocumentActionListener(this::onMinValueChanged)); + maxValue.getDocument().addDocumentListener(new DocumentActionListener(this::onMaxValueChanged)); + base.getDocument().addDocumentListener(new DocumentActionListener(this::onBaseChanged)); + + add(getLabeledField("Min Value *", minValue), "wrap"); + add(getLabeledField("Max Value (Exclusive) *", maxValue), "wrap"); + add(getLabeledField("Base", base), "wrap"); + } + + private void onMinValueChanged(ActionEvent actionEvent) { + model.setMinValue(minValue.getText()); + } + + private void onMaxValueChanged(ActionEvent actionEvent) { + model.setMaxValue(maxValue.getText()); + } + + private void onBaseChanged(ActionEvent actionEvent) { + model.setBase(base.getText()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/IpAddressGeneratorComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/IpAddressGeneratorComponent.java new file mode 100644 index 0000000..8288f80 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/IpAddressGeneratorComponent.java @@ -0,0 +1,30 @@ +package synfron.reshaper.burp.ui.components.rules.thens.generate; + +import synfron.reshaper.burp.core.utils.ValueGenerator; +import synfron.reshaper.burp.ui.models.rules.thens.generate.IIpAddressGeneratorModel; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class IpAddressGeneratorComponent extends GeneratorComponent { + + private JComboBox version; + + public IpAddressGeneratorComponent(IIpAddressGeneratorModel model, boolean allowVariableTags) { + super(model, allowVariableTags); + } + + protected void initComponent() { + version = createComboBox(ValueGenerator.IpVersion.values()); + + version.setSelectedItem(model.getVersion()); + + version.addActionListener(this::onVersionChanged); + + add(getLabeledField("Version", version), "wrap"); + } + + private void onVersionChanged(ActionEvent actionEvent) { + model.setVersion((ValueGenerator.IpVersion)version.getSelectedItem()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/PasswordGeneratorComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/PasswordGeneratorComponent.java new file mode 100644 index 0000000..582e5b2 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/PasswordGeneratorComponent.java @@ -0,0 +1,71 @@ +package synfron.reshaper.burp.ui.components.rules.thens.generate; + +import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.utils.PasswordCharacterGroup; +import synfron.reshaper.burp.ui.models.rules.thens.generate.IPasswordGeneratorModel; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; + +public class PasswordGeneratorComponent extends GeneratorComponent { + + private JTextField minLength; + private JTextField maxLength; + + public PasswordGeneratorComponent(IPasswordGeneratorModel model, boolean allowVariableTags) { + super(model, allowVariableTags); + } + + protected void initComponent() { + minLength = createTextField(allowVariableTags); + maxLength = createTextField(allowVariableTags); + + minLength.setText(model.getMinLength()); + maxLength.setText(model.getMaxLength()); + + minLength.getDocument().addDocumentListener(new DocumentActionListener(this::onMinLengthChanged)); + maxLength.getDocument().addDocumentListener(new DocumentActionListener(this::onMaxLengthChanged)); + + add(getLabeledField("Min Length *", minLength), "wrap"); + add(getLabeledField("Max Length (Exclusive) *", maxLength), "wrap"); + add(getCharacterGroupOptions(), "wrap"); + } + + private Component getCharacterGroupOptions() { + JPanel container = new JPanel(new MigLayout()); + + container.add(new JLabel("Character Groups *:"), "wrap"); + for (PasswordCharacterGroup group : PasswordCharacterGroup.values()) { + JCheckBox checkbox = new JCheckBox(group.toString()); + checkbox.putClientProperty("item", group); + + checkbox.setSelected(model.getCharacterGroups().contains(group)); + + checkbox.addActionListener(this::onPasswordGroupCheckboxChanged); + + container.add(checkbox, "wrap"); + } + + return container; + } + + private void onPasswordGroupCheckboxChanged(ActionEvent actionEvent) { + JCheckBox checkbox = (JCheckBox)actionEvent.getSource(); + PasswordCharacterGroup group = (PasswordCharacterGroup) checkbox.getClientProperty("item"); + if (checkbox.isSelected()) { + model.addPasswordCharacterGroups(group); + } else { + model.removePasswordCharacterGroups(group); + } + } + + private void onMinLengthChanged(ActionEvent actionEvent) { + model.setMinLength(minLength.getText()); + } + + private void onMaxLengthChanged(ActionEvent actionEvent) { + model.setMaxLength(maxLength.getText()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/TimestampGeneratorComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/TimestampGeneratorComponent.java new file mode 100644 index 0000000..853d1b2 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/TimestampGeneratorComponent.java @@ -0,0 +1,48 @@ +package synfron.reshaper.burp.ui.components.rules.thens.generate; + +import synfron.reshaper.burp.ui.models.rules.thens.generate.ITimestampGeneratorModel; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class TimestampGeneratorComponent extends GeneratorComponent { + + private JTextField format; + private JTextField minTimestamp; + private JTextField maxTimestamp; + + public TimestampGeneratorComponent(ITimestampGeneratorModel model, boolean allowVariableTags) { + super(model, allowVariableTags); + } + + protected void initComponent() { + format = createTextField(allowVariableTags); + minTimestamp = createTextField(allowVariableTags); + maxTimestamp = createTextField(allowVariableTags); + + format.setText(model.getFormat()); + minTimestamp.setText(model.getMinTimestamp()); + maxTimestamp.setText(model.getMaxTimestamp()); + + format.getDocument().addDocumentListener(new DocumentActionListener(this::onFormatChanged)); + minTimestamp.getDocument().addDocumentListener(new DocumentActionListener(this::onMinTimestampChanged)); + maxTimestamp.getDocument().addDocumentListener(new DocumentActionListener(this::onMaxTimestampChanged)); + + add(getLabeledField("Format", format), "wrap"); + add(getLabeledField("Min Timestamp", minTimestamp), "wrap"); + add(getLabeledField("Max Timestamp (Exclusive)", maxTimestamp), "wrap"); + } + + private void onFormatChanged(ActionEvent actionEvent) { + model.setFormat(format.getText()); + } + + private void onMinTimestampChanged(ActionEvent actionEvent) { + model.setMinTimestamp(minTimestamp.getText()); + } + + private void onMaxTimestampChanged(ActionEvent actionEvent) { + model.setMaxTimestamp(maxTimestamp.getText()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/UnixTimestampGeneratorComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/UnixTimestampGeneratorComponent.java new file mode 100644 index 0000000..2263b66 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/UnixTimestampGeneratorComponent.java @@ -0,0 +1,48 @@ +package synfron.reshaper.burp.ui.components.rules.thens.generate; + +import synfron.reshaper.burp.ui.models.rules.thens.generate.IUnixTimestampGeneratorModel; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class UnixTimestampGeneratorComponent extends GeneratorComponent { + + private JTextField format; + private JTextField minTimestamp; + private JTextField maxTimestamp; + + public UnixTimestampGeneratorComponent(IUnixTimestampGeneratorModel model, boolean allowVariableTags) { + super(model, allowVariableTags); + } + + protected void initComponent() { + format = createTextField(allowVariableTags); + minTimestamp = createTextField(allowVariableTags); + maxTimestamp = createTextField(allowVariableTags); + + format.setText(model.getFormat()); + minTimestamp.setText(model.getMinTimestamp()); + maxTimestamp.setText(model.getMaxTimestamp()); + + format.getDocument().addDocumentListener(new DocumentActionListener(this::onFormatChanged)); + minTimestamp.getDocument().addDocumentListener(new DocumentActionListener(this::onMinTimestampChanged)); + maxTimestamp.getDocument().addDocumentListener(new DocumentActionListener(this::onMaxTimestampChanged)); + + add(getLabeledField("Min/Max Timestamp Format", format), "wrap"); + add(getLabeledField("Min Timestamp", minTimestamp), "wrap"); + add(getLabeledField("Max Timestamp (Exclusive)", maxTimestamp), "wrap"); + } + + private void onFormatChanged(ActionEvent actionEvent) { + model.setFormat(format.getText()); + } + + private void onMinTimestampChanged(ActionEvent actionEvent) { + model.setMinTimestamp(minTimestamp.getText()); + } + + private void onMaxTimestampChanged(ActionEvent actionEvent) { + model.setMaxTimestamp(maxTimestamp.getText()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/UuidGeneratorComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/UuidGeneratorComponent.java new file mode 100644 index 0000000..a65e37f --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/UuidGeneratorComponent.java @@ -0,0 +1,58 @@ +package synfron.reshaper.burp.ui.components.rules.thens.generate; + +import synfron.reshaper.burp.core.utils.ValueGenerator; +import synfron.reshaper.burp.ui.models.rules.thens.generate.IUuidGeneratorModel; +import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class UuidGeneratorComponent extends GeneratorComponent { + + private JComboBox version; + private JTextField namespace; + private JTextField name; + + public UuidGeneratorComponent(IUuidGeneratorModel model, boolean allowVariableTags) { + super(model, allowVariableTags); + } + + protected void initComponent() { + version = createComboBox(ValueGenerator.UuidVersion.values()); + namespace = createTextField(allowVariableTags); + name = createTextField(allowVariableTags); + + version.setSelectedItem(model.getVersion()); + namespace.setText(model.getNamespace()); + name.setText(model.getName()); + + version.addActionListener(this::onVersionChanged); + namespace.getDocument().addDocumentListener(new DocumentActionListener(this::onNamespaceChanged)); + name.getDocument().addDocumentListener(new DocumentActionListener(this::onNameChanged)); + + add(getLabeledField("Version", version), "wrap"); + add(ComponentVisibilityManager.withVisibilityFieldChangeDependency( + getLabeledField("Namespace (UUID) *", namespace), + version, + () -> ((ValueGenerator.UuidVersion)version.getSelectedItem()).isHasInputs() + ), "wrap"); + add(ComponentVisibilityManager.withVisibilityFieldChangeDependency( + getLabeledField("Name *", name), + version, + () -> ((ValueGenerator.UuidVersion)version.getSelectedItem()).isHasInputs() + ), "wrap"); + } + + private void onVersionChanged(ActionEvent actionEvent) { + model.setVersion((ValueGenerator.UuidVersion)version.getSelectedItem()); + } + + private void onNamespaceChanged(ActionEvent actionEvent) { + model.setNamespace(namespace.getText()); + } + + private void onNameChanged(ActionEvent actionEvent) { + model.setName(name.getText()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/WordGeneratorComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/WordGeneratorComponent.java new file mode 100644 index 0000000..4df5f7e --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/generate/WordGeneratorComponent.java @@ -0,0 +1,54 @@ +package synfron.reshaper.burp.ui.components.rules.thens.generate; + +import synfron.reshaper.burp.core.utils.ValueGenerator; +import synfron.reshaper.burp.ui.models.rules.thens.generate.IWordGeneratorModel; +import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class WordGeneratorComponent extends GeneratorComponent { + + private JComboBox generatorType; + private JTextField count; + private JTextField separator; + + public WordGeneratorComponent(IWordGeneratorModel model, boolean allowVariableTags) { + super(model, allowVariableTags); + } + + protected void initComponent() { + generatorType = createComboBox(ValueGenerator.WordGeneratorType.values()); + count = createTextField(allowVariableTags); + separator = createTextField(allowVariableTags); + + generatorType.setSelectedItem(model.getGeneratorType()); + count.setText(model.getCount()); + separator.setText(model.getSeparator()); + + generatorType.addActionListener(this::onGeneratorTypeChanged); + count.getDocument().addDocumentListener(new DocumentActionListener(this::onCountChanged)); + separator.getDocument().addDocumentListener(new DocumentActionListener(this::onSeparatorChanged)); + + add(getLabeledField("Generator Type", generatorType), "wrap"); + add(getLabeledField("Count *", count), "wrap"); + add(ComponentVisibilityManager.withVisibilityFieldChangeDependency( + getLabeledField("Separator", separator), + count, + () -> !"1".equals(count.getText()) + ), "wrap"); + } + + private void onGeneratorTypeChanged(ActionEvent actionEvent) { + model.setGeneratorType((ValueGenerator.WordGeneratorType)generatorType.getSelectedItem()); + } + + private void onCountChanged(ActionEvent actionEvent) { + model.setCount(count.getText()); + } + + private void onSeparatorChanged(ActionEvent actionEvent) { + model.setSeparator(separator.getText()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/Base64TransformerComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/Base64TransformerComponent.java new file mode 100644 index 0000000..9c106f1 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/Base64TransformerComponent.java @@ -0,0 +1,50 @@ +package synfron.reshaper.burp.ui.components.rules.thens.transform; + +import synfron.reshaper.burp.core.messages.Encoder; +import synfron.reshaper.burp.core.rules.thens.entities.transform.Base64Variant; +import synfron.reshaper.burp.core.rules.thens.entities.transform.EncodeTransform; +import synfron.reshaper.burp.ui.models.rules.thens.transform.Base64TransformerModel; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class Base64TransformerComponent extends TransformerComponent { + + private JComboBox variant; + private JComboBox action; + private JComboBox encoding; + + public Base64TransformerComponent(Base64TransformerModel model) { + super(model); + } + + protected void initComponent() { + action = createComboBox(EncodeTransform.values()); + variant = createComboBox(Base64Variant.values()); + encoding = createComboBox(Encoder.getEncodings().toArray(new String[0]), true); + + variant.setSelectedItem(model.getVariant()); + action.setSelectedItem(model.getAction()); + encoding.setSelectedItem(model.getEncoding()); + + variant.addActionListener(this::onVariantChanged); + action.addActionListener(this::onActionChanged); + encoding.addActionListener(this::onEncodingChanged); + + add(getLabeledField("Variant", variant), "wrap"); + add(getLabeledField("Action", action), "wrap"); + add(getLabeledField("Encoding", encoding), "wrap"); + } + + private void onActionChanged(ActionEvent actionEvent) { + model.setAction((EncodeTransform)action.getSelectedItem()); + } + + private void onVariantChanged(ActionEvent actionEvent) { + model.setVariant((Base64Variant)variant.getSelectedItem()); + } + + private void onEncodingChanged(ActionEvent actionEvent) { + model.setEncoding((String) encoding.getSelectedItem()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/CaseTransformerComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/CaseTransformerComponent.java new file mode 100644 index 0000000..c422ba0 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/CaseTransformerComponent.java @@ -0,0 +1,30 @@ +package synfron.reshaper.burp.ui.components.rules.thens.transform; + +import synfron.reshaper.burp.core.utils.PhraseCase; +import synfron.reshaper.burp.ui.models.rules.thens.transform.CaseTransformerModel; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class CaseTransformerComponent extends TransformerComponent { + + private JComboBox phraseCase; + + public CaseTransformerComponent(CaseTransformerModel model) { + super(model); + } + + protected void initComponent() { + phraseCase = createComboBox(PhraseCase.values()); + + phraseCase.setSelectedItem(model.getPhraseCase()); + + phraseCase.addActionListener(this::onPhraseCaseChanged); + + add(getLabeledField("Phrase Case", phraseCase), "wrap"); + } + + private void onPhraseCaseChanged(ActionEvent actionEvent) { + model.setPhraseCase((PhraseCase)phraseCase.getSelectedItem()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/EscapeTransformerComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/EscapeTransformerComponent.java new file mode 100644 index 0000000..73e16b1 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/EscapeTransformerComponent.java @@ -0,0 +1,40 @@ +package synfron.reshaper.burp.ui.components.rules.thens.transform; + +import synfron.reshaper.burp.core.rules.thens.entities.transform.EntityType; +import synfron.reshaper.burp.core.rules.thens.entities.transform.EscapeTransform; +import synfron.reshaper.burp.ui.models.rules.thens.transform.EscapeTransformerModel; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class EscapeTransformerComponent extends TransformerComponent { + + private JComboBox entityType; + private JComboBox action; + + public EscapeTransformerComponent(EscapeTransformerModel model) { + super(model); + } + + protected void initComponent() { + action = createComboBox(EscapeTransform.values()); + entityType = createComboBox(EntityType.values()); + + entityType.setSelectedItem(model.getEntityType()); + action.setSelectedItem(model.getAction()); + + entityType.addActionListener(this::onEntityTypeChanged); + action.addActionListener(this::onActionChanged); + + add(getLabeledField("Entity Type", entityType), "wrap"); + add(getLabeledField("Action", action), "wrap"); + } + + private void onActionChanged(ActionEvent actionEvent) { + model.setAction((EscapeTransform)action.getSelectedItem()); + } + + private void onEntityTypeChanged(ActionEvent actionEvent) { + model.setEntityType((EntityType)entityType.getSelectedItem()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/HashTransformerComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/HashTransformerComponent.java new file mode 100644 index 0000000..fe70afa --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/HashTransformerComponent.java @@ -0,0 +1,30 @@ +package synfron.reshaper.burp.ui.components.rules.thens.transform; + +import synfron.reshaper.burp.core.rules.thens.entities.transform.HashType; +import synfron.reshaper.burp.ui.models.rules.thens.transform.HashTransformerModel; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class HashTransformerComponent extends TransformerComponent { + + private JComboBox hashType; + + public HashTransformerComponent(HashTransformerModel model) { + super(model); + } + + protected void initComponent() { + hashType = createComboBox(HashType.values()); + + hashType.setSelectedItem(model.getHashType()); + + hashType.addActionListener(this::onHashTypeChanged); + + add(getLabeledField("Hash Type", hashType), "wrap"); + } + + private void onHashTypeChanged(ActionEvent actionEvent) { + model.setHashType((HashType)hashType.getSelectedItem()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/HexTransformerComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/HexTransformerComponent.java new file mode 100644 index 0000000..bd7c6a8 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/HexTransformerComponent.java @@ -0,0 +1,40 @@ +package synfron.reshaper.burp.ui.components.rules.thens.transform; + +import synfron.reshaper.burp.core.messages.Encoder; +import synfron.reshaper.burp.core.rules.thens.entities.transform.TextTransform; +import synfron.reshaper.burp.ui.models.rules.thens.transform.HexTransformerModel; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class HexTransformerComponent extends TransformerComponent { + + private JComboBox action; + private JComboBox encoding; + + public HexTransformerComponent(HexTransformerModel model) { + super(model); + } + + protected void initComponent() { + action = createComboBox(TextTransform.values()); + encoding = createComboBox(Encoder.getEncodings().toArray(new String[0]), true); + + action.setSelectedItem(model.getAction()); + encoding.setSelectedItem(model.getEncoding()); + + action.addActionListener(this::onActionChanged); + encoding.addActionListener(this::onEncodingChanged); + + add(getLabeledField("Action", action), "wrap"); + add(getLabeledField("Encoding", encoding), "wrap"); + } + + private void onActionChanged(ActionEvent actionEvent) { + model.setAction((TextTransform)action.getSelectedItem()); + } + + private void onEncodingChanged(ActionEvent actionEvent) { + model.setEncoding((String) encoding.getSelectedItem()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/IntegerTransformerComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/IntegerTransformerComponent.java new file mode 100644 index 0000000..db6f519 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/IntegerTransformerComponent.java @@ -0,0 +1,39 @@ +package synfron.reshaper.burp.ui.components.rules.thens.transform; + +import synfron.reshaper.burp.ui.models.rules.thens.transform.IntegerTransformerModel; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class IntegerTransformerComponent extends TransformerComponent { + + private JTextField sourceBase; + private JTextField targetBase; + + public IntegerTransformerComponent(IntegerTransformerModel model) { + super(model); + } + + protected void initComponent() { + sourceBase = createTextField(true); + targetBase = createTextField(true); + + sourceBase.setText(model.getSourceBase()); + targetBase.setText(model.getTargetBase()); + + sourceBase.getDocument().addDocumentListener(new DocumentActionListener(this::onSourceBaseChanged)); + targetBase.getDocument().addDocumentListener(new DocumentActionListener(this::onTargetBaseChanged)); + + add(getLabeledField("Source Base", sourceBase), "wrap"); + add(getLabeledField("Target Base", targetBase), "wrap"); + } + + private void onSourceBaseChanged(ActionEvent actionEvent) { + model.setSourceBase(sourceBase.getText()); + } + + private void onTargetBaseChanged(ActionEvent actionEvent) { + model.setTargetBase(targetBase.getText()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/JwtDecodeTransformerComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/JwtDecodeTransformerComponent.java new file mode 100644 index 0000000..bcb9520 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/JwtDecodeTransformerComponent.java @@ -0,0 +1,30 @@ +package synfron.reshaper.burp.ui.components.rules.thens.transform; + +import synfron.reshaper.burp.core.rules.thens.entities.transform.JwtSegment; +import synfron.reshaper.burp.ui.models.rules.thens.transform.JwtDecodeTransformerModel; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class JwtDecodeTransformerComponent extends TransformerComponent { + + private JComboBox segment; + + public JwtDecodeTransformerComponent(JwtDecodeTransformerModel model) { + super(model); + } + + protected void initComponent() { + segment = createComboBox(JwtSegment.values()); + + segment.setSelectedItem(model.getSegment()); + + segment.addActionListener(this::onSegmentChanged); + + add(getLabeledField("Segment", segment), "wrap"); + } + + private void onSegmentChanged(ActionEvent actionEvent) { + model.setSegment((JwtSegment)segment.getSelectedItem()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/TransformerComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/TransformerComponent.java new file mode 100644 index 0000000..66c3874 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/TransformerComponent.java @@ -0,0 +1,38 @@ +package synfron.reshaper.burp.ui.components.rules.thens.transform; + +import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.models.rules.thens.transform.TransformerModel; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public abstract class TransformerComponent> extends JPanel implements IFormComponent { + + protected final T model; + private JTextField input; + + public TransformerComponent(T model) { + this.model = model; + + setLayout(new MigLayout()); + setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); + + input = createTextField(true); + + input.setText(model.getInput()); + + input.getDocument().addDocumentListener(new DocumentActionListener(this::onInputChanged)); + + add(getLabeledField("Input *", input), "wrap"); + + initComponent(); + } + + protected abstract void initComponent(); + + private void onInputChanged(ActionEvent actionEvent) { + model.setInput(input.getText()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/TrimTransformerComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/TrimTransformerComponent.java new file mode 100644 index 0000000..99f50b9 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/transform/TrimTransformerComponent.java @@ -0,0 +1,40 @@ +package synfron.reshaper.burp.ui.components.rules.thens.transform; + +import synfron.reshaper.burp.core.rules.thens.entities.transform.TrimOption; +import synfron.reshaper.burp.ui.models.rules.thens.transform.TrimTransformerModel; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class TrimTransformerComponent extends TransformerComponent { + + private JComboBox trimOption; + private JTextField characters; + + public TrimTransformerComponent(TrimTransformerModel model) { + super(model); + } + + protected void initComponent() { + trimOption = createComboBox(TrimOption.values()); + characters = createTextField(true); + + trimOption.setSelectedItem(model.getTrimOption()); + characters.setText(model.getCharacters()); + + trimOption.addActionListener(this::onTrimOptionChanged); + characters.getDocument().addDocumentListener(new DocumentActionListener(this::onCharactersChanged)); + + add(getLabeledField("Trim Option", trimOption), "wrap"); + add(getLabeledField("Trim Characters", characters), "wrap"); + } + + private void onTrimOptionChanged(ActionEvent actionEvent) { + model.setTrimOption((TrimOption)trimOption.getSelectedItem()); + } + + private void onCharactersChanged(ActionEvent actionEvent) { + model.setCharacters(characters.getText()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenContainerComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenContainerComponent.java index 1b90e57..47d5fb3 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenContainerComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenContainerComponent.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.components.rules.whens; import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.ui.components.rules.RuleOperationComponent; import synfron.reshaper.burp.ui.components.rules.RuleOperationContainerComponent; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; import synfron.reshaper.burp.ui.models.rules.whens.WhenModelType; @@ -10,7 +11,7 @@ public class WhenContainerComponent extends RuleOperationContainerComponent { - private final static Map, Class> componentMap; + private final static Map, Class>> componentMap; static { componentMap = new HashMap<>(); @@ -32,7 +33,7 @@ public WhenContainerComponent(ProtocolType protocolType) { } @Override - protected Map, Class> getComponentMap() { + protected Map, Class>> getComponentMap() { return componentMap; } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenListComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenListComponent.java index ffee4b5..8b54740 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenListComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenListComponent.java @@ -1,6 +1,9 @@ package synfron.reshaper.burp.ui.components.rules.whens; +import burp.BurpExtender; import synfron.reshaper.burp.core.ProtocolType; +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.core.rules.whens.When; import synfron.reshaper.burp.ui.components.rules.RuleOperationListComponent; @@ -11,11 +14,15 @@ import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; public class WhenListComponent extends RuleOperationListComponent> { + private final IEventListener generalSettingsChangedListener = this::onGeneralSettingsChanged; + public WhenListComponent(ProtocolType protocolType, RuleModel model) { super(protocolType, model); + BurpExtender.getGeneralSettings().withListener(generalSettingsChangedListener); } @Override @@ -23,9 +30,17 @@ public WhenListComponent(ProtocolType protocolType, RuleModel model) { return model.getWhens(); } + private void onGeneralSettingsChanged(PropertyChangedArgs propertyChangedArgs) { + if (propertyChangedArgs.getName().equals("hiddenWhenTypes")) { + syncOperationSelectorList(); + } + } + @Override protected List> getRuleOperationModelTypes() { - return Collections.unmodifiableList(WhenModelType.getTypes(protocolType)); + return WhenModelType.getTypes(protocolType).stream() + .filter(type -> !BurpExtender.getGeneralSettings().getHiddenWhenTypes().contains(type.getName())) + .collect(Collectors.toList()); } @Override diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/GeneratorVariableTagWizardComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/GeneratorVariableTagWizardComponent.java new file mode 100644 index 0000000..c464aa1 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/GeneratorVariableTagWizardComponent.java @@ -0,0 +1,64 @@ +package synfron.reshaper.burp.ui.components.rules.wizard.vars; + +import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.rules.thens.entities.generate.GenerateOption; +import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.components.rules.thens.generate.*; +import synfron.reshaper.burp.ui.models.rules.wizard.vars.GeneratorVariableTagWizardModel; +import synfron.reshaper.burp.ui.models.rules.wizard.vars.generator.*; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class GeneratorVariableTagWizardComponent extends JPanel implements IFormComponent { + private final GeneratorVariableTagWizardModel model; + private final JPanel generatorContainer = new JPanel(); + private JComboBox generateOption; + + public GeneratorVariableTagWizardComponent(GeneratorVariableTagWizardModel model) { + this.model = model; + initComponent(); + } + + private GeneratorComponent getGenerator() { + return switch (model.getGenerateOption()) { + case Uuid -> new UuidGeneratorComponent((UuidGeneratorVariableModel) model.getGenerator(), false); + case Words -> new WordGeneratorComponent((WordGeneratorVariableModel) model.getGenerator(), false); + case Bytes -> new BytesGeneratorComponent((BytesGeneratorVariableModel) model.getGenerator(), false); + case Integer -> new IntegerGeneratorComponent((IntegerGeneratorVariableModel) model.getGenerator(), false); + case IpAddress -> new IpAddressGeneratorComponent((IpAddressGeneratorVariableModel) model.getGenerator(), false); + case Timestamp -> new TimestampGeneratorComponent((TimestampGeneratorVariableModel) model.getGenerator(), false); + case UnixTimestamp -> new UnixTimestampGeneratorComponent((UnixTimestampGeneratorVariableModel) model.getGenerator(), false); + case Password -> new PasswordGeneratorComponent((PasswordGeneratorVariableModel) model.getGenerator(), false); + }; + } + + private void initComponent() { + setLayout(new MigLayout()); + generatorContainer.setBorder(BorderFactory.createEmptyBorder(0, -12, 0, 0)); + generateOption = createComboBox(GenerateOption.values()); + + generateOption.setSelectedItem(model.getGenerateOption()); + + generateOption.addActionListener(this::onSetGenerateOptionChanged); + + add(getLabeledField("Generate Option", generateOption), "wrap"); + add(generatorContainer, "wrap"); + + setGenerator(); + } + + private void setGenerator() { + GeneratorComponent generator = getGenerator(); + + generatorContainer.removeAll(); + generatorContainer.add(generator); + revalidate(); + repaint(); + } + + private void onSetGenerateOptionChanged(ActionEvent actionEvent) { + model.setGenerateOption((GenerateOption) generateOption.getSelectedItem()); + setGenerator(); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardContainerComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardContainerComponent.java index 748896d..b1a850c 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardContainerComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardContainerComponent.java @@ -35,6 +35,7 @@ public void setModel(IVariableTagWizardModel model) { case Special -> new SpecialVariableTagWizardComponent((SpecialVariableTagWizardModel) model); case CookieJar -> new CookieJarVariableTagWizardComponent((CookieJarVariableTagWizardModel) model); case Macro -> new MacroVariableTagWizardComponent((MacroVariableTagWizardModel) model, protocolType); + case Generator -> new GeneratorVariableTagWizardComponent((GeneratorVariableTagWizardModel) model); }; add(component); } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/HideItemsOptionPane.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/HideItemsOptionPane.java new file mode 100644 index 0000000..aa72187 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/HideItemsOptionPane.java @@ -0,0 +1,132 @@ +package synfron.reshaper.burp.ui.components.settings; + +import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.Tab; +import synfron.reshaper.burp.core.rules.thens.ThenType; +import synfron.reshaper.burp.core.rules.whens.WhenType; +import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.models.settings.HideItemsModel; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.util.HashSet; +import java.util.stream.Stream; + +public class HideItemsOptionPane extends JOptionPane implements IFormComponent { + + private final JPanel container; + private final HideItemsModel model; + + private HideItemsOptionPane(HideItemsModel model) { + super(new JPanel(new BorderLayout()), JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION); + container = (JPanel)message; + this.model = model; + addPropertyChangeListener(JOptionPane.VALUE_PROPERTY, this::onPropertyChanged); + initComponent(); + } + + private void onPropertyChanged(PropertyChangeEvent event) { + if (getValue() != null && (int)getValue() == JOptionPane.OK_OPTION) { + model.save(); + } else { + model.setDismissed(true); + } + } + + public static void showDialog(HideItemsModel model) { + HideItemsOptionPane optionPane = new HideItemsOptionPane(model); + JDialog dialog = optionPane.createDialog("Hide Features"); + dialog.setResizable(true); + + dialog.setModal(false); + dialog.setVisible(true); + } + + private void initComponent() { + container.add(getBody(), BorderLayout.CENTER); + } + + private void addCheckboxes(JPanel container, int maxRowLength, java.util.List items, HashSet checkedItems, ActionListener checkboxChangedListener) { + int rowItemCount = 1; + int totalCount = 0; + for (T item : items) { + totalCount++; + JCheckBox checkbox = new JCheckBox(item.toString()); + checkbox.putClientProperty("item", item); + + checkbox.setSelected(checkedItems.contains(item)); + + checkbox.addActionListener(checkboxChangedListener); + + container.add(checkbox, rowItemCount == maxRowLength || totalCount == items.size() ? "wrap" : ""); + + if (rowItemCount < maxRowLength) { + rowItemCount++; + } else { + rowItemCount = 1; + } + } + } + + private void onHiddenTabChanged(ActionEvent actionEvent) { + JCheckBox checkbox = (JCheckBox) actionEvent.getSource(); + Tab item = (Tab) checkbox.getClientProperty("item"); + + if (checkbox.isSelected()) { + model.addHiddenTab(item); + } else { + model.removeHiddenTab(item); + } + } + + private void onHiddenWhenTypeChanged(ActionEvent actionEvent) { + JCheckBox checkbox = (JCheckBox) actionEvent.getSource(); + String item = (String) checkbox.getClientProperty("item"); + + if (checkbox.isSelected()) { + model.addHiddenWhenType(item); + } else { + model.removeHiddenWhenType(item); + } + } + + private void onHiddenThenTypeChanged(ActionEvent actionEvent) { + JCheckBox checkbox = (JCheckBox) actionEvent.getSource(); + String item = (String) checkbox.getClientProperty("item"); + + if (checkbox.isSelected()) { + model.addHiddenThenType(item); + } else { + model.removeHiddenThenType(item); + } + } + + private Component getBody() { + JPanel container = new JPanel(new MigLayout()); + + JPanel hideTabs = new JPanel(new MigLayout()); + hideTabs.setBorder(BorderFactory.createEmptyBorder(4,4,4,4)); + hideTabs.add(new JLabel("Hide Tabs:"), "wrap"); + addCheckboxes(hideTabs, 4, Stream.of(Tab.values()).filter(Tab::isHideable).toList(), model.getHiddenTabs(), this::onHiddenTabChanged); + + JPanel hideWhenTypes = new JPanel(new MigLayout()); + hideWhenTypes.setBorder(BorderFactory.createEmptyBorder(4,4,4,4)); + hideWhenTypes.add(new JLabel("Hide When Type Options:"), "wrap"); + addCheckboxes(hideWhenTypes, 4, WhenType.getTypes().stream().map(WhenType::getName).sorted().distinct().toList(), model.getHiddenWhenTypes(), this::onHiddenWhenTypeChanged); + + + JPanel hideThenTypes = new JPanel(new MigLayout()); + hideThenTypes.setBorder(BorderFactory.createEmptyBorder(4,4,4,4)); + hideThenTypes.add(new JLabel("Hide Then Type Options:"), "wrap"); + addCheckboxes(hideThenTypes, 4, ThenType.getTypes().stream().map(ThenType::getName).sorted().distinct().toList(), model.getHiddenThenTypes(), this::onHiddenThenTypeChanged); + + container.add(hideTabs, "wrap"); + container.add(hideWhenTypes, "wrap"); + container.add(hideThenTypes, "wrap"); + + return container; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/SelectionTable.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/SelectionTable.java index 3f5f3e9..c4c0463 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/SelectionTable.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/SelectionTable.java @@ -53,7 +53,7 @@ private void onSelectAllChanged(ActionEvent actionEvent) { private void onTableChanged(TableModelEvent e) { if (e.getType() == TableModelEvent.UPDATE && e.getFirstRow() >= 0) { Vector row = tableModel.getDataVector().get(e.getFirstRow()); - boolean checkboxState = (Boolean) row.get(0); + boolean checkboxState = (Boolean) row.getFirst(); checkboxStateMap.put(row.get(1), checkboxState); if (!checkboxState && selectAll.isSelected()) { selectAll.setSelected(false); @@ -64,7 +64,7 @@ private void onTableChanged(TableModelEvent e) { @SuppressWarnings("unchecked") public List getSelectedValues() { return tableModel.getDataVector().stream() - .filter(row -> (boolean)row.get(0)) + .filter(row -> (boolean)row.getFirst()) .map(row -> (T)row.get(1)) .toList(); } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/SettingsTabComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/SettingsTabComponent.java index 207763d..6edb64f 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/SettingsTabComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/settings/SettingsTabComponent.java @@ -16,16 +16,15 @@ import synfron.reshaper.burp.core.vars.GlobalVariables; import synfron.reshaper.burp.core.vars.Variable; import synfron.reshaper.burp.ui.components.IFormComponent; -import synfron.reshaper.burp.ui.components.ITabActivationListener; +import synfron.reshaper.burp.ui.models.settings.HideItemsModel; import synfron.reshaper.burp.ui.utils.FocusActionListener; +import synfron.reshaper.burp.ui.utils.ModalPrompter; import javax.swing.*; import javax.swing.border.CompoundBorder; import javax.swing.filechooser.FileNameExtensionFilter; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.FocusEvent; -import java.awt.event.ItemEvent; +import java.awt.event.*; import java.io.File; import java.net.URL; import java.net.URLConnection; @@ -35,7 +34,7 @@ import java.util.Objects; import java.util.stream.Collectors; -public class SettingsTabComponent extends JPanel implements IFormComponent, ITabActivationListener { +public class SettingsTabComponent extends JPanel implements IFormComponent, HierarchyListener { private JCheckBox overwriteDuplicates; private SelectionTable exportHttpRulesTable; @@ -57,6 +56,8 @@ public class SettingsTabComponent extends JPanel implements IFormComponent, ITab private JCheckBox webSockets; private ButtonGroup importMethod; private ButtonGroup exportMethod; + private JSplitButton exportData; + private JSplitButton importData; public SettingsTabComponent() { initComponent(); @@ -77,12 +78,33 @@ private Component getGeneralSettings() { BorderFactory.createEmptyBorder(4,4,4,4)) ); - container.add(getMiscOptions()); - container.add(getCaptureTrafficOptions(), "top"); + container.add(LeftGeneralOptions()); + container.add(RightGeneralOptions(), "top"); return container; } - private Component getMiscOptions() { + private void onHideFeatures(ActionEvent actionEvent) { + HideItemsModel model = new HideItemsModel(generalSettings); + ModalPrompter.open(model, ignored -> HideItemsOptionPane.showDialog(model), true); + } + + private Component RightGeneralOptions() { + JPanel container = new JPanel(new MigLayout()); + container.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 0)); + + defaultEncoding = createComboBox(Encoder.getEncodings().toArray(new String[0])); + + defaultEncoding.setSelectedItem(generalSettings.getDefaultEncoding()); + + defaultEncoding.addActionListener(this::onSetDefaultEncodingChanged); + + + container.add(getLabeledField("Default Encoding", defaultEncoding), "wrap"); + container.add(getCaptureTrafficOptions(), "wrap"); + return container; + } + + private Component LeftGeneralOptions() { JPanel container = new JPanel(new MigLayout()); enableEventDiagnostics = new JCheckBox("Enable Event Diagnostics"); @@ -90,7 +112,7 @@ private Component getMiscOptions() { enableSanityCheckWarnings = new JCheckBox("Enable Sanity Check Warnings"); logInExtenderOutput = new JCheckBox("Replicate Logs in Extender Output"); logTabCharacterLimit = createTextField(false); - defaultEncoding = createComboBox(Encoder.getEncodings().toArray(new String[0])); + JButton hideFeatures = new JButton("Hide Features"); JButton resetData = new JButton("Reset Data"); enableEventDiagnostics.setSelected(generalSettings.isEnableEventDiagnostics()); @@ -98,14 +120,13 @@ private Component getMiscOptions() { enableSanityCheckWarnings.setSelected(generalSettings.isEnableSanityCheckWarnings()); logInExtenderOutput.setSelected(generalSettings.isLogInExtenderOutput()); logTabCharacterLimit.setText(Objects.toString(generalSettings.getLogTabCharacterLimit())); - defaultEncoding.setSelectedItem(generalSettings.getDefaultEncoding()); enableEventDiagnostics.addActionListener(this::onEnableEventDiagnosticsChanged); diagnosticValueMaxLength.addFocusListener(new FocusActionListener(this::onDiagnosticValueMaxLengthFocusChanged)); enableSanityCheckWarnings.addActionListener(this::onEnableSanityCheckWarningsChanged); logInExtenderOutput.addActionListener(this::onLogInExtenderOutputChanged); logTabCharacterLimit.addFocusListener(new FocusActionListener(this::onLogTabCharacterLimitFocusChanged)); - defaultEncoding.addActionListener(this::onSetDefaultEncodingChanged); + hideFeatures.addActionListener(this::onHideFeatures); resetData.addActionListener(this::onResetData); @@ -114,14 +135,16 @@ private Component getMiscOptions() { container.add(enableSanityCheckWarnings, "wrap"); container.add(logInExtenderOutput, "wrap"); container.add(getLabeledField("Logs Tab Character Limit", logTabCharacterLimit), "wrap"); - container.add(getLabeledField("Default Encoding", defaultEncoding), "wrap"); - container.add(resetData, "wrap"); + + JPanel buttons = new JPanel(new FlowLayout()); + buttons.add(hideFeatures); + buttons.add(resetData); + container.add(buttons); return container; } private Component getCaptureTrafficOptions() { JPanel container = new JPanel(new MigLayout()); - container.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 0)); proxy = new JCheckBox("Proxy"); repeater = new JCheckBox("Repeater"); @@ -255,7 +278,7 @@ private Component getExportSettings() { } private JSplitButton getExportDataButton() { - JSplitButton exportData = new JSplitButton("Export Data "); + exportData = new JSplitButton("Export Data (JSON) "); JPopupMenu exportOptions = new JPopupMenu(); @@ -268,6 +291,8 @@ private JSplitButton getExportDataButton() { exportFromYaml.setSelected(generalSettings.getExportMethod() == GeneralSettings.ExportMethod.Yaml); exportFromYaml.setActionCommand(GeneralSettings.ExportMethod.Yaml.name()); + setExportDataSelection(exportFromYaml); + exportData.addButtonClickedActionListener(this::onExportData); exportFromYaml.addItemListener(this::onExportMethodChange); @@ -298,7 +323,7 @@ private Component getImportSettings() { } private JSplitButton getImportDataButton() { - JSplitButton importData = new JSplitButton("Import Data "); + importData = new JSplitButton("Import Data (File) "); JPopupMenu importOptions = new JPopupMenu(); @@ -311,6 +336,8 @@ private JSplitButton getImportDataButton() { importFromUrl.setSelected(generalSettings.getImportMethod() == GeneralSettings.ImportMethod.Url); importFromUrl.setActionCommand(GeneralSettings.ImportMethod.Url.name()); + setImportDataSelection(importFromFile); + importData.addButtonClickedActionListener(this::onImportData); importFromFile.addItemListener(this::onImportMethodChange); @@ -327,6 +354,15 @@ private JSplitButton getImportDataButton() { private void onImportMethodChange(ItemEvent itemEvent) { generalSettings.setImportMethod(GeneralSettings.ImportMethod.valueOf(importMethod.getSelection().getActionCommand())); + setImportDataSelection((JRadioButtonMenuItem) itemEvent.getItem()); + } + + private void setImportDataSelection(JRadioButtonMenuItem fileMenuItem) { + if (fileMenuItem.isSelected()) { + importData.setText("Import Data (File) "); + } else { + importData.setText("Import Data (URL) "); + } } @@ -360,6 +396,15 @@ private JFileChooser createFileChooser(String title, GeneralSettings.ExportMetho private void onExportMethodChange(ItemEvent itemEvent) { generalSettings.setExportMethod(GeneralSettings.ExportMethod.valueOf(exportMethod.getSelection().getActionCommand())); + setExportDataSelection((JRadioButtonMenuItem)itemEvent.getItem()); + } + + private void setExportDataSelection(JRadioButtonMenuItem yamlMenuItem) { + if (yamlMenuItem.isSelected()) { + exportData.setText("Export Data (YAML) "); + } else { + exportData.setText("Export Data (JSON) "); + } } private void onExportData(ActionEvent actionEvent) { @@ -460,8 +505,22 @@ private void onImportFromUrl() { } @Override - public void onActivated() { - refreshLists(); + public void addNotify() { + super.addNotify(); + addHierarchyListener(this); + } + + @Override + public void removeNotify() { + removeHierarchyListener(this); + super.removeNotify(); + } + + @Override + public void hierarchyChanged(HierarchyEvent e) { + if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 && isShowing()) { + refreshLists(); + } } private void refreshLists() { diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/vars/VariableListComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/vars/VariableListComponent.java index 2be3906..477451b 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/vars/VariableListComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/vars/VariableListComponent.java @@ -4,6 +4,7 @@ import synfron.reshaper.burp.core.events.CollectionChangedArgs; 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.GlobalVariables; import synfron.reshaper.burp.core.vars.Variable; import synfron.reshaper.burp.core.vars.Variables; @@ -14,6 +15,9 @@ import javax.swing.event.ListSelectionEvent; import java.awt.*; import java.awt.event.ActionEvent; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; +import java.awt.event.ItemEvent; import java.util.Collections; import java.util.List; import java.util.Map; @@ -21,14 +25,17 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -public class VariableListComponent extends JPanel { +public class VariableListComponent extends JPanel implements HierarchyListener { private JList variableList; private DefaultListModel variableListModel; private VariableContainerComponent variableContainer; + private JRadioButtonMenuItem listVariable; + private JSplitButton add; + private boolean activated; private final IEventListener variablesCollectionChangedListener = this::onVariablesCollectionChanged; private final IEventListener variableModelChangedListener = this::onVariableModelChanged; private final IEventListener newVariableModelChangedListener = this::onNewVariableModelChanged; - private JRadioButtonMenuItem listVariable; + private final PropertyChangedEvent activationChangedEvent = new PropertyChangedEvent(); public VariableListComponent() { initComponent(); @@ -39,7 +46,8 @@ private void initComponent() { variableListModel = new DefaultListModel<>(); variableListModel.addAll(GlobalVariables.get().getValues().stream() - .map(variable -> new VariableModel(variable).withListener(variableModelChangedListener)) + .map(variable -> new VariableModel(variable).withListener(variableModelChangedListener) + .bindActivationChangedEvent(activationChangedEvent)) .collect(Collectors.toList())); variableList = new JList<>(variableListModel); @@ -60,6 +68,13 @@ private void onSelectionChanged(ListSelectionEvent listSelectionEvent) { VariableModel variable = variableList.getSelectedValue(); if (variable != null) { variableContainer.setModel(variable); + if (activated) { + activationChangedEvent.invoke(new PropertyChangedArgs( + this, + "activated", + variable + )); + } } else if (!defaultSelect()) { variableContainer.setModel(null); @@ -80,7 +95,7 @@ private Component getActionBar() { } private JSplitButton getAddButton() { - JSplitButton add = new JSplitButton("Add "); + add = new JSplitButton("Add (Single) "); JPopupMenu variableTypeOptions = new JPopupMenu(); ButtonGroup variableType = new ButtonGroup(); @@ -93,6 +108,7 @@ private JSplitButton getAddButton() { listVariable.setActionCommand("List"); add.addButtonClickedActionListener(this::onAdd); + listVariable.addItemListener(this::onListVariableSelectionChanged); variableType.add(singleVariable); variableType.add(listVariable); @@ -105,8 +121,17 @@ private JSplitButton getAddButton() { return add; } + private void onListVariableSelectionChanged(ItemEvent itemEvent) { + if (listVariable.isSelected()) { + add.setText("Add (List) "); + } else { + add.setText("Add (Single) "); + } + } + private void onAdd(ActionEvent actionEvent) { - VariableModel model = new VariableModel(listVariable.isSelected()).withListener(newVariableModelChangedListener); + VariableModel model = new VariableModel(listVariable.isSelected()).withListener(newVariableModelChangedListener) + .bindActivationChangedEvent(activationChangedEvent); variableListModel.addElement(model); variableList.setSelectedValue(model, true); } @@ -137,7 +162,7 @@ private void onDelete(ActionEvent actionEvent) { } private boolean defaultSelect() { - if (variableList.getSelectedValue() == null && variableListModel.size() > 0) { + if (variableList.getSelectedValue() == null && !variableListModel.isEmpty()) { variableList.setSelectedIndex(variableListModel.size() - 1); return true; } @@ -149,7 +174,8 @@ private void onVariablesCollectionChanged(CollectionChangedArgs collectionChange Variable item = (Variable) collectionChangedArgs.getItem(); switch (collectionChangedArgs.getAction()) { case Add -> { - VariableModel variableModel = new VariableModel(item).withListener(variableModelChangedListener); + VariableModel variableModel = new VariableModel(item).withListener(variableModelChangedListener) + .bindActivationChangedEvent(activationChangedEvent); variableListModel.addElement(variableModel); defaultSelect(); } @@ -177,6 +203,7 @@ private void onVariablesCollectionChanged(CollectionChangedArgs collectionChange .map(variable -> variableModelMap.containsKey(variable) ? variableModelMap.get(variable) : new VariableModel(variable).withListener(variableModelChangedListener) + .bindActivationChangedEvent(activationChangedEvent) ), draftModels ).collect(Collectors.toList())); @@ -201,10 +228,34 @@ private void onVariableModelChanged(PropertyChangedArgs propertyChangedArgs) { public void setSelectionContainer(VariableContainerComponent variableContainer) { this.variableContainer = variableContainer; - if (variableListModel.size() == 0) { - VariableModel variableModel = new VariableModel(listVariable.isSelected()).withListener(newVariableModelChangedListener); + if (variableListModel.isEmpty()) { + VariableModel variableModel = new VariableModel(listVariable.isSelected()).withListener(newVariableModelChangedListener).bindActivationChangedEvent(activationChangedEvent); variableListModel.addElement(variableModel); } defaultSelect(); } + + @Override + public void addNotify() { + super.addNotify(); + addHierarchyListener(this); + } + + @Override + public void removeNotify() { + removeHierarchyListener(this); + super.removeNotify(); + } + + @Override + public void hierarchyChanged(HierarchyEvent e) { + if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) { + this.activated = isShowing(); + activationChangedEvent.invoke(new PropertyChangedArgs( + this, + "activated", + activated ? variableList.getSelectedValue() : null + )); + } + } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/components/vars/VariablesTabComponent.java b/extension/src/main/java/synfron/reshaper/burp/ui/components/vars/VariablesTabComponent.java index 46b3ac2..38c00ee 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/components/vars/VariablesTabComponent.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/components/vars/VariablesTabComponent.java @@ -5,6 +5,8 @@ public class VariablesTabComponent extends JPanel { + private VariableListComponent variablesList; + public VariablesTabComponent() { initComponent(); } @@ -12,7 +14,7 @@ public VariablesTabComponent() { private void initComponent() { setLayout(new BorderLayout()); - VariableListComponent variablesList = new VariableListComponent(); + variablesList = new VariableListComponent(); VariableContainerComponent variableContainer = new VariableContainerComponent(); variablesList.setSelectionContainer(variableContainer); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleModel.java index 019c92e..a3bb54c 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleModel.java @@ -131,7 +131,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } rule.setEnabled(false); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleOperationModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleOperationModel.java index 098c7ff..61105ba 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleOperationModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleOperationModel.java @@ -46,8 +46,6 @@ protected void propertyChanged(String name, Object value) { public abstract boolean persist(); - public abstract boolean record(); - protected String getTargetName() { return ""; } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleOperationModelType.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleOperationModelType.java index 9b8f62b..f65dd6d 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleOperationModelType.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleOperationModelType.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.models.rules; +import lombok.AllArgsConstructor; import lombok.Getter; import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.IHttpRuleOperation; @@ -7,15 +8,19 @@ import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; +@AllArgsConstructor public class RuleOperationModelType

, T extends IRuleOperation> { @Getter private final Class

type; @Getter private final RuleOperationType ruleOperationType; + @Getter + private final boolean isDefault; protected RuleOperationModelType(Class

type, RuleOperationType ruleOperationType) { this.type = type; this.ruleOperationType = ruleOperationType; + isDefault = false; } public String getName() { diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBreakModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBreakModel.java index d47a2d1..9cbdd47 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBreakModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBreakModel.java @@ -22,7 +22,7 @@ public void setBreakType(RuleResponse breakType) { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setBreakType(breakType); @@ -30,15 +30,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return breakType.getName(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBuildHttpMessageModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBuildHttpMessageModel.java index b946a1f..bf446de 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBuildHttpMessageModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBuildHttpMessageModel.java @@ -128,7 +128,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setDataDirection(dataDirection); @@ -149,15 +149,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return dataDirection.name(); @@ -171,7 +162,7 @@ public RuleOperationModelType g @Override public List getVariableEntries() { return StringUtils.isNotEmpty(destinationVariableName) ? - List.of(new VariableSourceEntry(destinationVariableSource, destinationVariableName)) : + List.of(new VariableSourceEntry(destinationVariableSource, List.of(destinationVariableName))) : Collections.emptyList(); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenCommentModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenCommentModel.java index 974f2f0..cc5d30b 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenCommentModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenCommentModel.java @@ -33,7 +33,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setText(VariableString.getAsVariableString(text)); @@ -41,15 +41,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return abbreviateTargetName(text); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDelayModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDelayModel.java index e73ccf9..33c5b4e 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDelayModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDelayModel.java @@ -35,7 +35,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setDelay(VariableString.getAsVariableString(delay)); @@ -43,15 +43,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return delay; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDeleteValueModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDeleteValueModel.java index 88bb1a0..38bc3bb 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDeleteValueModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDeleteValueModel.java @@ -52,7 +52,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setIdentifier(VariableString.getAsVariableString(identifier)); @@ -62,15 +62,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return messageValue.getName(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDeleteVariableModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDeleteVariableModel.java index f6a34a5..b367624 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDeleteVariableModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDeleteVariableModel.java @@ -66,7 +66,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setTargetSource(targetSource); @@ -77,18 +77,9 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { - return abbreviateTargetName(VariableSourceEntry.getShortTag(targetSource, abbreviateTargetName(variableName))); + return abbreviateTargetName(VariableTag.getShortTag(targetSource, abbreviateTargetName(variableName))); } @Override diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDropModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDropModel.java index 16555a1..49becb6 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDropModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDropModel.java @@ -21,7 +21,7 @@ public void setDropMessage(boolean dropMessage) { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setDropMessage(dropMessage); @@ -29,15 +29,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return isDropMessage() ? "Yes" : "No"; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenEvaluateModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenEvaluateModel.java index 6ed047b..584664a 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenEvaluateModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenEvaluateModel.java @@ -110,7 +110,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setX(VariableString.getAsVariableString(x)); @@ -125,15 +125,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return operation.getName(); @@ -147,7 +138,7 @@ public RuleOperationModelType getType() { @Override public List getVariableEntries() { return StringUtils.isNotEmpty(destinationVariableName) ? - List.of(new VariableSourceEntry(destinationVariableSource, destinationVariableName)) : + List.of(new VariableSourceEntry(destinationVariableSource, List.of(destinationVariableName))) : Collections.emptyList(); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenExtractModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenExtractModel.java new file mode 100644 index 0000000..d2ba471 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenExtractModel.java @@ -0,0 +1,128 @@ +package synfron.reshaper.burp.ui.models.rules.thens; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.rules.thens.ThenExtract; +import synfron.reshaper.burp.core.rules.thens.entities.extract.ExtractorType; +import synfron.reshaper.burp.core.vars.*; +import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; + +import java.util.Collections; +import java.util.List; + +public class ThenExtractModel extends ThenModel implements IVariableCreator { + + @Getter + private String text = ""; + + @Getter + private ExtractorType extractorType; + @Getter + protected String extractor = ""; + @Getter + private VariableSource listVariableSource; + @Getter + private String listVariableName = ""; + @Getter + private String delimiter = "{{s:n}}"; + @Getter + private SetListItemsPlacement itemsPlacement; + + public ThenExtractModel(ProtocolType protocolType, ThenExtract then, Boolean isNew) { + super(protocolType, then, isNew); + text = VariableString.toString(then.getText(), text); + extractorType = then.getExtractorType(); + extractor = VariableString.toString(then.getExtractor(), extractor); + listVariableSource = then.getListVariableSource(); + listVariableName = VariableString.toString(then.getListVariableName(), listVariableName); + delimiter = VariableString.toString(then.getDelimiter(), delimiter); + itemsPlacement = then.getItemsPlacement(); + VariableCreatorRegistry.register(this); + } + + public void setText(String text) { + this.text = text; + propertyChanged("text", text); + } + + public void setExtractorType(ExtractorType extractorType) { + this.extractorType = extractorType; + propertyChanged("extractorType", extractorType); + } + + public void setExtractor(String extractor) { + this.extractor = extractor; + propertyChanged("extractor", extractor); + } + + public void setListVariableSource(VariableSource listVariableSource) { + this.listVariableSource = listVariableSource; + propertyChanged("listVariableSource", listVariableSource); + } + + public void setListVariableName(String listVariableName) { + this.listVariableName = listVariableName; + propertyChanged("listVariableName", listVariableName); + } + + public void setDelimiter(String delimiter) { + this.delimiter = delimiter; + propertyChanged("delimiter", delimiter); + } + + public void setItemsPlacement(SetListItemsPlacement itemsPlacement) { + this.itemsPlacement = itemsPlacement; + propertyChanged("itemsPlacement", itemsPlacement); + } + + public List validate() { + List errors = super.validate(); + if (StringUtils.isEmpty(text)) { + errors.add("Text is required"); + } + if (StringUtils.isEmpty(extractor)) { + errors.add(extractorType.getSyntax() + " is required"); + } else if (extractorType == ExtractorType.Chunk && !VariableString.isPotentialInt(extractor)) { + errors.add(extractorType.getSyntax() + "Index must be an integer"); + } + if (StringUtils.isEmpty(listVariableName)) { + errors.add("List Variable Name is required"); + } else if (!VariableString.isValidVariableName(listVariableName)) { + errors.add("List Variable Name is invalid"); + } + return errors; + } + + public boolean persist() { + if (!validate().isEmpty()) { + return false; + } + ruleOperation.setText(VariableString.getAsVariableString(text)); + ruleOperation.setExtractorType(extractorType); + ruleOperation.setExtractor(VariableString.getAsVariableString(extractor)); + ruleOperation.setListVariableSource(listVariableSource); + ruleOperation.setListVariableName(VariableString.getAsVariableString(listVariableName)); + ruleOperation.setDelimiter(VariableString.getAsVariableString(delimiter)); + ruleOperation.setItemsPlacement(itemsPlacement); + setValidated(true); + return true; + } + + @Override + protected String getTargetName() { + return VariableTag.getShortTag(listVariableSource, listVariableName); + } + + @Override + public RuleOperationModelType getType() { + return ThenModelType.Extract; + } + + @Override + public List getVariableEntries() { + return StringUtils.isNotEmpty(listVariableName) ? + List.of(new VariableSourceEntry(listVariableSource, List.of(listVariableName))) : + Collections.emptyList(); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenGenerateModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenGenerateModel.java new file mode 100644 index 0000000..bbe4833 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenGenerateModel.java @@ -0,0 +1,159 @@ +package synfron.reshaper.burp.ui.models.rules.thens; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.events.IEventListener; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.core.rules.thens.ThenGenerate; +import synfron.reshaper.burp.core.rules.thens.entities.generate.GenerateOption; +import synfron.reshaper.burp.core.rules.thens.entities.generate.IGenerator; +import synfron.reshaper.burp.core.utils.ObjectUtils; +import synfron.reshaper.burp.core.vars.SetListItemPlacement; +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.generate.*; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Getter +public class ThenGenerateModel extends ThenModel implements IVariableCreator { + + private GenerateOption generateOption; + + private GeneratorModel generator; + private final Map> generatorMap = new HashMap<>(); + private VariableSource destinationVariableSource; + private String destinationVariableName; + private SetListItemPlacement itemPlacement; + private String delimiter = "{{s:n}}"; + private String index; + private final IEventListener generatorPropertyChangedListener = this::onGeneratorPropertyChanged; + + public ThenGenerateModel(ProtocolType protocolType, ThenGenerate then, Boolean isNew) { + super(protocolType, then, isNew); + this.generateOption = then.getGenerateOption(); + this.generator = generatorMap.computeIfAbsent(this.generateOption, this::constructGeneratorModel); + this.destinationVariableSource = then.getDestinationVariableSource(); + this.destinationVariableName = VariableString.toString(then.getDestinationVariableName(), destinationVariableName); + itemPlacement = then.getItemPlacement(); + delimiter = VariableString.toString(then.getDelimiter(), delimiter); + index = VariableString.toString(then.getIndex(), index); + VariableCreatorRegistry.register(this); + } + + private GeneratorModel constructGeneratorModel(GenerateOption generateOption) { + return (switch (generateOption) { + case Uuid -> new UuidGeneratorModel(constructGenerator(generateOption)); + case Words -> new WordGeneratorModel(constructGenerator(generateOption)); + case Bytes -> new BytesGeneratorModel(constructGenerator(generateOption)); + case Integer -> new IntegerGeneratorModel(constructGenerator(generateOption)); + case IpAddress -> new IpAddressGeneratorModel(constructGenerator(generateOption)); + case Timestamp -> new TimestampGeneratorModel(constructGenerator(generateOption)); + case UnixTimestamp -> new UnixTimestampGeneratorModel(constructGenerator(generateOption)); + case Password -> new PasswordGeneratorModel(constructGenerator(generateOption)); + }).withListener(generatorPropertyChangedListener); + } + + private void onGeneratorPropertyChanged(PropertyChangedArgs propertyChangedArgs) { + setValidated(false); + } + + private T constructGenerator(GenerateOption generateOption) { + return generateOption.getGeneratorClass().isInstance(ruleOperation.getGenerator()) ? + (T)ruleOperation.getGenerator() : + (T) ObjectUtils.construct(generateOption.getGeneratorClass()); + } + + public void setGenerateOption(GenerateOption generateOption) { + this.generateOption = generateOption; + propertyChanged("generateOption", generateOption); + setGenerator(generatorMap.computeIfAbsent(this.generateOption, this::constructGeneratorModel)); + } + + public void setGenerator(GeneratorModel generator) { + this.generator = generator; + propertyChanged("generator", generator); + } + + public void setDestinationVariableSource(VariableSource destinationVariableSource) { + this.destinationVariableSource = destinationVariableSource; + propertyChanged("destinationVariableSource", destinationVariableSource); + } + + public void setDestinationVariableName(String destinationVariableName) { + this.destinationVariableName = destinationVariableName; + propertyChanged("destinationVariableName", destinationVariableName); + } + + public void setItemPlacement(SetListItemPlacement itemPlacement) { + this.itemPlacement = itemPlacement; + propertyChanged("itemPlacement", itemPlacement); + } + + public void setDelimiter(String delimiter) { + this.delimiter = delimiter; + propertyChanged("delimiter", delimiter); + } + + public void setIndex(String index) { + this.index = index; + propertyChanged("index", index); + } + + public List validate() { + List errors = super.validate(); + errors.addAll(generator.validate()); + if (StringUtils.isEmpty(destinationVariableName)) { + errors.add("Destination Variable Name is required"); + } else if (!VariableString.isValidVariableName(destinationVariableName)) { + errors.add("Destination Variable Name is invalid"); + } + if (destinationVariableSource.isList() && itemPlacement.isHasIndexSetter()) { + if (StringUtils.isEmpty(index)) { + errors.add("Index is required"); + } else if (!VariableString.isPotentialInt(index)) { + errors.add("Index must be an integer"); + } + } + return errors; + } + + public boolean persist() { + if (!validate().isEmpty()) { + return false; + } + ruleOperation.setGenerateOption(generateOption); + generator.persist(); + ruleOperation.setGenerator(generator.getGenerator()); + ruleOperation.setDestinationVariableSource(destinationVariableSource); + ruleOperation.setDestinationVariableName(VariableString.getAsVariableString(destinationVariableName)); + ruleOperation.setItemPlacement(itemPlacement); + ruleOperation.setDelimiter(VariableString.getAsVariableString(delimiter)); + ruleOperation.setIndex(VariableString.getAsVariableString(index)); + setValidated(true); + return true; + } + + @Override + protected String getTargetName() { + return generateOption.name(); + } + + @Override + public RuleOperationModelType getType() { + return ThenModelType.Generate; + } + + @Override + public List getVariableEntries() { + return StringUtils.isNotEmpty(destinationVariableName) ? + List.of(new VariableSourceEntry(destinationVariableSource, List.of(destinationVariableName))) : + Collections.emptyList(); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenHighlightModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenHighlightModel.java index f6c7f0e..57e4c4e 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenHighlightModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenHighlightModel.java @@ -22,7 +22,7 @@ public void setColor(HighlightColor color) { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setColor(color); @@ -30,15 +30,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return color.name(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenInterceptModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenInterceptModel.java index 80d3ba8..8bd5500 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenInterceptModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenInterceptModel.java @@ -22,7 +22,7 @@ public void setInterceptResponse(InterceptResponse interceptResponse) { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setInterceptResponse(interceptResponse); @@ -30,15 +30,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return interceptResponse.getName(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenLogModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenLogModel.java index 5d55d4e..5fe9d8a 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenLogModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenLogModel.java @@ -33,7 +33,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setText(VariableString.getAsVariableString(text)); @@ -41,15 +41,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return abbreviateTargetName(text); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenModelType.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenModelType.java index 0c43946..a8ed14e 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenModelType.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenModelType.java @@ -21,7 +21,7 @@ public class ThenModelType

, T extends Then> extends public static final ThenModelType Evaluate = new ThenModelType<>(ThenEvaluateModel.class, ThenType.Evaluate); public static final ThenModelType SetEventDirection = new ThenModelType<>(ThenSetEventDirectionModel.class, ThenType.SetEventDirection); public static final ThenModelType SetEncoding = new ThenModelType<>(ThenSetEncodingModel.class, ThenType.SetEncoding); - public static final ThenModelType SetValue = new ThenModelType<>(ThenSetValueModel.class, ThenType.SetValue); + public static final ThenModelType SetValue = new ThenModelType<>(ThenSetValueModel.class, ThenType.SetValue, true); public static final ThenModelType DeleteValue = new ThenModelType<>(ThenDeleteValueModel.class, ThenType.DeleteValue); public static final ThenModelType SetVariable = new ThenModelType<>(ThenSetVariableModel.class, ThenType.SetVariable); public static final ThenModelType DeleteVariable = new ThenModelType<>(ThenDeleteVariableModel.class, ThenType.DeleteVariable); @@ -36,11 +36,18 @@ public class ThenModelType

, T extends Then> extends public static final ThenModelType Intercept = new ThenModelType<>(ThenInterceptModel.class, ThenType.Intercept); public static final ThenModelType Repeat = new ThenModelType<>(ThenRepeatModel.class, ThenType.Repeat); public static final ThenModelType ReadFile = new ThenModelType<>(ThenReadFileModel.class, ThenType.ReadFile); + public static final ThenModelType Extract = new ThenModelType<>(ThenExtractModel.class, ThenType.Extract); + public static final ThenModelType Generate = new ThenModelType<>(ThenGenerateModel.class, ThenType.Generate); + public static final ThenModelType Transform = new ThenModelType<>(ThenTransformModel.class, ThenType.Transform); private ThenModelType(Class

type, RuleOperationType ruleOperationType) { super(type, ruleOperationType); } + private ThenModelType(Class

type, RuleOperationType ruleOperationType, boolean isDefault) { + super(type, ruleOperationType, isDefault); + } + public static List> getTypes(ProtocolType protocolType) { return Stream.of( Break, @@ -68,7 +75,10 @@ public static List> getTypes(ProtocolType protocolType) { Drop, Intercept, Repeat, - ReadFile + ReadFile, + Extract, + Generate, + Transform ).filter(type -> protocolType == null || type.hasProtocolType(protocolType)).collect(Collectors.toList()); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenParseHttpMessageModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenParseHttpMessageModel.java index a58d7dd..b2d37e9 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenParseHttpMessageModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenParseHttpMessageModel.java @@ -73,7 +73,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setDataDirection(dataDirection); @@ -90,15 +90,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return dataDirection.name(); @@ -113,7 +104,7 @@ public RuleOperationModelType g public List getVariableEntries() { return messageValueGetters.stream() .filter(getter -> StringUtils.isNotEmpty(getter.getDestinationVariableName())) - .map(getter -> new VariableSourceEntry(getter.getDestinationVariableSource(), getter.getDestinationVariableName())) + .map(getter -> new VariableSourceEntry(getter.getDestinationVariableSource(), List.of(getter.getDestinationVariableName()))) .collect(Collectors.toList()); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenPromptModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenPromptModel.java index f8da3b3..a63e7f9 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenPromptModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenPromptModel.java @@ -119,7 +119,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setDescription(VariableString.getAsVariableString(description)); @@ -135,15 +135,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return abbreviateTargetName(description); @@ -157,7 +148,7 @@ public RuleOperationModelType getType() { @Override public List getVariableEntries() { return StringUtils.isNotEmpty(captureVariableName) ? - List.of(new VariableSourceEntry(captureVariableSource, captureVariableName)) : + List.of(new VariableSourceEntry(captureVariableSource, List.of(captureVariableName))) : Collections.emptyList(); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenReadFileModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenReadFileModel.java index 08c32a1..a0157bf 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenReadFileModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenReadFileModel.java @@ -5,11 +5,7 @@ import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.Encoder; import synfron.reshaper.burp.core.rules.thens.ThenReadFile; -import synfron.reshaper.burp.core.rules.thens.ThenReadFile; -import synfron.reshaper.burp.core.vars.SetListItemPlacement; -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.core.vars.*; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; import java.util.Collections; @@ -101,7 +97,7 @@ public List validate() { if (StringUtils.isEmpty(filePath)) { errors.add("File Path is required"); } - if (!Encoder.isSupported(encoding) && !VariableString.hasTag(encoding)) { + if (!Encoder.isSupported(encoding) && !VariableTag.hasTag(encoding)) { errors.add("Unsupported encoding"); } if (StringUtils.isEmpty(captureVariableName)) { @@ -120,7 +116,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setFilePath(VariableString.getAsVariableString(filePath)); @@ -136,15 +132,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return abbreviateTargetName(filePath); @@ -158,7 +145,7 @@ public RuleOperationModelType getType() { @Override public List getVariableEntries() { return StringUtils.isNotEmpty(captureVariableName) ? - List.of(new VariableSourceEntry(captureVariableSource, captureVariableName)) : + List.of(new VariableSourceEntry(captureVariableSource, List.of(captureVariableName))) : Collections.emptyList(); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRepeatModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRepeatModel.java index 9edea77..52615ed 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRepeatModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRepeatModel.java @@ -9,6 +9,7 @@ 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.core.vars.VariableTag; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; import java.util.List; @@ -129,7 +130,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setSubGroupCount(Integer.parseInt(subGroupCount)); @@ -144,19 +145,10 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override public List getVariableEntries() { return repeatCondition == RepeatCondition.HasNextItem ? - List.of(new VariableSourceEntry(VariableSource.Event, entryVariableName)) : + List.of(new VariableSourceEntry(VariableSource.Event, List.of(entryVariableName))) : List.of(); } @@ -164,7 +156,7 @@ public List getVariableEntries() { protected String getTargetName() { return abbreviateTargetName(switch (repeatCondition) { case Count -> count; - case HasNextItem -> VariableSourceEntry.getTag(listVariableSource, listVariableName); + case HasNextItem -> VariableTag.getTag(listVariableSource, listVariableName); case WhileTrue -> booleanValue; }); } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunProcessModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunProcessModel.java index a262f16..91183fa 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunProcessModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunProcessModel.java @@ -159,7 +159,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setCommand(VariableString.getAsVariableString(command)); @@ -180,15 +180,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return abbreviateTargetName(command); @@ -202,7 +193,7 @@ public RuleOperationModelType getType() { @Override public List getVariableEntries() { return captureOutput && StringUtils.isNotEmpty(captureVariableName) ? - List.of(new VariableSourceEntry(captureVariableSource, captureVariableName)) : + List.of(new VariableSourceEntry(captureVariableSource, List.of(captureVariableName))) : Collections.emptyList(); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunRulesModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunRulesModel.java index e2cf469..81fc3b9 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunRulesModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunRulesModel.java @@ -40,7 +40,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setRuleName(ruleName); @@ -49,15 +49,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return runSingle ? abbreviateTargetName(ruleName) : "All"; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunScriptModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunScriptModel.java index 43d03e4..fdc5bb6 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunScriptModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunScriptModel.java @@ -44,7 +44,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setScript(script); @@ -53,15 +53,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return abbreviateTargetName(script); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSaveFileModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSaveFileModel.java index 505c09d..a788d59 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSaveFileModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSaveFileModel.java @@ -7,6 +7,7 @@ import synfron.reshaper.burp.core.rules.thens.ThenSaveFile; import synfron.reshaper.burp.core.rules.thens.entities.savefile.FileExistsAction; import synfron.reshaper.burp.core.vars.VariableString; +import synfron.reshaper.burp.core.vars.VariableTag; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; import java.util.List; @@ -55,14 +56,14 @@ public List validate() { if (StringUtils.isEmpty(filePath)) { errors.add("File Path is required"); } - if (!Encoder.isSupported(encoding) && !VariableString.hasTag(encoding)) { + if (!Encoder.isSupported(encoding) && !VariableTag.hasTag(encoding)) { errors.add("Unsupported encoding"); } return errors; } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setFilePath(VariableString.getAsVariableString(filePath)); @@ -73,15 +74,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return abbreviateTargetName(filePath); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendMessageModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendMessageModel.java index 4f6f9ee..2393e39 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendMessageModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendMessageModel.java @@ -42,7 +42,7 @@ public void setMessage(String message) { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setDataDirection(dataDirection); @@ -52,15 +52,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return abbreviateTargetName(message); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendRequestModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendRequestModel.java index 2e35d3d..e7121b2 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendRequestModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendRequestModel.java @@ -175,7 +175,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setRequest(VariableString.getAsVariableString(request)); @@ -198,15 +198,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override public RuleOperationModelType getType() { return ThenModelType.SendRequest; @@ -215,7 +206,7 @@ public RuleOperationModelType getType() { @Override public List getVariableEntries() { return captureOutput && StringUtils.isNotEmpty(captureVariableName) ? - List.of(new VariableSourceEntry(captureVariableSource, captureVariableName)) : + List.of(new VariableSourceEntry(captureVariableSource, List.of(captureVariableName))) : Collections.emptyList(); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendToModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendToModel.java index d32c8e2..6f1242f 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendToModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendToModel.java @@ -123,7 +123,7 @@ private void validatePort(List errors) { } } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setSendTo(sendTo); @@ -141,15 +141,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return sendTo.toString(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetEncodingModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetEncodingModel.java index b5b16b6..678d892 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetEncodingModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetEncodingModel.java @@ -5,6 +5,7 @@ import synfron.reshaper.burp.core.messages.Encoder; import synfron.reshaper.burp.core.rules.thens.ThenSetEncoding; import synfron.reshaper.burp.core.vars.VariableString; +import synfron.reshaper.burp.core.vars.VariableTag; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; import java.util.List; @@ -28,14 +29,14 @@ public void setEncoding(String encoding) { public List validate() { List errors = super.validate(); - if (!Encoder.isSupported(encoding) && !VariableString.hasTag(encoding)) { + if (!Encoder.isSupported(encoding) && !VariableTag.hasTag(encoding)) { errors.add("Unsupported encoding"); } return errors; } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setEncoding(VariableString.getAsVariableString(encoding)); @@ -43,15 +44,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return abbreviateTargetName(encoding); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetEventDirectionModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetEventDirectionModel.java index cfb3eca..4440be8 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetEventDirectionModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetEventDirectionModel.java @@ -22,7 +22,7 @@ public void setDataDirection(HttpDataDirection dataDirection) { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setDataDirection(dataDirection); @@ -30,15 +30,6 @@ public boolean persist() { return true; } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return dataDirection.name(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetModel.java index 4c74e7d..6cc1ded 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetModel.java @@ -42,7 +42,7 @@ public abstract class ThenSetModel

, T extends ThenS public ThenSetModel(ProtocolType protocolType, T then, Boolean isNew) { super(protocolType, then, isNew); useMessageValue = then.isUseMessageValue(); - sourceMessageValue = then.getSourceMessageValue() != null ? then.getSourceMessageValue() : Arrays.stream(MessageValue.values()).filter(value -> value.isGettable(protocolType)).findFirst().orElse(null);; + sourceMessageValue = then.getSourceMessageValue() != null ? then.getSourceMessageValue() : Arrays.stream(MessageValue.values()).filter(value -> value.isGettable(protocolType)).findFirst().orElse(null); sourceIdentifier = VariableString.toString(then.getSourceIdentifier(), sourceIdentifier); sourceIdentifierPlacement = then.getSourceIdentifierPlacement(); sourceMessageValueType = then.getSourceMessageValueType(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetValueModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetValueModel.java index 3dd96e9..5277b46 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetValueModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetValueModel.java @@ -23,7 +23,7 @@ public class ThenSetValueModel extends ThenSetModel value.isSettable(protocolType)).findFirst().orElse(null);; + destinationMessageValue = then.getDestinationMessageValue() != null ? then.getDestinationMessageValue() : Arrays.stream(MessageValue.values()).filter(value -> value.isSettable(protocolType)).findFirst().orElse(null); destinationIdentifier = VariableString.toString(then.getDestinationIdentifier(), destinationIdentifier); destinationIdentifierPlacement = then.getDestinationIdentifierPlacement(); } @@ -54,7 +54,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setDestinationMessageValue(destinationMessageValue); @@ -63,15 +63,6 @@ public boolean persist() { return super.persist(); } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return destinationMessageValue.getName(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetVariableModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetVariableModel.java index 36212e9..993db8c 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetVariableModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetVariableModel.java @@ -76,7 +76,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setTargetSource(targetSource); @@ -87,18 +87,9 @@ public boolean persist() { return super.persist(); } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { - return VariableSourceEntry.getShortTag(targetSource, variableName); + return VariableTag.getShortTag(targetSource, variableName); } @Override @@ -109,7 +100,7 @@ public RuleOperationModelType getType() { @Override public List getVariableEntries() { return StringUtils.isNotEmpty(variableName) ? - List.of(new VariableSourceEntry(targetSource, variableName)) : + List.of(new VariableSourceEntry(targetSource, List.of(variableName))) : Collections.emptyList(); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenTransformModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenTransformModel.java new file mode 100644 index 0000000..d34feb1 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenTransformModel.java @@ -0,0 +1,159 @@ +package synfron.reshaper.burp.ui.models.rules.thens; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.events.IEventListener; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.core.rules.thens.ThenTransform; +import synfron.reshaper.burp.core.rules.thens.entities.transform.TransformOption; +import synfron.reshaper.burp.core.rules.thens.entities.transform.ITransformer; +import synfron.reshaper.burp.core.utils.ObjectUtils; +import synfron.reshaper.burp.core.vars.SetListItemPlacement; +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.transform.*; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Getter +public class ThenTransformModel extends ThenModel implements IVariableCreator { + + private TransformOption transformOption; + + private TransformerModel transformer; + private final Map> transformerMap = new HashMap<>(); + private VariableSource destinationVariableSource; + private String destinationVariableName; + private SetListItemPlacement itemPlacement; + private String delimiter = "{{s:n}}"; + private String index; + private final IEventListener transformerPropertyChangedListener = this::onTransformerPropertyChanged; + + public ThenTransformModel(ProtocolType protocolType, ThenTransform then, Boolean isNew) { + super(protocolType, then, isNew); + this.transformOption = then.getTransformOption(); + this.transformer = transformerMap.computeIfAbsent(this.transformOption, this::constructTransformerModel); + this.destinationVariableSource = then.getDestinationVariableSource(); + this.destinationVariableName = VariableString.toString(then.getDestinationVariableName(), destinationVariableName); + itemPlacement = then.getItemPlacement(); + delimiter = VariableString.toString(then.getDelimiter(), delimiter); + index = VariableString.toString(then.getIndex(), index); + VariableCreatorRegistry.register(this); + } + + private TransformerModel constructTransformerModel(TransformOption transformOption) { + return (switch (transformOption) { + case Base64 -> new Base64TransformerModel(constructTransformer(transformOption)); + case Escape -> new EscapeTransformerModel(constructTransformer(transformOption)); + case JwtDecode -> new JwtDecodeTransformerModel(constructTransformer(transformOption)); + case Case -> new CaseTransformerModel(constructTransformer(transformOption)); + case Hash -> new HashTransformerModel(constructTransformer(transformOption)); + case Hex -> new HexTransformerModel(constructTransformer(transformOption)); + case Integer -> new IntegerTransformerModel(constructTransformer(transformOption)); + case Trim -> new TrimTransformerModel(constructTransformer(transformOption)); + }).withListener(transformerPropertyChangedListener); + } + + private void onTransformerPropertyChanged(PropertyChangedArgs propertyChangedArgs) { + setValidated(false); + } + + private T constructTransformer(TransformOption transformOption) { + return transformOption.getTransformerClass().isInstance(ruleOperation.getTransformer()) ? + (T)ruleOperation.getTransformer() : + (T) ObjectUtils.construct(transformOption.getTransformerClass()); + } + + public void setTransformOption(TransformOption transformOption) { + this.transformOption = transformOption; + propertyChanged("transformOption", transformOption); + setTransformer(transformerMap.computeIfAbsent(this.transformOption, this::constructTransformerModel)); + } + + public void setTransformer(TransformerModel transformer) { + this.transformer = transformer; + propertyChanged("transformer", transformer); + } + + public void setDestinationVariableSource(VariableSource destinationVariableSource) { + this.destinationVariableSource = destinationVariableSource; + propertyChanged("destinationVariableSource", destinationVariableSource); + } + + public void setDestinationVariableName(String destinationVariableName) { + this.destinationVariableName = destinationVariableName; + propertyChanged("destinationVariableName", destinationVariableName); + } + + public void setItemPlacement(SetListItemPlacement itemPlacement) { + this.itemPlacement = itemPlacement; + propertyChanged("itemPlacement", itemPlacement); + } + + public void setDelimiter(String delimiter) { + this.delimiter = delimiter; + propertyChanged("delimiter", delimiter); + } + + public void setIndex(String index) { + this.index = index; + propertyChanged("index", index); + } + + public List validate() { + List errors = super.validate(); + errors.addAll(transformer.validate()); + if (StringUtils.isEmpty(destinationVariableName)) { + errors.add("Destination Variable Name is required"); + } else if (!VariableString.isValidVariableName(destinationVariableName)) { + errors.add("Destination Variable Name is invalid"); + } + if (destinationVariableSource.isList() && itemPlacement.isHasIndexSetter()) { + if (StringUtils.isEmpty(index)) { + errors.add("Index is required"); + } else if (!VariableString.isPotentialInt(index)) { + errors.add("Index must be an integer"); + } + } + return errors; + } + + public boolean persist() { + if (!validate().isEmpty()) { + return false; + } + ruleOperation.setTransformOption(transformOption); + transformer.persist(); + ruleOperation.setTransformer(transformer.getTransformer()); + ruleOperation.setDestinationVariableSource(destinationVariableSource); + ruleOperation.setDestinationVariableName(VariableString.getAsVariableString(destinationVariableName)); + ruleOperation.setItemPlacement(itemPlacement); + ruleOperation.setDelimiter(VariableString.getAsVariableString(delimiter)); + ruleOperation.setIndex(VariableString.getAsVariableString(index)); + setValidated(true); + return true; + } + + @Override + protected String getTargetName() { + return transformOption.name(); + } + + @Override + public RuleOperationModelType getType() { + return ThenModelType.Transform; + } + + @Override + public List getVariableEntries() { + return StringUtils.isNotEmpty(destinationVariableName) ? + List.of(new VariableSourceEntry(destinationVariableSource, List.of(destinationVariableName))) : + Collections.emptyList(); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/VariableCreatorRegistry.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/VariableCreatorRegistry.java index d3595b0..ae9fbf4 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/VariableCreatorRegistry.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/VariableCreatorRegistry.java @@ -23,7 +23,7 @@ public static synchronized List getVariableEntries() { WeakReference listenerReference = iterator.next(); IVariableCreator creator = listenerReference.get(); if (creator != null) { - entries.addAll(creator.getVariableEntries().stream().filter(entry -> VariableString.isValidVariableName(entry.getName())).toList()); + entries.addAll(creator.getVariableEntries().stream().filter(entry -> VariableString.isValidVariableName(entry.getParams().getFirst())).toList()); } else { iterator.remove(); } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/buildhttpmessage/MessageValueSetterModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/buildhttpmessage/MessageValueSetterModel.java index 9da9f3d..697f290 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/buildhttpmessage/MessageValueSetterModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/buildhttpmessage/MessageValueSetterModel.java @@ -90,7 +90,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } messageValueSetter.setDestinationMessageValue(destinationMessageValue); @@ -99,12 +99,4 @@ public boolean persist() { messageValueSetter.setSourceText(VariableString.getAsVariableString(sourceText)); return true; } - - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/BytesGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/BytesGeneratorModel.java new file mode 100644 index 0000000..8f298c9 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/BytesGeneratorModel.java @@ -0,0 +1,53 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.rules.thens.entities.generate.BytesGenerator; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +@Getter +public class BytesGeneratorModel extends GeneratorModel implements IBytesGeneratorModel { + + private String length = ""; + private String encoding = StandardCharsets.ISO_8859_1.displayName(); + + public BytesGeneratorModel(BytesGenerator generator) { + super(generator); + length = VariableString.toString(generator.getLength(), length); + encoding = VariableString.toString(generator.getEncoding(), encoding); + } + + @Override + public void setLength(String length) { + this.length = length; + propertyChanged("length", length); + } + + @Override + public void setEncoding(String encoding) { + this.encoding = encoding; + propertyChanged("encoding", encoding); + } + + @Override + public List validate() { + List errors = super.validate(); + if (StringUtils.isEmpty(length)) { + errors.add("Length is required"); + } else if (!VariableString.isPotentialInt(length)) { + errors.add("Length must be an integer"); + } + return errors; + } + + @Override + public boolean persist() { + super.persist(); + generator.setLength(VariableString.getAsVariableString(length)); + generator.setEncoding(VariableString.getAsVariableString(encoding)); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/GeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/GeneratorModel.java new file mode 100644 index 0000000..da54f83 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/GeneratorModel.java @@ -0,0 +1,46 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +import lombok.Getter; +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.rules.thens.entities.generate.IGenerator; + +import java.util.ArrayList; +import java.util.List; + +@Getter +public abstract class GeneratorModel, G extends IGenerator> { + protected final G generator; + private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); + protected boolean validated; + + public GeneratorModel(G generator) { + this.generator = generator; + } + + protected void propertyChanged(String name, Object value) { + setValidated(false); + propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); + } + + public T withListener(IEventListener listener) { + getPropertyChangedEvent().add(listener); + return (T)this; + } + + protected void setValidated(boolean validated) { + if (validated != this.validated) { + this.validated = validated; + propertyChangedEvent.invoke(new PropertyChangedArgs(this, "validated", validated)); + } + } + + public List validate() { + return new ArrayList<>(); + } + + public boolean persist() { + return validate().isEmpty(); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IBytesGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IBytesGeneratorModel.java new file mode 100644 index 0000000..ac9a541 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IBytesGeneratorModel.java @@ -0,0 +1,11 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +public interface IBytesGeneratorModel extends IGeneratorModel { + void setLength(String length); + + void setEncoding(String encoding); + + String getLength(); + + String getEncoding(); +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IGeneratorModel.java new file mode 100644 index 0000000..d9d1d32 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IGeneratorModel.java @@ -0,0 +1,4 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +public interface IGeneratorModel> { +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IIntegerGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IIntegerGeneratorModel.java new file mode 100644 index 0000000..14f0804 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IIntegerGeneratorModel.java @@ -0,0 +1,15 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +public interface IIntegerGeneratorModel extends IGeneratorModel { + void setBase(String base); + + void setMaxValue(String maxValue); + + void setMinValue(String minValue); + + String getMinValue(); + + String getMaxValue(); + + String getBase(); +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IIpAddressGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IIpAddressGeneratorModel.java new file mode 100644 index 0000000..39a632d --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IIpAddressGeneratorModel.java @@ -0,0 +1,9 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +import synfron.reshaper.burp.core.utils.ValueGenerator; + +public interface IIpAddressGeneratorModel extends IGeneratorModel { + void setVersion(ValueGenerator.IpVersion version); + + ValueGenerator.IpVersion getVersion(); +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IPasswordGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IPasswordGeneratorModel.java new file mode 100644 index 0000000..1c23eab --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IPasswordGeneratorModel.java @@ -0,0 +1,19 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +import synfron.reshaper.burp.core.utils.PasswordCharacterGroup; + +public interface IPasswordGeneratorModel extends IGeneratorModel { + void setMinLength(String minLength); + + void setMaxLength(String maxLength); + + void addPasswordCharacterGroups(PasswordCharacterGroup passwordCharacterGroup); + + void removePasswordCharacterGroups(PasswordCharacterGroup passwordCharacterGroup); + + String getMinLength(); + + String getMaxLength(); + + java.util.EnumSet getCharacterGroups(); +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/ITimestampGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/ITimestampGeneratorModel.java new file mode 100644 index 0000000..3e3d783 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/ITimestampGeneratorModel.java @@ -0,0 +1,15 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +public interface ITimestampGeneratorModel extends IGeneratorModel { + void setFormat(String format); + + void setMinTimestamp(String minTimestamp); + + void setMaxTimestamp(String maxTimestamp); + + String getFormat(); + + String getMinTimestamp(); + + String getMaxTimestamp(); +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IUnixTimestampGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IUnixTimestampGeneratorModel.java new file mode 100644 index 0000000..5bab4d1 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IUnixTimestampGeneratorModel.java @@ -0,0 +1,15 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +public interface IUnixTimestampGeneratorModel extends IGeneratorModel { + void setFormat(String format); + + void setMinTimestamp(String minTimestamp); + + void setMaxTimestamp(String maxTimestamp); + + String getFormat(); + + String getMinTimestamp(); + + String getMaxTimestamp(); +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IUuidGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IUuidGeneratorModel.java new file mode 100644 index 0000000..eb374b4 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IUuidGeneratorModel.java @@ -0,0 +1,17 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +import synfron.reshaper.burp.core.utils.ValueGenerator; + +public interface IUuidGeneratorModel extends IGeneratorModel { + void setVersion(ValueGenerator.UuidVersion version); + + void setNamespace(String namespace); + + void setName(String name); + + ValueGenerator.UuidVersion getVersion(); + + String getNamespace(); + + String getName(); +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IWordGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IWordGeneratorModel.java new file mode 100644 index 0000000..28491f7 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IWordGeneratorModel.java @@ -0,0 +1,17 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +import synfron.reshaper.burp.core.utils.ValueGenerator; + +public interface IWordGeneratorModel extends IGeneratorModel { + void setGeneratorType(ValueGenerator.WordGeneratorType generatorType); + + void setCount(String count); + + void setSeparator(String separator); + + ValueGenerator.WordGeneratorType getGeneratorType(); + + String getCount(); + + String getSeparator(); +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IntegerGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IntegerGeneratorModel.java new file mode 100644 index 0000000..da78951 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IntegerGeneratorModel.java @@ -0,0 +1,68 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.rules.thens.entities.generate.IntegerGenerator; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.util.List; + +@Getter +public class IntegerGeneratorModel extends GeneratorModel implements IIntegerGeneratorModel { + private String minValue = "0"; + private String maxValue = "10"; + private String base = "10"; + + public IntegerGeneratorModel(IntegerGenerator generator) { + super(generator); + minValue = VariableString.toString(generator.getMinValue(), minValue); + maxValue = VariableString.toString(generator.getMaxValue(), maxValue); + base = VariableString.toString(generator.getBase(), base); + } + + @Override + public void setBase(String base) { + this.base = base; + propertyChanged("base", base); + } + + @Override + public void setMaxValue(String maxValue) { + this.maxValue = maxValue; + propertyChanged("maxValue", maxValue); + } + + @Override + public void setMinValue(String minValue) { + this.minValue = minValue; + propertyChanged("minValue", minValue); + } + + @Override + public List validate() { + List errors = super.validate(); + if (StringUtils.isEmpty(minValue)) { + errors.add("Min Value is required"); + } else if (!VariableString.isPotentialLong(minValue)) { + errors.add("Min Value must be a long integer"); + } + if (StringUtils.isEmpty(maxValue)) { + errors.add("Max Value is required"); + } else if (!VariableString.isPotentialLong(maxValue)) { + errors.add("Max Value must be a long integer"); + } + if (!StringUtils.isEmpty(base) && !VariableString.isPotentialInt(base)) { + errors.add("Base must be an integer"); + } + return errors; + } + + @Override + public boolean persist() { + super.persist(); + generator.setMinValue(VariableString.getAsVariableString(minValue)); + generator.setMaxValue(VariableString.getAsVariableString(maxValue)); + generator.setBase(VariableString.getAsVariableString(base)); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IpAddressGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IpAddressGeneratorModel.java new file mode 100644 index 0000000..17b252b --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/IpAddressGeneratorModel.java @@ -0,0 +1,29 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +import lombok.Getter; +import synfron.reshaper.burp.core.rules.thens.entities.generate.IpAddressGenerator; +import synfron.reshaper.burp.core.utils.ValueGenerator; + +@Getter +public class IpAddressGeneratorModel extends GeneratorModel implements IIpAddressGeneratorModel { + + private ValueGenerator.IpVersion version; + + public IpAddressGeneratorModel(IpAddressGenerator generator) { + super(generator); + version = generator.getVersion(); + } + + @Override + public void setVersion(ValueGenerator.IpVersion version) { + this.version = version; + propertyChanged("version", version); + } + + @Override + public boolean persist() { + super.persist(); + generator.setVersion(version); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/PasswordGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/PasswordGeneratorModel.java new file mode 100644 index 0000000..7c4b8e9 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/PasswordGeneratorModel.java @@ -0,0 +1,77 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.rules.thens.entities.generate.PasswordGenerator; +import synfron.reshaper.burp.core.utils.PasswordCharacterGroup; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.util.EnumSet; +import java.util.List; + +@Getter +public class PasswordGeneratorModel extends GeneratorModel implements IPasswordGeneratorModel { + + private String minLength = "8"; + private String maxLength = "64"; + private EnumSet characterGroups; + + public PasswordGeneratorModel(PasswordGenerator generator) { + super(generator); + minLength = VariableString.toString(generator.getMinLength(), minLength); + maxLength = VariableString.toString(generator.getMaxLength(), maxLength); + characterGroups = EnumSet.copyOf(generator.getCharacterGroups()); + } + + @Override + public void setMinLength(String minLength) { + this.minLength = minLength; + propertyChanged("minLength", minLength); + } + + @Override + public void setMaxLength(String maxLength) { + this.maxLength = maxLength; + propertyChanged("maxLength", maxLength); + } + + @Override + public void addPasswordCharacterGroups(PasswordCharacterGroup passwordCharacterGroup) { + characterGroups.add(passwordCharacterGroup); + propertyChanged("characterGroups", characterGroups); + } + + @Override + public void removePasswordCharacterGroups(PasswordCharacterGroup passwordCharacterGroup) { + characterGroups.remove(passwordCharacterGroup); + propertyChanged("characterGroups", characterGroups); + } + + @Override + public List validate() { + List errors = super.validate(); + if (StringUtils.isEmpty(minLength)) { + errors.add("Min Length is required"); + } else if (!VariableString.isPotentialInt(minLength)) { + errors.add("Index must be an integer"); + } + if (StringUtils.isEmpty(maxLength)) { + errors.add("Index is required"); + } else if (!VariableString.isPotentialInt(maxLength)) { + errors.add("Index must be an integer"); + } + if (characterGroups.isEmpty()) { + errors.add("Must choose at least one character group"); + } + return errors; + } + + @Override + public boolean persist() { + super.persist(); + generator.setMinLength(VariableString.getAsVariableString(minLength)); + generator.setMaxLength(VariableString.getAsVariableString(maxLength)); + generator.setCharacterGroups(EnumSet.copyOf(characterGroups)); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/TimestampGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/TimestampGeneratorModel.java new file mode 100644 index 0000000..01c61fc --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/TimestampGeneratorModel.java @@ -0,0 +1,47 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +import lombok.Getter; +import synfron.reshaper.burp.core.rules.thens.entities.generate.TimestampGenerator; +import synfron.reshaper.burp.core.vars.VariableString; + +@Getter +public class TimestampGeneratorModel extends GeneratorModel implements ITimestampGeneratorModel { + + private String format = "yyyy-MM-dd"; + private String minTimestamp = ""; + private String maxTimestamp = ""; + + public TimestampGeneratorModel(TimestampGenerator generator) { + super(generator); + format = VariableString.toString(generator.getFormat(), format); + minTimestamp = VariableString.toString(generator.getMinTimestamp(), minTimestamp); + maxTimestamp = VariableString.toString(generator.getMaxTimestamp(), maxTimestamp); + } + + @Override + public void setFormat(String format) { + this.format = format; + propertyChanged("format", format); + } + + @Override + public void setMinTimestamp(String minTimestamp) { + this.minTimestamp = minTimestamp; + propertyChanged("minTimestamp", minTimestamp); + } + + @Override + public void setMaxTimestamp(String maxTimestamp) { + this.maxTimestamp = maxTimestamp; + propertyChanged("maxTimestamp", maxTimestamp); + } + + @Override + public boolean persist() { + super.persist(); + generator.setFormat(VariableString.getAsVariableString(format)); + generator.setMinTimestamp(VariableString.getAsVariableString(minTimestamp)); + generator.setMaxTimestamp(VariableString.getAsVariableString(maxTimestamp)); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/UnixTimestampGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/UnixTimestampGeneratorModel.java new file mode 100644 index 0000000..faef73d --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/UnixTimestampGeneratorModel.java @@ -0,0 +1,47 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +import lombok.Getter; +import synfron.reshaper.burp.core.rules.thens.entities.generate.UnixTimestampGenerator; +import synfron.reshaper.burp.core.vars.VariableString; + +@Getter +public class UnixTimestampGeneratorModel extends GeneratorModel implements IUnixTimestampGeneratorModel { + + private String format = "yyyy-MM-dd"; + private String minTimestamp = ""; + private String maxTimestamp = ""; + + public UnixTimestampGeneratorModel(UnixTimestampGenerator generator) { + super(generator); + format = VariableString.toString(generator.getFormat(), format); + minTimestamp = VariableString.toString(generator.getMinTimestamp(), minTimestamp); + maxTimestamp = VariableString.toString(generator.getMaxTimestamp(), maxTimestamp); + } + + @Override + public void setFormat(String format) { + this.format = format; + propertyChanged("format", format); + } + + @Override + public void setMinTimestamp(String minTimestamp) { + this.minTimestamp = minTimestamp; + propertyChanged("minTimestamp", minTimestamp); + } + + @Override + public void setMaxTimestamp(String maxTimestamp) { + this.maxTimestamp = maxTimestamp; + propertyChanged("maxTimestamp", maxTimestamp); + } + + @Override + public boolean persist() { + super.persist(); + generator.setFormat(VariableString.getAsVariableString(format)); + generator.setMinTimestamp(VariableString.getAsVariableString(minTimestamp)); + generator.setMaxTimestamp(VariableString.getAsVariableString(maxTimestamp)); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/UuidGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/UuidGeneratorModel.java new file mode 100644 index 0000000..74ef6cb --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/UuidGeneratorModel.java @@ -0,0 +1,65 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.rules.thens.entities.generate.UuidGenerator; +import synfron.reshaper.burp.core.utils.ValueGenerator; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.util.List; + +@Getter +public class UuidGeneratorModel extends GeneratorModel implements IUuidGeneratorModel { + + private ValueGenerator.UuidVersion version; + + private String namespace = ""; + private String name = ""; + + public UuidGeneratorModel(UuidGenerator generator) { + super(generator); + version = generator.getVersion(); + namespace = VariableString.toString(generator.getNamespace(), namespace); + name = VariableString.toString(generator.getName(), name); + } + + @Override + public void setVersion(ValueGenerator.UuidVersion version) { + this.version = version; + propertyChanged("version", version); + } + + @Override + public void setNamespace(String namespace) { + this.namespace = namespace; + propertyChanged("namespace", namespace); + } + + @Override + public void setName(String name) { + this.name = name; + propertyChanged("name", name); + } + + public List validate() { + List errors = super.validate(); + if (version.isHasInputs()) { + if (StringUtils.isEmpty(namespace)) { + errors.add("Namespace is required"); + } + if (StringUtils.isEmpty(name)) { + errors.add("Name is required"); + } + } + return errors; + } + + @Override + public boolean persist() { + super.persist(); + generator.setVersion(version); + generator.setNamespace(VariableString.getAsVariableString(namespace)); + generator.setName(VariableString.getAsVariableString(name)); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/WordGeneratorModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/WordGeneratorModel.java new file mode 100644 index 0000000..e998bb4 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/generate/WordGeneratorModel.java @@ -0,0 +1,60 @@ +package synfron.reshaper.burp.ui.models.rules.thens.generate; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.rules.thens.entities.generate.WordGenerator; +import synfron.reshaper.burp.core.utils.ValueGenerator; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.util.List; + +@Getter +public class WordGeneratorModel extends GeneratorModel implements IWordGeneratorModel { + + private ValueGenerator.WordGeneratorType generatorType; + private String count = "1"; + private String separator = ""; + + public WordGeneratorModel(WordGenerator generator) { + super(generator); + generatorType = generator.getGeneratorType(); + count = VariableString.toString(generator.getCount(), count); + separator = VariableString.toString(generator.getSeparator(), separator); + } + + @Override + public void setGeneratorType(ValueGenerator.WordGeneratorType generatorType) { + this.generatorType = generatorType; + propertyChanged("generatorType", generatorType); + } + + @Override + public void setCount(String count) { + this.count = count; + propertyChanged("count", count); + } + + @Override + public void setSeparator(String separator) { + this.separator = separator; + propertyChanged("separator", separator); + } + + @Override + public List validate() { + List errors = super.validate(); + if (!StringUtils.isEmpty(count) && !VariableString.isPotentialInt(count)) { + errors.add("Count must be an integer"); + } + return errors; + } + + @Override + public boolean persist() { + super.persist(); + generator.setGeneratorType(generatorType); + generator.setSeparator(VariableString.getAsVariableString(separator)); + generator.setCount(VariableString.getAsVariableString(count)); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/parsehttpmessage/MessageValueGetterModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/parsehttpmessage/MessageValueGetterModel.java index 056dcca..6fe2fce 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/parsehttpmessage/MessageValueGetterModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/parsehttpmessage/MessageValueGetterModel.java @@ -136,7 +136,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } messageValueGetter.setSourceMessageValue(sourceMessageValue); @@ -149,12 +149,4 @@ public boolean persist() { messageValueGetter.setIndex(VariableString.getAsVariableString(index)); return true; } - - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/Base64TransformerModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/Base64TransformerModel.java new file mode 100644 index 0000000..3f6e86c --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/Base64TransformerModel.java @@ -0,0 +1,55 @@ +package synfron.reshaper.burp.ui.models.rules.thens.transform; + +import lombok.Getter; +import synfron.reshaper.burp.core.rules.thens.entities.transform.Base64Transformer; +import synfron.reshaper.burp.core.rules.thens.entities.transform.Base64Variant; +import synfron.reshaper.burp.core.rules.thens.entities.transform.EncodeTransform; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +@Getter +public class Base64TransformerModel extends TransformerModel { + + private Base64Variant variant; + private EncodeTransform action; + private String encoding = StandardCharsets.ISO_8859_1.displayName(); + + public Base64TransformerModel(Base64Transformer transformer) { + super(transformer); + variant = transformer.getVariant(); + action = transformer.getAction(); + encoding = VariableString.toString(transformer.getEncoding(), encoding); + } + + public void setVariant(Base64Variant variant) { + this.variant = variant; + propertyChanged("variant", variant); + } + + public void setAction(EncodeTransform action) { + this.action = action; + propertyChanged("action", action); + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + propertyChanged("encoding", encoding); + } + + @Override + public List validate() { + List errors = super.validate(); + return errors; + } + + @Override + public boolean persist() { + super.persist(); + transformer.setVariant(variant); + transformer.setAction(action); + transformer.setEncoding(VariableString.getAsVariableString(encoding)); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/CaseTransformerModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/CaseTransformerModel.java new file mode 100644 index 0000000..9df4adf --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/CaseTransformerModel.java @@ -0,0 +1,35 @@ +package synfron.reshaper.burp.ui.models.rules.thens.transform; + +import lombok.Getter; +import synfron.reshaper.burp.core.rules.thens.entities.transform.CaseTransformer; +import synfron.reshaper.burp.core.utils.PhraseCase; + +import java.util.List; + +@Getter +public class CaseTransformerModel extends TransformerModel { + + private PhraseCase phraseCase; + + public CaseTransformerModel(CaseTransformer transformer) { + super(transformer); + phraseCase = transformer.getPhraseCase(); + } + + public void setPhraseCase(PhraseCase phraseCase) { + this.phraseCase = phraseCase; + propertyChanged("phraseCase", phraseCase); + } + + @Override + public List validate() { + return super.validate(); + } + + @Override + public boolean persist() { + super.persist(); + transformer.setPhraseCase(phraseCase); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/EscapeTransformerModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/EscapeTransformerModel.java new file mode 100644 index 0000000..620abc2 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/EscapeTransformerModel.java @@ -0,0 +1,45 @@ +package synfron.reshaper.burp.ui.models.rules.thens.transform; + +import lombok.Getter; +import synfron.reshaper.burp.core.rules.thens.entities.transform.EntityType; +import synfron.reshaper.burp.core.rules.thens.entities.transform.EscapeTransform; +import synfron.reshaper.burp.core.rules.thens.entities.transform.EscapeTransformer; + +import java.util.List; + +@Getter +public class EscapeTransformerModel extends TransformerModel { + + private EntityType entityType; + private EscapeTransform action; + + public EscapeTransformerModel(EscapeTransformer transformer) { + super(transformer); + entityType = transformer.getEntityType(); + action = transformer.getAction(); + } + + public void setEntityType(EntityType entityType) { + this.entityType = entityType; + propertyChanged("entityType", entityType); + } + + public void setAction(EscapeTransform action) { + this.action = action; + propertyChanged("action", action); + } + + @Override + public List validate() { + List errors = super.validate(); + return errors; + } + + @Override + public boolean persist() { + super.persist(); + transformer.setEntityType(entityType); + transformer.setAction(action); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/HashTransformerModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/HashTransformerModel.java new file mode 100644 index 0000000..6a308ed --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/HashTransformerModel.java @@ -0,0 +1,35 @@ +package synfron.reshaper.burp.ui.models.rules.thens.transform; + +import lombok.Getter; +import synfron.reshaper.burp.core.rules.thens.entities.transform.HashTransformer; +import synfron.reshaper.burp.core.rules.thens.entities.transform.HashType; + +import java.util.List; + +@Getter +public class HashTransformerModel extends TransformerModel { + + private HashType hashType; + + public HashTransformerModel(HashTransformer transformer) { + super(transformer); + hashType = transformer.getHashType(); + } + + public void setHashType(HashType hashType) { + this.hashType = hashType; + propertyChanged("hashType", hashType); + } + + @Override + public List validate() { + return super.validate(); + } + + @Override + public boolean persist() { + super.persist(); + transformer.setHashType(hashType); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/HexTransformerModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/HexTransformerModel.java new file mode 100644 index 0000000..07c8d5e --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/HexTransformerModel.java @@ -0,0 +1,45 @@ +package synfron.reshaper.burp.ui.models.rules.thens.transform; + +import lombok.Getter; +import synfron.reshaper.burp.core.rules.thens.entities.transform.HexTransformer; +import synfron.reshaper.burp.core.rules.thens.entities.transform.TextTransform; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +@Getter +public class HexTransformerModel extends TransformerModel { + + private TextTransform action; + private String encoding = StandardCharsets.ISO_8859_1.displayName(); + + public HexTransformerModel(HexTransformer transformer) { + super(transformer); + action = transformer.getAction(); + encoding = VariableString.toString(transformer.getEncoding(), encoding); + } + + public void setAction(TextTransform action) { + this.action = action; + propertyChanged("action", action); + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + propertyChanged("encoding", encoding); + } + + @Override + public List validate() { + return super.validate(); + } + + @Override + public boolean persist() { + super.persist(); + transformer.setAction(action); + transformer.setEncoding(VariableString.getAsVariableString(encoding)); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/IntegerTransformerModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/IntegerTransformerModel.java new file mode 100644 index 0000000..e85590a --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/IntegerTransformerModel.java @@ -0,0 +1,51 @@ +package synfron.reshaper.burp.ui.models.rules.thens.transform; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.rules.thens.entities.transform.IntegerTransformer; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.util.List; + +@Getter +public class IntegerTransformerModel extends TransformerModel { + + private String sourceBase = "10"; + private String targetBase = "16"; + + public IntegerTransformerModel(IntegerTransformer transformer) { + super(transformer); + sourceBase = VariableString.toString(transformer.getSourceBase(), sourceBase); + targetBase = VariableString.toString(transformer.getTargetBase(), targetBase); + } + + public void setSourceBase(String sourceBase) { + this.sourceBase = sourceBase; + propertyChanged("sourceBase", sourceBase); + } + + public void setTargetBase(String targetBase) { + this.targetBase = targetBase; + propertyChanged("targetBase", targetBase); + } + + @Override + public List validate() { + List errors = super.validate(); + if (!StringUtils.isEmpty(sourceBase) && !VariableString.isPotentialInt(sourceBase)) { + errors.add("Source Base must be an integer"); + } + if (!StringUtils.isEmpty(targetBase) && !VariableString.isPotentialInt(targetBase)) { + errors.add("Target Base must be an integer"); + } + return errors; + } + + @Override + public boolean persist() { + super.persist(); + transformer.setSourceBase(VariableString.getAsVariableString(sourceBase)); + transformer.setTargetBase(VariableString.getAsVariableString(targetBase)); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/JwtDecodeTransformerModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/JwtDecodeTransformerModel.java new file mode 100644 index 0000000..2468157 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/JwtDecodeTransformerModel.java @@ -0,0 +1,35 @@ +package synfron.reshaper.burp.ui.models.rules.thens.transform; + +import lombok.Getter; +import synfron.reshaper.burp.core.rules.thens.entities.transform.JwtDecodeTransformer; +import synfron.reshaper.burp.core.rules.thens.entities.transform.JwtSegment; + +import java.util.List; + +@Getter +public class JwtDecodeTransformerModel extends TransformerModel { + + private JwtSegment segment; + + public JwtDecodeTransformerModel(JwtDecodeTransformer transformer) { + super(transformer); + segment = transformer.getSegment(); + } + + public void setSegment(JwtSegment segment) { + this.segment = segment; + propertyChanged("segment", segment); + } + + @Override + public List validate() { + return super.validate(); + } + + @Override + public boolean persist() { + super.persist(); + transformer.setSegment(segment); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/TransformerModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/TransformerModel.java new file mode 100644 index 0000000..fd53ca8 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/TransformerModel.java @@ -0,0 +1,64 @@ +package synfron.reshaper.burp.ui.models.rules.thens.transform; + +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.rules.thens.entities.transform.ITransformer; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.util.ArrayList; +import java.util.List; + +@Getter +public abstract class TransformerModel, R extends ITransformer> { + protected final R transformer; + + private String input = ""; + private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); + protected boolean validated; + + public TransformerModel(R transformer) { + this.transformer = transformer; + input = VariableString.toString(transformer.getInput(), input); + } + + public void setInput(String input) { + this.input = input; + propertyChanged("input", input); + } + + protected void propertyChanged(String name, Object value) { + setValidated(false); + propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); + } + + public T withListener(IEventListener listener) { + getPropertyChangedEvent().add(listener); + return (T)this; + } + + protected void setValidated(boolean validated) { + if (validated != this.validated) { + this.validated = validated; + propertyChangedEvent.invoke(new PropertyChangedArgs(this, "validated", validated)); + } + } + + public List validate() { + List errors = new ArrayList<>(); + if (StringUtils.isEmpty(input)) { + errors.add("Input is required"); + } + return errors; + } + + public boolean persist() { + if (!validate().isEmpty()) { + return false; + } + transformer.setInput(VariableString.getAsVariableString(input)); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/TrimTransformerModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/TrimTransformerModel.java new file mode 100644 index 0000000..5432e58 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/transform/TrimTransformerModel.java @@ -0,0 +1,44 @@ +package synfron.reshaper.burp.ui.models.rules.thens.transform; + +import lombok.Getter; +import synfron.reshaper.burp.core.rules.thens.entities.transform.TrimOption; +import synfron.reshaper.burp.core.rules.thens.entities.transform.TrimTransformer; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.util.List; + +@Getter +public class TrimTransformerModel extends TransformerModel { + + private TrimOption trimOption; + private String characters = ""; + + public TrimTransformerModel(TrimTransformer transformer) { + super(transformer); + trimOption = transformer.getTrimOption(); + characters = VariableString.toString(transformer.getCharacters(), characters); + } + + public void setTrimOption(TrimOption trimOption) { + this.trimOption = trimOption; + propertyChanged("trimOption", trimOption); + } + + public void setCharacters(String characters) { + this.characters = characters; + propertyChanged("characters", characters); + } + + @Override + public List validate() { + return super.validate(); + } + + @Override + public boolean persist() { + super.persist(); + transformer.setTrimOption(trimOption); + transformer.setCharacters(VariableString.getAsVariableString(characters)); + return true; + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenContentTypeModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenContentTypeModel.java index be1e57e..0670c2b 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenContentTypeModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenContentTypeModel.java @@ -22,22 +22,13 @@ public void setContentType(ContentType contentType) { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setContentType(contentType); return super.persist(); } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return contentType.getName(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenEventDirectionModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenEventDirectionModel.java index 447e3a2..ee71812 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenEventDirectionModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenEventDirectionModel.java @@ -22,22 +22,13 @@ public void setDataDirection(HttpDataDirection dataDirection) { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setDataDirection(dataDirection); return super.persist(); } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return dataDirection.name(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenFromToolModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenFromToolModel.java index 55e1a4d..76dc900 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenFromToolModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenFromToolModel.java @@ -22,22 +22,13 @@ public void setTool(BurpTool tool) { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setTool(tool); return super.persist(); } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return tool.name(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenHasEntityModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenHasEntityModel.java index f26f69f..1f6058e 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenHasEntityModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenHasEntityModel.java @@ -44,7 +44,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setMessageValue(messageValue); @@ -52,15 +52,6 @@ public boolean persist() { return super.persist(); } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return messageValue.getName(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenInScopeModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenInScopeModel.java index aaa4565..98e9392 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenInScopeModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenInScopeModel.java @@ -33,22 +33,13 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setUrl(VariableString.getAsVariableString(url)); return super.persist(); } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return abbreviateTargetName(url); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMatchesTextModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMatchesTextModel.java index 84d5fbe..a2412b9 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMatchesTextModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMatchesTextModel.java @@ -111,7 +111,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setIdentifier(VariableString.getAsVariableString(identifier)); @@ -127,15 +127,6 @@ public boolean persist() { return super.persist(); } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return abbreviateTargetName(matchText); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMessageTypeModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMessageTypeModel.java index 6c34be5..e5f14d0 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMessageTypeModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMessageTypeModel.java @@ -22,22 +22,13 @@ public void setMessageType(WebSocketMessageType messageType) { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setMessageType(messageType); return super.persist(); } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return messageType.name(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMimeTypeModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMimeTypeModel.java index ba658aa..f6721a1 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMimeTypeModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMimeTypeModel.java @@ -22,22 +22,13 @@ public void setMimeType(MimeType mimeType) { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setMimeType(mimeType); return super.persist(); } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return mimeType.getName(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenModelType.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenModelType.java index e4a8d26..9476a26 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenModelType.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenModelType.java @@ -13,7 +13,7 @@ public class WhenModelType

, T extends When> extends public static final WhenModelType EventDirection = new WhenModelType<>(WhenEventDirectionModel.class, WhenType.EventDirection); public static final WhenModelType WebSocketEventDirection = new WhenModelType<>(WhenWebSocketEventDirectionModel.class, WhenType.WebSocketEventDirection); public static final WhenModelType HasEntity = new WhenModelType<>(WhenHasEntityModel.class, WhenType.HasEntity); - public static final WhenModelType MatchesText = new WhenModelType<>(WhenMatchesTextModel.class, WhenType.MatchesText); + public static final WhenModelType MatchesText = new WhenModelType<>(WhenMatchesTextModel.class, WhenType.MatchesText, true); public static final WhenModelType ContentType = new WhenModelType<>(WhenContentTypeModel.class, WhenType.ContentType); public static final WhenModelType MimeType = new WhenModelType<>(WhenMimeTypeModel.class, WhenType.MimeType); public static final WhenModelType MessageType = new WhenModelType<>(WhenMessageTypeModel.class, WhenType.MessageType); @@ -26,6 +26,10 @@ private WhenModelType(Class

type, RuleOperationType ruleOperationType) { super(type, ruleOperationType); } + private WhenModelType(Class

type, RuleOperationType ruleOperationType, boolean isDefault) { + super(type, ruleOperationType, isDefault); + } + public static List> getTypes(ProtocolType protocolType) { return Stream.of( EventDirection, diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenProxyNameModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenProxyNameModel.java index 179aac6..f806183 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenProxyNameModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenProxyNameModel.java @@ -32,22 +32,13 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setProxyName(proxyName); return super.persist(); } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return abbreviateTargetName(proxyName); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenRepeatModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenRepeatModel.java index 18adbac..4dd81cf 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenRepeatModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenRepeatModel.java @@ -9,6 +9,7 @@ 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.core.vars.VariableTag; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; import synfron.reshaper.burp.ui.models.rules.thens.IVariableCreator; import synfron.reshaper.burp.ui.models.rules.thens.VariableCreatorRegistry; @@ -82,7 +83,7 @@ public List validate() { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setSubGroupCount(Integer.parseInt(subGroupCount)); @@ -93,18 +94,9 @@ public boolean persist() { return super.persist(); } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { - return abbreviateTargetName(VariableSourceEntry.getTag(listVariableSource, listVariableName)); + return abbreviateTargetName(VariableTag.getTag(listVariableSource, listVariableName)); } @Override @@ -114,6 +106,6 @@ public RuleOperationModelType getType() { @Override public List getVariableEntries() { - return List.of(new VariableSourceEntry(VariableSource.Event, entryVariableName)); + return List.of(new VariableSourceEntry(VariableSource.Event, List.of(entryVariableName))); } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenWebSocketEventDirectionModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenWebSocketEventDirectionModel.java index 35894e0..9e9df7f 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenWebSocketEventDirectionModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenWebSocketEventDirectionModel.java @@ -22,22 +22,13 @@ public void setDataDirection(WebSocketDataDirection dataDirection) { } public boolean persist() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } ruleOperation.setDataDirection(dataDirection); return super.persist(); } - @Override - public boolean record() { - if (validate().size() != 0) { - return false; - } - setValidated(true); - return true; - } - @Override protected String getTargetName() { return dataDirection.name(); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/AnnotationVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/AnnotationVariableTagWizardModel.java index d83be6e..ae20ee7 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/AnnotationVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/AnnotationVariableTagWizardModel.java @@ -5,7 +5,7 @@ import synfron.reshaper.burp.core.events.PropertyChangedEvent; import synfron.reshaper.burp.core.messages.MessageAnnotation; import synfron.reshaper.burp.core.vars.VariableSource; -import synfron.reshaper.burp.core.vars.VariableSourceEntry; +import synfron.reshaper.burp.core.vars.VariableTag; import java.util.ArrayList; import java.util.List; @@ -41,7 +41,7 @@ public VariableSource getVariableSource() { @Override public String getTag() { return validate().isEmpty() ? - VariableSourceEntry.getShortTag( + VariableTag.getShortTag( VariableSource.Annotation, messageAnnotation.name().toLowerCase() ) : diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CookieJarVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CookieJarVariableTagWizardModel.java index afb1472..a4e6d8d 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CookieJarVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CookieJarVariableTagWizardModel.java @@ -9,7 +9,7 @@ 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 synfron.reshaper.burp.core.vars.VariableTag; import java.util.ArrayList; import java.util.Collections; @@ -110,7 +110,7 @@ public VariableSource getVariableSource() { @Override public String getTag() { return validate().isEmpty() ? - VariableSourceEntry.getShortTag( + VariableTag.getShortTag( VariableSource.CookieJar, getTagSafe(domains.getSelectedOption()), getTagSafe(names.getSelectedOption()), diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CustomListVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CustomListVariableTagWizardModel.java index 2ea4c89..3707e74 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CustomListVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CustomListVariableTagWizardModel.java @@ -6,6 +6,7 @@ import synfron.reshaper.burp.core.vars.GetListItemPlacement; import synfron.reshaper.burp.core.vars.VariableSourceEntry; import synfron.reshaper.burp.core.vars.VariableString; +import synfron.reshaper.burp.core.vars.VariableTag; import java.util.List; @@ -50,7 +51,7 @@ public List validate() { @Override public String getTag() { return validate().isEmpty() ? - VariableSourceEntry.getShortTag( + VariableTag.getShortTag( getVariableSource(), getVariableName(), itemPlacement == GetListItemPlacement.Index ? index : itemPlacement.name() diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CustomVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CustomVariableTagWizardModel.java index cc37823..338b276 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CustomVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CustomVariableTagWizardModel.java @@ -6,6 +6,7 @@ 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.VariableTag; import java.util.ArrayList; import java.util.List; @@ -51,7 +52,7 @@ public List validate() { @Override public String getTag() { return validate().isEmpty() ? - VariableSourceEntry.getShortTag(getVariableSource(), variableName) : + VariableTag.getShortTag(getVariableSource(), variableName) : null; } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/EventListVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/EventListVariableTagWizardModel.java index 39b4823..9bef82f 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/EventListVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/EventListVariableTagWizardModel.java @@ -17,7 +17,7 @@ public EventListVariableTagWizardModel(List entries) { public List getUpdatedVariableNames(List entries) { return entries.stream() .filter(entry -> entry.getVariableSource() == VariableSource.EventList) - .map(VariableSourceEntry::getName) + .map(entry -> entry.getParams().getFirst()) .filter(VariableString::isValidVariableName) .distinct() .sorted(String::compareToIgnoreCase) diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/EventVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/EventVariableTagWizardModel.java index c90edcc..fb58063 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/EventVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/EventVariableTagWizardModel.java @@ -17,7 +17,7 @@ public EventVariableTagWizardModel(List entries) { public List getUpdatedVariableNames(List entries) { return entries.stream() .filter(entry -> entry.getVariableSource() == VariableSource.Event) - .map(VariableSourceEntry::getName) + .map(entry -> entry.getParams().getFirst()) .filter(VariableString::isValidVariableName) .distinct() .sorted(String::compareToIgnoreCase) diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/FileVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/FileVariableTagWizardModel.java index 35932fb..6062f1d 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/FileVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/FileVariableTagWizardModel.java @@ -6,7 +6,7 @@ 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 synfron.reshaper.burp.core.vars.VariableTag; import java.util.ArrayList; import java.util.List; @@ -56,7 +56,7 @@ public VariableSource getVariableSource() { @Override public String getTag() { return validate().isEmpty() ? - VariableSourceEntry.getShortTag(VariableSource.File, encoding, filePath) : + VariableTag.getShortTag(VariableSource.File, encoding, filePath) : null; } } diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GeneratorVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GeneratorVariableTagWizardModel.java new file mode 100644 index 0000000..c2b4e28 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GeneratorVariableTagWizardModel.java @@ -0,0 +1,69 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars; + +import lombok.Getter; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.core.events.PropertyChangedEvent; +import synfron.reshaper.burp.core.rules.thens.entities.generate.GenerateOption; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.ui.models.rules.wizard.vars.generator.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Getter +public class GeneratorVariableTagWizardModel implements IVariableTagWizardModel { + + private GenerateOption generateOption = GenerateOption.Uuid; + private GeneratorVariableModel generator; + private final Map> generatorMap = new HashMap<>(); + + private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); + + public GeneratorVariableTagWizardModel() { + setGenerateOption(generateOption); + } + + private GeneratorVariableModel constructGeneratorModel(GenerateOption generateOption) { + return switch (generateOption) { + case Uuid -> new UuidGeneratorVariableModel(); + case Words -> new WordGeneratorVariableModel(); + case Bytes -> new BytesGeneratorVariableModel(); + case Integer -> new IntegerGeneratorVariableModel(); + case IpAddress -> new IpAddressGeneratorVariableModel(); + case Timestamp -> new TimestampGeneratorVariableModel(); + case UnixTimestamp -> new UnixTimestampGeneratorVariableModel(); + case Password -> new PasswordGeneratorVariableModel(); + }; + } + + public void setGenerateOption(GenerateOption generateOption) { + this.generateOption = generateOption; + propertyChanged("generateOption", generateOption); + setGenerator(generatorMap.computeIfAbsent(this.generateOption, this::constructGeneratorModel)); + } + + public void setGenerator(GeneratorVariableModel generator) { + this.generator = generator; + propertyChanged("generator", generator); + } + + private void propertyChanged(String name, Object value) { + propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); + } + + @Override + public List validate() { + return generator.validate(); + } + + @Override + public VariableSource getVariableSource() { + return VariableSource.Generator; + } + + @Override + public String getTag() { + return generator.getTag(); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GlobalListVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GlobalListVariableTagWizardModel.java index 705ac44..4df2163 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GlobalListVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GlobalListVariableTagWizardModel.java @@ -18,7 +18,7 @@ public List getUpdatedVariableNames(List entries) { GlobalVariables.get().getValues().stream().filter(Variable::isList).map(Variable::getName), entries.stream() .filter(entry -> entry.getVariableSource() == VariableSource.GlobalList) - .map(VariableSourceEntry::getName) + .map(entry -> entry.getParams().getFirst()) ) .filter(VariableString::isValidVariableName) .distinct() diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GlobalVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GlobalVariableTagWizardModel.java index 726c1b3..4088b13 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GlobalVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/GlobalVariableTagWizardModel.java @@ -18,7 +18,7 @@ public List getUpdatedVariableNames(List entries) { GlobalVariables.get().getValues().stream().filter(variable -> !variable.isList()).map(Variable::getName), entries.stream() .filter(entry -> entry.getVariableSource() == VariableSource.Global) - .map(VariableSourceEntry::getName) + .map(entry -> entry.getParams().getFirst()) ) .filter(VariableString::isValidVariableName) .distinct() diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MacroVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MacroVariableTagWizardModel.java index 8cd4193..1104d7e 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MacroVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MacroVariableTagWizardModel.java @@ -7,7 +7,7 @@ import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.utils.TextUtils; import synfron.reshaper.burp.core.vars.VariableSource; -import synfron.reshaper.burp.core.vars.VariableSourceEntry; +import synfron.reshaper.burp.core.vars.VariableTag; import java.util.ArrayList; import java.util.List; @@ -67,7 +67,7 @@ public VariableSource getVariableSource() { @Override public String getTag() { return validate().isEmpty() ? - VariableSourceEntry.getShortTag( + VariableTag.getShortTag( VariableSource.Macro, macroItemNumber, messageValue.name().toLowerCase(), diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MessageVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MessageVariableTagWizardModel.java index 28ca84e..81351ec 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MessageVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/MessageVariableTagWizardModel.java @@ -6,7 +6,7 @@ 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 synfron.reshaper.burp.core.vars.VariableTag; import java.util.ArrayList; import java.util.List; @@ -53,7 +53,7 @@ public VariableSource getVariableSource() { @Override public String getTag() { return validate().isEmpty() ? - VariableSourceEntry.getShortTag( + VariableTag.getShortTag( VariableSource.Message, messageValue.name().toLowerCase(), messageValue.isIdentifierRequired() ? identifier : null diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SessionListVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SessionListVariableTagWizardModel.java index 4c2f260..fd121a2 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SessionListVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SessionListVariableTagWizardModel.java @@ -17,7 +17,7 @@ public SessionListVariableTagWizardModel(List entries) { public List getUpdatedVariableNames(List entries) { return entries.stream() .filter(entry -> entry.getVariableSource() == VariableSource.SessionList) - .map(VariableSourceEntry::getName) + .map(entry -> entry.getParams().getFirst()) .filter(VariableString::isValidVariableName) .distinct() .sorted(String::compareToIgnoreCase) diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SessionVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SessionVariableTagWizardModel.java index 2fa87e9..571f539 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SessionVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SessionVariableTagWizardModel.java @@ -17,7 +17,7 @@ public SessionVariableTagWizardModel(List entries) { public List getUpdatedVariableNames(List entries) { return entries.stream() .filter(entry -> entry.getVariableSource() == VariableSource.Session) - .map(VariableSourceEntry::getName) + .map(entry -> entry.getParams().getFirst()) .filter(VariableString::isValidVariableName) .distinct() .sorted(String::compareToIgnoreCase) diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SpecialVariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SpecialVariableTagWizardModel.java index eab1471..b06ceb7 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SpecialVariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SpecialVariableTagWizardModel.java @@ -5,7 +5,7 @@ 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.VariableTag; import java.util.ArrayList; import java.util.List; @@ -27,7 +27,7 @@ public class SpecialVariableTagWizardModel implements IVariableTagWizardModel { ); @Getter - private SpecialChar specialChar = specialChars.get(0); + private SpecialChar specialChar = specialChars.getFirst(); @Getter private String value; @@ -72,7 +72,7 @@ public VariableSource getVariableSource() { @Override public String getTag() { return validate().isEmpty() ? - VariableSourceEntry.getShortTag( + VariableTag.getShortTag( VariableSource.Special, specialChar.code + (specialChar.isValueRequired() ? value : "") ) : diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/VariableTagWizardModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/VariableTagWizardModel.java index 4e8c1b1..8eb1264 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/VariableTagWizardModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/VariableTagWizardModel.java @@ -50,7 +50,8 @@ public VariableTagWizardModel() { Map.entry(VariableSource.File, new FileVariableTagWizardModel()), Map.entry(VariableSource.Special, new SpecialVariableTagWizardModel()), Map.entry(VariableSource.CookieJar, new CookieJarVariableTagWizardModel()), - Map.entry(VariableSource.Annotation, new AnnotationVariableTagWizardModel()) + Map.entry(VariableSource.Annotation, new AnnotationVariableTagWizardModel()), + Map.entry(VariableSource.Generator, new GeneratorVariableTagWizardModel()) ); tagModel = tagModelMap.get(variableSource); diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/BytesGeneratorVariableModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/BytesGeneratorVariableModel.java new file mode 100644 index 0000000..34508b6 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/BytesGeneratorVariableModel.java @@ -0,0 +1,45 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars.generator; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.rules.thens.entities.generate.GenerateOption; +import synfron.reshaper.burp.core.utils.TextUtils; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableTag; +import synfron.reshaper.burp.ui.models.rules.thens.generate.IBytesGeneratorModel; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +@Getter +public class BytesGeneratorVariableModel extends GeneratorVariableModel implements IBytesGeneratorModel { + + private String length = ""; + private String encoding = StandardCharsets.ISO_8859_1.displayName(); + + public void setLength(String length) { + this.length = length; + propertyChanged("length", length); + } + + public void setEncoding(String encoding) { + this.encoding = encoding; + propertyChanged("encoding", encoding); + } + + @Override + public List validate() { + List errors = super.validate(); + if (StringUtils.isEmpty(length)) { + errors.add("Length is required"); + } else if (!TextUtils.isInt(length)) { + errors.add("Length must be an integer"); + } + return errors; + } + + @Override + public String getTagInternal() { + return VariableTag.getShortTag(VariableSource.Generator, GenerateOption.Bytes.name().toLowerCase(), length, encoding); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/GeneratorVariableModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/GeneratorVariableModel.java new file mode 100644 index 0000000..6b6b18a --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/GeneratorVariableModel.java @@ -0,0 +1,45 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars.generator; + +import lombok.Getter; +import synfron.reshaper.burp.core.events.IEventListener; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.core.events.PropertyChangedEvent; + +import java.util.ArrayList; +import java.util.List; + +@Getter +public abstract class GeneratorVariableModel> { + private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); + protected boolean validated; + + protected void propertyChanged(String name, Object value) { + setValidated(false); + propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); + } + + protected T withListener(IEventListener listener) { + getPropertyChangedEvent().add(listener); + return (T)this; + } + + protected void setValidated(boolean validated) { + if (validated != this.validated) { + this.validated = validated; + propertyChangedEvent.invoke(new PropertyChangedArgs(this, "validated", validated)); + } + } + + public List validate() { + return new ArrayList<>(); + } + + + public String getTag() { + return validate().isEmpty() ? + getTagInternal() : + null; + } + + public abstract String getTagInternal(); +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/IntegerGeneratorVariableModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/IntegerGeneratorVariableModel.java new file mode 100644 index 0000000..7fe23b2 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/IntegerGeneratorVariableModel.java @@ -0,0 +1,57 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars.generator; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.rules.thens.entities.generate.GenerateOption; +import synfron.reshaper.burp.core.utils.TextUtils; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableTag; +import synfron.reshaper.burp.ui.models.rules.thens.generate.IIntegerGeneratorModel; + +import java.util.List; + +@Getter +public class IntegerGeneratorVariableModel extends GeneratorVariableModel implements IIntegerGeneratorModel { + private String minValue = "0"; + private String maxValue = "10"; + private String base = "10"; + + public void setBase(String base) { + this.base = base; + propertyChanged("base", base); + } + + public void setMaxValue(String maxValue) { + this.maxValue = maxValue; + propertyChanged("maxValue", maxValue); + } + + public void setMinValue(String minValue) { + this.minValue = minValue; + propertyChanged("minValue", minValue); + } + + @Override + public List validate() { + List errors = super.validate(); + if (StringUtils.isEmpty(minValue)) { + errors.add("Min Value is required"); + } else if (!TextUtils.isLong(minValue)) { + errors.add("Min Value must be a long integer"); + } + if (StringUtils.isEmpty(maxValue)) { + errors.add("Max Value is required"); + } else if (!TextUtils.isLong(maxValue)) { + errors.add("Max Value must be a long integer"); + } + if (!StringUtils.isEmpty(base) && !TextUtils.isInt(base)) { + errors.add("Base must be an integer"); + } + return errors; + } + + @Override + public String getTagInternal() { + return VariableTag.getShortTag(VariableSource.Generator, GenerateOption.Integer.name().toLowerCase(), minValue, maxValue, base); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/IpAddressGeneratorVariableModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/IpAddressGeneratorVariableModel.java new file mode 100644 index 0000000..235cd52 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/IpAddressGeneratorVariableModel.java @@ -0,0 +1,24 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars.generator; + +import lombok.Getter; +import synfron.reshaper.burp.core.rules.thens.entities.generate.GenerateOption; +import synfron.reshaper.burp.core.utils.ValueGenerator; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableTag; +import synfron.reshaper.burp.ui.models.rules.thens.generate.IIpAddressGeneratorModel; + +@Getter +public class IpAddressGeneratorVariableModel extends GeneratorVariableModel implements IIpAddressGeneratorModel { + + private ValueGenerator.IpVersion version = ValueGenerator.IpVersion.V4; + + public void setVersion(ValueGenerator.IpVersion version) { + this.version = version; + propertyChanged("version", version); + } + + @Override + public String getTagInternal() { + return VariableTag.getShortTag(VariableSource.Generator, GenerateOption.IpAddress.name().toLowerCase(), version.name().toLowerCase()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/PasswordGeneratorVariableModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/PasswordGeneratorVariableModel.java new file mode 100644 index 0000000..4b1c9a8 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/PasswordGeneratorVariableModel.java @@ -0,0 +1,66 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars.generator; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.rules.thens.entities.generate.GenerateOption; +import synfron.reshaper.burp.core.utils.PasswordCharacterGroup; +import synfron.reshaper.burp.core.utils.TextUtils; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableTag; +import synfron.reshaper.burp.ui.models.rules.thens.generate.IPasswordGeneratorModel; + +import java.util.EnumSet; +import java.util.List; +import java.util.stream.Collectors; + +@Getter +public class PasswordGeneratorVariableModel extends GeneratorVariableModel implements IPasswordGeneratorModel { + + private String minLength = "8"; + private String maxLength = "64"; + private EnumSet characterGroups = EnumSet.allOf(PasswordCharacterGroup.class); + + public void setMinLength(String minLength) { + this.minLength = minLength; + propertyChanged("minLength", minLength); + } + + public void setMaxLength(String maxLength) { + this.maxLength = maxLength; + propertyChanged("maxLength", maxLength); + } + + public void addPasswordCharacterGroups(PasswordCharacterGroup passwordCharacterGroup) { + characterGroups.add(passwordCharacterGroup); + propertyChanged("characterGroups", characterGroups); + } + + public void removePasswordCharacterGroups(PasswordCharacterGroup passwordCharacterGroup) { + characterGroups.remove(passwordCharacterGroup); + propertyChanged("characterGroups", characterGroups); + } + + @Override + public List validate() { + List errors = super.validate(); + if (StringUtils.isEmpty(minLength)) { + errors.add("Min Length is required"); + } else if (!TextUtils.isInt(minLength)) { + errors.add("Index must be an integer"); + } + if (StringUtils.isEmpty(maxLength)) { + errors.add("Index is required"); + } else if (!TextUtils.isInt(maxLength)) { + errors.add("Index must be an integer"); + } + if (characterGroups.isEmpty()) { + errors.add("Must choose at least one character group"); + } + return errors; + } + + @Override + public String getTagInternal() { + return VariableTag.getShortTag(VariableSource.Generator, GenerateOption.Password.name().toLowerCase(), minLength, maxLength, characterGroups.stream().map(Enum::name).map(String::toLowerCase).collect(Collectors.joining(","))); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/TimestampGeneratorVariableModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/TimestampGeneratorVariableModel.java new file mode 100644 index 0000000..1145664 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/TimestampGeneratorVariableModel.java @@ -0,0 +1,35 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars.generator; + +import lombok.Getter; +import synfron.reshaper.burp.core.rules.thens.entities.generate.GenerateOption; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableTag; +import synfron.reshaper.burp.ui.models.rules.thens.generate.ITimestampGeneratorModel; + +@Getter +public class TimestampGeneratorVariableModel extends GeneratorVariableModel implements ITimestampGeneratorModel { + + private String format = "yyyy-MM-dd"; + private String minTimestamp = ""; + private String maxTimestamp = ""; + + public void setFormat(String format) { + this.format = format; + propertyChanged("format", format); + } + + public void setMinTimestamp(String minTimestamp) { + this.minTimestamp = minTimestamp; + propertyChanged("minTimestamp", minTimestamp); + } + + public void setMaxTimestamp(String maxTimestamp) { + this.maxTimestamp = maxTimestamp; + propertyChanged("maxTimestamp", maxTimestamp); + } + + @Override + public String getTagInternal() { + return VariableTag.getShortTag(VariableSource.Generator, GenerateOption.Timestamp.name().toLowerCase(), format, minTimestamp, maxTimestamp); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/UnixTimestampGeneratorVariableModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/UnixTimestampGeneratorVariableModel.java new file mode 100644 index 0000000..77c3288 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/UnixTimestampGeneratorVariableModel.java @@ -0,0 +1,35 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars.generator; + +import lombok.Getter; +import synfron.reshaper.burp.core.rules.thens.entities.generate.GenerateOption; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableTag; +import synfron.reshaper.burp.ui.models.rules.thens.generate.IUnixTimestampGeneratorModel; + +@Getter +public class UnixTimestampGeneratorVariableModel extends GeneratorVariableModel implements IUnixTimestampGeneratorModel { + + private String format = "yyyy-MM-dd"; + private String minTimestamp = ""; + private String maxTimestamp = ""; + + public void setFormat(String format) { + this.format = format; + propertyChanged("format", format); + } + + public void setMinTimestamp(String minTimestamp) { + this.minTimestamp = minTimestamp; + propertyChanged("minTimestamp", minTimestamp); + } + + public void setMaxTimestamp(String maxTimestamp) { + this.maxTimestamp = maxTimestamp; + propertyChanged("maxTimestamp", maxTimestamp); + } + + @Override + public String getTagInternal() { + return VariableTag.getShortTag(VariableSource.Generator, GenerateOption.UnixTimestamp.name().toLowerCase(), format, minTimestamp, maxTimestamp); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/UuidGeneratorVariableModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/UuidGeneratorVariableModel.java new file mode 100644 index 0000000..e2688d7 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/UuidGeneratorVariableModel.java @@ -0,0 +1,62 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars.generator; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.rules.thens.entities.generate.GenerateOption; +import synfron.reshaper.burp.core.utils.ValueGenerator; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableTag; +import synfron.reshaper.burp.ui.models.rules.thens.generate.IUuidGeneratorModel; + +import java.util.List; + +@Getter +public class UuidGeneratorVariableModel extends GeneratorVariableModel implements IUuidGeneratorModel { + + private ValueGenerator.UuidVersion version = ValueGenerator.UuidVersion.V4; + + private String namespace = ""; + private String name = ""; + + public void setVersion(ValueGenerator.UuidVersion version) { + this.version = version; + propertyChanged("version", version); + } + + public void setNamespace(String namespace) { + this.namespace = namespace; + propertyChanged("namespace", namespace); + } + + public void setName(String name) { + this.name = name; + propertyChanged("name", name); + } + + public List validate() { + List errors = super.validate(); + if (version.isHasInputs()) { + if (StringUtils.isEmpty(namespace)) { + errors.add("Namespace is required"); + } + if (StringUtils.isEmpty(name)) { + errors.add("Name is required"); + } + } + return errors; + } + + @Override + public String getTag() { + return validate().isEmpty() ? + getTagInternal() : + null; + } + + @Override + public String getTagInternal() { + return version.isHasInputs() ? + VariableTag.getShortTag(VariableSource.Generator, GenerateOption.Uuid.name().toLowerCase(), version.name().toLowerCase(), namespace, name) : + VariableTag.getShortTag(VariableSource.Generator, GenerateOption.Uuid.name().toLowerCase(), version.name().toLowerCase()); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/WordGeneratorVariableModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/WordGeneratorVariableModel.java new file mode 100644 index 0000000..3b2ce24 --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/generator/WordGeneratorVariableModel.java @@ -0,0 +1,49 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars.generator; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.rules.thens.entities.generate.GenerateOption; +import synfron.reshaper.burp.core.utils.TextUtils; +import synfron.reshaper.burp.core.utils.ValueGenerator; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableTag; +import synfron.reshaper.burp.ui.models.rules.thens.generate.IWordGeneratorModel; + +import java.util.List; + +@Getter +public class WordGeneratorVariableModel extends GeneratorVariableModel implements IWordGeneratorModel { + + private ValueGenerator.WordGeneratorType generatorType = ValueGenerator.WordGeneratorType.Word; + private String count = "1"; + private String separator = "\\n"; + + public void setGeneratorType(ValueGenerator.WordGeneratorType generatorType) { + this.generatorType = generatorType; + propertyChanged("generatorType", generatorType); + } + + public void setCount(String count) { + this.count = count; + propertyChanged("count", count); + } + + public void setSeparator(String separator) { + this.separator = separator; + propertyChanged("separator", separator); + } + + @Override + public List validate() { + List errors = super.validate(); + if (!StringUtils.isEmpty(count) && !TextUtils.isInt(count)) { + errors.add("Count must be an integer"); + } + return errors; + } + + @Override + public String getTagInternal() { + return VariableTag.getShortTag(VariableSource.Generator, GenerateOption.Words.name().toLowerCase(), generatorType.name().toLowerCase(), count, TextUtils.jsonUnescape(separator)); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/settings/HideItemsModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/settings/HideItemsModel.java new file mode 100644 index 0000000..d520efb --- /dev/null +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/settings/HideItemsModel.java @@ -0,0 +1,94 @@ +package synfron.reshaper.burp.ui.models.settings; + +import lombok.Getter; +import lombok.Setter; +import synfron.reshaper.burp.core.Tab; +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.settings.GeneralSettings; +import synfron.reshaper.burp.ui.utils.IPrompterModel; +import synfron.reshaper.burp.ui.utils.ModalPrompter; + +import java.util.HashSet; + +@Getter +public class HideItemsModel implements IPrompterModel { + private final GeneralSettings generalSettings; + private final HashSet hiddenThenTypes = new HashSet<>(); + private final HashSet hiddenWhenTypes = new HashSet<>(); + private final HashSet hiddenTabs = new HashSet<>(); + private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); + @Setter + private ModalPrompter modalPrompter; + private boolean dismissed; + + public HideItemsModel(GeneralSettings generalSettings) { + this.generalSettings = generalSettings; + hiddenWhenTypes.addAll(generalSettings.getHiddenWhenTypes()); + hiddenThenTypes.addAll(generalSettings.getHiddenThenTypes()); + hiddenTabs.addAll(generalSettings.getHiddenTabs()); + } + + public HideItemsModel withListener(IEventListener listener) { + getPropertyChangedEvent().add(listener); + return this; + } + + private void propertyChanged(String name, Object value) { + propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); + } + + public void addHiddenWhenType(String whenType) { + hiddenWhenTypes.add(whenType); + propertyChanged("hiddenWhenTypes", whenType); + + } + + public void addHiddenThenType(String thenType) { + hiddenThenTypes.add(thenType); + propertyChanged("hiddenThenTypes", thenType); + } + + public void addHiddenTab(Tab tab) { + hiddenTabs.add(tab); + propertyChanged("hiddenTabs", tab); + } + + public void removeHiddenWhenType(String whenType) { + hiddenWhenTypes.remove(whenType); + propertyChanged("hiddenWhenTypes", whenType); + } + + public void removeHiddenThenType(String thenType) { + hiddenThenTypes.remove(thenType); + propertyChanged("hiddenThenTypes", thenType); + } + + public void removeHiddenTab(Tab tab) { + hiddenTabs.remove(tab); + propertyChanged("hiddenTabs", tab); + } + + public boolean save() { + generalSettings.setHiddenTabs(hiddenTabs); + generalSettings.setHiddenThenTypes(hiddenThenTypes); + generalSettings.setHiddenWhenTypes(hiddenWhenTypes); + return true; + } + + @Override + public void resetPropertyChangedListener() { + propertyChangedEvent.clearListeners(); + } + + @Override + public boolean isInvalidated() { + return false; + } + + public void setDismissed(boolean dismissed) { + this.dismissed = dismissed; + propertyChanged("dismissed", dismissed); + } +} diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/models/vars/VariableModel.java b/extension/src/main/java/synfron/reshaper/burp/ui/models/vars/VariableModel.java index 43bfe67..fddd03e 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/models/vars/VariableModel.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/models/vars/VariableModel.java @@ -32,9 +32,12 @@ public class VariableModel { private boolean persistent; @Getter private boolean saved = true; + private boolean activated; + private boolean changedWhileInactive; @Getter private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); private final IEventListener variableChanged = this::onVariableChanged; + private final IEventListener activationChanged = this::onActivationChanged; public VariableModel(boolean isList) { this.isList = isList; @@ -55,10 +58,18 @@ public VariableModel(Variable variable) { } private void onVariableChanged(PropertyChangedArgs propertyChangedArgs) { + if (activated) { + syncProperties(); + } else { + changedWhileInactive = true; + } + } + + private void syncProperties() { SwingUtilities.invokeLater(() -> { value = StringUtils.defaultString(TextUtils.toString(variable.getValue())); if (isList) { - delimiter = StringEscapeUtils.escapeJava(((ListVariable)variable).getDelimiter()); + delimiter = StringEscapeUtils.escapeJava(((ListVariable) variable).getDelimiter()); } persistent = variable.isPersistent(); propertyChanged("this", this); @@ -66,11 +77,31 @@ private void onVariableChanged(PropertyChangedArgs propertyChangedArgs) { }); } + private void onActivationChanged(PropertyChangedArgs propertyChangedArgs) { + if (propertyChangedArgs.getValue() == this) { + if (!activated) { + activated = true; + if (changedWhileInactive) { + syncProperties(); + changedWhileInactive = false; + } + } + } else { + activated = false; + } + + } + public VariableModel withListener(IEventListener listener) { propertyChangedEvent.add(listener); return this; } + public VariableModel bindActivationChangedEvent(PropertyChangedEvent activationChangedEvent) { + activationChangedEvent.add(activationChanged); + return this; + } + public List validate() { List errors = new ArrayList<>(); if (StringUtils.isEmpty(name)) { @@ -121,7 +152,7 @@ private void propertyChanged(String name, Object value) { } public boolean save() { - if (validate().size() != 0) { + if (!validate().isEmpty()) { return false; } Variable variable = this.variable; diff --git a/extension/src/main/java/synfron/reshaper/burp/ui/utils/ContextMenuHandler.java b/extension/src/main/java/synfron/reshaper/burp/ui/utils/ContextMenuHandler.java index 75722c0..3ddf222 100644 --- a/extension/src/main/java/synfron/reshaper/burp/ui/utils/ContextMenuHandler.java +++ b/extension/src/main/java/synfron/reshaper/burp/ui/utils/ContextMenuHandler.java @@ -37,12 +37,12 @@ public List provideMenuItems(WebSocketContextMenuEvent event) { } private void onCreateWebSocketRule(List selectedItems, ActionEvent actionEvent) { - WebSocketMessage webSocketMessage = selectedItems.get(0); + WebSocketMessage webSocketMessage = selectedItems.getFirst(); openWhenWizard(new WhenWizardModel(new WebSocketEventInfo<>(WebSocketMessageType.Binary, WebSocketDataDirection.from(webSocketMessage.direction()), null, null, webSocketMessage.upgradeRequest(), webSocketMessage.annotations(), webSocketMessage.payload().getBytes(), new Variables()))); } private void onCreateHttpRule(List selectedItems, ActionEvent actionEvent) { - HttpRequestResponse httpRequestResponse = selectedItems.get(0); + HttpRequestResponse httpRequestResponse = selectedItems.getFirst(); openWhenWizard(new WhenWizardModel(new HttpEventInfo(null, null, null, httpRequestResponse.request(), httpRequestResponse.response(), httpRequestResponse.annotations(), new Variables()))); } diff --git a/runner/src/main/java/synfron/reshaper/burp/runner/Api.java b/runner/src/main/java/synfron/reshaper/burp/runner/Api.java index 7bfa8f8..cc305ff 100644 --- a/runner/src/main/java/synfron/reshaper/burp/runner/Api.java +++ b/runner/src/main/java/synfron/reshaper/burp/runner/Api.java @@ -904,7 +904,7 @@ public HttpResponse withMarkers(Marker... markers) { public static class ByteArrayImpl implements ByteArray { - private byte[] bytes; + private final byte[] bytes; public ByteArrayImpl(String text) { bytes = text.getBytes();