1 | | - | package com.nccgroup.loggerplusplus.logentry.logger; |
2 | | - | |
3 | | - | import burp.BurpExtender; |
4 | | - | import burp.IHttpRequestResponse; |
5 | | - | import com.nccgroup.loggerplusplus.*; |
6 | | - | import com.nccgroup.loggerplusplus.logentry.LogEntry; |
7 | | - | import com.nccgroup.loggerplusplus.logentry.LogEntryField; |
8 | | - | import com.nccgroup.loggerplusplus.logview.logtable.LogTable; |
9 | | - | import com.nccgroup.loggerplusplus.logview.logtable.LogTableColumn; |
10 | | - | import com.nccgroup.loggerplusplus.logview.logtable.LogTableColumnModel; |
11 | | - | import com.nccgroup.loggerplusplus.util.Globals; |
12 | | - | import com.nccgroup.loggerplusplus.util.MoreHelp; |
13 | | - | import org.apache.commons.text.StringEscapeUtils; |
14 | | - | |
15 | | - | import javax.swing.*; |
16 | | - | import javax.swing.filechooser.FileNameExtensionFilter; |
17 | | - | import javax.swing.table.TableColumn; |
18 | | - | import java.io.*; |
19 | | - | import java.util.ArrayList; |
20 | | - | import java.util.Collections; |
21 | | - | import java.util.Enumeration; |
22 | | - | |
23 | | - | /** |
24 | | - | * Created by corey on 21/08/17. |
25 | | - | */ |
26 | | - | public class FileLogger { |
27 | | - | //TODO REIMPLEMENT |
28 | | - | // private FileWriter autoSaveWriter; |
29 | | - | // private File autoSaveFile; |
30 | | - | // private final ExcelExporter exp; |
31 | | - | // private boolean autoLogIncludeRequests = false; |
32 | | - | // private boolean autoLogIncludeResponses = false; |
33 | | - | // |
34 | | - | // public FileLogger(){ |
35 | | - | // exp = new ExcelExporter(); |
36 | | - | // } |
37 | | - | // |
38 | | - | // public void saveLogs(boolean fullLogs){ |
39 | | - | // try { |
40 | | - | // File csvFile = getSaveFile("logger++_table", false); |
41 | | - | // if (csvFile != null) { |
42 | | - | // exp.exportTable(csvFile, fullLogs, false, true); |
43 | | - | // } |
44 | | - | // |
45 | | - | // } catch (IOException ex) { |
46 | | - | // LoggerPlusPlus.callbacks.printError(ex.getMessage()); |
47 | | - | // } |
48 | | - | // } |
49 | | - | // |
50 | | - | // public void autoLogItem(LogEntry entry, boolean includeRequests, boolean includeResponses) { |
51 | | - | // exp.exportItem(entry, includeRequests, includeResponses); |
52 | | - | // } |
53 | | - | // |
54 | | - | // // source: https://community.oracle.com/thread/1357495?start=0&tstart=0 |
55 | | - | // private File getSaveFile(String filename, boolean allowAppend) { |
56 | | - | // File csvFile = null; |
57 | | - | // JFileChooser chooser = null; |
58 | | - | // FileNameExtensionFilter filter = new FileNameExtensionFilter("Excel Format (CSV)", "csv"); |
59 | | - | // chooser = new JFileChooser(); |
60 | | - | // chooser.setDialogTitle("Saving Database"); |
61 | | - | // chooser.setFileFilter(filter); |
62 | | - | // chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); |
63 | | - | // chooser.setSelectedFile(new File(filename + ".csv")); |
64 | | - | // chooser.setAcceptAllFileFilterUsed(false); |
65 | | - | // |
66 | | - | // int val = chooser.showSaveDialog(null); |
67 | | - | // |
68 | | - | // if (val == JFileChooser.APPROVE_OPTION) { |
69 | | - | // csvFile = fixExtension(chooser.getSelectedFile(), "csv"); |
70 | | - | // if (csvFile == null) { |
71 | | - | // JOptionPane.showMessageDialog(JOptionPane.getFrameForComponent(BurpExtender.instance.getUiComponent()), "File Name Specified Not Supported", |
72 | | - | // "File Name Error", JOptionPane.ERROR_MESSAGE); |
73 | | - | // return getSaveFile(filename, allowAppend); |
74 | | - | // } |
75 | | - | // |
76 | | - | // try { |
77 | | - | // if (csvFile.exists()) { |
78 | | - | // if (allowAppend && validHeader(csvFile, false)) { |
79 | | - | // csvFile = appendOrOverwrite(csvFile); |
80 | | - | // } else { |
81 | | - | // csvFile = checkOverwrite(csvFile); |
82 | | - | // } |
83 | | - | // } else { |
84 | | - | // csvFile.createNewFile(); |
85 | | - | // } |
86 | | - | // } catch (IOException e) { |
87 | | - | // MoreHelp.showMessage("Could not create file. Do you have permissions for the folder?"); |
88 | | - | // return null; |
89 | | - | // } |
90 | | - | // return csvFile; |
91 | | - | // } |
92 | | - | // |
93 | | - | // return null; |
94 | | - | // } |
95 | | - | // |
96 | | - | // //Check if header in file matches that of the columns we will be exporting. |
97 | | - | // private boolean validHeader(File csvFile, boolean isFullLog) { |
98 | | - | // BufferedReader reader; |
99 | | - | // try { |
100 | | - | // reader = new BufferedReader(new FileReader(csvFile)); |
101 | | - | // } catch (FileNotFoundException e) { |
102 | | - | // return true; |
103 | | - | // } |
104 | | - | // try { |
105 | | - | // String thisHeader = getCSVHeader(LoggerPlusPlus.instance.getLogTable(), isFullLog); |
106 | | - | // String oldHeader = reader.readLine(); |
107 | | - | // return oldHeader == null || oldHeader.equalsIgnoreCase(thisHeader); |
108 | | - | // } catch (IOException e) { |
109 | | - | // return true; |
110 | | - | // } |
111 | | - | // } |
112 | | - | // |
113 | | - | // private File fixExtension(File file, String prefExt) { |
114 | | - | // String fileName = file.getName(); |
115 | | - | // String dir = file.getParentFile().getAbsolutePath(); |
116 | | - | // |
117 | | - | // String ext = null; |
118 | | - | // |
119 | | - | // try { |
120 | | - | // ext = fileName.substring(fileName.lastIndexOf(".")); |
121 | | - | // } catch (StringIndexOutOfBoundsException e) { |
122 | | - | // ext = null; |
123 | | - | // } |
124 | | - | // if (ext != null && !ext.equalsIgnoreCase("." + prefExt)) { |
125 | | - | // return file; |
126 | | - | // } |
127 | | - | // |
128 | | - | // String csvName; |
129 | | - | // if (ext == null || ext.length() == 0) { |
130 | | - | // csvName = fileName + "." + prefExt; |
131 | | - | // } else { |
132 | | - | // csvName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + prefExt; |
133 | | - | // } |
134 | | - | // |
135 | | - | // File csvCert = new File(dir, csvName); |
136 | | - | // |
137 | | - | // return csvCert; |
138 | | - | // } |
139 | | - | // |
140 | | - | // private File checkOverwrite(File file) throws IOException { |
141 | | - | // int val = JOptionPane.showConfirmDialog(null, "Replace Existing File?", "File Exists", |
142 | | - | // JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); |
143 | | - | // |
144 | | - | // if (val == JOptionPane.NO_OPTION) { |
145 | | - | // return getSaveFile(file.getName(), false); |
146 | | - | // } else if (val == JOptionPane.CANCEL_OPTION) { |
147 | | - | // return null; |
148 | | - | // } |
149 | | - | // file.delete(); |
150 | | - | // file.createNewFile(); |
151 | | - | // return file; |
152 | | - | // } |
153 | | - | // |
154 | | - | // private File appendOrOverwrite(File file) throws IOException { |
155 | | - | // Object[] options = {"Append", |
156 | | - | // "Overwrite", "Cancel"}; |
157 | | - | // int val = JOptionPane.showOptionDialog(null, |
158 | | - | // "Append to, or overwrite the existing file?", "File Exists", |
159 | | - | // JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); |
160 | | - | // if (val == JOptionPane.YES_OPTION) { |
161 | | - | // return file; |
162 | | - | // } else if (val == JOptionPane.NO_OPTION) { |
163 | | - | // file.delete(); |
164 | | - | // file.createNewFile(); |
165 | | - | // return file; |
166 | | - | // } else { |
167 | | - | // return null; |
168 | | - | // } |
169 | | - | // } |
170 | | - | // |
171 | | - | // |
172 | | - | // public void setAutoSave(boolean enabled) { |
173 | | - | // if (enabled) { |
174 | | - | // autoSaveFile = getSaveFile("logger++_auto", true); |
175 | | - | // if (autoSaveFile != null) { |
176 | | - | // LoggerPlusPlus.preferences.setSetting(Globals.PREF_AUTO_SAVE, true); |
177 | | - | // try { |
178 | | - | // autoSaveWriter = new FileWriter(autoSaveFile, true); |
179 | | - | // int result = JOptionPane.showConfirmDialog(null, "Include REQUEST bodies in the logs?","Automatic Logging", JOptionPane.YES_OPTION); |
180 | | - | // autoLogIncludeRequests = result == JOptionPane.YES_OPTION; |
181 | | - | // |
182 | | - | // result = JOptionPane.showConfirmDialog(null, "Include RESPONSE bodies in the logs?","Automatic Logging", JOptionPane.YES_OPTION); |
183 | | - | // autoLogIncludeResponses = result == JOptionPane.YES_OPTION; |
184 | | - | // if (autoSaveFile.length() == 0) |
185 | | - | // exp.addHeader(autoSaveWriter, autoLogIncludeRequests, autoLogIncludeResponses); |
186 | | - | // |
187 | | - | // LoggerPlusPlus.instance.getLogProcessor().addLogListener(this); |
188 | | - | // |
189 | | - | // } catch (IOException e) { |
190 | | - | // autoSaveFile = null; |
191 | | - | // enabled = false; |
192 | | - | // } |
193 | | - | // } else { |
194 | | - | // enabled = false; |
195 | | - | // } |
196 | | - | // } else { |
197 | | - | // autoSaveFile = null; |
198 | | - | // try{ |
199 | | - | // autoSaveWriter.close(); |
200 | | - | // } catch (Exception e) {} |
201 | | - | // autoSaveWriter = null; |
202 | | - | // LoggerPlusPlus.instance.getLogProcessor().removeLogListener(this); |
203 | | - | // } |
204 | | - | // LoggerPlusPlus.preferences.setSetting(Globals.PREF_AUTO_SAVE, enabled); |
205 | | - | // LoggerPlusPlus.instance.getLoggerOptionsPanel().setAutoSaveBtn(enabled); |
206 | | - | // } |
207 | | - | // |
208 | | - | // @Override |
209 | | - | // public void onRequestAdded(int modelIndex, final LogEntry logEntry, boolean hasResponse) { |
210 | | - | // if(!hasResponse) return; |
211 | | - | // Thread saveThread = new Thread(){ |
212 | | - | // @Override |
213 | | - | // public void run() { |
214 | | - | // synchronized (autoSaveWriter){ |
215 | | - | // autoLogItem(logEntry, autoLogIncludeRequests, autoLogIncludeResponses); |
216 | | - | // } |
217 | | - | // } |
218 | | - | // }; |
219 | | - | // saveThread.start(); |
220 | | - | // } |
221 | | - | // |
222 | | - | // @Override |
223 | | - | // public void onResponseUpdated(int modelRow, final LogEntry existingEntry) { |
224 | | - | // Thread saveThread = new Thread(){ |
225 | | - | // @Override |
226 | | - | // public void run() { |
227 | | - | // synchronized (autoSaveWriter){ |
228 | | - | // autoLogItem(existingEntry, autoLogIncludeRequests, autoLogIncludeResponses); |
229 | | - | // } |
230 | | - | // } |
231 | | - | // }; |
232 | | - | // saveThread.start(); |
233 | | - | // } |
234 | | - | // |
235 | | - | // @Override |
236 | | - | // public void onRequestRemoved(int modelIndex, LogEntry logEntry) { |
237 | | - | // |
238 | | - | // } |
239 | | - | // |
240 | | - | // @Override |
241 | | - | // public void onLogsCleared() { |
242 | | - | // |
243 | | - | // } |
244 | | - | // |
245 | | - | // // source: http://book.javanb.com/swing-hacks/swinghacks-chp-3-sect-6.html |
246 | | - | // public class ExcelExporter { |
247 | | - | // |
248 | | - | // public void addHeader(FileWriter writer, boolean isFullLog) throws IOException { |
249 | | - | // writer.write(getCSVHeader(LoggerPlusPlus.instance.getLogTable(), isFullLog) + "\n"); |
250 | | - | // } |
251 | | - | // |
252 | | - | // public void addHeader(FileWriter writer, boolean includeRequest, boolean includeResponse) throws IOException { |
253 | | - | // writer.write(getCSVHeader(LoggerPlusPlus.instance.getLogTable(), includeRequest, includeResponse) + "\n"); |
254 | | - | // } |
255 | | - | // |
256 | | - | // public void exportTable(File file, boolean isFullLog, boolean append, boolean header) throws IOException { |
257 | | - | // FileWriter out = new FileWriter(file, append); |
258 | | - | // |
259 | | - | // if (header) { |
260 | | - | // out.write(getCSVHeader(LoggerPlusPlus.instance.getLogTable(), isFullLog)); |
261 | | - | // out.write("\n"); |
262 | | - | // } |
263 | | - | // |
264 | | - | // for (LogEntry item : LoggerPlusPlus.instance.getLogProcessor().getLogEntries()) { |
265 | | - | // out.write(entryToCSVString(item, isFullLog) + "\n"); |
266 | | - | // } |
267 | | - | // |
268 | | - | // out.close(); |
269 | | - | // MoreHelp.showMessage("Log saved to " + file.getAbsolutePath()); |
270 | | - | // } |
271 | | - | // |
272 | | - | // public void exportItem(LogEntry logEntry, boolean includeRequests, boolean includeResponses) { |
273 | | - | // if(autoSaveWriter != null) { |
274 | | - | // try { |
275 | | - | // autoSaveWriter.write(entryToCSVString(logEntry, includeRequests, includeResponses)); |
276 | | - | // autoSaveWriter.write("\n"); |
277 | | - | // autoSaveWriter.flush(); |
278 | | - | // } catch (Exception e) { |
279 | | - | // MoreHelp.showMessage("Could not save log. Automatic logging will be disabled."); |
280 | | - | // setAutoSave(false); |
281 | | - | // } |
282 | | - | // }else{ |
283 | | - | // MoreHelp.showMessage("Could not save log. Automatic logging will be disabled."); |
284 | | - | // setAutoSave(false); |
285 | | - | // } |
286 | | - | // } |
287 | | - | // |
288 | | - | // } |
289 | | - | // |
290 | | - | // public static String getCSVHeader(LogTable table, boolean isFullLog) { |
291 | | - | // return getCSVHeader(table, isFullLog, isFullLog); |
292 | | - | // } |
293 | | - | // |
294 | | - | // public static String getCSVHeader(LogTable table, boolean includeRequest, boolean includeResponse) { |
295 | | - | // StringBuilder result = new StringBuilder(); |
296 | | - | // |
297 | | - | // boolean firstDone = false; |
298 | | - | // ArrayList<LogTableColumn> columns = new ArrayList<>(); |
299 | | - | // Enumeration<TableColumn> columnEnumeration = table.getColumnModel().getColumns(); |
300 | | - | // while(columnEnumeration.hasMoreElements()){ |
301 | | - | // columns.add((LogTableColumn) columnEnumeration.nextElement()); |
302 | | - | // } |
303 | | - | // |
304 | | - | // columns.remove(table.getColumnModel().getColumnByIdentifier(LogEntryField.NUMBER)); |
305 | | - | // |
306 | | - | // Collections.sort(columns); |
307 | | - | // for (LogTableColumn logTableColumn : columns) { |
308 | | - | // if(logTableColumn.isVisible()) { |
309 | | - | // if(firstDone) { |
310 | | - | // result.append(","); |
311 | | - | // }else{ |
312 | | - | // firstDone = true; |
313 | | - | // } |
314 | | - | // result.append(logTableColumn.getName()); |
315 | | - | // } |
316 | | - | // } |
317 | | - | // |
318 | | - | // if(includeRequest) { |
319 | | - | // result.append(","); |
320 | | - | // result.append("Request"); |
321 | | - | // } |
322 | | - | // if(includeResponse) { |
323 | | - | // result.append(","); |
324 | | - | // result.append("Response"); |
325 | | - | // } |
326 | | - | // return result.toString(); |
327 | | - | // } |
328 | | - | // |
329 | | - | // |
330 | | - | // public String entryToCSVString(LogEntry logEntry, boolean isFullLog) { |
331 | | - | // return entryToCSVString(logEntry, isFullLog, isFullLog); |
332 | | - | // } |
333 | | - | // |
334 | | - | // private String sanitize(String string){ |
335 | | - | // if(string == null) return null; |
336 | | - | // if(string.length() == 0) return ""; |
337 | | - | // char first = string.toCharArray()[0]; |
338 | | - | // switch (first){ |
339 | | - | // case '=': |
340 | | - | // case '-': |
341 | | - | // case '+': |
342 | | - | // case '@': { |
343 | | - | // return "'" + string; |
344 | | - | // } |
345 | | - | // } |
346 | | - | // return string; |
347 | | - | // } |
348 | | - | // |
349 | | - | // public String entryToCSVString(LogEntry logEntry, boolean includeRequests, boolean includeResponses) { |
350 | | - | // StringBuilder result = new StringBuilder(); |
351 | | - | // |
352 | | - | // LogTableColumnModel columnModel = LoggerPlusPlus.instance.getLogTable().getColumnModel(); |
353 | | - | // ArrayList<LogTableColumn> columns = new ArrayList<>(); |
354 | | - | // Enumeration<TableColumn> columnEnumeration = columnModel.getColumns(); |
355 | | - | // while(columnEnumeration.hasMoreElements()){ |
356 | | - | // columns.add((LogTableColumn) columnEnumeration.nextElement()); |
357 | | - | // } |
358 | | - | // |
359 | | - | // columns.remove(columnModel.getColumnByIdentifier(LogEntryField.NUMBER)); |
360 | | - | // |
361 | | - | // Collections.sort(columns); |
362 | | - | // boolean firstDone = false; |
363 | | - | // for (LogTableColumn logTableColumn : columns) { |
364 | | - | // if(logTableColumn.isVisible() && logTableColumn.getIdentifier() != LogEntryField.NUMBER){ |
365 | | - | // if(firstDone){ |
366 | | - | // result.append(","); |
367 | | - | // }else{ |
368 | | - | // firstDone = true; |
369 | | - | // } |
370 | | - | // String columnValue = String.valueOf(logEntry.getValueByKey(logTableColumn.getIdentifier())); |
371 | | - | // |
372 | | - | // result.append(StringEscapeUtils.escapeCsv(sanitize(columnValue))); |
373 | | - | // } |
374 | | - | // } |
375 | | - | // |
376 | | - | // IHttpRequestResponse requestResponse = logEntry.getRequestResponse(); |
377 | | - | // if(includeRequests) { |
378 | | - | // |
379 | | - | // result.append(","); |
380 | | - | // if (requestResponse != null && requestResponse.getRequest() != null) |
381 | | - | // result.append(StringEscapeUtils.escapeCsv(sanitize(new String(requestResponse.getRequest())))); |
382 | | - | // } |
383 | | - | // if(includeResponses) { |
384 | | - | // result.append(","); |
385 | | - | // if(requestResponse != null && requestResponse.getResponse() != null) |
386 | | - | // result.append(StringEscapeUtils.escapeCsv(sanitize(new String(requestResponse.getResponse())))); |
387 | | - | // } |
388 | | - | // return result.toString(); |
389 | | - | // } |
390 | | - | |
391 | | - | } |
392 | | - | |