diff --git a/addOns/automacrobuilder/CHANGELOG.md b/addOns/automacrobuilder/CHANGELOG.md index ba0875b..4bc4254 100644 --- a/addOns/automacrobuilder/CHANGELOG.md +++ b/addOns/automacrobuilder/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this add-on will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [v1.1.17] - 2024-02-29 +### Changed +- bugfix: fixed bug in strange text cursor caret movement in the StyledDocumentWithChunk which has JComponents. +- bugfix: fixed bug in dissapeared CR Jlabel component while editing in the ParmGenRegex. +- bugfix: fixed bug in getting into infinite loop after sending request which contain no contents. +- bugfix: fixed bug in problem when it cannot be displayed as ImageIcon in the StyledDocumentWithChunk. +- maintenance: Added Deprecated Annotation for no meaning doing things in PRequest. + ## [v1.1.16] - 2024-02-02 ### Changed - bugfix: fixed bug in tracking token68 in Authorization bearer header(which used in OAuth2.0) diff --git a/addOns/automacrobuilder/automacrobuilder.gradle.kts b/addOns/automacrobuilder/automacrobuilder.gradle.kts index 43a28b6..ec7b846 100644 --- a/addOns/automacrobuilder/automacrobuilder.gradle.kts +++ b/addOns/automacrobuilder/automacrobuilder.gradle.kts @@ -1,6 +1,6 @@ import org.zaproxy.gradle.addon.AddOnStatus -version = "1.1.16" +version = "1.1.17" description = "AutoMacroBuilder for ZAP" tasks.withType { diff --git a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/PRequest.java b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/PRequest.java index 0910d37..fa46949 100644 --- a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/PRequest.java +++ b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/PRequest.java @@ -37,7 +37,9 @@ public class PRequest extends ParseHTTPHeaders { private static org.apache.logging.log4j.Logger LOGGER4J = org.apache.logging.log4j.LogManager.getLogger(); + // @Deprecated(since = "1.2", forRemoval = true) 20240229 since no need hold chunks in this PRequest. private List chunks = null; + // @Deprecated(since = "1.2", forRemoval = true) 20240229 since no need hold doctext in this PRequest. private String doctext = null; public PRequest(String h, int p, boolean ssl, byte[] _binmessage, Encode _pageenc) { @@ -48,6 +50,8 @@ public PRequest(String h, int p, boolean ssl, byte[] _binmessage, Encode _pageen * create instance * pass argument chunkdoc, extract doctext from chunkdoc * + * @Deprecated 20240229 since no need hold chunks/doctext in this PRequest. + * * @param h * @param p * @param ssl @@ -55,7 +59,8 @@ public PRequest(String h, int p, boolean ssl, byte[] _binmessage, Encode _pageen * @param _pageenc * @param chunkdoc */ - public PRequest( + @Deprecated(since = "1.2", forRemoval = true) + PRequest( String h, int p, boolean ssl, @@ -65,11 +70,7 @@ public PRequest( super(h, p, ssl, _binmessage, _pageenc); if (chunkdoc != null) { chunks = chunkdoc.getRequestChunks(); - try { - doctext = chunkdoc.getText(0, chunkdoc.getLength()); - } catch (BadLocationException ex) { - Logger.getLogger(PRequest.class.getName()).log(Level.SEVERE, null, ex); - } + doctext = chunkdoc.getPlaceHolderStyleText(); } } @@ -99,8 +100,11 @@ public PRequest clone() { /** * Get List which is parsed request contents representation * + * @Deprecated 20240229 since no need hold chunks/doctext in this PRequest. + * * @return */ + @Deprecated(since = "1.2", forRemoval = true) public List getRequestChunks() { if (this.chunks == null) { String theaders = getHeaderOnly(); @@ -111,19 +115,37 @@ public List getRequestChunks() { return this.chunks; } + /** + * generate List which is parsed request contents representation + * @return + */ + public List generateRequestChunks() { + List chunks; + String theaders = getHeaderOnly(); + byte[] tbodies = getBodyBytes(); + String tcontent_type = getHeader("Content-Type"); + chunks = getRequestChunks(theaders, tbodies, tcontent_type); + return chunks; + } + /** * set doc text from StyledDocumentWithChunks(representating for PRequest) * + * @Deprecated 20240229 since no need hold chunks/doctext in this PRequest. + * * @param doc */ + @Deprecated(since = "1.2", forRemoval = true) public void setDocText(StyledDocumentWithChunk doc) { - try { - this.doctext = doc.getText(0, doc.getLength()); - } catch (BadLocationException ex) { - Logger.getLogger(PRequest.class.getName()).log(Level.SEVERE, null, ex); - } + this.doctext = doc.getPlaceHolderStyleText(); } + /** + * @Deprecated 20240229 since no need hold chunks/doctext in this PRequest. + * + * @return + */ + @Deprecated(since = "1.2", forRemoval = true) public String getDocText() { return this.doctext; } @@ -301,8 +323,11 @@ private List getRequestChunks( /** * update DocText and Chunks with specified chunks * + * @Deprecated 20240229 since no need hold chunks/doctext in this PRequest. + * * @param orgchunks */ + @Deprecated(since = "1.2", forRemoval = true) void updateDocAndChunks(List orgchunks) { if (orgchunks == null) return; diff --git a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/PResponse.java b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/PResponse.java index 363ad59..0af7f10 100644 --- a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/PResponse.java +++ b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/PResponse.java @@ -208,7 +208,7 @@ private List getResponseChunks( } boolean displayableTextContents = false; - if (tbodies.length < MAX_SIZE_DISPLAYABLE_TEXTS) { + if (tbodies != null && tbodies.length < MAX_SIZE_DISPLAYABLE_TEXTS) { if (mediaType.equalsIgnoreCase("text/html")) { displayableTextContents = true; } else if (!application_json_contents.isEmpty()) { diff --git a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/ParmGenMacroTrace.java b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/ParmGenMacroTrace.java index 142a5af..907a32e 100644 --- a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/ParmGenMacroTrace.java +++ b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/ParmGenMacroTrace.java @@ -832,14 +832,16 @@ public void updateOriginalBase(ParmGenMacroTrace runningInstance) { ent -> { int i = ent.getKey(); if (i < this.rlist.size()) { + /** List orgchunks = this.rlist .get(i) .request - .getRequestChunks(); // current display content chunks. + .generateRequestChunks(); // current display content chunks. ent.getValue() .request .updateDocAndChunks(orgchunks); // update chunks if possible. + **/ this.rlist.set(i, ent.getValue()); } }); diff --git a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/PrintableString.java b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/PrintableString.java new file mode 100644 index 0000000..3f86c44 --- /dev/null +++ b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/PrintableString.java @@ -0,0 +1,50 @@ +package org.zaproxy.zap.extension.automacrobuilder; + +import java.util.stream.IntStream; + +import static java.util.stream.Collectors.joining; + +public class PrintableString { + + private String nonPrintableString = null; + + public PrintableString(String nonPrintableString) { + this.nonPrintableString = nonPrintableString; + } + + public String convert(int len) { + return convert(this.nonPrintableString, len); + } + + public String convert(String original, int len) { + this.nonPrintableString = original; + + if (original == null || original.isEmpty()) { + return ""; + } else if (len > 0 && len < original.length()) { + int divideLen = len / 2; + int reminderlen = len % 2; + int originalLen = original.length(); + original = original.substring(0, divideLen + reminderlen) + "..." + original.substring(originalLen - divideLen, originalLen); + } + + String convertedString = ""; + try (IntStream istream = original.chars()) { // after executed, then this resource automatically be freed. + + convertedString = istream.mapToObj(ci -> { + String value = ""; + if (ci <= 0x001f || ci == 0x007f || (ci >= 0x0080)) { + try { + value = String.format("%%%02x", ci); + } catch (Exception e) { + } + } else { + value = String.valueOf((char) ci); + } + return value; + }).collect(joining()); + } + + return convertedString; + } +} diff --git a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/RequestChunk.java b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/RequestChunk.java index 73f0f21..26637aa 100644 --- a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/RequestChunk.java +++ b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/RequestChunk.java @@ -24,11 +24,15 @@ public enum CHUNKTYPE { CHUNKTYPE ctype; byte[] data; int partno; + int textPos;// text position in StyledDocument + int textLen;// text length in StyledDocument RequestChunk(CHUNKTYPE ctype, byte[] data, int partno) { this.ctype = ctype; this.data = data; this.partno = partno; + this.textPos = -1; + this.textLen = -1; } /** @@ -66,6 +70,19 @@ public int getPartNo() { return this.partno; } + public void setTextPosLen(int textPos, int textLen) { + this.textPos = textPos; + this.textLen = textLen; + } + + public int getTextPos() { + return this.textPos; + } + + public int getTextLen() { + return this.textLen; + } + public RequestChunk clone() { try { RequestChunk nobj = (RequestChunk) super.clone(); diff --git a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/generated/MacroBuilderUI.java b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/generated/MacroBuilderUI.java index c7f2b69..558d165 100644 --- a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/generated/MacroBuilderUI.java +++ b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/generated/MacroBuilderUI.java @@ -24,6 +24,7 @@ import java.util.regex.Pattern; import javax.swing.*; import javax.swing.border.LineBorder; +import javax.swing.text.DefaultStyledDocument; import javax.swing.text.JTextComponent; import javax.swing.text.StyledDocument; import com.google.gson.JsonElement; @@ -2189,10 +2190,10 @@ public String getMessageRequest() { /** * update current PRequestResponse with Edited(displayed) PRequestResponse * - * @param doc + * @param changedDoc */ @Override - public void ParmGenRegexSaveAction(StyledDocumentWithChunk doc) { + public void ParmGenRegexSaveAction(StyledDocumentWithChunk changedDoc) { int selectedTabIndex = getSelectedTabIndexOfMacroRequestList(); ParmGenMacroTrace pmt = getParmGenMacroTraceAtTabIndex(selectedTabIndex); if (pmt == null) return; @@ -2202,6 +2203,7 @@ public void ParmGenRegexSaveAction(StyledDocumentWithChunk doc) { int idx = requestJList.getSelectedIndex(); if(prequestResponseList != null && idx > -1 && idx < prequestResponseList.size()){ try { + /** PRequest newrequest = doc.reBuildPRequestFromDocTextAndChunks();// get edited request if (newrequest != null) { pmt.updateRequestCurrentList(idx, newrequest);// copy edited request to current request @@ -2209,8 +2211,17 @@ public void ParmGenRegexSaveAction(StyledDocumentWithChunk doc) { ndoc.setRequestChunks(newrequest); pmt.nullfetchResValAndCookieMan(); } + **/ + if (changedDoc != null) { + if (changedDoc.isRequest()) { + // update only the StyledDocument in messageRequest + StyledDocumentWithChunk updatedDoc = new StyledDocumentWithChunk(changedDoc); + messageRequest.setStyledDocument((StyledDocument) updatedDoc); + pmt.nullfetchResValAndCookieMan(); + } + } } catch (Exception ex) { - Logger.getLogger(MacroBuilderUI.class.getName()).log(Level.SEVERE, null, ex); + LOGGER4J.error(ex.getMessage(), ex); } } } diff --git a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/generated/ParmGenRegex.java b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/generated/ParmGenRegex.java index cdd9bf8..e07ba07 100644 --- a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/generated/ParmGenRegex.java +++ b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/generated/ParmGenRegex.java @@ -16,23 +16,13 @@ import java.util.ArrayList; import java.util.List; import java.util.ResourceBundle; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.swing.event.UndoableEditEvent; import javax.swing.event.UndoableEditListener; import javax.swing.text.*; import javax.swing.undo.UndoManager; -import org.zaproxy.zap.extension.automacrobuilder.CastUtils; -import org.zaproxy.zap.extension.automacrobuilder.InterfaceParmGenRegexSaveCancelAction; -import org.zaproxy.zap.extension.automacrobuilder.InterfaceRegex; -import org.zaproxy.zap.extension.automacrobuilder.PRequest; -import org.zaproxy.zap.extension.automacrobuilder.PRequestResponse; -import org.zaproxy.zap.extension.automacrobuilder.view.JTextPaneContents; -import org.zaproxy.zap.extension.automacrobuilder.ParmGenUtil; -import org.zaproxy.zap.extension.automacrobuilder.EnvironmentVariables; -import org.zaproxy.zap.extension.automacrobuilder.view.StyledDocumentWithChunk; -import org.zaproxy.zap.extension.automacrobuilder.view.SwingStyle; +import org.zaproxy.zap.extension.automacrobuilder.*; +import org.zaproxy.zap.extension.automacrobuilder.view.*; /** * @@ -66,7 +56,7 @@ public class ParmGenRegex extends javax.swing.JDialog { CustomHttpPanelHexModel hexModel = null; byte[] hexdata = null; - StyledDocumentWithChunk docwithchunk = null; + StyledDocumentWithChunk chunkDoc = null; public static final String Escaperegex = "([\\[\\]\\{\\}\\(\\)\\*\\<\\>\\.\\?\\+\\\"\\\'\\$])"; private static final ResourceBundle bundle = ResourceBundle.getBundle("burp/Bundle"); @@ -182,7 +172,7 @@ public void undoableEditHappened(UndoableEditEvent e) { StyledDocument origdoc = OriginalText.getStyledDocument(); createStyles(origdoc); - SwingStyle.clearAllCharacterAttributes(origdoc); + clearAllCharacterAttributesExceptPlaceHolderStyles(origdoc); //RegexTextのUndo/Redo origdoc.addUndoableEditListener(new UndoableEditListener() { @@ -193,9 +183,10 @@ public void undoableEditHappened(UndoableEditEvent e) { }); } - public ParmGenRegex(InterfaceParmGenRegexSaveCancelAction _actionwin, String _reg, StyledDocument doc){ + public ParmGenRegex(InterfaceParmGenRegexSaveCancelAction _actionwin, String _reg, StyledDocumentWithChunk chunkDoc){ initComponents(); - + + this.chunkDoc = chunkDoc; um = new UndoManager(); original_um = new UndoManager(); To.setEnabled(false); @@ -206,42 +197,40 @@ public ParmGenRegex(InterfaceParmGenRegexSaveCancelAction _actionwin, String _re this.setModal(true); RegexText.setText(_reg); - OriginalText.setStyledDocument(doc); - createStyles(doc); + OriginalText.setStyledDocument(this.chunkDoc); + createStyles(this.chunkDoc ); - SwingStyle.clearAllCharacterAttributes(doc); + clearAllCharacterAttributesExceptPlaceHolderStyles(this.chunkDoc); OriginalText.setCaretPosition(0); boolean hasBinaryContents = false; isLabelSaveBtn = false; - if (doc instanceof StyledDocumentWithChunk) { - this.docwithchunk = CastUtils.castToType(doc); - hasBinaryContents = this.docwithchunk.hasBinaryContents(); - isLabelSaveBtn = this.docwithchunk.isRequest(); - } - if(hasBinaryContents) { - RegexTest.setEnabled(false); - } - - addHexView(isLabelSaveBtn); + + hasBinaryContents = this.chunkDoc.hasBinaryContents(); + isLabelSaveBtn = this.chunkDoc.isRequest(); if (isLabelSaveBtn) { JMenuItem insertCR = new JMenuItem(bundle.getString("ParmGenRegex.insCR.text")); OrigUndoRedoMenu.add(insertCR); insertCR.addActionListener(e -> { int cpos = OriginalText.getCaretPosition(); try { - this.docwithchunk.insertString(cpos,"\r", this.docwithchunk.getCRstyle()); + this.chunkDoc.insertString(cpos,"\r", this.chunkDoc.getCRstyle()); } catch (BadLocationException badLocationException) { LOGGER4J.error("", badLocationException); } }); } - - - if (this.docwithchunk != null) { - byte[] hexdata = this.docwithchunk.getBytes(); + + if(hasBinaryContents) { + RegexTest.setEnabled(false); + } + + addHexView(isLabelSaveBtn); + + if (this.chunkDoc != null) { + byte[] hexdata = this.chunkDoc.getBytes(); if (hexdata != null) { hexModel.setData(hexdata); } @@ -253,8 +242,7 @@ public ParmGenRegex(InterfaceParmGenRegexSaveCancelAction _actionwin, String _re Cancel.setText(regexactionwin.getParmGenRegexCancelBtnText(isLabelSaveBtn)); } - - //RegexTextのUndo/Redo + // Undo/Redo for RegexText Document rexdoc = RegexText.getDocument(); rexdoc.addUndoableEditListener(new UndoableEditListener() { public void undoableEditHappened(UndoableEditEvent e) { @@ -262,9 +250,9 @@ public void undoableEditHappened(UndoableEditEvent e) { um.addEdit(e.getEdit()); } }); - //RegexText Undo/Redo - doc.addUndoableEditListener(new UndoableEditListener() { + // Undo/Redo for chunkdoc + this.chunkDoc.addUndoableEditListener(new UndoableEditListener() { public void undoableEditHappened(UndoableEditEvent e) { //add edit actions to UndoManager original_um.addEdit(e.getEdit()); @@ -330,7 +318,7 @@ private void printer(String s){ String hex = s.replaceAll("\r", ""); hex = hex.replaceAll("\n", ""); - EnvironmentVariables.plog.debuglog(1,"["+hex+"]\n"); + LOGGER4J.debug("["+hex+"]\n"); } /** @@ -349,7 +337,7 @@ private void NewSearch(){ //String original = OriginalText.getText(); StyledDocument doc = OriginalText.getStyledDocument(); - SwingStyle.clearAllCharacterAttributes(doc); + clearAllCharacterAttributesExceptPlaceHolderStyles(doc); foundTextAttrPos.clear(); @@ -361,7 +349,7 @@ private void NewSearch(){ try { original = doc.getText(0, doc.getLength()); } catch (BadLocationException ex) { - Logger.getLogger(ParmGenRegex.class.getName()).log(Level.SEVERE, null, ex); + LOGGER4J.error(ex.getMessage(), ex); } init(regex, original); @@ -379,9 +367,16 @@ private void NewSearch(){ compiledregex = ParmGenUtil.Pattern_compile(regex, flags); m = compiledregex.matcher(original); - }catch(Exception e){ - EnvironmentVariables.plog.printException(e); - JOptionPane.showMessageDialog(this,bundle.getString("ParmGenRegex.OptionPaneErrorMessage_RegexSyntaxError.text")+ e.toString() , bundle.getString("ParmGenRegex.ErrorOptionPaneTitle.text"), JOptionPane.ERROR_MESSAGE); + }catch(Exception ex){ + LOGGER4J.error(ex.getMessage(), ex); + JOptionPane.showMessageDialog( + this, + bundle.getString( + "ParmGenRegex.OptionPaneErrorMessage_RegexSyntaxError.text") + + ex.toString(), + bundle.getString("ParmGenRegex.ErrorOptionPaneTitle.text"), + JOptionPane.ERROR_MESSAGE + ); return; } @@ -394,68 +389,68 @@ private void NewSearch(){ int fcount=0; while (m.find()) { - found = true; - fcount++; - int spt0 = -1; - int ept0 = -1; - int spt = -1; - int ept = -1; - int gcnt = m.groupCount(); - String matchval = null; - if ( gcnt > 0){ - spt0 = m.start(); - ept0 = m.end(); - for(int n = 0; n < gcnt ; n++){ - spt = m.start(n+1); - ept = m.end(n+1); - matchval = m.group(n+1); + found = true; + fcount++; + int spt0 = -1; + int ept0 = -1; + int spt = -1; + int ept = -1; + int gcnt = m.groupCount(); + String matchval = null; + if ( gcnt > 0){ + spt0 = m.start(); + ept0 = m.end(); + for(int n = 0; n < gcnt ; n++){ + spt = m.start(n+1); + ept = m.end(n+1); + matchval = m.group(n+1); + } + if ( matchval == null){ + matchval = m.group(); + } + if ( spt0 > spt){ + spt0 = spt; + } + if(ept0 < ept){ + ept0 = ept; + } + // spt0--->sptept-->ept0 + }else{//Nothing Groups... + spt0 = m.start(); + ept0 = m.end(); + matchval = m.group(); + } + if ( spt0 >=0 && ept0 >= 0 ){ + + try { + + // spt0--->sptept-->ept0 + + if (ept0 > spt0) { + Style outerStyle = doc.getStyle(GROUP_OUTER_STYLENAME); + doc.setCharacterAttributes(spt0, ept0-spt0, outerStyle, false); + RegexSelectedTextPos rpos = new RegexSelectedTextPos(spt0, ept0); + foundTextAttrPos.add(rpos); } - if ( matchval == null){ - matchval = m.group(); - } - if ( spt0 > spt){ - spt0 = spt; + + if (ept > spt) { + Style innerStyle = doc.getStyle(GROUP_INNER_STYLENAME); + doc.setCharacterAttributes(spt, ept-spt, innerStyle, false); + RegexSelectedTextPos rpos = new RegexSelectedTextPos(spt, ept); + foundTextAttrPos.add(rpos); } - if(ept0 < ept){ - ept0 = ept; + + //int pos = OriginalText.getCaretPosition(); + int pos = doc.getLength(); + findplist.add(ept0); + if ( fidx == -1){ + fidx = 0; } - // spt0--->sptept-->ept0 - }else{//Nothing Groups... - spt0 = m.start(); - ept0 = m.end(); - matchval = m.group(); - } - if ( spt0 >=0 && ept0 >= 0 ){ - - try { - - // spt0--->sptept-->ept0 - - if (ept0 > spt0) { - Style outerStyle = doc.getStyle(GROUP_OUTER_STYLENAME); - doc.setCharacterAttributes(spt0, ept0-spt0, outerStyle, false); - RegexSelectedTextPos rpos = new RegexSelectedTextPos(spt0, ept0); - foundTextAttrPos.add(rpos); - } - - if (ept > spt) { - Style innerStyle = doc.getStyle(GROUP_INNER_STYLENAME); - doc.setCharacterAttributes(spt, ept-spt, innerStyle, false); - RegexSelectedTextPos rpos = new RegexSelectedTextPos(spt, ept); - foundTextAttrPos.add(rpos); - } - - //int pos = OriginalText.getCaretPosition(); - int pos = doc.getLength(); - findplist.add(ept0); - if ( fidx == -1){ - fidx = 0; - } - } catch (Exception e) { - EnvironmentVariables.plog.printException(e); - } + } catch (Exception ex) { + LOGGER4J.error(ex.getMessage(), ex); } + } } if ( fidx != -1){ @@ -494,15 +489,15 @@ void addHexView(boolean editable) { if (editable) { TextTab.addChangeListener(e -> { int selIndex = TextTab.getSelectedIndex();//tabbedpanes selectedidx 0start.. - if (this.docwithchunk != null){ + if (this.chunkDoc != null){ switch(selIndex) { case 1: - hexdata = this.docwithchunk.getBytes(); + hexdata = this.chunkDoc.getBytes(); hexModel.setData(hexdata); break; default: hexdata = hexModel.getData(); - this.docwithchunk.updateStyleDocAndChunkFromHex(hexdata); + this.chunkDoc.updateStyleDocAndChunkFromHex(hexdata); OriginalText.repaint(); break; } @@ -958,15 +953,15 @@ private void ColumnPolicyActionPerformed(java.awt.event.ActionEvent evt) {//GEN- private void SaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_SaveActionPerformed // TODO add your handling code here: - if(regexactionwin!=null && this.docwithchunk != null){ + if(regexactionwin!=null && this.chunkDoc != null){ int selIndex = TextTab.getSelectedIndex();//tabbedpanes selectedidx 0start.. if (selIndex == 1) { // hex dump view - if (this.docwithchunk.isRequest()) { + if (this.chunkDoc.isRequest()) { hexdata = hexModel.getData(); - this.docwithchunk.updateStyleDocAndChunkFromHex(hexdata); + this.chunkDoc.updateStyleDocAndChunkFromHex(hexdata); } } - regexactionwin.ParmGenRegexSaveAction(this.docwithchunk); + regexactionwin.ParmGenRegexSaveAction(this.chunkDoc); dispose(); return; } @@ -1100,6 +1095,17 @@ private void SelectPatternActionPerformed(java.awt.event.ActionEvent evt) {//GEN } }//GEN-LAST:event_SelectPatternActionPerformed + private void clearAllCharacterAttributesExceptPlaceHolderStyles(StyledDocument doc) { + if (doc instanceof StyledDocumentWithChunk) { + StyledDocumentWithChunk docWithChunk = (StyledDocumentWithChunk) doc; + List listOfPlaceHolderStyle = docWithChunk.getListOfPlaceHolderStyle(); + SwingStyle.clearAllCharacterAttributes(docWithChunk); + docWithChunk.applyPlaceHolderStyle(listOfPlaceHolderStyle); + } else { + SwingStyle.clearAllCharacterAttributes(doc); + } + } + public static class RegexSelectedTextPos { int st; int et; diff --git a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/view/ChunkJbutton.java b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/view/ChunkJbutton.java new file mode 100644 index 0000000..addd1e2 --- /dev/null +++ b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/view/ChunkJbutton.java @@ -0,0 +1,26 @@ +package org.zaproxy.zap.extension.automacrobuilder.view; + +import javax.swing.*; + +/** + * JButton which stored arbitary data for displaying on StyleDocument + * + */ +@SuppressWarnings({"unchecked", "serial"}) +public class ChunkJbutton extends JButton { + private int partno; + private byte[] chunk; + public ChunkJbutton(int partno, byte[] chunk) { + super(); + this.partno = partno; + this.chunk = chunk; + } + + public int getPartNo() { + return this.partno; + } + + public byte[] getChunk() { + return this.chunk; + } +} diff --git a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/view/InterfacePlaceHolderStyle.java b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/view/InterfacePlaceHolderStyle.java new file mode 100644 index 0000000..d9750cc --- /dev/null +++ b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/view/InterfacePlaceHolderStyle.java @@ -0,0 +1,7 @@ +package org.zaproxy.zap.extension.automacrobuilder.view; + +public interface InterfacePlaceHolderStyle { + public int getPos(); + + public String getStyleName(); +} diff --git a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/view/PlaceHolderStyle.java b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/view/PlaceHolderStyle.java new file mode 100644 index 0000000..6ff78ea --- /dev/null +++ b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/view/PlaceHolderStyle.java @@ -0,0 +1,23 @@ +package org.zaproxy.zap.extension.automacrobuilder.view; + +import org.zaproxy.zap.extension.automacrobuilder.view.InterfacePlaceHolderStyle; + +public class PlaceHolderStyle implements InterfacePlaceHolderStyle { + private String styleName; + private int pos; + + public PlaceHolderStyle(int pos, String styleName) { + this.pos = pos; + this.styleName = styleName; + } + + @Override + public int getPos() { + return this.pos; + } + + @Override + public String getStyleName() { + return this.styleName; + } +} diff --git a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/view/PlaceHolderStyleChunk.java b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/view/PlaceHolderStyleChunk.java new file mode 100644 index 0000000..c9ce7dc --- /dev/null +++ b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/view/PlaceHolderStyleChunk.java @@ -0,0 +1,23 @@ +package org.zaproxy.zap.extension.automacrobuilder.view; + +public class PlaceHolderStyleChunk extends PlaceHolderStyle { + + private int partNo; + private byte[] chunkByte; + + public PlaceHolderStyleChunk(int pos, String styleName, int partNo, byte[] chunkByte) { + super(pos, styleName); + this.partNo = partNo; + this.chunkByte = chunkByte; + } + + public int getPartNo() { + return partNo; + } + + public byte[] getChunkByte() { + return this.chunkByte; + } + + +} diff --git a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/view/StyledDocumentWithChunk.java b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/view/StyledDocumentWithChunk.java index 6a42345..e925df5 100644 --- a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/view/StyledDocumentWithChunk.java +++ b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/view/StyledDocumentWithChunk.java @@ -9,35 +9,30 @@ import static org.zaproxy.zap.extension.automacrobuilder.ParmGenUtil.ImageIconLoadStatus; -import java.awt.Color; -import java.awt.Font; -import java.awt.Insets; +import java.awt.*; import java.net.URL; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.*; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.List; import javax.swing.ImageIcon; -import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.border.LineBorder; -import javax.swing.text.BadLocationException; -import javax.swing.text.DefaultStyledDocument; -import javax.swing.text.Style; -import javax.swing.text.StyleConstants; +import javax.swing.text.*; @SuppressWarnings({"unchecked", "serial"}) public class StyledDocumentWithChunk extends DefaultStyledDocument { private static org.apache.logging.log4j.Logger LOGGER4J = org.apache.logging.log4j.LogManager.getLogger(); - private static final String CHUNK_STYLENAME = "StyledDocumentWithChunk.STYLE"; + private static final String EMBED_ISO8859_BINARY = "StyledDocumentWithChunk.EMBED_ISO8859_BINARY"; private static final String CRIMAGE_STYLENAME = "StyledDocumentWithChunk.CRSTYLE_IMAGE"; private static final ResourceBundle bundle = ResourceBundle.getBundle("burp/Bundle"); + private static final String PLACE_HOLDER_SIGN = "§"; private final String[] styleNames = { - CHUNK_STYLENAME, + EMBED_ISO8859_BINARY, CRIMAGE_STYLENAME }; @@ -102,11 +97,8 @@ public StyledDocumentWithChunk(StyledDocumentWithChunk chunkdoc) { requestChunks = ListDeepCopy.listDeepCopyRequestChunk( chunkdoc.requestChunks); // copy from source - try { - generateStyledDocFromRequestText(chunkdoc.getText(0, chunkdoc.getLength())); - } catch (BadLocationException ex) { - LOGGER4J.error(ex.getMessage(), ex); - } + reCreateStyledDocFromRequestTextAndChunks(chunkdoc.getPlaceHolderStyleText(), null); + } else { LOGGER4J.debug("chunkdoc is RESPONSE"); enc = chunkdoc.enc; @@ -198,123 +190,113 @@ public boolean hasBinaryContents() { } /** - * Rebuild PRequest from intenal text and chunks. This method no affects contents of this. + * Rebuild PRequest from intenal text and chunks. + * This method no affects contents of this. * * @return */ public PRequest reBuildPRequestFromDocTextAndChunks() { byte[] data = reBuildPRequestFromDocTextAndChunks(null); if (data != null) { - return new PRequest(host, port, isSSL, data, enc, this); + return new PRequest(host, port, isSSL, data, enc); } return null; } /** - * Rebuild PRequest from specified(or intenal) text This method no affects contents of this. + * Rebuild PRequest binary from specified(or intenal) PlaceHolderStyleText and internal this.requestChunks. + * This method no affects contents of this. * - * @param text - * @return + * @param placeHolderStyleText + * @return binary of PRequest */ - private byte[] reBuildPRequestFromDocTextAndChunks(String text) { + private byte[] reBuildPRequestFromDocTextAndChunks(String placeHolderStyleText) { if (requestChunks == null) return null; - try { - if (text == null || text.isEmpty()) { - text = this.getText(0, getLength()); - } - Charset charset = enc.getIANACharset(); - byte[] docbytes = text.getBytes(charset); - ParmGenBinUtil contarray = new ParmGenBinUtil(docbytes); - ParmGenBinUtil resultarray = new ParmGenBinUtil(); - byte[] PLS_PREFIX = CONTENTS_PLACEHOLDER_PREFIX.getBytes(); - byte[] PLS_SUFFIX = CONTENTS_PLACEHOLDER_SUFFIX.getBytes(); - int npos = -1; - int cpos = 0; - int sfxstpos = -1; - while ((npos = contarray.indexOf(PLS_PREFIX, cpos)) != -1) { - resultarray.concat(contarray.subBytes(cpos, npos)); - cpos = npos + PLS_PREFIX.length; - if ((sfxstpos = contarray.indexOf(PLS_SUFFIX, cpos)) != -1) { - if (sfxstpos > cpos && sfxstpos - cpos <= PARTNO_MAXLEN) { - String nstr = new String(contarray.subBytes(cpos, sfxstpos), charset); - if (nstr.matches("[0-9]+")) { - int partno = Integer.parseInt(nstr); - Optional ochunk = - requestChunks.stream() - .filter( - c -> - (c.getChunkType() - == RequestChunk - .CHUNKTYPE - .CONTENTS - || c.getChunkType() - == RequestChunk - .CHUNKTYPE - .CONTENTSIMG) - && c.getPartNo() == partno) - .findFirst(); - RequestChunk resultchunk = ochunk.orElse(null); - if (resultchunk != null && resultchunk.getBytes().length > 0) { - resultarray.concat(resultchunk.getBytes()); - } - cpos = sfxstpos + PLS_SUFFIX.length; + if (placeHolderStyleText == null || placeHolderStyleText.isEmpty()) { + placeHolderStyleText = this.getPlaceHolderStyleText(); + } + Charset charset = enc.getIANACharset(); + byte[] docbytes = placeHolderStyleText.getBytes(charset); + ParmGenBinUtil contarray = new ParmGenBinUtil(docbytes); + ParmGenBinUtil resultarray = new ParmGenBinUtil(); + byte[] PLS_PREFIX = CONTENTS_PLACEHOLDER_PREFIX.getBytes(); + byte[] PLS_SUFFIX = CONTENTS_PLACEHOLDER_SUFFIX.getBytes(); + int npos = -1; + int cpos = 0; + int sfxstpos = -1; + while ((npos = contarray.indexOf(PLS_PREFIX, cpos)) != -1) { + resultarray.concat(contarray.subBytes(cpos, npos)); + cpos = npos + PLS_PREFIX.length; + if ((sfxstpos = contarray.indexOf(PLS_SUFFIX, cpos)) != -1) { + if (sfxstpos > cpos && sfxstpos - cpos <= PARTNO_MAXLEN) { + String nstr = new String(contarray.subBytes(cpos, sfxstpos), charset); + if (nstr.matches("[0-9]+")) { + int partno = Integer.parseInt(nstr); + Optional ochunk = + requestChunks.stream() + .filter( + c -> + (c.getChunkType() + == RequestChunk + .CHUNKTYPE + .CONTENTS + || c.getChunkType() + == RequestChunk + .CHUNKTYPE + .CONTENTSIMG) + && c.getPartNo() == partno) + .findFirst(); + RequestChunk resultchunk = ochunk.orElse(null); + if (resultchunk != null && resultchunk.getBytes().length > 0) { + resultarray.concat(resultchunk.getBytes()); } + cpos = sfxstpos + PLS_SUFFIX.length; } } } - if (cpos < docbytes.length) { - resultarray.concat(contarray.subBytes(cpos, docbytes.length)); - } - - // requestChunks = newrequest.getRequestChunks(); - return resultarray.getBytes(); - } catch (BadLocationException ex) { - LOGGER4J.error(ex.getMessage(), ex); } - return null; + if (cpos < docbytes.length) { + resultarray.concat(contarray.subBytes(cpos, docbytes.length)); + } + + // requestChunks = newrequest.getRequestChunks(); + return resultarray.getBytes(); } /** - * update StyledDocument with specified request binary data. this method use carefully. host, + * update StyledDocument with specified hexBytes(request binary data). this method use carefully. host, * port, isSSL, enc parameter is No changed. so if you need to update these 4 params then you * must newly create this instance. * - * @param hexbytes + * @param hexBytes */ - public void updateStyleDocAndChunkFromHex(byte[] hexbytes) { - if (hexbytes == null) return; + public void updateStyleDocAndChunkFromHex(byte[] hexBytes) { + if (hexBytes == null) return; Charset charset = enc.getIANACharset(); - String doctext = ""; - - try { - doctext = this.getText(0, this.getLength()); - } catch (BadLocationException ex) { - LOGGER4J.error(ex.getMessage(), ex); - return; - } + String placeHolderStyleText = this.getPlaceHolderStyleText(); - byte[] docbytes = doctext.getBytes(charset); - ParmGenBinUtil docarray = new ParmGenBinUtil(docbytes); - ParmGenBinUtil hexarray = new ParmGenBinUtil(hexbytes); - ParmGenBinUtil resultarray = new ParmGenBinUtil(); + byte[] placeHolderStyleTextBytes = placeHolderStyleText.getBytes(charset); + ParmGenBinUtil currentPLaceHolderStyleArray = new ParmGenBinUtil(placeHolderStyleTextBytes); + ParmGenBinUtil hexArray = new ParmGenBinUtil(hexBytes); + ParmGenBinUtil resultPlaceHolderStyleArray = new ParmGenBinUtil();// array of PlaceHolderStyleText byte[] PLS_PREFIX = CONTENTS_PLACEHOLDER_PREFIX.getBytes(); byte[] PLS_SUFFIX = CONTENTS_PLACEHOLDER_SUFFIX.getBytes(); int npos = -1; int cpos = 0; int hpos = 0; - while ((npos = docarray.indexOf(PLS_PREFIX, cpos)) != -1) { + while ((npos = currentPLaceHolderStyleArray.indexOf(PLS_PREFIX, cpos)) != -1) { int siz = 0; if (npos > cpos) { siz = npos - cpos; - resultarray.concat(hexarray.subBytes(hpos, hpos + siz)); + resultPlaceHolderStyleArray.concat(hexArray.subBytes(hpos, hpos + siz)); hpos += siz; } cpos = npos + PLS_PREFIX.length; - resultarray.concat(PLS_PREFIX); + resultPlaceHolderStyleArray.concat(PLS_PREFIX); - if ((npos = docarray.indexOf(PLS_SUFFIX, cpos)) != -1) { + if ((npos = currentPLaceHolderStyleArray.indexOf(PLS_SUFFIX, cpos)) != -1) { if (npos > cpos && npos - cpos <= PARTNO_MAXLEN) { - byte[] partnobytes = docarray.subBytes(cpos, npos); + byte[] partnobytes = currentPLaceHolderStyleArray.subBytes(cpos, npos); String partnostr = new String(partnobytes, charset); if (partnostr.matches("[0-9]+")) { int partno = Integer.parseInt(partnostr); @@ -337,7 +319,7 @@ public void updateStyleDocAndChunkFromHex(byte[] hexbytes) { siz = resultchunk.getBytes().length; if (siz > 0) { // update resultChunk.data with hexdata. - resultchunk.setByte(hexarray.subBytes(hpos, hpos + siz)); + resultchunk.setByte(hexArray.subBytes(hpos, hpos + siz)); LOGGER4J.debug( "update chunk from hexdata partno:" + partno @@ -349,14 +331,14 @@ public void updateStyleDocAndChunkFromHex(byte[] hexbytes) { } } npos += PLS_SUFFIX.length; - resultarray.concat(docarray.subBytes(cpos, npos)); + resultPlaceHolderStyleArray.concat(currentPLaceHolderStyleArray.subBytes(cpos, npos)); cpos = npos; } } - if (hpos < hexbytes.length) { - resultarray.concat(hexarray.subBytes(hpos, hexbytes.length)); + if (hpos < hexBytes.length) { + resultPlaceHolderStyleArray.concat(hexArray.subBytes(hpos, hexBytes.length)); } - generateStyledDocFromRequestText(new String(resultarray.getBytes(), charset)); + reCreateStyledDocFromRequestTextAndChunks(new String(resultPlaceHolderStyleArray.getBytes(), charset), null); } /** @@ -387,20 +369,10 @@ public byte[] getBytes() { * @param newrequest */ private void updateRequest(PRequest newrequest) { - - requestChunks = newrequest.getRequestChunks(); + requestChunks = newrequest.generateRequestChunks(); responseChunks = null; - - String text = newrequest.getDocText(); - - if (text != null && text.length() > 0) { - // update StyledDocument with text - generateStyledDocFromRequestText(text); - } else { - // update StyledDocument with requestChunk - updateRequest(); - newrequest.setDocText(this); - } + updateRequest(); + //newrequest.setDocText(this); } private void destroyDocumentAndRecreateStyles() { @@ -464,7 +436,12 @@ private void updateRequest() { case CONTENTSIMG: { Style s = null; - if (chunk.getBytes().length > MAX_SIZE_REQUEST_PART) { + // it's difficult to manipulate image as text in StyleDocument + // because the Multi-part form data has text encoding(UTF-8) + // but image data can't display properly with using it's encoding. + // so we must display image data as IMAGE ICON. + if (pageenc.getIANACharset() != StandardCharsets.ISO_8859_1 || chunk.getBytes().length > MAX_SIZE_REQUEST_PART) { + String toolTip = bundle.getString("ParmGenRegex.UndisplayableAsTextLargerData.text"); // s = doc.getStyle("binary"); String partno = CONTENTS_PLACEHOLDER_PREFIX @@ -475,25 +452,29 @@ private void updateRequest() { try { icon = new ImageIcon(chunk.getBytes(), partno); LOGGER4J.debug("icon status:" + ImageIconLoadStatus(icon)); - } catch (Exception e) { + } catch (Exception ex) { + LOGGER4J.error(ex.getMessage(), ex); + } + if (icon.getImageLoadStatus() != MediaTracker.COMPLETE) { + toolTip = bundle.getString("ParmGenRegex.BrokenData.text"); icon = new ImageIcon(BRKICONURL, partno); } // doc.addStyle(partno, def); - s = makeStyleImageButton(icon, bundle.getString("ParmGenRegex.UndisplayableLargerData.text"), partno); + s = makeStyleImageButton(icon, toolTip, chunk.getPartNo(), chunk.getBytes()); LOGGER4J.debug("@CONTENTS length:" + chunk.getBytes().length); - element = partno; + element = PLACE_HOLDER_SIGN; } else { - s = null; LOGGER4J.trace( "@CONTENTS[" + new String( - chunk.getBytes(), pageenc.getIANACharset()) + chunk.getBytes(), StandardCharsets.ISO_8859_1) + "]"); - element = new String(chunk.getBytes(), pageenc.getIANACharset()); + element = new String(chunk.getBytes(), StandardCharsets.ISO_8859_1); + s = this.addOrGetStyle(EMBED_ISO8859_BINARY); } if (s == null) { - insertStringCR(pos, element); + insertString(pos, element, null); } else { insertString(pos, element, s); } @@ -509,9 +490,9 @@ private void updateRequest() { + CONTENTS_PLACEHOLDER_SUFFIX; ImageIcon icon = new ImageIcon(BINICONURL, partno); // doc.addStyle(partno, def); - s = makeStyleImageButton(icon,bundle.getString("ParmGenRegex.UndisplayableLargerData.text"),partno); + s = makeStyleImageButton(icon,bundle.getString("ParmGenRegex.UndisplayableAsTextLargerData.text"),chunk.getPartNo(), chunk.getBytes()); LOGGER4J.debug("BINICONED @CONTENTS length:" + chunk.getBytes().length); - element = partno; + element = PLACE_HOLDER_SIGN; } else { s = null; LOGGER4J.trace( @@ -546,6 +527,9 @@ private void updateRequest() { insertStringCR(pos, element); break; } + if (element != null && element.isEmpty()) { + chunk.setTextPosLen(pos, element.length()); + } pos = this.getLength(); } } catch (BadLocationException ex) { @@ -573,7 +557,7 @@ public void updateResponse(PResponse presponse) { Style defaultStyle = SwingStyle.getDefaultStyle(this); - String partno = CONTENTS_PLACEHOLDER_PREFIX + "0" + CONTENTS_PLACEHOLDER_SUFFIX; + String partno = PLACE_HOLDER_SIGN; StyleConstants.setAlignment(defaultStyle, StyleConstants.ALIGN_CENTER); List chunks = responseChunks; @@ -587,21 +571,27 @@ public void updateResponse(PResponse presponse) { Style s = null; String elem; ImageIcon icon = null; + String toolTip; switch (chunk.getChunkType()) { case CONTENTSBINARY: icon = new ImageIcon(BINICONURL, partno); - s = makeStyleImageButton(icon,bundle.getString("ParmGenRegex.UndisplayableLargerData.text"), partno); + s = makeStyleImageButton(icon,bundle.getString("ParmGenRegex.UndisplayableAsTextLargerData.text"), 0, chunk.getBytes()); elem = partno; LOGGER4J.debug("CONTENTSBINARY[" + elem + "]pos:" + pos); break; case CONTENTSIMG: + toolTip = bundle.getString("ParmGenRegex.UndisplayableAsTextLargerData.text"); try { icon = new ImageIcon(chunk.getBytes(), partno); LOGGER4J.debug("icon status:" + ImageIconLoadStatus(icon)); } catch (Exception e) { icon = new ImageIcon(BRKICONURL, partno); } - s = makeStyleImageButton(icon, bundle.getString("ParmGenRegex.BrokenData.text"),partno); + if (icon.getImageLoadStatus() != MediaTracker.COMPLETE) { + toolTip = bundle.getString("ParmGenRegex.BrokenData.text"); + icon = new ImageIcon(BRKICONURL, partno); + } + s = makeStyleImageButton(icon, toolTip,1, chunk.getBytes()); elem = partno; LOGGER4J.debug("CONTENTSIMG[" + elem + "]pos:" + pos); break; @@ -623,21 +613,30 @@ public void updateResponse(PResponse presponse) { } /** - * create button with ImageIcon and add eventhandler. + * * * @param icon * @param actioncommand * @return */ - public Style makeStyleImageButton(ImageIcon icon, String toolTip, String actioncommand) { - String styleName = "Image" + actioncommand; + /** + * create ChunkJButton for ImageIcon and add eventhandler. + * + * @param icon + * @param toolTip + * @param partno + * @param chunk + * @return + */ + public Style makeStyleImageButton(ImageIcon icon, String toolTip, int partno, byte[] chunk) { + String styleName = "ChunkImage" + partno; Style imageStyle = addOrGetStyle(styleName); StyleConstants.setAlignment(imageStyle, StyleConstants.ALIGN_CENTER); - JButton button = new JButton(); + ChunkJbutton button = new ChunkJbutton(partno, chunk); button.setIcon(icon); button.setToolTipText(toolTip); button.setMargin(new Insets(0, 0, 0, 0)); - button.setActionCommand(actioncommand); + button.setActionCommand(styleName); button.addActionListener( e -> { LOGGER4J.debug("button pressed:" + e.getActionCommand()); @@ -697,48 +696,53 @@ private void insertStringCR(int pos, String text) { } /** - * Generate StyledDocument from RequestText + * Destroy and Create StyledDocument from RequestText and Chunks * - * @param requesttext + * @param placeHolderStyleText PlaceHolderStyleText of Request + * @param requestChunksNew if this value is null, internal this.requestChunks is used. */ - private void generateStyledDocFromRequestText(String requesttext) { + private void reCreateStyledDocFromRequestTextAndChunks(String placeHolderStyleText, List requestChunksNew) { + + if (requestChunksNew != null) { + this.requestChunks = requestChunksNew; + } - if (requesttext == null || requesttext.isEmpty() || requestChunks == null) return; + if (placeHolderStyleText == null || placeHolderStyleText.isEmpty() || this.requestChunks == null) return; destroyDocumentAndRecreateStyles(); int npos = -1; int cpos = 0; - while ((npos = requesttext.indexOf(CONTENTS_PLACEHOLDER_PREFIX, cpos)) != -1) { + while ((npos = placeHolderStyleText.indexOf(CONTENTS_PLACEHOLDER_PREFIX, cpos)) != -1) { LOGGER4J.debug("CONTENTS_PLACEHOLDER_PREFIX found"); if (npos > cpos) { - insertStringCR(this.getLength(), requesttext.substring(cpos, npos)); + insertStringCR(this.getLength(), placeHolderStyleText.substring(cpos, npos)); } cpos = npos; String element = CONTENTS_PLACEHOLDER_PREFIX; Style s = null; int pnopos = cpos + CONTENTS_PLACEHOLDER_PREFIX.length(); // partno start position - if ((npos = requesttext.indexOf(CONTENTS_PLACEHOLDER_SUFFIX, pnopos)) != -1) { + if ((npos = placeHolderStyleText.indexOf(CONTENTS_PLACEHOLDER_SUFFIX, pnopos)) != -1) { LOGGER4J.debug( "CONTENTS_PLACEHOLDER_SUFFIX found npos,cpos=" + npos + "," + pnopos + " [" - + requesttext.substring(pnopos, npos) + + placeHolderStyleText.substring(pnopos, npos) + "]"); if (npos > pnopos && npos - pnopos <= PARTNO_MAXLEN) { element = CONTENTS_PLACEHOLDER_PREFIX - + requesttext.substring(pnopos, npos) + + placeHolderStyleText.substring(pnopos, npos) + CONTENTS_PLACEHOLDER_SUFFIX; LOGGER4J.debug("element[" + element + "]"); - String nstr = requesttext.substring(pnopos, npos).trim(); + String nstr = placeHolderStyleText.substring(pnopos, npos).trim(); if (nstr.matches("[0-9]+")) { int partno = Integer.parseInt(nstr); String partnostr = Integer.toString(partno); Optional ochunks = - requestChunks.stream() + this.requestChunks.stream() .filter( c -> (c.getChunkType() @@ -754,7 +758,7 @@ private void generateStyledDocFromRequestText(String requesttext) { RequestChunk content_chunk = ochunks.orElse(null); if (content_chunk != null && content_chunk.getBytes().length > 0) { ImageIcon icon = null; - String toolTip ; + String toolTip = "Broken Data"; if (content_chunk.getChunkType() == RequestChunk.CHUNKTYPE.CONTENTS) { icon = new ImageIcon(BINICONURL, partnostr); toolTip = bundle.getString("ParmGenRegex.BinaryData.text"); @@ -763,29 +767,159 @@ private void generateStyledDocFromRequestText(String requesttext) { icon = new ImageIcon(content_chunk.getBytes(), partnostr); toolTip = "Image"; LOGGER4J.debug("icon status:" + ImageIconLoadStatus(icon)); - } catch (Exception e) { + } catch (Exception ex) { + LOGGER4J.error(ex.getMessage(), ex); + } + if (icon.getImageLoadStatus() != MediaTracker.COMPLETE) { toolTip = bundle.getString("ParmGenRegex.BrokenData.text"); icon = new ImageIcon(BRKICONURL, partnostr); } } - s = makeStyleImageButton(icon, toolTip,partnostr); + s = makeStyleImageButton(icon, toolTip,partno, content_chunk.getBytes()); } } } } if (s != null) { try { - this.insertString(this.getLength(), element, s); + LOGGER4J.debug("insert placeHolderSign s=" + (s==null?"NULL" : "not null")); + this.insertString(this.getLength(), PLACE_HOLDER_SIGN, s); } catch (BadLocationException ex) { LOGGER4J.error(ex.getMessage(), ex); + element = ""; } } else { insertStringCR(this.getLength(), element); } cpos += element.length(); } - if (cpos < requesttext.length()) { - insertStringCR(this.getLength(), requesttext.substring(cpos, requesttext.length())); + if (cpos < placeHolderStyleText.length()) { + insertStringCR(this.getLength(), placeHolderStyleText.substring(cpos, placeHolderStyleText.length())); } } + + + + public void printComponentsInThisDoc() { + int pos = 0; + int endPos = this.getLength(); + for(pos = 0; pos < endPos; pos++) { + Element elm = this.getCharacterElement(pos); + if (elm != null) { + AttributeSet attrSet = elm.getAttributes(); + if (attrSet != null) { + String styleName = ""; + // I can get StyleName and Component from the AttributeSet at last! + Object name = attrSet.getAttribute(AttributeSet.NameAttribute); + if (name != null) { + styleName = (String)name; + } + Component compo = StyleConstants.getComponent(attrSet); + if (compo != null) { + if (compo instanceof ChunkJbutton) { + ChunkJbutton button = (ChunkJbutton) compo; + LOGGER4J.debug("pos:" + pos +" style:[" + styleName + "] chunk partno:" + button.getPartNo() + " chunksize=" + button.getChunk().length); + } + } + } + } + } + } + + /** + * get List of PlaceHolder which has JComponent characterAttribute in StyleDocument + * + * @return + */ + public List getListOfPlaceHolderStyle() { + int pos = 0; + int endPos = this.getLength(); + List listOfPlaceHolderStyleChunk = new ArrayList<>(); + for(pos = 0; pos < endPos; pos++) { + Element elm = this.getCharacterElement(pos); + if (elm != null) { + AttributeSet attrSet = elm.getAttributes(); + if (attrSet != null) { + String styleName = ""; + // I can get StyleName and Component from the AttributeSet at last! + Object name = attrSet.getAttribute(AttributeSet.NameAttribute); + if (name != null) { + styleName = CastUtils.castToType(name); + } + Component compo = StyleConstants.getComponent(attrSet); + if (compo != null) { + if (compo instanceof ChunkJbutton) { + ChunkJbutton button = CastUtils.castToType(compo); + LOGGER4J.debug("pos:" + pos +" style:[" + styleName + "] chunk partno:" + button.getPartNo() + " chunksize=" + button.getChunk().length); + PlaceHolderStyleChunk placeHolderStyleChunk = new PlaceHolderStyleChunk(pos, styleName, button.getPartNo(), button.getChunk()); + listOfPlaceHolderStyleChunk.add(placeHolderStyleChunk); + } else if (compo instanceof JLabel) { + JLabel jLabel = CastUtils.castToType(compo); + LOGGER4J.debug("pos:" + pos + " style:[" + styleName + "]"); + PlaceHolderStyle placeHolderStyle = new PlaceHolderStyle(pos, styleName); + listOfPlaceHolderStyleChunk.add(placeHolderStyle); + } + } + } + } + } + return listOfPlaceHolderStyleChunk; + } + + /** + * get PlaceHolderStyleText from this content. + * + * @return PLaceHolderStyleText + */ + public String getPlaceHolderStyleText() { + try { + StringBuffer resultBuffer = new StringBuffer(); + String originalText = this.getText(0, getLength()); + int lastPos = getLength(); + List listOfPlaceHolderStyle = getListOfPlaceHolderStyle(); + int stPos = 0; + int endPos = -1; + for(InterfacePlaceHolderStyle placeHolderStyle: listOfPlaceHolderStyle) { + endPos = placeHolderStyle.getPos(); + resultBuffer.append(originalText.substring(stPos, endPos)); + if (placeHolderStyle instanceof PlaceHolderStyleChunk) { + PlaceHolderStyleChunk styleChunk = CastUtils.castToType(placeHolderStyle); + String placeHolder = CONTENTS_PLACEHOLDER_PREFIX + styleChunk.getPartNo() + CONTENTS_PLACEHOLDER_SUFFIX; + resultBuffer.append(placeHolder); + } else { + resultBuffer.append(originalText.substring(endPos, endPos+1)); + } + stPos = endPos + 1; + } + if (stPos < lastPos) { + resultBuffer.append(originalText.substring(stPos, lastPos)); + } + return resultBuffer.toString(); + + }catch(Exception ex) { + LOGGER4J.error(ex.getMessage(), ex); + } + return null; + } + + /** + * apply PLaceHolderStyle to this StyleDocument. + * usecase is to restore the PlaceHolder CharacterAttributes after clearing CharacterAttributes + * + * @param listOfPlaceHolderStyle + */ + public void applyPlaceHolderStyle(List listOfPlaceHolderStyle) { + for(InterfacePlaceHolderStyle placeHolderStyle: listOfPlaceHolderStyle) { + String styleName = placeHolderStyle.getStyleName(); + int pos = placeHolderStyle.getPos(); + if (styleName != null) { + Style innerStyle = this.getStyle(styleName); + LOGGER4J.debug("apply placeHolderstyle pos:" + pos); + this.setCharacterAttributes(pos, 1, innerStyle, false); + } + } + } + } + + diff --git a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/zap/PopUpItemSingleSend.java b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/zap/PopUpItemSingleSend.java index 63f686a..97310c2 100644 --- a/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/zap/PopUpItemSingleSend.java +++ b/addOns/automacrobuilder/src/main/java/org/zaproxy/zap/extension/automacrobuilder/zap/PopUpItemSingleSend.java @@ -84,6 +84,13 @@ private void singleSendSelectedRequest(MacroBuilderUI f_mbui, StartedActiveScanC SwingTimerFakeRunner runner = new SwingTimerFakeRunner(selectedTabIndex, f_mbui, new Runnable() { @Override public void run() { + // by below calling methods, + // all three display components(messageRequest/messageResponse/MacroComments) + // will be updated by sending result. + // messageRequest may have request being edited in it's own StyledDocument, + // but by result of sending messages, + // it will modify request message so must be update also messageRequest contents. + // so contents being edited in messageRequest may be discarded. f_mbui.updateCurrentSelectedRequestListDisplayContents(); f_mbui.showMessageViewOnWorkBench(1); } diff --git a/addOns/automacrobuilder/src/main/resources/burp/Bundle.properties b/addOns/automacrobuilder/src/main/resources/burp/Bundle.properties index cfba3c0..008e957 100644 --- a/addOns/automacrobuilder/src/main/resources/burp/Bundle.properties +++ b/addOns/automacrobuilder/src/main/resources/burp/Bundle.properties @@ -195,7 +195,7 @@ ParmGenRegex.comboModel_columnpolicy_0orMore(lazy).text=0 or more(lazy) ParmGenRegex.comboModel_columnpolicy_0orMore(greedy).text=0 or more(greedy) ParmGenRegex.insCR.text =Insert CR ParmGenRegex.SelectPattern.text=Update Regex with selected text. -ParmGenRegex.UndisplayableLargerData.text=sorry, data isn't displayable for it's larger size. +ParmGenRegex.UndisplayableAsTextLargerData.text=sorry, data isn't displayable as text for some reason. ParmGenRegex.BinaryData.text=sorry, this binary data is can't displayable as text. ParmGenRegex.BrokenData.text=sorry. this binary data is can't displayable such as format errors or something. ParmGenTokenJDialog.DialogTitle.text=Tracking parameters list