├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── workflows
│ ├── codeql.yml
│ ├── prerelease.yaml
│ └── releases.yaml
├── .gitignore
├── BappDescription.html
├── BappManifest.bmf
├── LICENSE
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── images
├── aliases.png
├── colorfilters.png
├── filters.png
└── grep.png
├── settings.gradle
└── src
├── main
├── java
│ └── com
│ │ └── nccgroup
│ │ └── loggerplusplus
│ │ ├── LoggerContextMenuFactory.java
│ │ ├── LoggerPlusPlus.java
│ │ ├── MainViewController.java
│ │ ├── about
│ │ └── AboutPanel.java
│ │ ├── exports
│ │ ├── AutomaticLogExporter.java
│ │ ├── Base64Exporter.java
│ │ ├── CSVExporter.java
│ │ ├── CSVExporterControlPanel.java
│ │ ├── ContextMenuExportProvider.java
│ │ ├── ElasticExporter.java
│ │ ├── ElasticExporterConfigDialog.java
│ │ ├── ElasticExporterControlPanel.java
│ │ ├── ExportController.java
│ │ ├── ExportPanelProvider.java
│ │ ├── HARExporter.java
│ │ ├── HARExporterControlPanel.java
│ │ ├── HarSerializer.java
│ │ ├── JSONExporter.java
│ │ ├── JSONExporterControlPanel.java
│ │ └── LogExporter.java
│ │ ├── filter
│ │ ├── ColorizingFilterRule.java
│ │ ├── ComparisonOperator.java
│ │ ├── FilterExpression.java
│ │ ├── FilterExpressionSerializer.java
│ │ ├── FilterRule.java
│ │ ├── LogicalOperator.java
│ │ ├── SavedFilterSerializer.java
│ │ ├── TableColorRuleSerializer.java
│ │ ├── TagSerializer.java
│ │ ├── colorfilter
│ │ │ ├── ColorFilterListener.java
│ │ │ └── TableColorRule.java
│ │ ├── logfilter
│ │ │ ├── LogFilterController.java
│ │ │ └── LogTableFilter.java
│ │ ├── parser
│ │ │ ├── ASTAlias.java
│ │ │ ├── ASTComparison.java
│ │ │ ├── ASTExpression.java
│ │ │ ├── AliasCheckVisitor.java
│ │ │ ├── Filter.jj
│ │ │ ├── Filter.jjt
│ │ │ ├── FilterEvaluationVisitor.java
│ │ │ ├── FilterParser.java
│ │ │ ├── FilterParserConstants.java
│ │ │ ├── FilterParserDefaultVisitor.java
│ │ │ ├── FilterParserTokenManager.java
│ │ │ ├── FilterParserTreeConstants.java
│ │ │ ├── FilterParserVisitor.java
│ │ │ ├── JJTFilterParserState.java
│ │ │ ├── Node.java
│ │ │ ├── ParseException.java
│ │ │ ├── SanityCheckVisitor.java
│ │ │ ├── SimpleCharStream.java
│ │ │ ├── SimpleNode.java
│ │ │ ├── Token.java
│ │ │ ├── TokenMgrError.java
│ │ │ └── VisitorData.java
│ │ ├── savedfilter
│ │ │ └── SavedFilter.java
│ │ └── tag
│ │ │ ├── Tag.java
│ │ │ └── TagListener.java
│ │ ├── filterlibrary
│ │ ├── FilterLibraryController.java
│ │ ├── FilterLibraryListener.java
│ │ ├── FilterLibraryPanel.java
│ │ └── FilterLibraryTableModel.java
│ │ ├── grepper
│ │ ├── GrepResults.java
│ │ ├── GrepResultsTable.java
│ │ ├── GrepperController.java
│ │ ├── GrepperListener.java
│ │ ├── GrepperPanel.java
│ │ └── UniquePatternMatchTable.java
│ │ ├── help
│ │ └── HelpPanel.java
│ │ ├── imports
│ │ └── LoggerImport.java
│ │ ├── logentry
│ │ ├── FieldGroup.java
│ │ ├── LogEntry.java
│ │ ├── LogEntryField.java
│ │ ├── LogEntryFieldSerializer.java
│ │ ├── LogEntrySerializer.java
│ │ └── Status.java
│ │ ├── logging
│ │ ├── BurpAppender.java
│ │ └── LoggingController.java
│ │ ├── logview
│ │ ├── LogTableFilterStatusListener.java
│ │ ├── LogViewController.java
│ │ ├── LogViewPanel.java
│ │ ├── MainControlsPanel.java
│ │ ├── MultipleLogEntryMenu.java
│ │ ├── SingleLogEntryMenu.java
│ │ ├── entryviewer
│ │ │ ├── RequestViewerController.java
│ │ │ └── RequestViewerPanel.java
│ │ ├── logtable
│ │ │ ├── LogTable.java
│ │ │ ├── LogTableColumn.java
│ │ │ ├── LogTableColumnModel.java
│ │ │ ├── LogTableController.java
│ │ │ ├── LogTableModel.java
│ │ │ ├── TableHeader.java
│ │ │ └── TableHeaderMenu.java
│ │ └── processor
│ │ │ ├── EntryImportWorker.java
│ │ │ ├── LogProcessor.java
│ │ │ └── LogProcessorHelper.java
│ │ ├── preferences
│ │ ├── LoggerPreferenceFactory.java
│ │ ├── PreferencesController.java
│ │ └── PreferencesPanel.java
│ │ ├── reflection
│ │ ├── ReflectionController.java
│ │ ├── filter
│ │ │ ├── BlacklistFilter.java
│ │ │ ├── LengthFilter.java
│ │ │ └── ParameterFilter.java
│ │ └── transformer
│ │ │ ├── Base64DecodeTransformer.java
│ │ │ ├── Base64EncodeTransformer.java
│ │ │ ├── HTMLEscapeTransformer.java
│ │ │ ├── HTMLUnescapeTransformer.java
│ │ │ ├── HexEncodeTransformer.java
│ │ │ ├── JsonEscapeTransformer.java
│ │ │ ├── JsonUnescapeTransformer.java
│ │ │ ├── ParameterValueTransformer.java
│ │ │ ├── URLDecodeTransformer.java
│ │ │ ├── URLEncodeTransformer.java
│ │ │ ├── XMLEscapeTransformer.java
│ │ │ └── XMLUnescapeTransformer.java
│ │ └── util
│ │ ├── FieldSelectorDialog.java
│ │ ├── Globals.java
│ │ ├── MoreHelp.java
│ │ ├── NamedThreadFactory.java
│ │ ├── PausableThreadPoolExecutor.java
│ │ ├── SwingWorkerWithProgressDialog.java
│ │ └── userinterface
│ │ ├── ColorEditor.java
│ │ ├── LoggerMenu.java
│ │ ├── NoTextSelectionCaret.java
│ │ ├── ScrollablePanel.java
│ │ ├── WrappedTextPane.java
│ │ ├── dialog
│ │ ├── ColorFilterDialog.java
│ │ ├── ColorFilterTable.java
│ │ ├── ColorFilterTableModel.java
│ │ ├── TagDialog.java
│ │ ├── TagTable.java
│ │ └── TagTableModel.java
│ │ └── renderer
│ │ ├── BooleanRenderer.java
│ │ ├── ButtonRenderer.java
│ │ ├── ColorRenderer.java
│ │ ├── FilterRenderer.java
│ │ ├── LeftTableCellRenderer.java
│ │ └── TagRenderer.java
└── resources
│ ├── AboutMain.png
│ ├── GitHubLogoBlack.png
│ ├── GitHubLogoWhite.png
│ ├── NCCGroup.png
│ ├── NCCLarge.png
│ ├── TwitterLogo.png
│ └── log4j2.xml
└── test
└── java
└── Test.java
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Help improve Logger++
4 | title: ''
5 | labels: bug
6 | assignees: CoreyD97
7 |
8 | ---
9 |
10 | **Description:**
11 |
12 | **Steps To Reproduce:**
13 |
14 |
15 | **Expected behavior:**
16 |
17 |
18 | **Screenshots:**
19 |
20 | **Version:**
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Help make Logger++ awesome!
4 | title: ''
5 | labels: enhancement
6 | assignees: CoreyD97
7 |
8 | ---
9 |
10 | **Feature description:**
11 | I want...
12 |
13 | **Scenario example:**
14 | This would... (make it easier to write filters, help export logs to other tools, etc)
15 |
--------------------------------------------------------------------------------
/.github/workflows/codeql.yml:
--------------------------------------------------------------------------------
1 | name: "CodeQL"
2 |
3 | on:
4 | push:
5 | branches: [ 'master' ]
6 | pull_request:
7 | # The branches below must be a subset of the branches above
8 | branches: [ 'master' ]
9 | schedule:
10 | - cron: '30 11 * * 2'
11 |
12 | jobs:
13 | analyze:
14 | name: Analyze
15 | runs-on: ubuntu-latest
16 | permissions:
17 | actions: read
18 | contents: read
19 | security-events: write
20 |
21 | strategy:
22 | fail-fast: false
23 | matrix:
24 | language: [ 'java' ]
25 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
26 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
27 |
28 | steps:
29 | - name: Checkout repository
30 | uses: actions/checkout@v3
31 |
32 | - name: Set up Java
33 | uses: actions/setup-java@v2
34 | with:
35 | distribution: adopt
36 | java-version: '17'
37 |
38 | # Initializes the CodeQL tools for scanning.
39 | - name: Initialize CodeQL
40 | uses: github/codeql-action/init@v2
41 | with:
42 | languages: ${{ matrix.language }}
43 | # If you wish to specify custom queries, you can do so here or in a config file.
44 | # By default, queries listed here will override any specified in a config file.
45 | # Prefix the list here with "+" to use these queries and those in the config file.
46 |
47 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
48 | queries: +security-and-quality
49 |
50 |
51 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
52 | # If this step fails, then you should remove it and run the build manually (see below)
53 | - name: Autobuild
54 | uses: github/codeql-action/autobuild@v2
55 |
56 | # ℹ️ Command-line programs to run using the OS shell.
57 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
58 |
59 | # If the Autobuild fails above, remove it and uncomment the following three lines.
60 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
61 |
62 | # - run: |
63 | # echo "Run, Build Application using script"
64 | # ./location_of_script_within_repo/buildscript.sh
65 |
66 | - name: Perform CodeQL Analysis
67 | uses: github/codeql-action/analyze@v2
68 | with:
69 | category: "/language:${{matrix.language}}"
70 |
--------------------------------------------------------------------------------
/.github/workflows/prerelease.yaml:
--------------------------------------------------------------------------------
1 | name: "pre-release"
2 |
3 | on:
4 | push:
5 | branches:
6 | - "master"
7 |
8 | jobs:
9 | release:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Checkout source code
13 | uses: actions/checkout@v2.3.4
14 | with:
15 | lfs: true
16 | fetch-depth: 0
17 |
18 | - name: Set up Java
19 | uses: actions/setup-java@v2
20 | with:
21 | distribution: adopt
22 | java-version: '17'
23 |
24 | # burpsuite_pro.jar is not available, disable tests
25 | - name: Build
26 | run: ./gradlew build -x test
27 |
28 | - uses: "marvinpinto/action-automatic-releases@latest"
29 | with:
30 | repo_token: "${{ secrets.GITHUB_TOKEN }}"
31 | prerelease: true
32 | automatic_release_tag: "latest"
33 | files: |
34 | releases/*.jar
35 | id: "automatic_releases"
36 |
--------------------------------------------------------------------------------
/.github/workflows/releases.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | name: releases
3 |
4 | on:
5 | push:
6 | tags:
7 | - "v*"
8 |
9 | jobs:
10 | release:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Checkout source code
14 | uses: actions/checkout@v2.3.4
15 | with:
16 | lfs: true
17 | fetch-depth: 0
18 |
19 | - name: Set up Java
20 | uses: actions/setup-java@v2
21 | with:
22 | distribution: adopt
23 | java-version: '17'
24 |
25 | # burpsuite_pro.jar is not available, disable tests
26 | - name: Build
27 | run: ./gradlew build -x test
28 |
29 | - uses: "marvinpinto/action-automatic-releases@latest"
30 | with:
31 | repo_token: "${{ secrets.GITHUB_TOKEN }}"
32 | prerelease: false
33 | files: |
34 | releases/*.jar
35 | id: "automatic_releases"
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/
2 | .*/
3 | build/
4 | out/
5 | Util/
6 | libs/burpsuite_pro.jar
7 | BurpLogger++.iml
8 | TODO
9 | .classpath
10 | .project
11 | build.xml
12 | hs_err_*.log
13 | .vscode/**/*
14 | releases/**/*
15 | .settings/
--------------------------------------------------------------------------------
/BappDescription.html:
--------------------------------------------------------------------------------
1 |
Logger++ is a multithreaded logging extension for Burp Suite. In addition to logging requests and responses from all Burp Suite tools, the extension allows advanced filters to be defined to highlight interesting entries or filter logs to only those which match the filter.
2 |
3 | A built in grep tool allows the logs to be searched to locate entries which match a specified pattern, and extract the values of the capture groups.
4 |
5 | To enable logs to be used in other systems, the table can also be uploaded to elasticsearch or exported to CSV.
6 |
7 | Features:
8 |
9 |
10 | - Logs all the tools that are sending requests and receiving responses
11 | - Ability to log from a specific tool
12 | - Ability to save the results in CSV format
13 | - Ability to show results of custom regular expressions in request/response
14 | - User can customise the column headers
15 | - Advanced Filters can be created to display only requests matching specific conditions
16 | - Row highlighting can be added using advanced filters to make interesting requests more visible
17 | - Requests which match a filter can be automatically tagged (e.g. Admin, Low Privilege User, etc.)
18 | - Grep through logs
19 | - Live requests and responses
20 | - Multiple view options
21 | - Pop out view panel
22 | - Multithreaded
23 |
24 |
--------------------------------------------------------------------------------
/BappManifest.bmf:
--------------------------------------------------------------------------------
1 | Uuid: 470b7057b86f41c396a97903377f3d81
2 | ExtensionType: 1
3 | Name: Logger++
4 | RepoName: logger-plus-plus
5 | ScreenVersion: 3.20.0
6 | SerialVersion: 22
7 | MinPlatformVersion: 8
8 | ProOnly: False
9 | Author: Corey Arthur, NCC Group
10 | ShortDescription: Logs requests and responses for all Burp tools in a sortable table.
11 | EntryPoint: releases/LoggerPlusPlus.jar
12 | BuildCommand: ./gradlew jar
13 | SupportedProducts: Pro, Community
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Logger++
2 | Advanced Logging for Burp Suite
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Developed by Corey
12 | Arthur [](https://twitter.com/coreyd97/)
13 | Originally by Soroush
14 | Dalili [](https://twitter.com/irsdl/)
15 |
16 | Released as open source by NCC Group Plc - https://www.nccgroup.com/
17 | Released under AGPL-3.0 see LICENSE for more information
18 |
19 | Description
20 | ----
21 |
22 | Logger++ is a multithreaded logging extension for Burp Suite. In addition to logging requests and responses from all
23 | Burp Suite tools, the extension allows advanced filters to be defined to highlight interesting entries or filter logs to
24 | only those which match the filter.
25 |
26 | A built in grep tool allows the logs to be searched to locate entries which match a specified pattern, and extract the
27 | values of the capture groups.
28 |
29 | To enable logs to be used in other systems, the table can also be uploaded to elasticsearch or exported to CSV.
30 |
31 | Features:
32 |
33 | - Works with the latest version of Burp Suite (tested on 1.7.27)
34 | - Logs all the tools that are sending requests and receiving responses
35 | - Ability to log from a specific tool
36 | - Ability to save the results in CSV format
37 | - Ability to show results of custom regular expressions in request/response
38 | - User can customise the column headers
39 | - Advanced Filters can be created to display only requests matching a specific string or regex pattern.
40 | - Row highlighting can be added using advanced filters to make interesting requests more visible.
41 | - Grep through logs.
42 | - Live requests and responses.
43 | - Multiple view options.
44 | - Pop out view panel.
45 | - Multithreaded.
46 |
47 | Current Limitations:
48 |
49 | - Cannot log the requests' actual time unless originating from proxy tool.
50 | - Cannot calculate the actual delay between a request and its response unless originating from proxy tool.
51 |
52 | Screenshots
53 | ----------------------
54 |
55 | Log Filters
56 |
57 | 
58 |
59 | Row Highlights
60 |
61 | 
62 |
63 | Grep Search
64 |
65 | 
66 |
67 |
68 | Usage
69 | ----
70 | You can use this extension without using the BApp store. In order to install the latest version of this extension from
71 | the GitHub repository, follow these steps:
72 |
73 | 1. Download the [latest release jar](https://github.com/nccgroup/LoggerPlusPlus/releases/latest) .
74 |
75 | 2. In Burp Suite, click on the "Extender" tab, then in the "Extensions" tab click on the "Add" button and select the
76 | downloaded "loggerplusplus.jar" file.
77 |
78 | 3. You should now be able to see the "Logger++" tab in Burp Suite. If it cannot log anything, check your Burp Suite
79 | extension settings. If the save buttons are disabled, make sure that the requested libraries have been loaded
80 | successfully; Unload and then reload the extension and try again. If you have found an issue, please report it in the
81 | GitHub project.
82 |
83 | 4. You can configure this extension by using its "option" tab and by right click on the columns' headers.
84 |
85 | 5. If you like the project, give the repo a star! <3
86 |
87 | 
88 |
89 | Contributing
90 | ----
91 |
92 | ### Building from Source
93 |
94 | If you'd like to build the project from source, the project uses Gradle to simplify the process:
95 |
96 | 1. Clone the repository: `git clone https://github.com/nccgroup/LoggerPlusPlus.git`
97 | 2. Within the project folder, execute `gradlew jar` (Linux) `gradlew.bat jar` (Windows)
98 | 3. Once complete, you can find the built Jar in the project's `releases` folder.
99 |
100 | ### Testing
101 |
102 | IntelliJ Idea has been used to develop the project, but feel free to use any IDE you prefer. The following instructions
103 | are for Idea, but the process will be similar for other IDEs.
104 |
105 | 1. Within Idea, click `File > Open`, then select the project's `build.gradle` file.
106 | 2. Click "Open as Project" in the next dialog.
107 | 3. To run/debug the application, navigate to `Run > Edit Configurations`, then add a new "Application" configuration
108 | targeting the `TestLogger` class.
109 |
110 | ### Reporting bugs
111 |
112 | If you have found an issue, please report it via [GitHub](https://github.com/nccgroup/LoggerPlusPlus/issues/new/choose).
113 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id "io.freefair.lombok" version "6.5.1"
4 | }
5 |
6 | sourceCompatibility = JavaVersion.VERSION_17
7 | targetCompatibility = JavaVersion.VERSION_17
8 |
9 | repositories {
10 | mavenCentral()
11 | maven {
12 | url "https://jitpack.io"
13 | }
14 | }
15 |
16 | dependencies {
17 | implementation 'net.portswigger.burp.extensions:montoya-api:2023.5'
18 | implementation 'org.swinglabs:swingx:1.6.1'
19 | implementation 'com.github.CoreyD97:Burp-Montoya-Utilities:234d21d'
20 | // implementation 'org.elasticsearch.client:elasticsearch-rest-high-level-client:7.17.9'
21 | implementation 'co.elastic.clients:elasticsearch-java:8.6.2'
22 | implementation 'org.apache.httpcomponents:httpclient:4.5.13'
23 | implementation 'org.apache.commons:commons-text:1.10.0'
24 | implementation 'org.apache.logging.log4j:log4j-core:2.19.0'
25 |
26 | testRuntimeOnly files("${System.properties['user.home']}/BurpSuitePro/burpsuite_pro.jar")
27 | }
28 |
29 | jar {
30 | baseName = project.name
31 | duplicatesStrategy = DuplicatesStrategy.EXCLUDE
32 |
33 | from {
34 | (configurations.runtimeClasspath).collect { it.isDirectory() ? it : zipTree(it) }
35 | } {
36 | exclude "META-INF/*.SF"
37 | exclude "META-INF/*.DSA"
38 | exclude "META-INF/*.RSA"
39 | }
40 | }
41 |
42 | tasks.withType(Jar) {
43 | destinationDir = file("$rootDir/releases")
44 | }
45 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PortSwigger/logger-plus-plus/6fd5f21b714bb3aef2b34d709b0d05b8ade15d2c/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/images/aliases.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PortSwigger/logger-plus-plus/6fd5f21b714bb3aef2b34d709b0d05b8ade15d2c/images/aliases.png
--------------------------------------------------------------------------------
/images/colorfilters.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PortSwigger/logger-plus-plus/6fd5f21b714bb3aef2b34d709b0d05b8ade15d2c/images/colorfilters.png
--------------------------------------------------------------------------------
/images/filters.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PortSwigger/logger-plus-plus/6fd5f21b714bb3aef2b34d709b0d05b8ade15d2c/images/filters.png
--------------------------------------------------------------------------------
/images/grep.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PortSwigger/logger-plus-plus/6fd5f21b714bb3aef2b34d709b0d05b8ade15d2c/images/grep.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'LoggerPlusPlus'
2 |
3 | //if(file("../BurpExtenderUtilities").exists()){
4 | // includeBuild('../BurpExtenderUtilities'){
5 | // dependencySubstitution{
6 | // substitute module('com.github.CoreyD97:BurpExtenderUtilities') with project(':')
7 | // }
8 | // }
9 | //}
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/MainViewController.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.PopOutPanel;
4 | import com.nccgroup.loggerplusplus.about.AboutPanel;
5 | import com.nccgroup.loggerplusplus.help.HelpPanel;
6 | import com.nccgroup.loggerplusplus.util.Globals;
7 |
8 | import javax.swing.*;
9 | import java.awt.*;
10 |
11 | public class MainViewController {
12 |
13 | private final JTabbedPane tabbedPane;
14 | private final PopOutPanel popOutWrapper;
15 |
16 | public MainViewController() {
17 | this.tabbedPane = new JTabbedPane();
18 | LoggerPlusPlus loggerPlusPlus = LoggerPlusPlus.instance;
19 | tabbedPane.addTab("View Logs", null, loggerPlusPlus.getLogViewController().getLogViewPanel(), null);
20 | tabbedPane.addTab("Filter Library", null, loggerPlusPlus.getLibraryController().getFilterLibraryPanel(), null);
21 | tabbedPane.addTab("Grep Values", null, loggerPlusPlus.getGrepperController().getGrepperPanel(), null);
22 | tabbedPane.addTab("Options", null, loggerPlusPlus.getPreferencesController().getPreferencesPanel(), null);
23 | tabbedPane.addTab("About", null, new AboutPanel(loggerPlusPlus.getPreferencesController().getPreferences()), null);
24 | tabbedPane.addTab("Help", null, new HelpPanel(), null);
25 | this.popOutWrapper = new PopOutPanel(LoggerPlusPlus.montoya, tabbedPane, Globals.APP_NAME);
26 | }
27 |
28 | public Component getUiComponent() {
29 | return popOutWrapper;
30 | }
31 |
32 | public JTabbedPane getTabbedPanel(){
33 | return tabbedPane;
34 | }
35 |
36 | public PopOutPanel getPopOutWrapper() {
37 | return popOutWrapper;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/exports/AutomaticLogExporter.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.exports;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 | import com.nccgroup.loggerplusplus.logentry.LogEntry;
5 |
6 | public abstract class AutomaticLogExporter extends LogExporter {
7 |
8 | protected AutomaticLogExporter(ExportController exportController, Preferences preferences){
9 | super(exportController, preferences);
10 | }
11 |
12 | /**
13 | * Configure the exporter ready for use
14 | * @throws Exception Setup not completed
15 | */
16 | abstract void setup() throws Exception;
17 |
18 | /**
19 | * Handle the export of a received entry
20 | * @param logEntry
21 | */
22 | abstract void exportNewEntry(LogEntry logEntry);
23 |
24 | /**
25 | * Handle the export of a received entry
26 | * @param logEntry
27 | */
28 | abstract void exportUpdatedEntry(LogEntry logEntry);
29 |
30 | /**
31 | * Clean up the exporter and its resources
32 | * @throws Exception
33 | */
34 | abstract void shutdown() throws Exception;
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/exports/Base64Exporter.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.exports;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 | import com.google.gson.Gson;
5 | import com.google.gson.JsonObject;
6 | import com.nccgroup.loggerplusplus.LoggerPlusPlus;
7 | import com.nccgroup.loggerplusplus.logentry.LogEntry;
8 | import com.nccgroup.loggerplusplus.util.MoreHelp;
9 | import com.nccgroup.loggerplusplus.util.SwingWorkerWithProgressDialog;
10 |
11 | import javax.swing.*;
12 | import java.awt.event.ActionEvent;
13 | import java.io.File;
14 | import java.io.FileWriter;
15 | import java.util.ArrayList;
16 | import java.util.Base64;
17 | import java.util.List;
18 |
19 | /**
20 | * Created by corey on 21/08/17.
21 | */
22 | public class Base64Exporter extends LogExporter implements ContextMenuExportProvider {
23 |
24 | public Base64Exporter(ExportController exportController, Preferences preferences) {
25 | super(exportController, preferences);
26 | }
27 |
28 | public void exportEntries(List entries, boolean includeRequest, boolean includeResponse) {
29 | if (!includeRequest && !includeResponse)
30 | throw new IllegalArgumentException("Must include either request, response or both.");
31 | try {
32 | File file = MoreHelp.getSaveFile("LoggerPlusPlus_Base64.json", "JSON Format", "json");
33 | if (file.exists() && !MoreHelp.shouldOverwriteExistingFilePrompt()) return;
34 |
35 | SwingWorkerWithProgressDialog importWorker = new SwingWorkerWithProgressDialog(
36 | LoggerPlusPlus.instance.getLoggerFrame(),
37 | "Base64 Encoded JSON Export", "Exporting as Base64 encoded JSON...", entries.size()) {
38 | @Override
39 | protected Void doInBackground() throws Exception {
40 | super.doInBackground();
41 | try (FileWriter fileWriter = new FileWriter(file, false)) {
42 | Gson gson = LoggerPlusPlus.gsonProvider.getGson();
43 | ArrayList jsonEntries = new ArrayList<>();
44 | Base64.Encoder encoder = Base64.getEncoder();
45 | for (LogEntry entry : entries) {
46 | JsonObject jsonEntry = new JsonObject();
47 | if (includeRequest) {
48 | jsonEntry.addProperty("request",
49 | encoder.encodeToString(entry.getRequestBytes()));
50 | }
51 |
52 | if (includeResponse) {
53 | jsonEntry.addProperty("response",
54 | encoder.encodeToString(entry.getResponseBytes()));
55 | }
56 | jsonEntries.add(jsonEntry);
57 | }
58 |
59 | gson.toJson(jsonEntries, fileWriter);
60 | }
61 |
62 | return null;
63 | }
64 |
65 | @Override
66 | protected void done() {
67 | super.done();
68 | JOptionPane.showMessageDialog(LoggerPlusPlus.instance.getLoggerFrame(),
69 | "Export as Base64 completed.",
70 | "Base64 Export", JOptionPane.INFORMATION_MESSAGE);
71 | }
72 | };
73 |
74 | importWorker.execute();
75 |
76 | } catch (Exception e) {
77 | //Cancelled.
78 | }
79 | }
80 |
81 | @Override
82 | public JMenuItem getExportEntriesMenuItem(List entries) {
83 | JMenu parent = new JMenu(String.format("Export %d %s as Base64 (JSON Formatted)",
84 | entries.size(), entries.size() != 1 ? "entries" : "entry"));
85 |
86 | parent.add(new JMenuItem(new AbstractAction(entries.size() == 1 ? "Request Only" : "Requests Only") {
87 | @Override
88 | public void actionPerformed(ActionEvent e) {
89 | exportEntries(entries, true, false);
90 | }
91 | }));
92 |
93 | parent.add(new JMenuItem(new AbstractAction(entries.size() == 1 ? "Response Only" : "Responses Only") {
94 | @Override
95 | public void actionPerformed(ActionEvent e) {
96 | exportEntries(entries, false, true);
97 | }
98 | }));
99 |
100 | parent.add(new JMenuItem(new AbstractAction(entries.size() == 1 ? "Request and Response" : "Requests and Responses") {
101 | @Override
102 | public void actionPerformed(ActionEvent e) {
103 | exportEntries(entries, true, true);
104 | }
105 | }));
106 |
107 | return parent;
108 | }
109 |
110 | public ExportController getExportController() {
111 | return this.exportController;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/exports/CSVExporterControlPanel.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.exports;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Alignment;
4 | import com.coreyd97.BurpExtenderUtilities.PanelBuilder;
5 | import com.nccgroup.loggerplusplus.LoggerPlusPlus;
6 | import com.nccgroup.loggerplusplus.logentry.LogEntry;
7 |
8 | import javax.swing.*;
9 | import java.awt.*;
10 | import java.awt.event.ActionEvent;
11 | import java.util.List;
12 |
13 | public class CSVExporterControlPanel extends JPanel {
14 |
15 | private final CSVExporter csvExporter;
16 |
17 | CSVExporterControlPanel(CSVExporter csvExporter){
18 | this.csvExporter = csvExporter;
19 | this.setLayout(new BorderLayout());
20 |
21 | JButton manualSaveButton = new JButton("Export as CSV");
22 | manualSaveButton.addActionListener(actionEvent -> {
23 | final List entries = LoggerPlusPlus.instance.getLogEntries();
24 | csvExporter.exportEntries(entries);
25 | });
26 |
27 | JToggleButton exportButton = new JToggleButton("Auto-export as CSV");
28 | exportButton.addActionListener(new AbstractAction() {
29 | @Override
30 | public void actionPerformed(ActionEvent actionEvent) {
31 | boolean newSelectedState = exportButton.isSelected();
32 | boolean operationSuccess = exportButton.isSelected() ? enableExporter() : disableExporter();
33 | exportButton.setSelected(!newSelectedState ^ operationSuccess);
34 | }
35 | });
36 |
37 | this.add(PanelBuilder.build(new JComponent[][]{
38 | new JComponent[]{manualSaveButton},
39 | new JComponent[]{exportButton}
40 | }, new int[][]{
41 | new int[]{1},
42 | new int[]{1}
43 | }, Alignment.FILL, 1.0, 1.0), BorderLayout.CENTER);
44 |
45 | this.setBorder(BorderFactory.createTitledBorder("CSV Exporter"));
46 | }
47 |
48 | private boolean enableExporter(){
49 | try {
50 | this.csvExporter.getExportController().enableExporter(this.csvExporter);
51 | return true;
52 | } catch (Exception e) {
53 | return false;
54 | }
55 | }
56 |
57 | private boolean disableExporter(){
58 | try{
59 | this.csvExporter.getExportController().disableExporter(this.csvExporter);
60 | return true;
61 | }catch (Exception e){
62 | return false;
63 | }
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/exports/ContextMenuExportProvider.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.exports;
2 |
3 | import com.nccgroup.loggerplusplus.logentry.LogEntry;
4 |
5 | import javax.swing.*;
6 | import java.util.List;
7 |
8 | public interface ContextMenuExportProvider {
9 | JMenuItem getExportEntriesMenuItem(List entries);
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/exports/ElasticExporterControlPanel.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.exports;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Alignment;
4 | import com.coreyd97.BurpExtenderUtilities.PanelBuilder;
5 | import com.nccgroup.loggerplusplus.LoggerPlusPlus;
6 | import com.nccgroup.loggerplusplus.util.Globals;
7 | import org.apache.logging.log4j.LogManager;
8 | import org.apache.logging.log4j.Logger;
9 |
10 | import javax.swing.*;
11 | import java.awt.*;
12 | import java.awt.event.ActionEvent;
13 | import java.util.concurrent.ExecutionException;
14 |
15 | public class ElasticExporterControlPanel extends JPanel {
16 |
17 | private final ElasticExporter elasticExporter;
18 | private static final String STARTING_TEXT = "Starting Elastic Exporter...";
19 | private static final String STOPPING_TEXT = "Stopping Elastic Exporter...";
20 | private static final String START_TEXT = "Start Elastic Exporter";
21 | private static final String STOP_TEXT = "Stop Elastic Exporter";
22 |
23 | Logger logger = LogManager.getLogger(this);
24 |
25 | public ElasticExporterControlPanel(ElasticExporter elasticExporter) {
26 | this.elasticExporter = elasticExporter;
27 | this.setLayout(new BorderLayout());
28 |
29 | JButton showConfigDialogButton = new JButton(new AbstractAction("Configure Elastic Exporter") {
30 | @Override
31 | public void actionPerformed(ActionEvent actionEvent) {
32 | new ElasticExporterConfigDialog(LoggerPlusPlus.instance.getLoggerFrame(), elasticExporter)
33 | .setVisible(true);
34 |
35 | //Dialog closed. Update previous project entry filter to current value.
36 | String newFilter = elasticExporter.getPreferences().getSetting(Globals.PREF_ELASTIC_FILTER);
37 | elasticExporter.getPreferences().setSetting(Globals.PREF_ELASTIC_FILTER_PROJECT_PREVIOUS, newFilter);
38 | }
39 | });
40 |
41 | JToggleButton exportButton = new JToggleButton("Start Elastic Exporter");
42 | exportButton.addActionListener(new AbstractAction() {
43 | @Override
44 | public void actionPerformed(ActionEvent actionEvent) {
45 | boolean buttonNowActive = exportButton.isSelected();
46 | exportButton.setEnabled(false);
47 | exportButton.setText(buttonNowActive ? STARTING_TEXT : STOPPING_TEXT);
48 | new SwingWorker(){
49 | Exception exception;
50 |
51 | @Override
52 | protected Boolean doInBackground() throws Exception {
53 | boolean success = false;
54 | try {
55 | if (exportButton.isSelected()) {
56 | enableExporter();
57 | } else {
58 | disableExporter();
59 | }
60 | success = true;
61 | }catch (Exception e){
62 | this.exception = e;
63 | }
64 | return success;
65 | }
66 |
67 | @Override
68 | protected void done() {
69 | try {
70 | if(exception != null) {
71 | JOptionPane.showMessageDialog(exportButton, "Could not start elastic exporter: " +
72 | exception.getMessage() + "\nSee the logs for more information.", "Elastic Exporter", JOptionPane.ERROR_MESSAGE);
73 | logger.error("Could not start elastic exporter.", exception);
74 | }
75 | Boolean success = get();
76 | boolean isRunning = buttonNowActive ^ !success;
77 | exportButton.setSelected(isRunning);
78 | showConfigDialogButton.setEnabled(!isRunning);
79 |
80 | exportButton.setText(isRunning ? STOP_TEXT : START_TEXT);
81 |
82 | } catch (InterruptedException | ExecutionException e) {
83 | e.printStackTrace();
84 | }
85 | exportButton.setEnabled(true);
86 | }
87 | }.execute();
88 | }
89 | });
90 |
91 | if (isExporterEnabled()){
92 | exportButton.setSelected(true);
93 | exportButton.setText(STOP_TEXT);
94 | showConfigDialogButton.setEnabled(false);
95 | }
96 |
97 |
98 | this.add(PanelBuilder.build(new JComponent[][]{
99 | new JComponent[]{showConfigDialogButton},
100 | new JComponent[]{exportButton}
101 | }, new int[][]{
102 | new int[]{1},
103 | new int[]{1}
104 | }, Alignment.FILL, 1.0, 1.0), BorderLayout.CENTER);
105 |
106 |
107 | this.setBorder(BorderFactory.createTitledBorder("Elastic Exporter"));
108 | }
109 |
110 | private void enableExporter() throws Exception {
111 | this.elasticExporter.getExportController().enableExporter(this.elasticExporter);
112 | }
113 |
114 | private void disableExporter() throws Exception {
115 | this.elasticExporter.getExportController().disableExporter(this.elasticExporter);
116 | }
117 |
118 | private boolean isExporterEnabled() {
119 | return this.elasticExporter.getExportController().getEnabledExporters().contains(this.elasticExporter);
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/exports/ExportController.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.exports;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 | import com.nccgroup.loggerplusplus.logentry.LogEntry;
5 |
6 | import java.util.ArrayList;
7 | import java.util.Collections;
8 | import java.util.HashMap;
9 | import java.util.List;
10 |
11 | public class ExportController {
12 | private final Preferences preferences;
13 | private final HashMap, LogExporter> exporters;
14 | private final List enabledExporters;
15 |
16 | public ExportController(Preferences preferences) {
17 | this.preferences = preferences;
18 |
19 | this.exporters = new HashMap<>();
20 | this.enabledExporters = Collections.synchronizedList(new ArrayList<>());
21 |
22 | initializeExporters();
23 | }
24 |
25 | private void initializeExporters() {
26 | this.exporters.put(CSVExporter.class, new CSVExporter(this, preferences));
27 | this.exporters.put(JSONExporter.class, new JSONExporter(this, preferences));
28 | this.exporters.put(HARExporter.class, new HARExporter(this, preferences));
29 | this.exporters.put(Base64Exporter.class, new Base64Exporter(this, preferences));
30 | this.exporters.put(ElasticExporter.class, new ElasticExporter(this, preferences));
31 | }
32 |
33 | public HashMap, LogExporter> getExporters() {
34 | return exporters;
35 | }
36 |
37 | public List getEnabledExporters() {
38 | return enabledExporters;
39 | }
40 |
41 | public void enableExporter(AutomaticLogExporter logExporter) throws Exception {
42 | logExporter.setup();
43 | this.enabledExporters.add(logExporter);
44 | }
45 |
46 | public void disableExporter(AutomaticLogExporter logExporter) throws Exception {
47 | this.enabledExporters.remove(logExporter);
48 | logExporter.shutdown();
49 | }
50 |
51 | public void exportNewEntry(LogEntry logEntry) {
52 | for (AutomaticLogExporter exporter : this.enabledExporters) {
53 | exporter.exportNewEntry(logEntry);
54 | }
55 | }
56 |
57 | public void exportUpdatedEntry(LogEntry logEntry) {
58 | for (AutomaticLogExporter exporter : this.enabledExporters) {
59 | exporter.exportUpdatedEntry(logEntry);
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/exports/ExportPanelProvider.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.exports;
2 |
3 | import javax.swing.*;
4 |
5 | public interface ExportPanelProvider {
6 | /**
7 | * Build the control panel to be displayed in the preferences tab
8 | *
9 | * @return JComponent Component to be displayed
10 | */
11 | JComponent getExportPanel();
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/exports/HARExporter.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.exports;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 | import com.google.gson.Gson;
5 | import com.google.gson.GsonBuilder;
6 | import com.google.gson.reflect.TypeToken;
7 | import com.nccgroup.loggerplusplus.logentry.LogEntry;
8 | import com.nccgroup.loggerplusplus.util.Globals;
9 | import com.nccgroup.loggerplusplus.util.MoreHelp;
10 | import com.nccgroup.loggerplusplus.util.SwingWorkerWithProgressDialog;
11 |
12 | import javax.swing.*;
13 | import java.awt.event.ActionEvent;
14 | import java.io.File;
15 | import java.io.FileWriter;
16 | import java.lang.reflect.Type;
17 | import java.util.List;
18 |
19 | public class HARExporter extends LogExporter implements ExportPanelProvider, ContextMenuExportProvider {
20 |
21 | private final HARExporterControlPanel controlPanel;
22 |
23 | public HARExporter(ExportController exportController, Preferences preferences) {
24 | super(exportController, preferences);
25 | this.controlPanel = new HARExporterControlPanel(this);
26 | }
27 |
28 | @Override
29 | public JComponent getExportPanel() {
30 | return this.controlPanel;
31 | }
32 |
33 | public void exportEntries(List entries) {
34 | try {
35 | File file = MoreHelp.getSaveFile("LoggerPlusPlus.har", "HAR Format", "har");
36 | if (file.exists() && !MoreHelp.shouldOverwriteExistingFilePrompt())
37 | return;
38 |
39 | SwingWorkerWithProgressDialog importWorker = new SwingWorkerWithProgressDialog(
40 | JOptionPane.getFrameForComponent(this.controlPanel), "HAR Export", "Exporting as HAR...",
41 | entries.size()) {
42 | @Override
43 | protected Void doInBackground() throws Exception {
44 | super.doInBackground();
45 | try (FileWriter fileWriter = new FileWriter(file, false)) {
46 | Type logEntryListType = new TypeToken>(){}.getType();
47 | Gson gson = new GsonBuilder().registerTypeAdapter(logEntryListType, new HarSerializer(String.valueOf(Globals.VERSION), "LoggerPlusPlus")).create();
48 | gson.toJson(entries, logEntryListType, fileWriter);
49 | }
50 |
51 | return null;
52 | }
53 |
54 | @Override
55 | protected void done() {
56 | super.done();
57 | JOptionPane.showMessageDialog(controlPanel, "Export as HAR completed.", "HAR Export",
58 | JOptionPane.INFORMATION_MESSAGE);
59 | }
60 | };
61 |
62 | importWorker.execute();
63 |
64 | } catch (Exception e) {
65 | // Cancelled.
66 | }
67 | }
68 |
69 | @Override
70 | public JMenuItem getExportEntriesMenuItem(List entries) {
71 | return new JMenuItem(new AbstractAction(
72 | String.format("Export %d %s as HAR", entries.size(), entries.size() != 1 ? "entries" : "entry")) {
73 | @Override
74 | public void actionPerformed(ActionEvent e) {
75 | exportEntries(entries);
76 | }
77 | });
78 | }
79 |
80 | public ExportController getExportController() {
81 | return this.exportController;
82 | }
83 | }
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/exports/HARExporterControlPanel.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.exports;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Alignment;
4 | import com.coreyd97.BurpExtenderUtilities.PanelBuilder;
5 | import com.nccgroup.loggerplusplus.LoggerPlusPlus;
6 | import com.nccgroup.loggerplusplus.logentry.LogEntry;
7 |
8 | import javax.swing.*;
9 | import java.awt.*;
10 | import java.util.List;
11 |
12 | public class HARExporterControlPanel extends JPanel {
13 | HARExporterControlPanel(HARExporter harExporter) {
14 | this.setLayout(new BorderLayout());
15 |
16 | JButton manualSaveButton = new JButton("Export as HAR");
17 | manualSaveButton.addActionListener(actionEvent -> {
18 | final List entries = LoggerPlusPlus.instance.getLogEntries();
19 | harExporter.exportEntries(entries);
20 | });
21 |
22 | this.add(PanelBuilder.build(new JComponent[][] { new JComponent[] { manualSaveButton }, },
23 | new int[][] { new int[] { 1 }, }, Alignment.FILL, 1.0, 1.0), BorderLayout.CENTER);
24 |
25 | this.setBorder(BorderFactory.createTitledBorder("HAR Exporter"));
26 | }
27 | }
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/exports/JSONExporter.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.exports;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 | import com.google.gson.Gson;
5 | import com.nccgroup.loggerplusplus.LoggerPlusPlus;
6 | import com.nccgroup.loggerplusplus.logentry.LogEntry;
7 | import com.nccgroup.loggerplusplus.util.MoreHelp;
8 | import com.nccgroup.loggerplusplus.util.SwingWorkerWithProgressDialog;
9 |
10 | import javax.swing.*;
11 | import java.awt.event.ActionEvent;
12 | import java.io.File;
13 | import java.io.FileWriter;
14 | import java.util.List;
15 |
16 | /**
17 | * Created by corey on 21/08/17.
18 | */
19 | public class JSONExporter extends LogExporter implements ExportPanelProvider, ContextMenuExportProvider {
20 |
21 | private final JSONExporterControlPanel controlPanel;
22 |
23 | public JSONExporter(ExportController exportController, Preferences preferences) {
24 | super(exportController, preferences);
25 | this.controlPanel = new JSONExporterControlPanel(this);
26 | }
27 |
28 | @Override
29 | public JComponent getExportPanel() {
30 | return this.controlPanel;
31 | }
32 |
33 | public void exportEntries(List entries) {
34 | try {
35 | File file = MoreHelp.getSaveFile("LoggerPlusPlus.json", "JSON Format", "json");
36 | if (file.exists() && !MoreHelp.shouldOverwriteExistingFilePrompt()) return;
37 |
38 | SwingWorkerWithProgressDialog importWorker = new SwingWorkerWithProgressDialog(
39 | JOptionPane.getFrameForComponent(this.controlPanel),
40 | "JSON Export", "Exporting as JSON...", entries.size()){
41 | @Override
42 | protected Void doInBackground() throws Exception {
43 | super.doInBackground();
44 | try(FileWriter fileWriter = new FileWriter(file, false)) {
45 | Gson gson = LoggerPlusPlus.gsonProvider.getGson();
46 | gson.toJson(entries, fileWriter);
47 | }
48 |
49 | return null;
50 | }
51 |
52 | @Override
53 | protected void done() {
54 | super.done();
55 | JOptionPane.showMessageDialog(controlPanel, "Export as JSON completed.",
56 | "JSON Export", JOptionPane.INFORMATION_MESSAGE);
57 | }
58 | };
59 |
60 | importWorker.execute();
61 |
62 | }catch (Exception e){
63 | //Cancelled.
64 | }
65 | }
66 |
67 | @Override
68 | public JMenuItem getExportEntriesMenuItem(List entries) {
69 | return new JMenuItem(new AbstractAction(String.format("Export %d %s as JSON",
70 | entries.size(), entries.size() != 1 ? "entries" : "entry")) {
71 | @Override
72 | public void actionPerformed(ActionEvent e) {
73 | exportEntries(entries);
74 | }
75 | });
76 | }
77 |
78 | public ExportController getExportController() {
79 | return this.exportController;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/exports/JSONExporterControlPanel.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.exports;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Alignment;
4 | import com.coreyd97.BurpExtenderUtilities.PanelBuilder;
5 | import com.nccgroup.loggerplusplus.LoggerPlusPlus;
6 | import com.nccgroup.loggerplusplus.logentry.LogEntry;
7 |
8 | import javax.swing.*;
9 | import java.awt.*;
10 | import java.util.List;
11 |
12 | public class JSONExporterControlPanel extends JPanel {
13 |
14 | JSONExporterControlPanel(JSONExporter jsonExporter){
15 | this.setLayout(new BorderLayout());
16 |
17 | JButton manualSaveButton = new JButton("Export as JSON");
18 | manualSaveButton.addActionListener(actionEvent -> {
19 | final List entries = LoggerPlusPlus.instance.getLogEntries();
20 | jsonExporter.exportEntries(entries);
21 | });
22 |
23 | this.add(PanelBuilder.build(new JComponent[][]{
24 | new JComponent[]{manualSaveButton},
25 | }, new int[][]{
26 | new int[]{1},
27 | }, Alignment.FILL, 1.0, 1.0), BorderLayout.CENTER);
28 |
29 | this.setBorder(BorderFactory.createTitledBorder("JSON Exporter"));
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/exports/LogExporter.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.exports;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 |
5 | public abstract class LogExporter {
6 |
7 | protected final ExportController exportController;
8 | protected final Preferences preferences;
9 |
10 | protected LogExporter(ExportController exportController, Preferences preferences){
11 | this.exportController = exportController;
12 | this.preferences = preferences;
13 | }
14 |
15 | public Preferences getPreferences() {
16 | return preferences;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/ColorizingFilterRule.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filter;
2 |
3 | import com.google.gson.annotations.JsonAdapter;
4 | import com.nccgroup.loggerplusplus.filter.colorfilter.TableColorRule;
5 | import lombok.Getter;
6 | import lombok.Setter;
7 |
8 | import java.awt.*;
9 |
10 | public abstract class ColorizingFilterRule extends FilterRule {
11 |
12 | @Getter @Setter
13 | private Color backgroundColor;
14 | @Getter @Setter
15 | private Color foregroundColor;
16 | @Getter @Setter
17 | private short priority;
18 | @Getter @Setter
19 | private boolean enabled;
20 |
21 | protected ColorizingFilterRule(String name){
22 | super(name);
23 | }
24 |
25 | protected ColorizingFilterRule(String name, FilterExpression filterExpression){
26 | super(name, filterExpression);
27 | }
28 |
29 | protected ColorizingFilterRule(String name, String filter){
30 | super(name, filter);
31 | }
32 |
33 | @Override
34 | public boolean equals(Object obj) {
35 | if(obj instanceof ColorizingFilterRule){
36 | return ((ColorizingFilterRule) obj).getUuid().equals(this.getUuid());
37 | }else{
38 | return super.equals(obj);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/ComparisonOperator.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filter;
2 |
3 | public enum ComparisonOperator {
4 | EQUAL("=="), NOT_EQUAL("!="), GREATER_THAN(">"), LESS_THAN("<"),
5 | GREATER_THAN_EQUAL(">="), LESS_THAN_EQUAL("<="), CONTAINS("CONTAINS"), IN("IN"), MATCHES("MATCHES");
6 |
7 | private final String label;
8 |
9 | ComparisonOperator(String label) {
10 | this.label = label;
11 | }
12 |
13 | public String getLabel() {
14 | return this.label;
15 | }
16 |
17 | @Override
18 | public String toString() {
19 | return label;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/FilterExpression.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filter;
2 |
3 | import com.nccgroup.loggerplusplus.LoggerPlusPlus;
4 | import com.nccgroup.loggerplusplus.filter.parser.*;
5 | import com.nccgroup.loggerplusplus.logentry.FieldGroup;
6 | import com.nccgroup.loggerplusplus.logentry.LogEntry;
7 | import com.nccgroup.loggerplusplus.logentry.LogEntryField;
8 | import lombok.Getter;
9 |
10 | import java.util.HashMap;
11 | import java.util.HashSet;
12 |
13 | public class FilterExpression {
14 |
15 | @Getter
16 | protected ASTExpression ast;
17 |
18 | @Getter
19 | protected HashSet snippetDependencies;
20 |
21 | @Getter
22 | protected HashSet requiredContexts;
23 |
24 | public FilterExpression(String filterString) throws ParseException {
25 | this(null, filterString);
26 | }
27 |
28 | public FilterExpression(String alias, String filterString) throws ParseException {
29 | this.ast = FilterParser.parseFilter(filterString);
30 | HashMap filterInfo = FilterParser.validateFilterDependencies(LoggerPlusPlus.instance.getLibraryController(), alias, this.ast);
31 | snippetDependencies = (HashSet) filterInfo.get("dependencies");
32 | requiredContexts = (HashSet) filterInfo.get("contexts");
33 | }
34 |
35 | public boolean matches(LogEntry entry){
36 | FilterEvaluationVisitor visitor = new FilterEvaluationVisitor(LoggerPlusPlus.instance.getLibraryController());
37 | return visitor.visit(ast, entry);
38 | }
39 |
40 | public void addConditionToFilter(LogicalOperator logicalOperator, LogEntryField field,
41 | ComparisonOperator booleanOperator, String value) throws ParseException {
42 | String existing;
43 | if (this.ast.getLogicalOperator() != null && !this.ast.getLogicalOperator().equals(logicalOperator)) {
44 | existing = "(" + this.ast.getFilterString() + ")";
45 | } else {
46 | existing = this.ast.getFilterString();
47 | }
48 |
49 | this.ast = FilterParser.parseFilter(String.format("%s %s %s %s %s", existing, logicalOperator.toString(), field.toString(), booleanOperator, value));
50 | HashMap filterInfo = FilterParser.validateFilterDependencies(LoggerPlusPlus.instance.getLibraryController(), null, this.ast);
51 | snippetDependencies = (HashSet) filterInfo.get("dependencies");
52 | requiredContexts = (HashSet) filterInfo.get("contexts");
53 | }
54 |
55 | @Override
56 | public String toString() {
57 | return ast.getFilterString();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/FilterExpressionSerializer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filter;
2 |
3 | import com.google.gson.*;
4 | import com.nccgroup.loggerplusplus.filter.parser.ParseException;
5 |
6 | import java.lang.reflect.Type;
7 |
8 | public class FilterExpressionSerializer implements JsonSerializer, JsonDeserializer {
9 |
10 | @Override
11 | public JsonElement serialize(FilterExpression filter, Type type, JsonSerializationContext jsonSerializationContext) {
12 | JsonObject object = new JsonObject();
13 | object.addProperty("filter", filter.toString());
14 | return object;
15 | }
16 |
17 | @Override
18 | public FilterExpression deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
19 | FilterExpression filter = null;
20 | try {
21 | filter = new FilterExpression(jsonElement.getAsJsonObject().get("filter").getAsString());
22 | } catch (ParseException e) {
23 | }
24 | return filter;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/FilterRule.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filter;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | import com.nccgroup.loggerplusplus.filter.parser.ParseException;
5 | import lombok.Getter;
6 |
7 | import java.util.UUID;
8 |
9 | public abstract class FilterRule {
10 |
11 | @Getter @SerializedName("uid")
12 | private UUID uuid;
13 | @Getter
14 | private String name;
15 | @Getter
16 | private String filterString;
17 | @Getter @SerializedName("filter")
18 | private FilterExpression filterExpression;
19 |
20 | public FilterRule(String name){
21 | this.name = name;
22 | this.uuid = UUID.randomUUID();
23 | }
24 |
25 | public FilterRule(String name, FilterExpression filterExpression){
26 | this(name);
27 | this.filterExpression = filterExpression;
28 | this.filterString = filterExpression.toString();
29 | }
30 |
31 | public FilterRule(String name, String filterString){
32 | this(name);
33 | trySetFilter(filterString);
34 | }
35 |
36 | protected void setUuid(UUID uuid) {
37 | this.uuid = uuid;
38 | }
39 |
40 | public void setFilter(FilterExpression expression) {
41 | this.filterExpression = expression;
42 | if(expression != null) this.filterString = expression.toString();
43 | }
44 |
45 | public void setName(String name){
46 | this.name = name;
47 | }
48 |
49 | public boolean trySetFilter(String filterString){
50 | this.filterString = filterString;
51 | try{
52 | parseAndSetFilter(filterString);
53 | }catch (ParseException e){
54 | return false;
55 | }
56 |
57 | return true;
58 | }
59 |
60 | public void parseAndSetFilter(String filterString) throws ParseException {
61 | this.filterString = filterString;
62 | try {
63 | this.filterExpression = new FilterExpression(name, filterString);
64 | }catch (ParseException e){
65 | this.filterExpression = null;
66 | throw e;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/LogicalOperator.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filter;
2 |
3 | public enum LogicalOperator {
4 | AND("AND"), OR("OR"), XOR("XOR");
5 |
6 | private final String label;
7 |
8 | LogicalOperator(String label){
9 | this.label = label;
10 | }
11 |
12 | public String getLabel() {
13 | return label;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/SavedFilterSerializer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filter;
2 |
3 | import com.google.gson.*;
4 | import com.nccgroup.loggerplusplus.filter.savedfilter.SavedFilter;
5 |
6 | import java.lang.reflect.Type;
7 | import java.util.UUID;
8 |
9 | public class SavedFilterSerializer implements JsonSerializer, JsonDeserializer {
10 |
11 | @Override
12 | public JsonElement serialize(SavedFilter tag, Type type, JsonSerializationContext context) {
13 | JsonObject object = new JsonObject();
14 | object.addProperty("uid", tag.getUuid().toString());
15 | object.addProperty("name", tag.getName());
16 | object.add("filter", context.serialize(tag.getFilterExpression()));
17 | return object;
18 | }
19 |
20 | @Override
21 | public SavedFilter deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException {
22 | JsonObject obj = jsonElement.getAsJsonObject();
23 | String uid = obj.get("uid").getAsString();
24 | String name = obj.get("name").getAsString();
25 | FilterExpression filterExpression = context.deserialize(obj.get("filter"), FilterExpression.class);
26 |
27 | SavedFilter tag = new SavedFilter(name, filterExpression);
28 | tag.setUuid(UUID.fromString(uid));
29 | return tag;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/TableColorRuleSerializer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filter;
2 |
3 | import com.google.gson.*;
4 | import com.nccgroup.loggerplusplus.filter.colorfilter.TableColorRule;
5 |
6 | import java.awt.*;
7 | import java.lang.reflect.Type;
8 | import java.util.UUID;
9 |
10 | public class TableColorRuleSerializer implements JsonSerializer, JsonDeserializer {
11 |
12 | @Override
13 | public JsonElement serialize(TableColorRule tag, Type type, JsonSerializationContext context) {
14 | JsonObject object = new JsonObject();
15 | object.addProperty("uid", tag.getUuid().toString());
16 | object.addProperty("name", tag.getName());
17 | object.add("filter", context.serialize(tag.getFilterExpression()));
18 | object.add("foregroundColor", context.serialize(tag.getForegroundColor()));
19 | object.add("backgroundColor", context.serialize(tag.getBackgroundColor()));
20 | object.addProperty("enabled", tag.isEnabled());
21 | object.addProperty("priority", tag.getPriority());
22 | return object;
23 | }
24 |
25 | @Override
26 | public TableColorRule deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException {
27 | JsonObject obj = jsonElement.getAsJsonObject();
28 | String uid = obj.get("uid").getAsString();
29 | String name = obj.has("name") ? obj.get("name").getAsString() : "";
30 | FilterExpression filterExpression = context.deserialize(obj.get("filter"), FilterExpression.class);
31 | Color foregroundColor = context.deserialize(obj.get("foregroundColor"), Color.class);
32 | Color backgroundColor = context.deserialize(obj.get("backgroundColor"), Color.class);
33 | boolean enabled = obj.get("enabled").getAsBoolean();
34 | short priority = obj.get("priority").getAsShort();
35 |
36 | TableColorRule tag = new TableColorRule(name, filterExpression);
37 | tag.setUuid(UUID.fromString(uid));
38 | tag.setForegroundColor(foregroundColor);
39 | tag.setBackgroundColor(backgroundColor);
40 | tag.setEnabled(enabled);
41 | tag.setPriority(priority);
42 | return tag;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/TagSerializer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filter;
2 |
3 | import com.google.gson.*;
4 | import com.nccgroup.loggerplusplus.filter.parser.ParseException;
5 | import com.nccgroup.loggerplusplus.filter.tag.Tag;
6 |
7 | import java.awt.*;
8 | import java.lang.reflect.Type;
9 | import java.util.UUID;
10 |
11 | public class TagSerializer implements JsonSerializer, JsonDeserializer {
12 |
13 | @Override
14 | public JsonElement serialize(Tag tag, Type type, JsonSerializationContext context) {
15 | JsonObject object = new JsonObject();
16 | object.addProperty("uid", tag.getUuid().toString());
17 | object.addProperty("name", tag.getName());
18 | object.add("filter", context.serialize(tag.getFilterExpression()));
19 | object.add("foregroundColor", context.serialize(tag.getForegroundColor()));
20 | object.add("backgroundColor", context.serialize(tag.getBackgroundColor()));
21 | object.addProperty("enabled", tag.isEnabled());
22 | object.addProperty("priority", tag.getPriority());
23 | return object;
24 | }
25 |
26 | @Override
27 | public Tag deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException {
28 | JsonObject obj = jsonElement.getAsJsonObject();
29 | String uid = obj.get("uid").getAsString();
30 | String name = obj.get("name").getAsString();
31 | FilterExpression filterExpression = context.deserialize(obj.get("filter"), FilterExpression.class);
32 | Color foregroundColor = context.deserialize(obj.get("foregroundColor"), Color.class);
33 | Color backgroundColor = context.deserialize(obj.get("backgroundColor"), Color.class);
34 | boolean enabled = obj.get("enabled").getAsBoolean();
35 | short priority = obj.get("priority").getAsShort();
36 |
37 | Tag tag = new Tag(name, filterExpression);
38 | tag.setUuid(UUID.fromString(uid));
39 | tag.setForegroundColor(foregroundColor);
40 | tag.setBackgroundColor(backgroundColor);
41 | tag.setEnabled(enabled);
42 | tag.setPriority(priority);
43 | return tag;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/colorfilter/ColorFilterListener.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filter.colorfilter;
2 |
3 | /**
4 | * Created by corey on 20/07/17.
5 | */
6 | public interface ColorFilterListener {
7 |
8 | void onColorFilterChange(TableColorRule filter);
9 |
10 | void onColorFilterAdd(TableColorRule filter);
11 |
12 | void onColorFilterRemove(TableColorRule filter);
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/colorfilter/TableColorRule.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filter.colorfilter;
2 |
3 | import com.nccgroup.loggerplusplus.filter.ColorizingFilterRule;
4 | import com.nccgroup.loggerplusplus.filter.FilterExpression;
5 | import lombok.AccessLevel;
6 | import lombok.Getter;
7 |
8 | /**
9 | * Created by corey on 19/07/17.
10 | */
11 | public class TableColorRule extends ColorizingFilterRule implements Comparable{
12 |
13 | @Getter(AccessLevel.PUBLIC)
14 | private boolean shouldRetest = true;
15 |
16 | public TableColorRule(){
17 | super("", "");
18 | }
19 |
20 | public TableColorRule(String title, String filterString) {
21 | super(title, filterString);
22 | }
23 |
24 | public TableColorRule(String title, FilterExpression filterExpression) {
25 | super(title, filterExpression);
26 | }
27 |
28 | @Override
29 | public boolean trySetFilter(String filterString){
30 | boolean success = super.trySetFilter(filterString);
31 | if(success) shouldRetest = true;
32 | return success;
33 | }
34 |
35 | @Override
36 | public void setFilter(FilterExpression filter) {
37 | super.setFilter(filter);
38 | shouldRetest = true;
39 | }
40 |
41 | @Override
42 | public void setEnabled(boolean enabled) {
43 | super.setEnabled(enabled);
44 | shouldRetest = true;
45 | }
46 |
47 | @Override
48 | public int compareTo(TableColorRule tableColorRule) {
49 | return ((Comparable) this.getPriority()).compareTo(tableColorRule.getPriority());
50 | }
51 |
52 | @Override
53 | public String toString() {
54 | return "ColorFilter[" + (this.getFilterExpression() != null ? this.getFilterExpression().toString() : getFilterString()) + "]";
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/logfilter/LogTableFilter.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filter.logfilter;
2 |
3 | import com.nccgroup.loggerplusplus.filter.FilterExpression;
4 | import com.nccgroup.loggerplusplus.filter.parser.ParseException;
5 | import com.nccgroup.loggerplusplus.logentry.LogEntry;
6 | import com.nccgroup.loggerplusplus.logview.logtable.LogTableModel;
7 | import lombok.Getter;
8 |
9 | import javax.swing.*;
10 | import javax.swing.table.TableModel;
11 |
12 | public class LogTableFilter extends RowFilter {
13 |
14 | @Getter
15 | private FilterExpression filterExpression;
16 |
17 | public LogTableFilter(String filterString) throws ParseException {
18 | this.filterExpression = new FilterExpression(filterString);
19 | }
20 |
21 | public LogTableFilter(FilterExpression filterExpression){
22 | this.filterExpression = filterExpression;
23 | }
24 |
25 | @Override
26 | public boolean include(RowFilter.Entry entry) {
27 | int index = (int) entry.getIdentifier();
28 | TableModel tableModel = (TableModel) entry.getModel();
29 | if(tableModel instanceof LogTableModel){
30 | LogEntry logEntry = ((LogTableModel) tableModel).getRow(index);
31 | return filterExpression.matches(logEntry);
32 | }
33 | return false;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/parser/ASTAlias.java:
--------------------------------------------------------------------------------
1 | /* Generated By:JJTree: Do not edit this line. ASTAlias.java Version 7.0 */
2 | /* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
3 | package com.nccgroup.loggerplusplus.filter.parser;
4 |
5 | public
6 | class ASTAlias extends SimpleNode {
7 |
8 | public String identifier;
9 | public ASTExpression filter;
10 |
11 | public ASTAlias(int id) {
12 | super(id);
13 | }
14 |
15 | public ASTAlias(FilterParser p, int id) {
16 | super(p, id);
17 | }
18 |
19 | @Override
20 | public String getFilterString() {
21 | return "#" + identifier;
22 | }
23 |
24 | @Override
25 | public String toString() {
26 | return String.format("ASTAlias[id=%s]", identifier);
27 | }
28 |
29 | /** Accept the visitor. **/
30 | public Object jjtAccept(FilterParserVisitor visitor, VisitorData data) {
31 |
32 | return
33 | visitor.visit(this, data);
34 | }
35 | }
36 | /* JavaCC - OriginalChecksum=b5d9705c3b2352700f09763675b026ae (do not edit this line) */
37 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/parser/ASTComparison.java:
--------------------------------------------------------------------------------
1 | /* Generated By:JJTree: Do not edit this line. ASTComparison.java Version 7.0 */
2 | /* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
3 | package com.nccgroup.loggerplusplus.filter.parser;
4 |
5 | import com.nccgroup.loggerplusplus.filter.ComparisonOperator;
6 | import com.nccgroup.loggerplusplus.logentry.LogEntryField;
7 | import com.nccgroup.loggerplusplus.logview.processor.LogProcessor;
8 | import org.apache.commons.text.StringEscapeUtils;
9 |
10 | import java.util.Date;
11 | import java.util.Set;
12 | import java.util.regex.Pattern;
13 | import java.util.stream.Collectors;
14 |
15 | public
16 | class ASTComparison extends SimpleNode {
17 |
18 | Object left, right;
19 | ComparisonOperator comparisonOperator;
20 |
21 | public ASTComparison(int id) {
22 | super(id);
23 | }
24 |
25 | public ASTComparison(FilterParser p, int id) {
26 | super(p, id);
27 | }
28 |
29 | /**
30 | * Accept the visitor.
31 | **/
32 | public Object jjtAccept(FilterParserVisitor visitor, VisitorData data) {
33 |
34 | return visitor.visit(this, data);
35 | }
36 |
37 | public ComparisonOperator getComparisonOperator() {
38 | return comparisonOperator;
39 | }
40 |
41 | public Object getLeft() {
42 | return left;
43 | }
44 |
45 | public Object getRight() {
46 | return right;
47 | }
48 |
49 | @Override
50 | public String toString() {
51 | Class> leftClass = left instanceof LogEntryField ? ((LogEntryField) left).getType() : left.getClass();
52 | Class> rightClass = right instanceof LogEntryField ? ((LogEntryField) right).getType() : right.getClass();
53 | return String.format("ASTComparison[left=%s (%s), op=%s, right=%s (%s)]", left, leftClass, comparisonOperator, right, rightClass);
54 | }
55 |
56 | @Override
57 | public String getFilterString() {
58 | return String.format("%s %s %s", convertObjectToString(left), comparisonOperator.getLabel(), convertObjectToString(right));
59 | }
60 |
61 | private String convertObjectToString(Object obj){
62 | if(obj instanceof Pattern) {
63 | if (comparisonOperator == ComparisonOperator.MATCHES) return "\"" + obj + "\"";
64 | else return "/" + obj + "/";
65 | }else if(obj instanceof String){
66 | return "\"" + StringEscapeUtils.escapeJava((String) obj) + "\"";
67 | }else if(obj instanceof Set){
68 | StringBuilder sb = new StringBuilder();
69 | sb.append("[");
70 | sb.append(((Set) obj).stream().map(item -> {
71 | if(item instanceof String) return "\"" + item + "\"";
72 | else return String.valueOf(item);
73 | }).collect(Collectors.joining(", ")));
74 | sb.append("]");
75 | return sb.toString();
76 | }else if(obj instanceof Date){
77 | return "\"" + LogProcessor.LOGGER_DATE_FORMAT.format(obj) + "\"";
78 | }
79 | return String.valueOf(obj);
80 | }
81 |
82 | }
83 | /* JavaCC - OriginalChecksum=bdaeeba5ee349a11518169d312e524e0 (do not edit this line) */
84 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/parser/ASTExpression.java:
--------------------------------------------------------------------------------
1 | /* Generated By:JJTree: Do not edit this line. ASTExpression.java Version 7.0 */
2 | /* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
3 | package com.nccgroup.loggerplusplus.filter.parser;
4 |
5 | import com.nccgroup.loggerplusplus.filter.LogicalOperator;
6 |
7 | public
8 | class ASTExpression extends SimpleNode {
9 |
10 | boolean inverse = false;
11 | LogicalOperator op;
12 |
13 | public ASTExpression(int id) {
14 | super(id);
15 | }
16 |
17 | public ASTExpression(FilterParser p, int id) {
18 | super(p, id);
19 | }
20 |
21 | @Override
22 | public String getFilterString() {
23 | StringBuilder sb = new StringBuilder();
24 | for (int i = 0; i < this.children.length; i++) {
25 | String childString = this.children[i].getFilterString();
26 | if (this.children[i] instanceof ASTExpression && !((ASTExpression) this.children[i]).inverse)
27 | sb.append("(" + childString + ")");
28 | else
29 | sb.append(childString);
30 |
31 | if (i != this.children.length - 1) {
32 | sb.append(" " + op.getLabel() + " ");
33 | }
34 | }
35 |
36 | if (inverse) return "!(" + sb.toString() + ")";
37 | else return sb.toString();
38 | }
39 |
40 | public LogicalOperator getLogicalOperator() {
41 | return op;
42 | }
43 |
44 | public void addCondition(ASTExpression comparison){
45 | jjtAddChild(comparison, this.jjtGetNumChildren());
46 | }
47 |
48 | public void addCondition(ASTComparison comparison){
49 | jjtAddChild(comparison, this.jjtGetNumChildren());
50 | }
51 |
52 | @Override
53 | public String toString() {
54 | return String.format("ASTExpression[inverse=%s, op=%s]", inverse, op);
55 | }
56 |
57 | /**
58 | * Accept the visitor.
59 | **/
60 | public Object jjtAccept(FilterParserVisitor visitor, VisitorData data) {
61 | return visitor.visit(this, data);
62 | }
63 | }
64 | /* JavaCC - OriginalChecksum=f3e2fc4905864ee71fff41d667f32963 (do not edit this line) */
65 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/parser/AliasCheckVisitor.java:
--------------------------------------------------------------------------------
1 | /* Generated By:JavaCC: Do not edit this line. FilterParserDefaultVisitor.java Version 7.0.2 */
2 | package com.nccgroup.loggerplusplus.filter.parser;
3 |
4 | import com.nccgroup.loggerplusplus.filter.savedfilter.SavedFilter;
5 | import com.nccgroup.loggerplusplus.filterlibrary.FilterLibraryController;
6 | import com.nccgroup.loggerplusplus.logentry.FieldGroup;
7 | import com.nccgroup.loggerplusplus.logentry.LogEntryField;
8 | import lombok.extern.log4j.Log4j2;
9 |
10 | import java.util.*;
11 | import java.util.stream.Collectors;
12 |
13 | @Log4j2
14 | public class AliasCheckVisitor implements FilterParserVisitor{
15 |
16 | private FilterLibraryController filterLibraryController;
17 |
18 | public AliasCheckVisitor(FilterLibraryController filterLibraryController){
19 | this.filterLibraryController = filterLibraryController;
20 | }
21 |
22 | public VisitorData defaultVisit(SimpleNode node, VisitorData data){
23 | node.childrenAccept(this, data);
24 | return data;
25 | }
26 |
27 | @Override
28 | public VisitorData visit(SimpleNode node, VisitorData data){
29 | return defaultVisit(node, data);
30 | }
31 |
32 | public VisitorData visit(String alias, SimpleNode node){
33 | log.debug("Starting sanity check on expression (%s) alias (%s) ".formatted(node.toString(), alias));
34 | VisitorData visitorData = new VisitorData();
35 | visitorData.setData("dependencies", new HashSet());
36 | visitorData.setData("contexts", new HashSet());
37 | Stack visitStack = new Stack();
38 | visitorData.setData("aliasVisitList", visitStack);
39 | if (alias != null) {
40 | visitStack.push(alias.toUpperCase());
41 | }
42 | return visit(node, visitorData);
43 | }
44 |
45 | @Override
46 | public VisitorData visit(ASTExpression node, VisitorData data){
47 | return defaultVisit(node, data);
48 | }
49 |
50 | @Override
51 | public VisitorData visit(ASTComparison node, VisitorData visitorData){
52 | HashSet contexts = (HashSet) visitorData.getData().get("contexts");
53 | if(node.left instanceof LogEntryField) contexts.add(((LogEntryField) node.left).getFieldGroup());
54 | if(node.right instanceof LogEntryField) contexts.add(((LogEntryField) node.right).getFieldGroup());
55 | defaultVisit(node, visitorData);
56 | return visitorData;
57 | }
58 |
59 | @Override
60 | public VisitorData visit(ASTAlias node, VisitorData data) {
61 | //Add this alias to our dependencies
62 | Stack aliasVisitList = (Stack) data.getData().get("aliasVisitList");
63 | try {
64 | log.debug("Visiting " + node.identifier);
65 | if (aliasVisitList.contains(node.identifier.toUpperCase())) {
66 | //We're recursing, don't continue!
67 | aliasVisitList.push(node.identifier.toUpperCase());
68 | String visitOrder = aliasVisitList.stream().collect(Collectors.joining("->"));
69 | data.addError("Recursion detected in filter. Alias trace: " + visitOrder);
70 | return data;
71 | }
72 |
73 | aliasVisitList.push(node.identifier.toUpperCase());
74 | log.debug("Current Visit Queue " + aliasVisitList.toString());
75 |
76 |
77 | ((HashSet) data.getData().get("dependencies")).add(node.identifier.toUpperCase());
78 |
79 | //Now sanity check on the aliased filter with our existing data
80 | Optional aliasedFilter = filterLibraryController.getFilterSnippets().stream().filter(savedFilter -> savedFilter.getName().equalsIgnoreCase(node.identifier)).findFirst();
81 | if (aliasedFilter.isPresent()) {
82 | visit(aliasedFilter.get().getFilterExpression().getAst(), data);
83 | } else {
84 | data.addError("Could not find a filter in the library for alias: " + node.identifier);
85 | }
86 |
87 |
88 | return data;
89 | }finally {
90 | log.debug("Leaving " + node.identifier);
91 | aliasVisitList.pop();
92 | log.debug("Current Visit Queue " + aliasVisitList.toString());
93 | }
94 | }
95 | }
96 | /* JavaCC - OriginalChecksum=b30458d637879c9662107beea18204f0 (do not edit this line) */
97 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/parser/FilterParserConstants.java:
--------------------------------------------------------------------------------
1 | /* Generated By:JJTree&JavaCC: Do not edit this line. FilterParserConstants.java */
2 | package com.nccgroup.loggerplusplus.filter.parser;
3 |
4 |
5 | /**
6 | * Token literal values and constants.
7 | * Generated by org.javacc.parser.OtherFilesGen#start()
8 | */
9 | public interface FilterParserConstants {
10 |
11 | /** End of File. */
12 | int EOF = 0;
13 | /** RegularExpression Id. */
14 | int EQ = 2;
15 | /** RegularExpression Id. */
16 | int NEQ = 3;
17 | /** RegularExpression Id. */
18 | int GT = 4;
19 | /** RegularExpression Id. */
20 | int LT = 5;
21 | /** RegularExpression Id. */
22 | int GEQ = 6;
23 | /** RegularExpression Id. */
24 | int LEQ = 7;
25 | /** RegularExpression Id. */
26 | int OR = 8;
27 | /** RegularExpression Id. */
28 | int AND = 9;
29 | /** RegularExpression Id. */
30 | int XOR = 10;
31 | /** RegularExpression Id. */
32 | int CONTAINS = 11;
33 | /** RegularExpression Id. */
34 | int IN = 12;
35 | /** RegularExpression Id. */
36 | int BOOLEAN = 13;
37 | /** RegularExpression Id. */
38 | int NUMBER = 14;
39 | /** RegularExpression Id. */
40 | int DIGIT = 15;
41 | /** RegularExpression Id. */
42 | int REGEXLITERAL_IN_FORWARD_SLASHES = 16;
43 | /** RegularExpression Id. */
44 | int REGEX_IN_FORWARD_SLASHES = 17;
45 | /** RegularExpression Id. */
46 | int MATCHES = 18;
47 | /** RegularExpression Id. */
48 | int LPAREN = 19;
49 | /** RegularExpression Id. */
50 | int RPAREN = 20;
51 | /** RegularExpression Id. */
52 | int INVERSE = 21;
53 | /** RegularExpression Id. */
54 | int DOT = 22;
55 | /** RegularExpression Id. */
56 | int IDENTIFIER = 23;
57 | /** RegularExpression Id. */
58 | int ARRAY_START = 24;
59 | /** RegularExpression Id. */
60 | int ARRAY_END = 25;
61 | /** RegularExpression Id. */
62 | int ARRAY_SEPARATOR = 26;
63 | /** RegularExpression Id. */
64 | int ALIAS_SYMBOL = 27;
65 | /** RegularExpression Id. */
66 | int OPEN_SINGLE_QUOTE_STRING = 28;
67 | /** RegularExpression Id. */
68 | int OPEN_DOUBLE_QUOTE_STRING = 29;
69 | /** RegularExpression Id. */
70 | int SINGLE_STRING_BODY = 30;
71 | /** RegularExpression Id. */
72 | int CLOSE_SINGLE_QUOTE_STRING = 31;
73 | /** RegularExpression Id. */
74 | int DOUBLE_STRING_BODY = 32;
75 | /** RegularExpression Id. */
76 | int CLOSE_DOUBLE_QUOTE_STRING = 33;
77 | /** RegularExpression Id. */
78 | int UNKNOWN = 34;
79 |
80 | /** Lexical state. */
81 | int DEFAULT = 0;
82 | /** Lexical state. */
83 | int SINGLE_QUOTED_STRING = 1;
84 | /** Lexical state. */
85 | int DOUBLE_QUOTED_STRING = 2;
86 |
87 | /** Literal token values. */
88 | String[] tokenImage = {
89 | "",
90 | "\" \"",
91 | "",
92 | "\"!=\"",
93 | "\">\"",
94 | "\"<\"",
95 | "\">=\"",
96 | "\"<=\"",
97 | "",
98 | "",
99 | "",
100 | "\"CONTAINS\"",
101 | "\"IN\"",
102 | "",
103 | "",
104 | "",
105 | "",
106 | "",
107 | "\"MATCHES\"",
108 | "\"(\"",
109 | "\")\"",
110 | "",
111 | "\".\"",
112 | "",
113 | "\"[\"",
114 | "\"]\"",
115 | "\",\"",
116 | "\"#\"",
117 | "\"\\\'\"",
118 | "\"\\\"\"",
119 | "",
120 | "\"\\\'\"",
121 | "",
122 | "\"\\\"\"",
123 | "",
124 | };
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/parser/FilterParserDefaultVisitor.java:
--------------------------------------------------------------------------------
1 | /* Generated By:JavaCC: Do not edit this line. FilterParserDefaultVisitor.java Version 7.0.2 */
2 | package com.nccgroup.loggerplusplus.filter.parser;
3 |
4 | public class FilterParserDefaultVisitor implements FilterParserVisitor{
5 | public Object defaultVisit(SimpleNode node, VisitorData data){
6 | node.childrenAccept(this, data);
7 | return data;
8 | }
9 | public Object visit(SimpleNode node, VisitorData data){
10 | return defaultVisit(node, data);
11 | }
12 | public Object visit(ASTExpression node, VisitorData data){
13 | return defaultVisit(node, data);
14 | }
15 | public Object visit(ASTComparison node, VisitorData data){
16 | return defaultVisit(node, data);
17 | }
18 | public Object visit(ASTAlias node, VisitorData data){
19 | return defaultVisit(node, data);
20 | }
21 | }
22 | /* JavaCC - OriginalChecksum=06ac44fa53bd2978a8b7d3aa6de4fced (do not edit this line) */
23 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/parser/FilterParserTreeConstants.java:
--------------------------------------------------------------------------------
1 | /* Generated By:JavaCC: Do not edit this line. FilterParserTreeConstants.java Version 5.0 */
2 | package com.nccgroup.loggerplusplus.filter.parser;
3 |
4 | public interface FilterParserTreeConstants
5 | {
6 | public int JJTVOID = 0;
7 | public int JJTEXPRESSION = 1;
8 | public int JJTCOMPARISON = 2;
9 | public int JJTALIAS = 3;
10 |
11 |
12 | public String[] jjtNodeName = {
13 | "void",
14 | "Expression",
15 | "Comparison",
16 | "Alias",
17 | };
18 | }
19 | /* JavaCC - OriginalChecksum=a8f71270ce0cb112d3284149dfad33e2 (do not edit this line) */
20 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/parser/FilterParserVisitor.java:
--------------------------------------------------------------------------------
1 | /* Generated By:JavaCC: Do not edit this line. FilterParserVisitor.java Version 5.0 */
2 | package com.nccgroup.loggerplusplus.filter.parser;
3 |
4 | public interface FilterParserVisitor
5 | {
6 | public Object visit(SimpleNode node, VisitorData data);
7 | public Object visit(ASTExpression node, VisitorData data);
8 | public Object visit(ASTComparison node, VisitorData data);
9 | public Object visit(ASTAlias node, VisitorData data);
10 | }
11 | /* JavaCC - OriginalChecksum=1d4b7dd7f55608a77745498f1be093dd (do not edit this line) */
12 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/parser/JJTFilterParserState.java:
--------------------------------------------------------------------------------
1 | /* Generated By:JavaCC: Do not edit this line. JJTFilterParserState.java Version 5.0 */
2 | package com.nccgroup.loggerplusplus.filter.parser;
3 |
4 | public class JJTFilterParserState {
5 | private java.util.List nodes;
6 | private java.util.List marks;
7 |
8 | private int sp; // number of nodes on stack
9 | private int mk; // current mark
10 | private boolean node_created;
11 |
12 | public JJTFilterParserState() {
13 | nodes = new java.util.ArrayList();
14 | marks = new java.util.ArrayList();
15 | sp = 0;
16 | mk = 0;
17 | }
18 |
19 | /* Determines whether the current node was actually closed and
20 | pushed. This should only be called in the final user action of a
21 | node scope. */
22 | public boolean nodeCreated() {
23 | return node_created;
24 | }
25 |
26 | /* Call this to reinitialize the node stack. It is called
27 | automatically by the parser's ReInit() method. */
28 | public void reset() {
29 | nodes.clear();
30 | marks.clear();
31 | sp = 0;
32 | mk = 0;
33 | }
34 |
35 | /* Returns the root node of the AST. It only makes sense to call
36 | this after a successful parse. */
37 | public Node rootNode() {
38 | return nodes.get(0);
39 | }
40 |
41 | /* Pushes a node on to the stack. */
42 | public void pushNode(Node n) {
43 | nodes.add(n);
44 | ++sp;
45 | }
46 |
47 | /* Returns the node on the top of the stack, and remove it from the
48 | stack. */
49 | public Node popNode() {
50 | if (--sp < mk) {
51 | mk = marks.remove(marks.size()-1);
52 | }
53 | return nodes.remove(nodes.size()-1);
54 | }
55 |
56 | /* Returns the node currently on the top of the stack. */
57 | public Node peekNode() {
58 | return nodes.get(nodes.size()-1);
59 | }
60 |
61 | /* Returns the number of children on the stack in the current node
62 | scope. */
63 | public int nodeArity() {
64 | return sp - mk;
65 | }
66 |
67 |
68 | public void clearNodeScope(Node n) {
69 | while (sp > mk) {
70 | popNode();
71 | }
72 | mk = marks.remove(marks.size()-1);
73 | }
74 |
75 |
76 | public void openNodeScope(Node n) {
77 | marks.add(mk);
78 | mk = sp;
79 | n.jjtOpen();
80 | }
81 |
82 |
83 | /* A definite node is constructed from a specified number of
84 | children. That number of nodes are popped from the stack and
85 | made the children of the definite node. Then the definite node
86 | is pushed on to the stack. */
87 | public void closeNodeScope(Node n, int num) {
88 | mk = marks.remove(marks.size()-1);
89 | while (num-- > 0) {
90 | Node c = popNode();
91 | c.jjtSetParent(n);
92 | n.jjtAddChild(c, num);
93 | }
94 | n.jjtClose();
95 | pushNode(n);
96 | node_created = true;
97 | }
98 |
99 |
100 | /* A conditional node is constructed if its condition is true. All
101 | the nodes that have been pushed since the node was opened are
102 | made children of the conditional node, which is then pushed
103 | on to the stack. If the condition is false the node is not
104 | constructed and they are left on the stack. */
105 | public void closeNodeScope(Node n, boolean condition) {
106 | if (condition) {
107 | int a = nodeArity();
108 | mk = marks.remove(marks.size()-1);
109 | while (a-- > 0) {
110 | Node c = popNode();
111 | c.jjtSetParent(n);
112 | n.jjtAddChild(c, a);
113 | }
114 | n.jjtClose();
115 | pushNode(n);
116 | node_created = true;
117 | } else {
118 | mk = marks.remove(marks.size()-1);
119 | node_created = false;
120 | }
121 | }
122 | }
123 | /* JavaCC - OriginalChecksum=4bd4e2bc0a8feefbb219e6f891cd825b (do not edit this line) */
124 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/parser/Node.java:
--------------------------------------------------------------------------------
1 | /* Generated By:JJTree: Do not edit this line. Node.java Version 7.0 */
2 | /* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
3 | package com.nccgroup.loggerplusplus.filter.parser;
4 |
5 | /* All AST nodes must implement this interface. It provides basic
6 | machinery for constructing the parent and child relationships
7 | between nodes. */
8 |
9 | public
10 | interface Node {
11 |
12 | /** This method is called after the node has been made the current
13 | node. It indicates that child nodes can now be added to it. */
14 | public void jjtOpen();
15 |
16 | /** This method is called after all the child nodes have been
17 | added. */
18 | public void jjtClose();
19 |
20 | /** This pair of methods are used to inform the node of its
21 | parent. */
22 | public void jjtSetParent(Node n);
23 | public Node jjtGetParent();
24 |
25 | /** This method tells the node to add its argument to the node's
26 | list of children. */
27 | public void jjtAddChild(Node n, int i);
28 |
29 | /** This method returns a child node. The children are numbered
30 | from zero, left to right. */
31 | public Node jjtGetChild(int i);
32 |
33 | /** Return the number of children the node has. */
34 | public int jjtGetNumChildren();
35 |
36 | public int getId();
37 |
38 | public String getFilterString();
39 |
40 | /** Accept the visitor. **/
41 | public Object jjtAccept(FilterParserVisitor visitor, VisitorData data);
42 | }
43 | /* JavaCC - OriginalChecksum=14b049954a3cc3bef39f1a1a74457d0b (do not edit this line) */
44 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/parser/SanityCheckVisitor.java:
--------------------------------------------------------------------------------
1 | /* Generated By:JavaCC: Do not edit this line. FilterParserDefaultVisitor.java Version 7.0.2 */
2 | package com.nccgroup.loggerplusplus.filter.parser;
3 |
4 | import com.nccgroup.loggerplusplus.filter.ComparisonOperator;
5 | import com.nccgroup.loggerplusplus.logentry.LogEntryField;
6 |
7 | import java.util.Collection;
8 | import java.util.Date;
9 | import java.util.regex.Pattern;
10 |
11 | public class SanityCheckVisitor implements FilterParserVisitor{
12 |
13 | public VisitorData defaultVisit(SimpleNode node, VisitorData data){
14 | node.childrenAccept(this, data);
15 | return data;
16 | }
17 | public VisitorData visit(SimpleNode node, VisitorData data){
18 | return defaultVisit(node, data);
19 | }
20 |
21 | public VisitorData visit(SimpleNode node){
22 | return visit(node, new VisitorData());
23 | }
24 |
25 | public VisitorData visit(ASTExpression node, VisitorData data){
26 | return defaultVisit(node, data);
27 | }
28 | public VisitorData visit(ASTComparison node, VisitorData visitorData) {
29 | defaultVisit(node, visitorData);
30 |
31 | Class leftType, rightType;
32 | leftType = (node.left instanceof LogEntryField) ? ((LogEntryField) node.left).getType() : node.left.getClass();
33 | rightType = (node.right instanceof LogEntryField) ? ((LogEntryField) node.right).getType() : node.right.getClass();
34 | if (leftType == null || rightType == null) return visitorData;
35 |
36 | if (node.comparisonOperator == ComparisonOperator.LESS_THAN || node.comparisonOperator == ComparisonOperator.LESS_THAN_EQUAL
37 | || node.comparisonOperator == ComparisonOperator.GREATER_THAN || node.comparisonOperator == ComparisonOperator.GREATER_THAN_EQUAL) {
38 | boolean valid = (Date.class.isAssignableFrom(leftType) || Date.class.isAssignableFrom(rightType))
39 | || (Number.class.isAssignableFrom(leftType) && Number.class.isAssignableFrom(rightType));
40 | if (!valid) {
41 | visitorData.addError(String.format("Operator %s cannot be used to compare groups of type %s and %s.",
42 | node.comparisonOperator, leftType.getTypeName(), rightType.getTypeName()));
43 | }
44 | } else if (node.left instanceof Pattern) {
45 | visitorData.addError("The left operand of a comparison cannot be a pattern.");
46 | } else if (node.right instanceof Pattern && !String.class.isAssignableFrom(leftType)) {
47 | visitorData.addError("Regular expressions can only be used on string elements.");
48 | } else if (node.comparisonOperator == ComparisonOperator.CONTAINS && !(String.class.isAssignableFrom(leftType) && String.class.isAssignableFrom(leftType))) {
49 | visitorData.addError("The CONTAINS operator can only be used on string elements.");
50 | } else if (node.comparisonOperator == ComparisonOperator.IN && Collection.class.isAssignableFrom(rightType)) {
51 | visitorData.addError("The IN operator requires the right-hand object of the comparison to be a collection (e.g. list, set)!");
52 | }
53 |
54 | return visitorData;
55 | }
56 |
57 | @Override
58 | public VisitorData visit(ASTAlias node, VisitorData data) {
59 | return data;
60 | }
61 | }
62 | /* JavaCC - OriginalChecksum=b30458d637879c9662107beea18204f0 (do not edit this line) */
63 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/parser/SimpleNode.java:
--------------------------------------------------------------------------------
1 | /* Generated By:JJTree: Do not edit this line. SimpleNode.java Version 7.0 */
2 | /* JavaCCOptions:MULTI=true,NODE_USES_PARSER=false,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
3 | package com.nccgroup.loggerplusplus.filter.parser;
4 |
5 | public abstract class SimpleNode implements Node {
6 |
7 | protected Node parent;
8 | protected Node[] children;
9 | protected int id;
10 | protected Object value;
11 | protected FilterParser parser;
12 |
13 | public SimpleNode(int i) {
14 | id = i;
15 | }
16 |
17 | public SimpleNode(FilterParser p, int i) {
18 | this(i);
19 | parser = p;
20 | }
21 |
22 | public void jjtOpen() {
23 | }
24 |
25 | public void jjtClose() {
26 | }
27 |
28 | public void jjtSetParent(Node n) { parent = n; }
29 | public Node jjtGetParent() { return parent; }
30 |
31 | public void jjtAddChild(Node n, int i) {
32 | if (children == null) {
33 | children = new Node[i + 1];
34 | } else if (i >= children.length) {
35 | Node c[] = new Node[i + 1];
36 | System.arraycopy(children, 0, c, 0, children.length);
37 | children = c;
38 | }
39 | children[i] = n;
40 | }
41 |
42 | public Node jjtGetChild(int i) {
43 | return children[i];
44 | }
45 |
46 | public int jjtGetNumChildren() {
47 | return (children == null) ? 0 : children.length;
48 | }
49 |
50 | public void jjtSetValue(Object value) { this.value = value; }
51 | public Object jjtGetValue() { return value; }
52 |
53 | /** Accept the visitor. **/
54 | public Object jjtAccept(FilterParserVisitor visitor, VisitorData data)
55 | {
56 | return visitor.visit(this, data);
57 | }
58 |
59 | /** Accept the visitor. **/
60 | public Object childrenAccept(FilterParserVisitor visitor, VisitorData data)
61 | {
62 | if (children != null) {
63 | for (int i = 0; i < children.length; ++i) {
64 | children[i].jjtAccept(visitor, data);
65 | }
66 | }
67 | return data;
68 | }
69 |
70 | /* You can override these two methods in subclasses of SimpleNode to
71 | customize the way the node appears when the tree is dumped. If
72 | your output uses more than one line you should override
73 | toString(String), otherwise overriding toString() is probably all
74 | you need to do. */
75 |
76 | public String toString() {
77 | return FilterParserTreeConstants.jjtNodeName[id];
78 | }
79 | public String toString(String prefix) { return prefix + toString(); }
80 |
81 | /* Override this method if you want to customize how the node dumps
82 | out its children. */
83 |
84 | public void dump(String prefix) {
85 | System.out.println(toString(prefix));
86 | if (children != null) {
87 | for (int i = 0; i < children.length; ++i) {
88 | SimpleNode n = (SimpleNode)children[i];
89 | if (n != null) {
90 | n.dump(prefix + " ");
91 | }
92 | }
93 | }
94 | }
95 |
96 | public int getId() {
97 | return id;
98 | }
99 | }
100 |
101 | /* JavaCC - OriginalChecksum=dd4a72dc91922f5bdce98b5fa723a79c (do not edit this line) */
102 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/parser/Token.java:
--------------------------------------------------------------------------------
1 | /* Generated By:JavaCC: Do not edit this line. Token.java Version 7.0 */
2 | /* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COLUMN=true,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
3 | package com.nccgroup.loggerplusplus.filter.parser;
4 |
5 | /**
6 | * Describes the input token stream.
7 | */
8 |
9 | public class Token implements java.io.Serializable {
10 |
11 | /**
12 | * The version identifier for this Serializable class.
13 | * Increment only if the serialized form of the
14 | * class changes.
15 | */
16 | private static final long serialVersionUID = 1L;
17 |
18 | /**
19 | * An integer that describes the kind of this token. This numbering
20 | * system is determined by JavaCCParser, and a table of these numbers is
21 | * stored in the file ...Constants.java.
22 | */
23 | public int kind;
24 |
25 | /** The line number of the first character of this Token. */
26 | public int beginLine;
27 | /** The column number of the first character of this Token. */
28 | public int beginColumn;
29 | /** The line number of the last character of this Token. */
30 | public int endLine;
31 | /** The column number of the last character of this Token. */
32 | public int endColumn;
33 |
34 | /**
35 | * The string image of the token.
36 | */
37 | public String image;
38 |
39 | /**
40 | * A reference to the next regular (non-special) token from the input
41 | * stream. If this is the last token from the input stream, or if the
42 | * token manager has not read tokens beyond this one, this field is
43 | * set to null. This is true only if this token is also a regular
44 | * token. Otherwise, see below for a description of the contents of
45 | * this field.
46 | */
47 | public Token next;
48 |
49 | /**
50 | * This field is used to access special tokens that occur prior to this
51 | * token, but after the immediately preceding regular (non-special) token.
52 | * If there are no such special tokens, this field is set to null.
53 | * When there are more than one such special token, this field refers
54 | * to the last of these special tokens, which in turn refers to the next
55 | * previous special token through its specialToken field, and so on
56 | * until the first special token (whose specialToken field is null).
57 | * The next fields of special tokens refer to other special tokens that
58 | * immediately follow it (without an intervening regular token). If there
59 | * is no such token, this field is null.
60 | */
61 | public Token specialToken;
62 |
63 | /**
64 | * An optional attribute value of the Token.
65 | * Tokens which are not used as syntactic sugar will often contain
66 | * meaningful groups that will be used later on by the compiler or
67 | * interpreter. This attribute value is often different from the image.
68 | * Any subclass of Token that actually wants to return a non-null value can
69 | * override this method as appropriate.
70 | */
71 | public Object getValue() {
72 | return null;
73 | }
74 |
75 | /**
76 | * No-argument constructor
77 | */
78 | public Token() {}
79 |
80 | /**
81 | * Constructs a new token for the specified Image.
82 | */
83 | public Token(int kind)
84 | {
85 | this(kind, null);
86 | }
87 |
88 | /**
89 | * Constructs a new token for the specified Image and Kind.
90 | */
91 | public Token(int kind, String image)
92 | {
93 | this.kind = kind;
94 | this.image = image;
95 | }
96 |
97 | /**
98 | * Returns the image.
99 | */
100 | public String toString()
101 | {
102 | return image;
103 | }
104 |
105 | /**
106 | * Returns a new Token object, by default. However, if you want, you
107 | * can create and return subclass objects based on the value of ofKind.
108 | * Simply add the cases to the switch for all those special cases.
109 | * For example, if you have a subclass of Token called IDToken that
110 | * you want to create if ofKind is ID, simply add something like :
111 | *
112 | * case MyParserConstants.ID : return new IDToken(ofKind, image);
113 | *
114 | * to the following switch statement. Then you can cast matchedToken
115 | * variable to the appropriate type and use sit in your lexical actions.
116 | */
117 | public static Token newToken(int ofKind, String image)
118 | {
119 | switch(ofKind)
120 | {
121 | default : return new Token(ofKind, image);
122 | }
123 | }
124 |
125 | public static Token newToken(int ofKind)
126 | {
127 | return newToken(ofKind, null);
128 | }
129 |
130 | }
131 | /* JavaCC - OriginalChecksum=ad0fa790578b537791f3359d11e09484 (do not edit this line) */
132 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/parser/TokenMgrError.java:
--------------------------------------------------------------------------------
1 | /* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 7.0 */
2 | /* JavaCCOptions: */
3 | package com.nccgroup.loggerplusplus.filter.parser;
4 |
5 | /** Token Manager Error. */
6 | public class TokenMgrError extends Error
7 | {
8 |
9 | /**
10 | * The version identifier for this Serializable class.
11 | * Increment only if the serialized form of the
12 | * class changes.
13 | */
14 | private static final long serialVersionUID = 1L;
15 |
16 | /*
17 | * Ordinals for various reasons why an Error of this type can be thrown.
18 | */
19 |
20 | /**
21 | * Lexical error occurred.
22 | */
23 | public static final int LEXICAL_ERROR = 0;
24 |
25 | /**
26 | * An attempt was made to create a second instance of a static token manager.
27 | */
28 | public static final int STATIC_LEXER_ERROR = 1;
29 |
30 | /**
31 | * Tried to change to an invalid lexical state.
32 | */
33 | public static final int INVALID_LEXICAL_STATE = 2;
34 |
35 | /**
36 | * Detected (and bailed out of) an infinite loop in the token manager.
37 | */
38 | public static final int LOOP_DETECTED = 3;
39 |
40 | /**
41 | * Indicates the reason why the exception is thrown. It will have
42 | * one of the above 4 groups.
43 | */
44 | int errorCode;
45 |
46 | /**
47 | * Replaces unprintable characters by their escaped (or unicode escaped)
48 | * equivalents in the given string
49 | */
50 | protected static final String addEscapes(String str) {
51 | StringBuffer retval = new StringBuffer();
52 | char ch;
53 | for (int i = 0; i < str.length(); i++) {
54 | switch (str.charAt(i))
55 | {
56 | case '\b':
57 | retval.append("\\b");
58 | continue;
59 | case '\t':
60 | retval.append("\\t");
61 | continue;
62 | case '\n':
63 | retval.append("\\n");
64 | continue;
65 | case '\f':
66 | retval.append("\\f");
67 | continue;
68 | case '\r':
69 | retval.append("\\r");
70 | continue;
71 | case '\"':
72 | retval.append("\\\"");
73 | continue;
74 | case '\'':
75 | retval.append("\\\'");
76 | continue;
77 | case '\\':
78 | retval.append("\\\\");
79 | continue;
80 | default:
81 | if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
82 | String s = "0000" + Integer.toString(ch, 16);
83 | retval.append("\\u" + s.substring(s.length() - 4, s.length()));
84 | } else {
85 | retval.append(ch);
86 | }
87 | continue;
88 | }
89 | }
90 | return retval.toString();
91 | }
92 |
93 | /**
94 | * Returns a detailed message for the Error when it is thrown by the
95 | * token manager to indicate a lexical error.
96 | * Parameters :
97 | * EOFSeen : indicates if EOF caused the lexical error
98 | * curLexState : lexical state in which this error occurred
99 | * errorLine : line number when the error occurred
100 | * errorColumn : column number when the error occurred
101 | * errorAfter : prefix that was seen before this error occurred
102 | * curchar : the offending character
103 | * Note: You can customize the lexical error message by modifying this method.
104 | */
105 | protected static String LexicalErr(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, int curChar) {
106 | char curChar1 = (char)curChar;
107 | return("Lexical error at line " +
108 | errorLine + ", column " +
109 | errorColumn + ". Encountered: " +
110 | (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar1)) + "\"") + " (" + (int)curChar + "), ") +
111 | "after : \"" + addEscapes(errorAfter) + "\"");
112 | }
113 |
114 | /**
115 | * You can also modify the body of this method to customize your error messages.
116 | * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
117 | * of end-users concern, so you can return something like :
118 | *
119 | * "Internal Error : Please file a bug report .... "
120 | *
121 | * from this method for such cases in the release version of your parser.
122 | */
123 | public String getMessage() {
124 | return super.getMessage();
125 | }
126 |
127 | /*
128 | * Constructors of various flavors follow.
129 | */
130 |
131 | /** No arg constructor. */
132 | public TokenMgrError() {
133 | }
134 |
135 | /** Constructor with message and reason. */
136 | public TokenMgrError(String message, int reason) {
137 | super(message);
138 | errorCode = reason;
139 | }
140 |
141 | /** Full Constructor. */
142 | public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, int curChar, int reason) {
143 | this(LexicalErr(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
144 | }
145 | }
146 | /* JavaCC - OriginalChecksum=953dd5619161d3bf95d01cc7354e7d76 (do not edit this line) */
147 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/parser/VisitorData.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filter.parser;
2 |
3 | import java.util.ArrayList;
4 | import java.util.HashMap;
5 |
6 | public class VisitorData {
7 |
8 | private ArrayList errors = new ArrayList<>();
9 | private boolean success = true;
10 | private HashMap data = new HashMap<>();
11 |
12 | VisitorData(){
13 |
14 | }
15 |
16 | public void addError(String error){
17 | this.errors.add(error);
18 | this.success = false;
19 | }
20 |
21 | public void setSuccess(boolean success){
22 | this.success = success;
23 | }
24 |
25 | public boolean isSuccess() {
26 | return success;
27 | }
28 |
29 | public ArrayList getErrors() {
30 | return errors;
31 | }
32 |
33 | public String getErrorString(){
34 | StringBuilder sb = new StringBuilder();
35 | for (int i = 0; i < errors.size(); i++) {
36 | sb.append(errors.get(i));
37 | if(i != errors.size()-1) sb.append("\n");
38 | }
39 | return sb.toString();
40 | }
41 |
42 | public HashMap getData() {
43 | return data;
44 | }
45 |
46 | public void setData(String key, Object value){
47 | this.data.put(key, value);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/savedfilter/SavedFilter.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filter.savedfilter;
2 |
3 | import com.nccgroup.loggerplusplus.filter.FilterExpression;
4 | import com.nccgroup.loggerplusplus.filter.FilterRule;
5 | import com.nccgroup.loggerplusplus.filter.parser.ParseException;
6 |
7 | /**
8 | * Created by corey on 19/07/17.
9 | */
10 | public class SavedFilter extends FilterRule {
11 |
12 | public SavedFilter(String name, String filterString) {
13 | super(name.replaceAll("[^a-zA-Z0-9_.]", "_"));
14 | this.trySetFilter(filterString);
15 | }
16 |
17 | public SavedFilter(String name, FilterExpression filterExpression){
18 | super(name, filterExpression);
19 | }
20 |
21 | @Override
22 | public void setName(String name) {
23 | name = name.replaceAll("[^a-zA-Z0-9_.]", "_");
24 | super.setName(name);
25 | }
26 |
27 | @Override
28 | public boolean equals(Object o) {
29 | if(o instanceof SavedFilter){
30 | SavedFilter other = (SavedFilter) o;
31 | return other.getName().equals(getName()) && other.getFilterString().equals(getFilterString());
32 | }else{
33 | return super.equals(o);
34 | }
35 | }
36 |
37 | @Override
38 | public String toString() {
39 | return "SavedFilter[" + this.getName() + ", " + (this.getFilterExpression() == null ? this.getFilterString() : this.getFilterExpression()) + "]";
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/tag/Tag.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filter.tag;
2 |
3 | import com.nccgroup.loggerplusplus.filter.ColorizingFilterRule;
4 | import com.nccgroup.loggerplusplus.filter.FilterExpression;
5 | import com.nccgroup.loggerplusplus.filter.logfilter.LogTableFilter;
6 | import com.nccgroup.loggerplusplus.filter.parser.ParseException;
7 | import com.nccgroup.loggerplusplus.filterlibrary.FilterLibraryController;
8 | import lombok.Getter;
9 |
10 | import java.awt.*;
11 | import java.util.UUID;
12 |
13 | /**
14 | * Created by corey on 19/07/17.
15 | */
16 | public class Tag extends ColorizingFilterRule implements Comparable {
17 |
18 | @Getter
19 | private boolean shouldRetest = true;
20 |
21 | public Tag(){
22 | super("", "");
23 | }
24 |
25 | public Tag(String title, String filterString) {
26 | super(title, filterString);
27 | }
28 |
29 | public Tag(String title, FilterExpression filterExpression) {
30 | super(title, filterExpression);
31 | }
32 |
33 | @Override
34 | public boolean trySetFilter(String filterString){
35 | boolean success = super.trySetFilter(filterString);
36 | if(success) shouldRetest = true;
37 | return success;
38 | }
39 |
40 | @Override
41 | public void setFilter(FilterExpression filter) {
42 | super.setFilter(filter);
43 | shouldRetest = true;
44 | }
45 |
46 | @Override
47 | public void setEnabled(boolean enabled) {
48 | super.setEnabled(enabled);
49 | shouldRetest = true;
50 | }
51 |
52 | @Override
53 | public void setPriority(short priority) {
54 | super.setPriority(priority);
55 | shouldRetest = true;
56 | }
57 |
58 | @Override
59 | public int compareTo(Tag tag) {
60 | return ((Comparable) this.getPriority()).compareTo(tag.getPriority());
61 | }
62 |
63 | public boolean shouldRetest() {
64 | return shouldRetest;
65 | }
66 |
67 | @Override
68 | public String toString() {
69 | return this.getName();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filter/tag/TagListener.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filter.tag;
2 |
3 | /**
4 | * Created by corey on 20/07/17.
5 | */
6 | public interface TagListener {
7 |
8 | void onTagChange(Tag filter);
9 |
10 | void onTagAdd(Tag filter);
11 |
12 | void onTagRemove(Tag filter);
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filterlibrary/FilterLibraryListener.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filterlibrary;
2 |
3 | import com.nccgroup.loggerplusplus.filter.savedfilter.SavedFilter;
4 |
5 | public interface FilterLibraryListener {
6 | void onFilterAdded(SavedFilter savedFilter, int index);
7 | void onFilterRemoved(SavedFilter savedFilter, int index);
8 | void onFilterModified(SavedFilter savedFilter, int index);
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filterlibrary/FilterLibraryPanel.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filterlibrary;
2 |
3 | import com.nccgroup.loggerplusplus.filter.parser.ParseException;
4 | import com.nccgroup.loggerplusplus.filter.savedfilter.SavedFilter;
5 | import com.nccgroup.loggerplusplus.util.userinterface.renderer.ButtonRenderer;
6 | import com.nccgroup.loggerplusplus.util.userinterface.renderer.FilterRenderer;
7 |
8 | import javax.swing.*;
9 | import java.awt.*;
10 | import java.awt.event.MouseAdapter;
11 | import java.awt.event.MouseEvent;
12 |
13 | /**
14 | * Created by corey on 27/08/17.
15 | */
16 | public class FilterLibraryPanel extends JPanel {
17 |
18 | private final FilterLibraryController libraryController;
19 |
20 | public FilterLibraryPanel(FilterLibraryController libraryController){
21 | super(new BorderLayout());
22 |
23 | this.libraryController = libraryController;
24 |
25 | JTable libraryTable = new JTable(new FilterLibraryTableModel(this.libraryController));
26 | libraryTable.setRowHeight(25);
27 | libraryTable.setFillsViewportHeight(true);
28 | libraryTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
29 | libraryTable.setAutoCreateRowSorter(false);
30 | libraryTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
31 | ((JComponent) libraryTable.getDefaultRenderer(JButton.class)).setOpaque(true);
32 | libraryTable.getColumnModel().getColumn(1).setCellRenderer(new FilterRenderer());
33 | libraryTable.getColumnModel().getColumn(2).setCellRenderer(new ButtonRenderer());
34 | libraryTable.getColumnModel().getColumn(3).setCellRenderer(new ButtonRenderer());
35 |
36 | libraryTable.addMouseListener(new MouseAdapter() {
37 | @Override
38 | public void mouseReleased(MouseEvent mouseEvent) {
39 | if(SwingUtilities.isLeftMouseButton(mouseEvent)) {
40 | int col = libraryTable.columnAtPoint(mouseEvent.getPoint());
41 | int row = libraryTable.rowAtPoint(mouseEvent.getPoint());
42 | ((FilterLibraryTableModel) libraryTable.getModel()).onClick(row, col);
43 | }
44 | }
45 | });
46 |
47 | JPanel controlPanel = new JPanel(new GridLayout(1,0));
48 | JButton addFilterButton = new JButton("Add Snippet");
49 | addFilterButton.setPreferredSize(new Dimension(0, 75));
50 | addFilterButton.addActionListener(actionEvent -> {
51 | libraryController.addFilter(new SavedFilter("Unnamed", "Response.body CONTAINS \"Example\""));
52 | });
53 | JButton removeSelectedButton = new JButton("Remove Selected");
54 | removeSelectedButton.setMinimumSize(new Dimension(0, 75));
55 | removeSelectedButton.addActionListener(actionEvent -> {
56 | int selectedRow = libraryTable.getSelectedRow();
57 | if(selectedRow == -1) return;
58 | SavedFilter filter = libraryController.getFilterSnippets().get(selectedRow);
59 | libraryController.removeFilter(filter);
60 | });
61 | controlPanel.add(addFilterButton);
62 | controlPanel.add(removeSelectedButton);
63 |
64 | JScrollPane tableScrollPane = new JScrollPane(libraryTable);
65 | this.add(tableScrollPane, BorderLayout.CENTER);
66 | this.add(controlPanel, BorderLayout.SOUTH);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/filterlibrary/FilterLibraryTableModel.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.filterlibrary;
2 |
3 | import com.nccgroup.loggerplusplus.LoggerPlusPlus;
4 | import com.nccgroup.loggerplusplus.filter.parser.ParseException;
5 | import com.nccgroup.loggerplusplus.filter.savedfilter.SavedFilter;
6 | import com.nccgroup.loggerplusplus.util.userinterface.dialog.ColorFilterDialog;
7 | import com.nccgroup.loggerplusplus.util.MoreHelp;
8 |
9 | import javax.swing.*;
10 | import javax.swing.table.AbstractTableModel;
11 |
12 | public class FilterLibraryTableModel extends AbstractTableModel implements FilterLibraryListener {
13 |
14 | private final FilterLibraryController controller;
15 | JButton btnApplyFilter;
16 | JButton btnSetColorFilter;
17 | private final String[] columnNames = {"Alias", "Snippet", "", ""};
18 |
19 | public FilterLibraryTableModel(FilterLibraryController controller){
20 | this.controller = controller;
21 | this.controller.addFilterListener(this);
22 | btnApplyFilter = new JButton("Set as LogFilter");
23 | btnSetColorFilter = new JButton("Use as Color LogFilter");
24 | }
25 |
26 | @Override
27 | public int getRowCount() {
28 | return controller.getFilterSnippets().size();
29 | }
30 |
31 | @Override
32 | public int getColumnCount() {
33 | return columnNames.length;
34 | }
35 |
36 | @Override
37 | public Object getValueAt(int row, int column) {
38 | if(row >= controller.getFilterSnippets().size()) return null;
39 | SavedFilter savedFilter = controller.getFilterSnippets().get(row);
40 | switch (column){
41 | case 0: return savedFilter.getName();
42 | case 1: {
43 | return savedFilter.getFilterExpression() == null ? savedFilter.getFilterString() : savedFilter.getFilterExpression();
44 | }
45 | case 2: return btnApplyFilter;
46 | case 3: return btnSetColorFilter;
47 | }
48 | return null;
49 | }
50 |
51 | @Override
52 | public String getColumnName(int column) {
53 | return columnNames[column];
54 | }
55 |
56 | @Override
57 | public boolean isCellEditable(int rowIndex, int columnIndex) {
58 | return columnIndex == 0 || columnIndex == 1;
59 | }
60 |
61 | @Override
62 | public void setValueAt(Object value, int row, int column) {
63 | SavedFilter savedFilter = controller.getFilterSnippets().get(row);
64 | if(savedFilter == null) return;
65 | if(column == 0) {
66 | savedFilter.setName((String) value);
67 | if(!((String) value).equalsIgnoreCase(savedFilter.getName())){
68 | JOptionPane.showMessageDialog(LoggerPlusPlus.instance.getMainViewController().getUiComponent(), "Alias names may only contain alphanumeric characters and the symbols period (.) and underscore (_)\n" +
69 | "Invalid characters have been replaced with an underscore.", "Alias Error", JOptionPane.WARNING_MESSAGE);
70 | }
71 | }
72 | if(column == 1){
73 | try{
74 | savedFilter.parseAndSetFilter((String) value);
75 | controller.propagateChangesToSnippetUsers(savedFilter);
76 | }catch (ParseException e){
77 | //Not a valid filter...
78 | MoreHelp.showLargeOutputDialog("Filter Exception", "" + e.getMessage().replaceAll("\n", "
") + "");
79 | // JOptionPane.showMessageDialog(LoggerPlusPlus.instance.getMainViewController().getUiComponent(), "" + e.getMessage().replaceAll("\n", "
") + "", "Filter Exception", JOptionPane.ERROR_MESSAGE);
80 | }
81 | }
82 | controller.saveFilters();
83 | }
84 |
85 | public void onClick(int row, int col) {
86 | if(row < 0 || row >= controller.getFilterSnippets().size()) return;
87 | SavedFilter savedFilter = controller.getFilterSnippets().get(row);
88 | if(col == 2){
89 | LoggerPlusPlus.instance.getLogViewController().getLogFilterController().setFilter(savedFilter.getFilterString());
90 | LoggerPlusPlus.instance.getMainViewController().getTabbedPanel().setSelectedIndex(0);
91 | return;
92 | }
93 | if(col == 3){
94 | controller.addColorFilter(savedFilter.getName(), savedFilter.getFilterExpression());
95 | ColorFilterDialog dialog = new ColorFilterDialog(LoggerPlusPlus.instance.getLibraryController());
96 | dialog.setVisible(true);
97 | }
98 | }
99 |
100 | @Override
101 | public void onFilterAdded(SavedFilter savedFilter, int index) {
102 | int rows = getRowCount();
103 | SwingUtilities.invokeLater(() -> {
104 | this.fireTableRowsInserted(index, index);
105 | });
106 | }
107 |
108 | @Override
109 | public void onFilterModified(SavedFilter savedFilter, int index) {
110 | SwingUtilities.invokeLater(() -> {
111 | this.fireTableRowsUpdated(index, index);
112 | });
113 | }
114 |
115 | @Override
116 | public void onFilterRemoved(SavedFilter savedFilter, int index) {
117 | SwingUtilities.invokeLater(() -> {
118 | this.fireTableRowsDeleted(index, index);
119 | });
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/grepper/GrepResults.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.grepper;
2 |
3 | import com.nccgroup.loggerplusplus.logentry.LogEntry;
4 |
5 | import java.util.ArrayList;
6 |
7 | public class GrepResults {
8 | private final LogEntry entry;
9 | private final ArrayList results;
10 | private int requestMatches = 0;
11 | private int responseMatches = 0;
12 |
13 |
14 | public GrepResults(LogEntry entry) {
15 | this.entry = entry;
16 | this.results = new ArrayList<>();
17 | }
18 |
19 | public ArrayList getMatches() {
20 | return results;
21 | }
22 |
23 | public LogEntry getLogEntry() {
24 | return this.entry;
25 | }
26 |
27 | public void addRequestMatch(Match match) {
28 | this.results.add(match);
29 | this.requestMatches++;
30 | }
31 |
32 | public void addResponseMatch(Match match) {
33 | this.results.add(match);
34 | this.responseMatches++;
35 | }
36 |
37 | public int getRequestMatches() {
38 | return requestMatches;
39 | }
40 |
41 | public int getResponseMatches() {
42 | return responseMatches;
43 | }
44 |
45 | public static class Match {
46 | public final String[] groups;
47 | public final int startIndex;
48 | public final int endIndex;
49 | public final boolean isRequest;
50 |
51 | Match(String[] groups, boolean isRequest, int startIndex, int endIndex) {
52 | this.groups = groups;
53 | this.isRequest = isRequest;
54 | this.startIndex = startIndex;
55 | this.endIndex = endIndex;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/grepper/GrepperListener.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.grepper;
2 |
3 | import java.util.regex.Pattern;
4 |
5 | public interface GrepperListener {
6 | void onSearchStarted(Pattern pattern, int searchEntries);
7 | void onEntryProcessed(GrepResults entryResults);
8 | void onResetRequested();
9 | void onSearchComplete();
10 | void onShutdownInitiated();
11 | void onShutdownComplete();
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/grepper/UniquePatternMatchTable.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.grepper;
2 |
3 |
4 | import javax.swing.*;
5 | import javax.swing.table.AbstractTableModel;
6 | import java.util.ArrayList;
7 | import java.util.HashMap;
8 | import java.util.LinkedHashMap;
9 | import java.util.regex.Pattern;
10 |
11 | public class UniquePatternMatchTable extends JTable implements GrepperListener {
12 | private final GrepperController controller;
13 | private final ArrayList entryKeys;
14 | private final HashMap valueCountMap;
15 |
16 | public UniquePatternMatchTable(GrepperController controller){
17 | super();
18 | this.controller = controller;
19 | this.setModel(new UniqueValueTableModel());
20 | this.setAutoCreateRowSorter(true);
21 | this.setColumnSelectionAllowed(true);
22 | this.entryKeys = new ArrayList<>();
23 | this.valueCountMap = new LinkedHashMap<>();
24 |
25 | this.controller.addListener(this);
26 | }
27 |
28 | public void reset(){
29 | synchronized (this.valueCountMap) {
30 | this.valueCountMap.clear();
31 | }
32 | synchronized (this.entryKeys){
33 | this.entryKeys.clear();
34 | }
35 | SwingUtilities.invokeLater(() -> ((UniqueValueTableModel) this.getModel()).fireTableDataChanged());
36 | }
37 |
38 | public void addEntry(GrepResults entry) {
39 | synchronized (valueCountMap) {
40 | synchronized (entryKeys) {
41 | for (GrepResults.Match result : entry.getMatches()) {
42 | String key = result.groups[0];
43 | int index = entryKeys.indexOf(key);
44 | if (index == -1) {
45 | entryKeys.add(key);
46 | valueCountMap.put(key, new UniqueMatch(result.groups));
47 | } else {
48 | valueCountMap.get(key).increment();
49 | }
50 | }
51 | }
52 | }
53 | }
54 |
55 | @Override
56 | public void onSearchStarted(Pattern pattern, int searchEntries) {
57 | reset();
58 | ((UniqueValueTableModel) getModel()).groups = pattern.matcher("").groupCount();
59 | ((AbstractTableModel) this.getModel()).fireTableStructureChanged();
60 | }
61 |
62 | @Override
63 | public void onEntryProcessed(GrepResults entryResults) {
64 | if(entryResults != null) addEntry(entryResults);
65 | }
66 |
67 | @Override
68 | public void onSearchComplete() {
69 | ((AbstractTableModel) this.getModel()).fireTableDataChanged();
70 | }
71 |
72 | @Override
73 | public void onResetRequested() {
74 | reset();
75 | }
76 |
77 | @Override
78 | public void onShutdownInitiated() {
79 |
80 | }
81 |
82 | @Override
83 | public void onShutdownComplete() {
84 | ((AbstractTableModel) this.getModel()).fireTableDataChanged();
85 | }
86 |
87 |
88 | public class UniqueValueTableModel extends AbstractTableModel {
89 |
90 | int groups = 0;
91 |
92 | @Override
93 | public String getColumnName(int column) {
94 | if(column == 0) return "Value";
95 | if(column == groups+1) return "Count";
96 | return "Group " + column;
97 | }
98 |
99 | @Override
100 | public int getRowCount() {
101 | if(valueCountMap == null) return 0;
102 | else return valueCountMap.size();
103 | }
104 |
105 | @Override
106 | public int getColumnCount() {
107 | return groups+2;
108 | }
109 |
110 | @Override
111 | public Class> getColumnClass(int columnIndex) {
112 | if(columnIndex == groups+1) return Integer.class;
113 | return String.class;
114 | }
115 |
116 | @Override
117 | public Object getValueAt(int row, int col) {
118 | String key = entryKeys.get(row);
119 | if(col == 0) return key;
120 | UniqueMatch match = valueCountMap.get(key);
121 | if(col == groups+1) return match.count;
122 | return match.groups[col];
123 | }
124 | }
125 |
126 | static class UniqueMatch {
127 | String key;
128 | String[] groups;
129 | int count;
130 |
131 | UniqueMatch(String[] match){
132 | this.key = match[0];
133 | this.groups = match;
134 | this.count = 1;
135 | }
136 |
137 | private void increment(){
138 | this.count++;
139 | }
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logentry/FieldGroup.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.logentry;
2 |
3 | import java.util.Arrays;
4 | import java.util.HashMap;
5 | import java.util.List;
6 |
7 | public enum FieldGroup {
8 | ENTRY("Entry", "Log", "Proxy"),
9 | REQUEST("Request"),
10 | RESPONSE("Response");
11 | private String label;
12 | private List additionalLabels;
13 |
14 | private static final HashMap groupLabelMap = new HashMap<>();
15 |
16 | static {
17 | for (FieldGroup fieldGroup : FieldGroup.values()) {
18 | groupLabelMap.put(fieldGroup.label.toUpperCase(), fieldGroup);
19 | fieldGroup.additionalLabels.forEach(label -> groupLabelMap.put(label.toUpperCase(), fieldGroup));
20 | }
21 | }
22 |
23 | FieldGroup(String primaryLabel, String... labels) {
24 | this.label = primaryLabel;
25 | additionalLabels = Arrays.asList(labels);
26 | }
27 |
28 | public String getLabel() {
29 | return label;
30 | }
31 |
32 | public static FieldGroup findByLabel(String label) {
33 | return groupLabelMap.get(label.toUpperCase());
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logentry/LogEntryFieldSerializer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.logentry;
2 |
3 | import com.google.gson.*;
4 |
5 | import java.lang.reflect.Type;
6 |
7 | public class LogEntryFieldSerializer implements JsonSerializer, JsonDeserializer {
8 |
9 | @Override
10 | public LogEntryField deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
11 | return LogEntryField.getByFullyQualifiedName(json.getAsString());
12 | }
13 |
14 | @Override
15 | public JsonElement serialize(LogEntryField src, Type typeOfSrc, JsonSerializationContext context) {
16 | return context.serialize(src.getFullLabel());
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logentry/LogEntrySerializer.java:
--------------------------------------------------------------------------------
1 | //
2 | // Burp Suite Logger++
3 | //
4 | // Released as open source by NCC Group Plc - https://www.nccgroup.trust/
5 | //
6 | // Originally Developed by Soroush Dalili (@irsdl)
7 | // Maintained by Corey Arthur (@CoreyD97)
8 | //
9 | // Project link: http://www.github.com/nccgroup/BurpSuiteLoggerPlusPlus
10 | //
11 | // Released under AGPL see LICENSE for more information
12 | //
13 |
14 | package com.nccgroup.loggerplusplus.logentry;
15 |
16 | import com.google.gson.JsonElement;
17 | import com.google.gson.JsonObject;
18 | import com.google.gson.JsonSerializationContext;
19 | import com.google.gson.JsonSerializer;
20 |
21 | import java.lang.reflect.Type;
22 | import java.util.Arrays;
23 | import java.util.List;
24 |
25 | public class LogEntrySerializer implements JsonSerializer {
26 |
27 | private final List excludedFields = Arrays.asList(LogEntryField.NUMBER);
28 |
29 | @Override
30 | public JsonElement serialize(LogEntry src, Type typeOfSrc, JsonSerializationContext context) {
31 | JsonObject entry = new JsonObject();
32 | for (FieldGroup group : FieldGroup.values()) {
33 | JsonObject groupEntries = new JsonObject();
34 | for (LogEntryField fieldInGroup : LogEntryField.getFieldsInGroup(group)) {
35 | if(excludedFields.contains(fieldInGroup)) continue;
36 | groupEntries.add(fieldInGroup.getLabels()[0], context.serialize(src.getValueByKey(fieldInGroup)));
37 | }
38 | entry.add(group.getLabel(), groupEntries);
39 | }
40 | return entry;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logentry/Status.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.logentry;
2 |
3 | public enum Status {
4 | UNPROCESSED, AWAITING_RESPONSE, PROCESSED
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logging/BurpAppender.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.logging;
2 |
3 | import com.nccgroup.loggerplusplus.LoggerPlusPlus;
4 | import org.apache.logging.log4j.Level;
5 | import org.apache.logging.log4j.core.Appender;
6 | import org.apache.logging.log4j.core.Core;
7 | import org.apache.logging.log4j.core.Filter;
8 | import org.apache.logging.log4j.core.LogEvent;
9 | import org.apache.logging.log4j.core.appender.AbstractAppender;
10 | import org.apache.logging.log4j.core.config.plugins.Plugin;
11 | import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
12 | import org.apache.logging.log4j.core.config.plugins.PluginElement;
13 | import org.apache.logging.log4j.core.config.plugins.PluginFactory;
14 | import org.apache.logging.log4j.core.layout.PatternLayout;
15 |
16 | @Plugin(name="BurpAppender", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE)
17 | public class BurpAppender extends AbstractAppender {
18 |
19 | public BurpAppender(String name, Filter filter){
20 | super(name, filter, PatternLayout.createDefaultLayout(), false, null);
21 | }
22 |
23 | @PluginFactory
24 | public static BurpAppender createAppender(@PluginAttribute("name") String name, @PluginElement("Filter") Filter filter) {
25 | return new BurpAppender(name, filter);
26 | }
27 |
28 | @Override
29 | public void append(LogEvent event) {
30 | String message = new String(this.getLayout().toByteArray(event));
31 | if(LoggerPlusPlus.montoya == null) return;
32 |
33 | if (event.getLevel().isInRange(Level.WARN, Level.FATAL)) {
34 | LoggerPlusPlus.montoya.logging().logToError(message);
35 | } else {
36 | LoggerPlusPlus.montoya.logging().logToOutput(message);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logging/LoggingController.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.logging;
2 |
3 | import burp.api.montoya.MontoyaApi;
4 | import com.coreyd97.BurpExtenderUtilities.IGsonProvider;
5 | import com.nccgroup.loggerplusplus.util.Globals;
6 | import lombok.extern.log4j.Log4j2;
7 | import org.apache.logging.log4j.Level;
8 | import org.apache.logging.log4j.LogManager;
9 | import org.apache.logging.log4j.core.LoggerContext;
10 | import org.apache.logging.log4j.core.appender.ConsoleAppender;
11 |
12 | @Log4j2
13 | public class LoggingController {
14 |
15 | private final IGsonProvider gsonProvider;
16 | private Level logLevel;
17 |
18 | public LoggingController(IGsonProvider gsonProvider, MontoyaApi montoyaApi) {
19 | this.gsonProvider = gsonProvider;
20 | logLevel = gsonProvider.getGson().fromJson(montoyaApi.persistence().preferences().getString(Globals.PREF_LOG_LEVEL), Level.class);
21 | if(montoyaApi.extension().filename() == null){ //Loaded from classpath. Log to console!
22 | LoggerContext context = (LoggerContext) LogManager.getContext(false);
23 | ConsoleAppender.Builder appenderBuilder = new ConsoleAppender.Builder();
24 | appenderBuilder.setName("ConsoleAppender");
25 | ConsoleAppender consoleAppender = appenderBuilder.build();
26 | consoleAppender.start();
27 | context.getRootLogger().addAppender(consoleAppender);
28 | }
29 | setLogLevel(logLevel);
30 | }
31 |
32 | public void setLogLevel(Level logLevel) {
33 | this.logLevel = logLevel;
34 | LoggerContext context = (LoggerContext) LogManager.getContext(false);
35 | context.getConfiguration().getRootLogger().setLevel(logLevel);
36 | context.updateLoggers();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logview/LogTableFilterStatusListener.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.logview;
2 |
3 | public interface LogTableFilterStatusListener {
4 | void onFilteringStart();
5 | void onFilteringFinish();
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logview/LogViewController.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.logview;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 | import com.coreyd97.BurpExtenderUtilities.VariableViewPanel;
5 | import com.nccgroup.loggerplusplus.LoggerPlusPlus;
6 | import com.nccgroup.loggerplusplus.filter.logfilter.LogFilterController;
7 | import com.nccgroup.loggerplusplus.filterlibrary.FilterLibraryController;
8 | import com.nccgroup.loggerplusplus.logview.entryviewer.RequestViewerController;
9 | import com.nccgroup.loggerplusplus.logview.logtable.LogTableController;
10 | import lombok.Getter;
11 |
12 | public class LogViewController {
13 |
14 | @Getter
15 | private final FilterLibraryController filterLibraryController;
16 |
17 | @Getter
18 | private final Preferences preferences;
19 |
20 | @Getter
21 | private final LogFilterController logFilterController;
22 |
23 | @Getter
24 | private final LogTableController logTableController;
25 |
26 | @Getter
27 | private final RequestViewerController requestViewerController;
28 |
29 | @Getter
30 | private final LogViewPanel logViewPanel;
31 |
32 | public LogViewController(FilterLibraryController filterLibraryController){
33 | this.filterLibraryController = filterLibraryController;
34 | this.preferences = LoggerPlusPlus.instance.getPreferencesController().getPreferences();
35 |
36 | this.logTableController = new LogTableController(this, filterLibraryController);
37 | this.logFilterController = new LogFilterController(this);
38 | this.requestViewerController = new RequestViewerController(preferences);
39 |
40 | //Build UI
41 | this.logViewPanel = new LogViewPanel(this);
42 | }
43 |
44 | public void setPanelLayout(VariableViewPanel.View view){
45 | this.logViewPanel.getTableViewerSplitPanel().setView(view);
46 | }
47 |
48 | public void setEntryViewerLayout(VariableViewPanel.View view){
49 | this.logViewPanel.getRequestViewerPanel().getVariableViewPanel().setView(view);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logview/LogViewPanel.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.logview;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Alignment;
4 | import com.coreyd97.BurpExtenderUtilities.PanelBuilder;
5 | import com.coreyd97.BurpExtenderUtilities.Preferences;
6 | import com.coreyd97.BurpExtenderUtilities.VariableViewPanel;
7 | import com.nccgroup.loggerplusplus.logview.entryviewer.RequestViewerPanel;
8 | import com.nccgroup.loggerplusplus.logview.logtable.LogTable;
9 | import com.nccgroup.loggerplusplus.util.Globals;
10 |
11 | import javax.swing.*;
12 | import java.awt.*;
13 | import java.awt.event.MouseAdapter;
14 | import java.awt.event.MouseEvent;
15 |
16 | /**
17 | * Created by corey on 24/08/17.
18 | */
19 | public class LogViewPanel extends JPanel {
20 |
21 | private final LogViewController controller;
22 | private final Preferences preferences;
23 | private final MainControlsPanel mainControlsPanel;
24 | private final LogTable logTable;
25 | private final JScrollPane logTableScrollPane;
26 | private final RequestViewerPanel requestViewerPanel;
27 | private final VariableViewPanel tableViewerSplitPanel;
28 |
29 | public LogViewPanel(LogViewController controller){
30 | this.controller = controller;
31 | this.preferences = controller.getPreferences();
32 |
33 | mainControlsPanel = new MainControlsPanel(controller.getLogFilterController());
34 |
35 | logTable = controller.getLogTableController().getLogTable();
36 |
37 | logTableScrollPane = new JScrollPane(logTable,ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
38 | ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);//View
39 | logTableScrollPane.addMouseWheelListener(mouseWheelEvent -> {
40 | JScrollBar scrollBar = logTableScrollPane.getVerticalScrollBar();
41 | preferences.setSetting(Globals.PREF_AUTO_SCROLL,
42 | scrollBar.getValue() + scrollBar.getHeight() >= scrollBar.getMaximum());
43 | });
44 | logTableScrollPane.getVerticalScrollBar().addMouseListener(new MouseAdapter() {
45 | @Override
46 | public void mouseReleased(MouseEvent mouseEvent) {
47 | JScrollBar scrollBar = logTableScrollPane.getVerticalScrollBar();
48 | preferences.setSetting(Globals.PREF_AUTO_SCROLL,
49 | scrollBar.getValue() + scrollBar.getHeight() >= scrollBar.getMaximum());
50 | }
51 | });
52 |
53 | requestViewerPanel = controller.getRequestViewerController().getRequestViewerPanel();
54 |
55 | tableViewerSplitPanel = new VariableViewPanel(controller.getPreferences(), Globals.PREF_LAYOUT,
56 | logTableScrollPane, "Log Table",
57 | requestViewerPanel, "Request/Response", VariableViewPanel.View.VERTICAL);
58 |
59 | buildUI();
60 | }
61 |
62 | private void buildUI(){
63 | this.removeAll();
64 | this.setLayout(new BorderLayout());
65 |
66 | JPanel panel = PanelBuilder.build(new Component[][]{
67 | new Component[]{mainControlsPanel},
68 | new Component[]{tableViewerSplitPanel},
69 | }, new int[][]{
70 | new int[]{0},
71 | new int[]{1}
72 | }, Alignment.FILL, 1.0, 1.0);
73 |
74 | this.add(panel, BorderLayout.CENTER);
75 | }
76 |
77 | public VariableViewPanel getTableViewerSplitPanel() {
78 | return tableViewerSplitPanel;
79 | }
80 |
81 | public RequestViewerPanel getRequestViewerPanel() {
82 | return requestViewerPanel;
83 | }
84 |
85 | public LogTable getLogTable() {
86 | return logTable;
87 | }
88 |
89 | public JScrollPane getScrollPane() {
90 | return logTableScrollPane;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logview/MainControlsPanel.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.logview;
2 |
3 | import com.nccgroup.loggerplusplus.LoggerPlusPlus;
4 | import com.nccgroup.loggerplusplus.filter.logfilter.LogFilterController;
5 | import com.nccgroup.loggerplusplus.util.userinterface.dialog.ColorFilterDialog;
6 | import com.nccgroup.loggerplusplus.util.userinterface.dialog.TagDialog;
7 |
8 | import javax.swing.*;
9 | import java.awt.*;
10 |
11 | public class MainControlsPanel extends JPanel {
12 |
13 | private final LogFilterController logFilterController;
14 |
15 | public MainControlsPanel(LogFilterController logFilterController){
16 | super(new GridBagLayout());
17 |
18 | this.logFilterController = logFilterController;
19 | GridBagConstraints gbc = new GridBagConstraints();
20 | gbc.fill = GridBagConstraints.BOTH;
21 | gbc.gridx = 0;
22 | gbc.weightx = 0;
23 | gbc.weighty = 1;
24 |
25 | this.add(new JLabel(" Filter: "), gbc);
26 |
27 | gbc.gridx = 1;
28 | gbc.weightx = 99.0;
29 | this.add(logFilterController.getFilterField(), gbc);
30 |
31 | final JButton tagsButton = new JButton("Tags");
32 | tagsButton.addActionListener(actionEvent -> new TagDialog(LoggerPlusPlus.instance.getLibraryController()).setVisible(true));
33 |
34 | gbc.gridx = 2;
35 | gbc.weightx = 0;
36 | this.add(tagsButton, gbc);
37 |
38 | final JButton colorFilterButton = new JButton("Colorize");
39 | colorFilterButton.addActionListener(actionEvent -> new ColorFilterDialog(LoggerPlusPlus.instance.getLibraryController()).setVisible(true));
40 |
41 | gbc.gridx = 3;
42 | gbc.weightx = 0;
43 | this.add(colorFilterButton, gbc);
44 |
45 | final JButton clearLogsButton = new JButton("Clear Logs");
46 | clearLogsButton.addActionListener(actionEvent ->
47 | logFilterController.getLogViewController().getLogTableController().reset());
48 |
49 | gbc.gridx = 4;
50 | gbc.weightx = 0;
51 | this.add(clearLogsButton, gbc);
52 | }
53 |
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logview/entryviewer/RequestViewerController.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.logview.entryviewer;
2 |
3 | import burp.api.montoya.ui.editor.EditorOptions;
4 | import burp.api.montoya.ui.editor.HttpRequestEditor;
5 | import burp.api.montoya.ui.editor.HttpResponseEditor;
6 | import com.coreyd97.BurpExtenderUtilities.Preferences;
7 | import com.nccgroup.loggerplusplus.LoggerPlusPlus;
8 | import com.nccgroup.loggerplusplus.logentry.LogEntry;
9 | import lombok.Getter;
10 |
11 | @Getter
12 | public class RequestViewerController {
13 |
14 | private final Preferences preferences;
15 | private final HttpRequestEditor requestEditor;
16 | private final HttpResponseEditor responseEditor;
17 | private final RequestViewerPanel requestViewerPanel;
18 |
19 | private LogEntry currentEntry;
20 |
21 | public RequestViewerController(Preferences preferences) {
22 | this.preferences = preferences;
23 | this.requestEditor = LoggerPlusPlus.montoya.userInterface().createHttpRequestEditor(EditorOptions.READ_ONLY);
24 | this.responseEditor = LoggerPlusPlus.montoya.userInterface().createHttpResponseEditor(EditorOptions.READ_ONLY);
25 | this.requestViewerPanel = new RequestViewerPanel(this);
26 | }
27 |
28 | public void setDisplayedEntity(LogEntry logEntry) {
29 | // Only update message if it's new. This fixes issue #164 and improves performance during heavy scanning.
30 | if (this.currentEntry == logEntry) { return; }
31 |
32 | this.currentEntry = logEntry;
33 |
34 | if (logEntry == null || logEntry.getRequest() == null) {
35 | requestEditor.setRequest(null);
36 | }else{
37 | requestEditor.setRequest(logEntry.getRequest());
38 | }
39 |
40 | if (logEntry == null || logEntry.getResponse() == null) {
41 | responseEditor.setResponse(null);
42 | }else{
43 | responseEditor.setResponse(logEntry.getResponse());
44 | }
45 | }
46 |
47 | public void setMarkers(){
48 |
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logview/entryviewer/RequestViewerPanel.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.logview.entryviewer;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.PopOutPanel;
4 | import com.coreyd97.BurpExtenderUtilities.VariableViewPanel;
5 | import com.nccgroup.loggerplusplus.LoggerPlusPlus;
6 | import com.nccgroup.loggerplusplus.util.Globals;
7 |
8 | public class RequestViewerPanel extends PopOutPanel {
9 |
10 | private final RequestViewerController controller;
11 | private final VariableViewPanel variableViewPanel;
12 |
13 | public RequestViewerPanel(RequestViewerController controller){
14 | super(LoggerPlusPlus.montoya);
15 | this.controller = controller;
16 |
17 | this.variableViewPanel = new VariableViewPanel(controller.getPreferences(), Globals.PREF_MESSAGE_VIEW_LAYOUT,
18 | controller.getRequestEditor().uiComponent(), "Request",
19 | controller.getResponseEditor().uiComponent(), "Response",
20 | VariableViewPanel.View.HORIZONTAL);
21 |
22 | this.setComponent(variableViewPanel);
23 | this.setTitle("Request/Response Viewer");
24 | }
25 |
26 | public VariableViewPanel getVariableViewPanel() {
27 | return variableViewPanel;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logview/logtable/LogTableColumn.java:
--------------------------------------------------------------------------------
1 | //
2 | // Burp Suite Logger++
3 | //
4 | // Released as open source by NCC Group Plc - https://www.nccgroup.trust/
5 | //
6 | // Developed by Soroush Dalili (@irsdl)
7 | //
8 | // Project link: http://www.github.com/nccgroup/BurpSuiteLoggerPlusPlus
9 | //
10 | // Released under AGPL see LICENSE for more information
11 | //
12 |
13 | package com.nccgroup.loggerplusplus.logview.logtable;
14 |
15 | // To define a structure for table headers
16 | // This will provide a high degree of customisation
17 | // a sample JSON object which will be converted to this object is as follows:
18 | // "{'columnsDefinition':[{'id':'number','visibleName':'#','width':50,'type':'int','readonly':true,'order':1,'visible':true,'description':'Item index number','isRegEx':false,'regExData':{'regExString':'','regExCaseSensitive':false}}]}";
19 |
20 | import com.google.gson.*;
21 | import com.nccgroup.loggerplusplus.logentry.LogEntryField;
22 |
23 | import javax.swing.table.TableColumn;
24 | import java.lang.reflect.Type;
25 |
26 | public class LogTableColumn extends TableColumn implements Comparable{
27 |
28 | private String name;
29 | private int order;
30 | private String visibleName;
31 | private boolean visible;
32 | private boolean readOnly;
33 | private String description;
34 | private String defaultVisibleName;
35 |
36 | @Override
37 | public void setPreferredWidth(int width){
38 | super.setPreferredWidth(width);
39 | }
40 | @Override
41 | public void setWidth(int width){
42 | super.setWidth(width);
43 | this.setPreferredWidth(width);
44 | }
45 |
46 | @Override
47 | public LogEntryField getIdentifier() { return (LogEntryField) this.identifier; }
48 | public String getName() {
49 | return name;
50 | }
51 | public void setName(String name) {
52 | this.name = name;
53 | }
54 | public String getVisibleName() {
55 | return visibleName;
56 | }
57 | public void setVisibleName(String visibleName) {
58 | this.visibleName = visibleName;
59 | }
60 |
61 | public boolean isReadOnly() {
62 | return readOnly;
63 | }
64 | public void setReadOnly(boolean readOnly) {
65 | this.readOnly = readOnly;
66 | }
67 |
68 | public int getOrder() {
69 | return order;
70 | }
71 |
72 | public void setOrder(int order) {
73 | this.order = order;
74 | }
75 |
76 | public boolean isVisible() {
77 | return visible;
78 | }
79 | public void setVisible(boolean visible) {
80 | this.visible = visible;
81 | }
82 | public String getDescription() {
83 | return description;
84 | }
85 |
86 | public String getDefaultVisibleName() {
87 | return defaultVisibleName;
88 | }
89 |
90 |
91 | @Override
92 | public Object getHeaderValue() {
93 | return this.getVisibleName();
94 | }
95 |
96 | @Override
97 | public int compareTo(LogTableColumn logTableColumn) {
98 | return Integer.compare(this.order, logTableColumn.order);
99 | }
100 |
101 | public static class ColumnSerializer implements JsonDeserializer, JsonSerializer {
102 | //id, name, enabled, defaultVisibleName, visibleName, width, type, readonly, order, visible, description, isRegEx, regExData
103 | @Override
104 | public JsonElement serialize(LogTableColumn column, Type type, JsonSerializationContext jsonSerializationContext) {
105 | JsonObject object = new JsonObject();
106 | object.addProperty("id", String.valueOf(column.identifier));
107 | object.addProperty("order", column.order);
108 | object.addProperty("name", column.name);
109 | object.addProperty("defaultVisibleName", column.defaultVisibleName);
110 | object.addProperty("visibleName", column.visibleName);
111 | object.addProperty("preferredWidth", column.width);
112 | object.addProperty("readonly", column.readOnly);
113 | object.addProperty("visible", column.visible);
114 | object.addProperty("description", column.description);
115 | return object;
116 | }
117 |
118 | @Override
119 | public LogTableColumn deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
120 | LogTableColumn column = null;
121 | JsonObject object = jsonElement.getAsJsonObject();
122 | column = new LogTableColumn();
123 | column.identifier = LogEntryField.getByFullyQualifiedName(object.get("id").getAsString());
124 | column.name = object.get("name").getAsString();
125 | column.order = object.get("order").getAsInt();
126 | column.defaultVisibleName = object.get("defaultVisibleName").getAsString();
127 | column.visibleName = object.get("visibleName").getAsString();
128 | column.setWidth(object.get("preferredWidth").getAsInt());
129 | column.readOnly = object.get("readonly").getAsBoolean();
130 | column.visible = object.get("visible").getAsBoolean();
131 | column.description = object.get("description").getAsString();
132 |
133 | return column;
134 | }
135 | }
136 |
137 | @Override
138 | public String toString() {
139 | return "LogTableColumn[" + identifier + "]";
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logview/logtable/LogTableController.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.logview.logtable;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 | import com.nccgroup.loggerplusplus.filterlibrary.FilterLibraryController;
5 | import com.nccgroup.loggerplusplus.logview.LogViewController;
6 | import com.nccgroup.loggerplusplus.util.Globals;
7 |
8 | public class LogTableController {
9 |
10 | private final LogViewController logViewController;
11 | private final FilterLibraryController filterLibraryController;
12 | private final Preferences preferences;
13 | private final LogTableModel logTableModel;
14 | private final LogTableColumnModel logTableColumnModel;
15 | private final TableHeader tableHeader;
16 | private final LogTable logTable;
17 |
18 | public LogTableController(LogViewController logViewController, FilterLibraryController filterLibraryController){
19 | this.logViewController = logViewController;
20 | this.filterLibraryController = filterLibraryController;
21 | this.preferences = logViewController.getPreferences();
22 |
23 | this.logTableColumnModel = new LogTableColumnModel(this);
24 | this.logTableModel = new LogTableModel(this, logTableColumnModel);
25 | this.tableHeader = new TableHeader(this);
26 | this.logTable = new LogTable(this);
27 |
28 | this.filterLibraryController.addColorFilterListener(logTableModel);
29 | this.filterLibraryController.addTagListener(logTableModel);
30 | }
31 |
32 | public LogViewController getLogViewController() {
33 | return logViewController;
34 | }
35 |
36 | public LogTableColumnModel getLogTableColumnModel() {
37 | return logTableColumnModel;
38 | }
39 |
40 | public LogTableModel getLogTableModel() {
41 | return logTableModel;
42 | }
43 |
44 | public LogTable getLogTable() {
45 | return logTable;
46 | }
47 |
48 | public TableHeader getTableHeader() {
49 | return tableHeader;
50 | }
51 |
52 | public Preferences getPreferences() {
53 | return preferences;
54 | }
55 |
56 |
57 | public void reset(){
58 | logTableModel.reset();
59 | }
60 |
61 | public int getMaximumEntries(){
62 | return preferences.getSetting(Globals.PREF_MAXIMUM_ENTRIES);
63 | }
64 |
65 | public void reinitialize(){
66 | //TODO Reinitialize table model
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logview/logtable/TableHeader.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.logview.logtable;
2 |
3 | import javax.swing.*;
4 | import javax.swing.table.JTableHeader;
5 | import java.awt.*;
6 | import java.awt.event.MouseAdapter;
7 | import java.awt.event.MouseEvent;
8 |
9 | // This was used to create tool tips
10 | public class TableHeader extends JTableHeader {
11 |
12 |
13 | TableHeader(LogTableController logTableController) {
14 | super(logTableController.getLogTableColumnModel());
15 |
16 | this.setTable(logTableController.getLogTable());
17 |
18 | this.addMouseListener(new MouseAdapter(){
19 | @Override
20 | public void mouseReleased(MouseEvent e)
21 | {
22 | if ( SwingUtilities.isRightMouseButton( e )){
23 | // get the coordinates of the mouse click
24 | Point p = e.getPoint();
25 | int columnIndex = columnAtPoint(p);
26 | LogTableColumn column = (LogTableColumn) getColumnModel().getColumn(columnIndex);
27 |
28 | TableHeaderMenu tblHeaderMenu = new TableHeaderMenu(logTableController, column);
29 | tblHeaderMenu.showMenu(e);
30 | }
31 | }
32 | });
33 |
34 | }
35 |
36 | @Override
37 | public String getToolTipText(MouseEvent e) {
38 |
39 | // get the coordinates of the mouse click
40 | Point p = e.getPoint();
41 | int columnID = TableHeader.this.getTable().convertColumnIndexToModel(TableHeader.this.getTable().columnAtPoint(p));
42 | LogTableColumn column = (LogTableColumn) TableHeader.this.getTable().getColumnModel().getColumn(columnID);
43 |
44 | String retStr;
45 | try {
46 | retStr = column.getDescription();
47 | } catch (NullPointerException | ArrayIndexOutOfBoundsException ex) {
48 | retStr = "";
49 | }
50 | if (retStr.length() < 1) {
51 | retStr = super.getToolTipText(e);
52 | }
53 | return retStr;
54 |
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logview/logtable/TableHeaderMenu.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.logview.logtable;
2 |
3 | import com.nccgroup.loggerplusplus.logentry.FieldGroup;
4 | import com.nccgroup.loggerplusplus.util.MoreHelp;
5 |
6 | import javax.swing.*;
7 | import java.awt.event.ActionEvent;
8 | import java.awt.event.ActionListener;
9 | import java.awt.event.MouseEvent;
10 | import java.util.*;
11 |
12 |
13 | public class TableHeaderMenu extends JPopupMenu{
14 |
15 | private final LogTableController logTableController;
16 | private final LogTable logTable;
17 | private final LogTableColumn columnObj;
18 |
19 | public TableHeaderMenu(LogTableController logTableController, LogTableColumn columnObj)
20 | {
21 | this.logTableController = logTableController;
22 | this.logTable = logTableController.getLogTable();
23 | this.columnObj=columnObj;
24 |
25 | }
26 |
27 | public void showMenu(MouseEvent e){
28 |
29 | JPopupMenu menu = new JPopupMenu("Popup");
30 | JMenuItem item = new JMenuItem(columnObj.getVisibleName() + " (" + columnObj.getIdentifier().getFullLabel() + ")");
31 |
32 | item.setEnabled(false);
33 | menu.add(item);
34 | menu.addSeparator();
35 |
36 | item = new JMenuItem("Rename");
37 | item.addActionListener(new ActionListener() {
38 | public void actionPerformed(ActionEvent e) {
39 | String newValue = MoreHelp.showPlainInputMessage("Rename the \"" + columnObj.getDefaultVisibleName()+
40 | "\" column", "Rename column name", columnObj.getVisibleName());
41 | if(newValue.isEmpty()){
42 | newValue = columnObj.getDefaultVisibleName();
43 | }
44 | // Save it only if it is different! no need to refresh the columns
45 | if(!newValue.equals(columnObj.getDefaultVisibleName())){
46 | columnObj.setVisibleName(newValue);
47 | logTableController.getLogTableColumnModel().saveLayout();
48 | }
49 | }
50 | });
51 | menu.add(item);
52 |
53 | item = new JMenuItem("Hide");
54 | item.addActionListener(new ActionListener() {
55 | public void actionPerformed(ActionEvent e) {
56 | logTable.getColumnModel().toggleHidden(columnObj);
57 | }
58 | });
59 | menu.add(item);
60 |
61 | JMenu subMenuVisibleCols = new JMenu("Visible columns");
62 | item = new JMenuItem("Make all visible");
63 | item.addActionListener(new ActionListener() {
64 | public void actionPerformed(ActionEvent e) {
65 | for (LogTableColumn column : logTable.getColumnModel().getAllColumns()) {
66 | logTable.getColumnModel().showColumn(column);
67 | }
68 | logTableController.getLogTableColumnModel().saveLayout();
69 | }
70 | });
71 | subMenuVisibleCols.add(item);
72 |
73 | Map groupMenus = new HashMap<>();
74 |
75 | for (LogTableColumn logTableColumn : logTable.getColumnModel().getAllColumns()) {
76 |
77 | FieldGroup group = logTableColumn.getIdentifier().getFieldGroup();
78 | if (!groupMenus.containsKey(group)) {
79 | groupMenus.put(group, new JMenu(group.getLabel()));
80 | }
81 | JMenu fieldGroupMenu = groupMenus.get(group);
82 |
83 | JMenuItem visibleItem = new JCheckBoxMenuItem(logTableColumn.getVisibleName());
84 | visibleItem.setSelected(logTableColumn.isVisible());
85 | visibleItem.addActionListener(e1 -> logTable.getColumnModel().toggleHidden(logTableColumn));
86 | fieldGroupMenu.add(visibleItem);
87 | }
88 |
89 | List fieldGroups = new ArrayList(groupMenus.keySet());
90 | fieldGroups.sort(Enum::compareTo);
91 |
92 | for (FieldGroup fieldGroup : fieldGroups) {
93 | subMenuVisibleCols.add(groupMenus.get(fieldGroup));
94 | }
95 |
96 | menu.add(subMenuVisibleCols);
97 |
98 | menu.show(e.getComponent(), e.getX(), e.getY());
99 | }
100 |
101 |
102 |
103 | }
104 |
105 |
106 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logview/processor/EntryImportWorker.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.logview.processor;
2 |
3 | import burp.api.montoya.core.ToolType;
4 | import burp.api.montoya.http.message.HttpRequestResponse;
5 | import burp.api.montoya.http.message.requests.HttpRequest;
6 | import burp.api.montoya.http.message.responses.HttpResponse;
7 | import burp.api.montoya.proxy.ProxyHttpRequestResponse;
8 | import com.nccgroup.loggerplusplus.logentry.LogEntry;
9 |
10 | import javax.swing.*;
11 | import java.util.ArrayList;
12 | import java.util.List;
13 | import java.util.concurrent.CountDownLatch;
14 | import java.util.concurrent.ThreadPoolExecutor;
15 | import java.util.function.Consumer;
16 |
17 | public class EntryImportWorker extends SwingWorker {
18 |
19 | private final LogProcessor logProcessor;
20 | private final ToolType originatingTool;
21 | private final List proxyEntries;
22 | private final List httpEntries;
23 | private final Consumer> interimConsumer;
24 | private final Runnable callback;
25 | private final boolean sendToAutoExporters;
26 |
27 | private EntryImportWorker(Builder builder){
28 | this.logProcessor = builder.logProcessor;
29 | this.originatingTool = builder.originatingTool;
30 | this.proxyEntries = builder.proxyEntries;
31 | this.httpEntries = builder.httpEntries;
32 | this.interimConsumer = builder.interimConsumer;
33 | this.callback = builder.callback;
34 | this.sendToAutoExporters = builder.sendToAutoExporters;
35 | }
36 |
37 | @Override
38 | protected Void doInBackground() throws Exception {
39 | logProcessor.getEntryProcessExecutor().pause(); //Pause the processor, we don't want it mixing with our import.
40 | boolean isProxyEntries = proxyEntries.size() > 0;
41 | int count = isProxyEntries ? proxyEntries.size() : httpEntries.size();
42 |
43 |
44 | CountDownLatch countDownLatch = new CountDownLatch(count);
45 | ThreadPoolExecutor entryImportExecutor = logProcessor.getEntryImportExecutor();
46 | for (int index = 0; index < count; index++) {
47 | if(entryImportExecutor.isShutdown() || this.isCancelled()) return null;
48 | HttpRequest request;
49 | HttpResponse response;
50 | if(isProxyEntries){
51 | request = proxyEntries.get(index).finalRequest();
52 | response = proxyEntries.get(index).originalResponse();
53 | }else{
54 | request = httpEntries.get(index).request();
55 | response = httpEntries.get(index).response();
56 | }
57 | final LogEntry logEntry = new LogEntry(originatingTool, request, response);
58 | int finalIndex = index;
59 | entryImportExecutor.submit(() -> {
60 | if(this.isCancelled()) return;
61 | LogEntry result = logProcessor.processEntry(logEntry);
62 | if(result != null) {
63 | logProcessor.addNewEntry(logEntry, sendToAutoExporters);
64 | }
65 | publish(finalIndex);
66 | countDownLatch.countDown();
67 | });
68 | }
69 | countDownLatch.await();
70 | return null;
71 | }
72 |
73 | @Override
74 | protected void process(List chunks) {
75 | if(this.interimConsumer != null)
76 | interimConsumer.accept(chunks);
77 | }
78 |
79 | @Override
80 | protected void done() {
81 | logProcessor.getEntryProcessExecutor().resume();
82 | if(this.callback != null) callback.run();
83 | super.done();
84 | }
85 |
86 | public static class Builder {
87 |
88 | private final LogProcessor logProcessor;
89 | private ToolType originatingTool = ToolType.EXTENSIONS;
90 | private List proxyEntries = new ArrayList<>();
91 | private List httpEntries = new ArrayList<>();
92 | private Consumer> interimConsumer;
93 | private Runnable callback;
94 | private boolean sendToAutoExporters = false;
95 |
96 | Builder(LogProcessor logProcessor){
97 | this.logProcessor = logProcessor;
98 | }
99 |
100 | public Builder setOriginatingTool(ToolType originatingTool){
101 | this.originatingTool = originatingTool;
102 | return this;
103 | }
104 |
105 | public Builder setProxyEntries(List entries) {
106 | this.proxyEntries.addAll(entries);
107 | this.httpEntries.clear();
108 | return this;
109 | }
110 |
111 | public Builder setHttpEntries(List entries) {
112 | this.httpEntries.addAll(entries);
113 | this.proxyEntries.clear();
114 | return this;
115 | }
116 |
117 | public Builder setInterimConsumer(Consumer> interimConsumer) {
118 | this.interimConsumer = interimConsumer;
119 | return this;
120 | }
121 |
122 | public Builder setCallback(Runnable callback) {
123 | this.callback = callback;
124 | return this;
125 | }
126 |
127 | //Control if the imported entries should also be sent to exporters (e.g. ElasticSearch)
128 | //Prevents existing entries being re-exported
129 | public Builder setSendToAutoExporters(boolean autoExport) {
130 | this.sendToAutoExporters = autoExport;
131 | return this;
132 | }
133 |
134 | public EntryImportWorker build() {
135 | return new EntryImportWorker(this);
136 | }
137 | }
138 | }
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/logview/processor/LogProcessorHelper.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.logview.processor;
2 |
3 | import burp.api.montoya.core.Annotations;
4 | import com.nccgroup.loggerplusplus.util.Globals;
5 | import org.apache.commons.lang3.StringUtils;
6 |
7 | import java.util.regex.Matcher;
8 |
9 | public class LogProcessorHelper {
10 |
11 | public static Annotations addIdentifierInComment(Integer identifier, Annotations annotations) {
12 | String originalComment = annotations.notes() != null ? annotations.notes() : "";
13 | annotations = annotations.withNotes(originalComment + "$LPP:" + identifier + "$");
14 | return annotations;
15 | }
16 |
17 | public static Object[] extractAndRemoveIdentifierFromRequestResponseComment(Annotations annotations) {
18 | Integer identifier = null;
19 | if (!StringUtils.isEmpty(annotations.notes())) {
20 | Matcher matcher = Globals.LOG_ENTRY_ID_PATTERN.matcher(annotations.notes());
21 | if (matcher.find()) {
22 | identifier = Integer.parseInt(matcher.group(1));
23 | annotations = annotations.withNotes(matcher.replaceAll(""));
24 | }
25 | }
26 |
27 | return new Object[]{identifier,annotations};
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/preferences/PreferencesController.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.preferences;
2 |
3 | import burp.api.montoya.MontoyaApi;
4 | import com.coreyd97.BurpExtenderUtilities.IGsonProvider;
5 | import com.coreyd97.BurpExtenderUtilities.ILogProvider;
6 | import com.coreyd97.BurpExtenderUtilities.Preferences;
7 | import com.nccgroup.loggerplusplus.LoggerPlusPlus;
8 | import lombok.Getter;
9 | import lombok.extern.log4j.Log4j2;
10 | import org.apache.logging.log4j.LogManager;
11 | import org.apache.logging.log4j.Logger;
12 |
13 | @Log4j2
14 | public class PreferencesController {
15 |
16 | @Getter
17 | private final IGsonProvider gsonProvider;
18 |
19 | @Getter
20 | private final Preferences preferences;
21 |
22 | private PreferencesPanel preferencesPanel;
23 |
24 | public PreferencesController(MontoyaApi montoya) {
25 | this.gsonProvider = LoggerPlusPlus.gsonProvider;
26 | this.preferences = new LoggerPreferenceFactory(montoya,
27 | gsonProvider,
28 | new ILogProvider() {
29 | @Override
30 | public void logOutput(String message) {
31 | log.debug(message);
32 | }
33 |
34 | @Override
35 | public void logError(String errorMessage) {
36 | log.error(errorMessage);
37 | }
38 | }
39 | ).buildPreferences();
40 | }
41 |
42 | public PreferencesPanel getPreferencesPanel() {
43 | if(this.preferencesPanel == null) {
44 | this.preferencesPanel = new PreferencesPanel(this);
45 | }
46 |
47 | return preferencesPanel;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/reflection/filter/BlacklistFilter.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.reflection.filter;
2 |
3 | import burp.api.montoya.http.message.params.HttpParameter;
4 | import com.coreyd97.BurpExtenderUtilities.Preferences;
5 | import com.google.gson.reflect.TypeToken;
6 | import com.nccgroup.loggerplusplus.util.MoreHelp;
7 | import org.apache.commons.lang3.StringUtils;
8 |
9 | import java.util.Arrays;
10 | import java.util.HashSet;
11 | import java.util.Set;
12 | import java.util.TreeSet;
13 |
14 | public class BlacklistFilter extends ParameterFilter {
15 |
16 | private static String BLACKLIST_PREF = "parameterValueBlacklist";
17 | private static HashSet defaultBlacklist = new HashSet<>(Arrays.asList("0","1","true","false"));
18 |
19 | private final Set blacklist = new TreeSet(String.CASE_INSENSITIVE_ORDER);
20 |
21 | public BlacklistFilter(Preferences preferences){
22 | super(preferences, "Value Blacklist");
23 | preferences.registerSetting(BLACKLIST_PREF, new TypeToken>(){}.getType(), defaultBlacklist);
24 |
25 | blacklist.addAll(preferences.getSetting(BLACKLIST_PREF));
26 | }
27 |
28 | @Override
29 | public boolean isFiltered(HttpParameter parameter) {
30 | return blacklist.contains(parameter.value());
31 | }
32 |
33 | @Override
34 | public void showConfigDialog() {
35 | String valueString = MoreHelp.showPlainInputMessage("Enter comma separated blacklist values:", "Parameter Value Blacklist", StringUtils.join(blacklist, ","));
36 | String[] values = valueString.split(",");
37 | blacklist.clear();
38 | for (String value : values) {
39 | if(!value.isEmpty()) {
40 | blacklist.add(value.trim());
41 | }
42 | }
43 | preferences.setSetting(BLACKLIST_PREF, blacklist);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/reflection/filter/LengthFilter.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.reflection.filter;
2 |
3 | import burp.api.montoya.http.message.params.HttpParameter;
4 | import com.coreyd97.BurpExtenderUtilities.Alignment;
5 | import com.coreyd97.BurpExtenderUtilities.PanelBuilder;
6 | import com.coreyd97.BurpExtenderUtilities.Preferences;
7 | import com.nccgroup.loggerplusplus.LoggerPlusPlus;
8 |
9 | import javax.swing.*;
10 |
11 | public class LengthFilter extends ParameterFilter {
12 |
13 | private static String LENGTH_MIN_PREF = "lengthMinFilter";
14 | private static String LENGTH_MAX_PREF = "lengthMaxFilter";
15 | private int min_length;
16 | private int max_length;
17 |
18 | public LengthFilter(Preferences preferences){
19 | super(preferences, "Value Length Range");
20 | preferences.registerSetting(LENGTH_MAX_PREF, int.class, 999);
21 | preferences.registerSetting(LENGTH_MIN_PREF, int.class, 3);
22 |
23 | min_length = preferences.getSetting(LENGTH_MIN_PREF);
24 | max_length = preferences.getSetting(LENGTH_MAX_PREF);
25 | }
26 |
27 | @Override
28 | public boolean isFiltered(HttpParameter parameter) {
29 | int len = parameter.value().length();
30 | return len < min_length || len > max_length;
31 |
32 | }
33 |
34 | @Override
35 | public void showConfigDialog() {
36 | JLabel info = new JLabel("Enter parameter value length range:");
37 | JSpinner minLengthSpinner = new JSpinner(new SpinnerNumberModel(min_length, 0, 99999, 1));
38 | JSpinner maxLengthSpinner = new JSpinner(new SpinnerNumberModel(max_length, 0, 99999, 1));
39 | JPanel panel = PanelBuilder.build(new JComponent[][]{
40 | new JComponent[]{info, info},
41 | new JComponent[]{new JLabel("Minimum: "), minLengthSpinner},
42 | new JComponent[]{new JLabel("Maximum: "), maxLengthSpinner}
43 | }, new int[][]{
44 | new int[]{0},
45 | new int[]{1},
46 | new int[]{1},
47 | }, Alignment.FILL, 1.0, 1.0);
48 | int result = JOptionPane.showConfirmDialog(LoggerPlusPlus.instance.getLoggerFrame(), panel, "Reflection Value Length Filter", JOptionPane.OK_CANCEL_OPTION);
49 | if(result == JOptionPane.OK_OPTION){
50 | min_length = (int) minLengthSpinner.getValue();
51 | max_length = (int) maxLengthSpinner.getValue();
52 | preferences.setSetting(LENGTH_MIN_PREF, min_length);
53 | preferences.setSetting(LENGTH_MAX_PREF, max_length);
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/reflection/filter/ParameterFilter.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.reflection.filter;
2 |
3 | import burp.api.montoya.http.message.params.HttpParameter;
4 | import com.coreyd97.BurpExtenderUtilities.Preferences;
5 |
6 | public abstract class ParameterFilter {
7 |
8 | protected final Preferences preferences;
9 | private final String name;
10 | private final String enabledPrefKey;
11 | private boolean enabled;
12 |
13 | ParameterFilter(Preferences preferences, String name){
14 | this.preferences = preferences;
15 | this.name = name;
16 | this.enabledPrefKey = "ParamFilter_" + name + "_Enabled";
17 | preferences.registerSetting(enabledPrefKey, boolean.class, true);
18 | this.enabled = preferences.getSetting(enabledPrefKey);
19 | }
20 |
21 | public String getName(){
22 | return this.name;
23 | };
24 |
25 | public void setEnabled(boolean enabled){
26 | this.enabled = enabled;
27 | preferences.setSetting(enabledPrefKey, enabled);
28 | }
29 |
30 | public boolean isEnabled() {
31 | return enabled;
32 | }
33 |
34 | public abstract boolean isFiltered(HttpParameter parameter);
35 | public abstract void showConfigDialog();
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/reflection/transformer/Base64DecodeTransformer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.reflection.transformer;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 |
5 | import java.io.UnsupportedEncodingException;
6 | import java.util.Base64;
7 |
8 | public class Base64DecodeTransformer extends ParameterValueTransformer {
9 |
10 | public Base64DecodeTransformer(Preferences preferences){
11 | super(preferences, "Base64 Decode");
12 | }
13 |
14 | @Override
15 | public String transform(String string) throws UnsupportedEncodingException {
16 | return new String(Base64.getDecoder().decode(string.getBytes()));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/reflection/transformer/Base64EncodeTransformer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.reflection.transformer;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 |
5 | import java.io.UnsupportedEncodingException;
6 | import java.util.Base64;
7 |
8 | public class Base64EncodeTransformer extends ParameterValueTransformer {
9 |
10 | public Base64EncodeTransformer(Preferences preferences){
11 | super(preferences, "Base64 Encode");
12 | }
13 |
14 | @Override
15 | public String transform(String string) throws UnsupportedEncodingException {
16 | return new String(Base64.getEncoder().encode(string.getBytes()));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/reflection/transformer/HTMLEscapeTransformer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.reflection.transformer;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 | import org.apache.commons.text.StringEscapeUtils;
5 |
6 | public class HTMLEscapeTransformer extends ParameterValueTransformer {
7 |
8 | public HTMLEscapeTransformer(Preferences preferences){
9 | super(preferences, "HTML Escape");
10 | }
11 |
12 | @Override
13 | public String transform(String string) {
14 | return StringEscapeUtils.escapeHtml4(string);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/reflection/transformer/HTMLUnescapeTransformer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.reflection.transformer;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 | import org.apache.commons.text.StringEscapeUtils;
5 |
6 | public class HTMLUnescapeTransformer extends ParameterValueTransformer {
7 |
8 | public HTMLUnescapeTransformer(Preferences preferences){
9 | super(preferences, "HTML Unescape");
10 | }
11 |
12 | @Override
13 | public String transform(String string) {
14 | return StringEscapeUtils.unescapeHtml4(string);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/reflection/transformer/HexEncodeTransformer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.reflection.transformer;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 | import org.apache.commons.codec.binary.Hex;
5 |
6 | import java.io.UnsupportedEncodingException;
7 |
8 | public class HexEncodeTransformer extends ParameterValueTransformer {
9 |
10 | public HexEncodeTransformer(Preferences preferences){
11 | super(preferences, "Hex Encode");
12 | }
13 |
14 | @Override
15 | public String transform(String string) throws UnsupportedEncodingException {
16 | return Hex.encodeHexString(string.getBytes());
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/reflection/transformer/JsonEscapeTransformer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.reflection.transformer;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 | import org.apache.commons.text.StringEscapeUtils;
5 |
6 | public class JsonEscapeTransformer extends ParameterValueTransformer {
7 |
8 | public JsonEscapeTransformer(Preferences preferences){
9 | super(preferences, "Json Escape");
10 | }
11 |
12 | @Override
13 | public String transform(String string) {
14 | return StringEscapeUtils.escapeJson(string);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/reflection/transformer/JsonUnescapeTransformer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.reflection.transformer;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 | import org.apache.commons.text.StringEscapeUtils;
5 |
6 | public class JsonUnescapeTransformer extends ParameterValueTransformer {
7 |
8 | public JsonUnescapeTransformer(Preferences preferences){
9 | super(preferences, "Json Unescape");
10 | }
11 |
12 | @Override
13 | public String transform(String string) {
14 | return StringEscapeUtils.unescapeJson(string);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/reflection/transformer/ParameterValueTransformer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.reflection.transformer;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 |
5 | public abstract class ParameterValueTransformer {
6 |
7 | protected final Preferences preferences;
8 | private final String name;
9 | private final String enabledPrefKey;
10 | private boolean enabled;
11 |
12 | ParameterValueTransformer(Preferences preferences, String name){
13 | this.preferences = preferences;
14 | this.name = name;
15 | this.enabledPrefKey = "ParamTransformer_" + name + "_Enabled";
16 | preferences.registerSetting(enabledPrefKey, boolean.class, true);
17 | this.enabled = preferences.getSetting(enabledPrefKey);
18 | }
19 |
20 | public String getName(){
21 | return this.name;
22 | };
23 |
24 | public void setEnabled(boolean enabled){
25 | this.enabled = enabled;
26 | preferences.setSetting(enabledPrefKey, enabled);
27 | }
28 |
29 | public boolean isEnabled() {
30 | return enabled;
31 | }
32 |
33 | public abstract String transform(String value) throws Exception;
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/reflection/transformer/URLDecodeTransformer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.reflection.transformer;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 |
5 | import java.io.UnsupportedEncodingException;
6 | import java.net.URLDecoder;
7 |
8 | public class URLDecodeTransformer extends ParameterValueTransformer {
9 |
10 | public URLDecodeTransformer(Preferences preferences){
11 | super(preferences, "URL Decode");
12 | }
13 |
14 | @Override
15 | public String transform(String string) throws UnsupportedEncodingException {
16 | return URLDecoder.decode(string, "UTF-8");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/reflection/transformer/URLEncodeTransformer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.reflection.transformer;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 |
5 | import java.io.UnsupportedEncodingException;
6 | import java.net.URLEncoder;
7 |
8 | public class URLEncodeTransformer extends ParameterValueTransformer {
9 |
10 | public URLEncodeTransformer(Preferences preferences){
11 | super(preferences, "URL Encode");
12 | }
13 |
14 | @Override
15 | public String transform(String string) throws UnsupportedEncodingException {
16 | return URLEncoder.encode(string, "UTF-8");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/reflection/transformer/XMLEscapeTransformer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.reflection.transformer;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 | import org.apache.commons.text.StringEscapeUtils;
5 |
6 | public class XMLEscapeTransformer extends ParameterValueTransformer {
7 |
8 | public XMLEscapeTransformer(Preferences preferences){
9 | super(preferences, "XML Escape");
10 | }
11 |
12 | @Override
13 | public String transform(String string) {
14 | return StringEscapeUtils.escapeXml11(string);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/reflection/transformer/XMLUnescapeTransformer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.reflection.transformer;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Preferences;
4 | import org.apache.commons.text.StringEscapeUtils;
5 |
6 | public class XMLUnescapeTransformer extends ParameterValueTransformer {
7 |
8 | public XMLUnescapeTransformer(Preferences preferences){
9 | super(preferences, "XML Unescape");
10 | }
11 |
12 | @Override
13 | public String transform(String string) {
14 | return StringEscapeUtils.unescapeXml(string);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/util/NamedThreadFactory.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.util;
2 |
3 | import java.util.concurrent.ThreadFactory;
4 | import java.util.concurrent.atomic.AtomicInteger;
5 |
6 | public class NamedThreadFactory implements ThreadFactory {
7 |
8 | private final String name;
9 | private final AtomicInteger atomicInteger;
10 |
11 | public NamedThreadFactory(String name){
12 | this.name = name;
13 | this.atomicInteger = new AtomicInteger(0);
14 | }
15 |
16 | @Override
17 | public Thread newThread(Runnable r) {
18 | return new Thread(r, String.format("%s-Thread-%d", this.name, this.atomicInteger.incrementAndGet()));
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/util/PausableThreadPoolExecutor.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.util;
2 |
3 | import java.util.concurrent.*;
4 | import java.util.concurrent.locks.Condition;
5 | import java.util.concurrent.locks.ReentrantLock;
6 |
7 | public class PausableThreadPoolExecutor extends ThreadPoolExecutor {
8 | private boolean isPaused;
9 | private ReentrantLock pauseLock = new ReentrantLock();
10 | private Condition unpaused = pauseLock.newCondition();
11 |
12 | public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) {
13 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
14 | }
15 |
16 | public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory) {
17 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
18 | }
19 |
20 | public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, RejectedExecutionHandler handler) {
21 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
22 | }
23 |
24 | public PausableThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
25 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
26 | }
27 |
28 | protected void beforeExecute(Thread t, Runnable r) {
29 | super.beforeExecute(t, r);
30 | pauseLock.lock();
31 | try {
32 | while (isPaused) unpaused.await();
33 | } catch(InterruptedException ie) {
34 | t.interrupt();
35 | } finally {
36 | pauseLock.unlock();
37 | }
38 | }
39 |
40 | public void pause() {
41 | pauseLock.lock();
42 | try {
43 | isPaused = true;
44 | } finally {
45 | pauseLock.unlock();
46 | }
47 | }
48 |
49 | public void resume() {
50 | pauseLock.lock();
51 | try {
52 | isPaused = false;
53 | unpaused.signalAll();
54 | } finally {
55 | pauseLock.unlock();
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/util/SwingWorkerWithProgressDialog.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.util;
2 |
3 | import com.coreyd97.BurpExtenderUtilities.Alignment;
4 | import com.coreyd97.BurpExtenderUtilities.PanelBuilder;
5 |
6 | import javax.swing.*;
7 | import java.awt.*;
8 | import java.awt.event.ActionEvent;
9 | import java.util.Collections;
10 | import java.util.List;
11 |
12 | public abstract class SwingWorkerWithProgressDialog extends SwingWorker {
13 |
14 | private final JProgressBar jProgressBar;
15 | private final JDialog dialog;
16 |
17 | public SwingWorkerWithProgressDialog(Frame dialogOwner, String title, String message, int progressBarMax){
18 | jProgressBar = new JProgressBar(0, progressBarMax);
19 | dialog = new JDialog(dialogOwner, title, false);
20 | JLabel messageLabel = new JLabel(message);
21 | JButton cancelButton = new JButton(new AbstractAction("Cancel") {
22 | @Override
23 | public void actionPerformed(ActionEvent actionEvent) {
24 | SwingWorkerWithProgressDialog.this.cancel(true);
25 | }
26 | });
27 |
28 | JPanel bodyPanel = PanelBuilder.build(new Component[][]{
29 | new Component[]{messageLabel, messageLabel},
30 | new Component[]{jProgressBar, cancelButton}
31 | }, new int[][]{
32 | new int[]{0, 0},
33 | new int[]{1, 0}
34 | }, Alignment.CENTER, 0.8, 0.8);
35 |
36 | dialog.add(bodyPanel);
37 | dialog.setResizable(false);
38 | dialog.pack();
39 |
40 | dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
41 | }
42 |
43 | @Override
44 | protected T doInBackground() throws Exception {
45 | dialog.setVisible(true);
46 | return null;
47 | }
48 |
49 | @Override
50 | protected void process(List chunks) {
51 | jProgressBar.setValue(Collections.max(chunks));
52 | }
53 |
54 | @Override
55 | protected void done() {
56 | dialog.dispose();
57 | super.done();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/util/userinterface/ColorEditor.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.util.userinterface;
2 |
3 | import javax.swing.*;
4 | import javax.swing.table.TableCellEditor;
5 | import java.awt.*;
6 | import java.awt.event.ActionEvent;
7 | import java.awt.event.ActionListener;
8 | //https://docs.oracle.com/javase/tutorial/uiswing/components/table.html
9 | public class ColorEditor extends AbstractCellEditor implements TableCellEditor, ActionListener {
10 | Color currentColor;
11 | JButton button;
12 | JColorChooser colorChooser;
13 | JDialog dialog;
14 | protected static final String EDIT = "edit";
15 |
16 | public ColorEditor() {
17 | button = new JButton();
18 | button.setActionCommand(EDIT);
19 | button.addActionListener(this);
20 | button.setBorderPainted(false);
21 |
22 | //Set up the dialog that the button brings up.
23 | colorChooser = new JColorChooser();
24 | dialog = JColorChooser.createDialog(button,
25 | "Pick a Color",
26 | true, //modal
27 | colorChooser,
28 | this, //OK button handler
29 | null); //no CANCEL button handler
30 | }
31 |
32 | public void actionPerformed(ActionEvent e) {
33 | if (EDIT.equals(e.getActionCommand())) {
34 | //The user has clicked the cell, so
35 | //bring up the dialog.
36 | button.setBackground(currentColor);
37 | colorChooser.setColor(currentColor);
38 | dialog.setVisible(true);
39 |
40 | fireEditingStopped(); //Make the renderer reappear.
41 |
42 | } else { //User pressed dialog's "OK" button.
43 | currentColor = colorChooser.getColor();
44 | }
45 | }
46 |
47 | //Implement the one CellEditor method that AbstractCellEditor doesn't.
48 | public Object getCellEditorValue() {
49 | return currentColor;
50 | }
51 |
52 | //Implement the one method defined by TableCellEditor.
53 | public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
54 | currentColor = (Color)value;
55 | return button;
56 | }
57 | }
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/util/userinterface/NoTextSelectionCaret.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.util.userinterface;
2 |
3 | import javax.swing.text.DefaultCaret;
4 | import javax.swing.text.JTextComponent;
5 |
6 | public class NoTextSelectionCaret extends DefaultCaret {
7 | public NoTextSelectionCaret(JTextComponent component){
8 | setBlinkRate(component.getCaret().getBlinkRate());
9 | component.setHighlighter(null);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/util/userinterface/WrappedTextPane.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.util.userinterface;
2 |
3 | import javax.swing.*;
4 | import javax.swing.text.*;
5 |
6 | public class WrappedTextPane extends JTextPane {
7 |
8 | public WrappedTextPane(StyledDocument styledDocument){
9 | this.setEditorKit(new WrapEditorKit());
10 | }
11 |
12 | public WrappedTextPane(){
13 | this.setEditorKit(new WrapEditorKit());
14 | }
15 |
16 | class WrapEditorKit extends StyledEditorKit {
17 | ViewFactory factory = new WrapColumnFactory();
18 | public ViewFactory getViewFactory() {
19 | return factory;
20 | }
21 | }
22 |
23 | class WrapColumnFactory implements ViewFactory {
24 | public View create(Element elem) {
25 | String kind = elem.getName();
26 | if (kind != null) {
27 | if (kind.equals(AbstractDocument.ContentElementName)) {
28 | return new WrapLabelView(elem);
29 | } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
30 | return new ParagraphView(elem);
31 | } else if (kind.equals(AbstractDocument.SectionElementName)) {
32 | return new BoxView(elem, View.Y_AXIS);
33 | } else if (kind.equals(StyleConstants.ComponentElementName)) {
34 | return new ComponentView(elem);
35 | } else if (kind.equals(StyleConstants.IconElementName)) {
36 | return new IconView(elem);
37 | }
38 | }
39 |
40 | // default to text display
41 | return new LabelView(elem);
42 | }
43 | }
44 |
45 | class WrapLabelView extends LabelView {
46 | public WrapLabelView(Element elem) {
47 | super(elem);
48 | }
49 |
50 | public float getMinimumSpan(int axis) {
51 | switch (axis) {
52 | case View.X_AXIS:
53 | return 0;
54 | case View.Y_AXIS:
55 | return super.getMinimumSpan(axis);
56 | default:
57 | throw new IllegalArgumentException("Invalid axis: " + axis);
58 | }
59 | }
60 |
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/util/userinterface/dialog/ColorFilterDialog.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.util.userinterface.dialog;
2 |
3 | import com.nccgroup.loggerplusplus.filter.colorfilter.TableColorRule;
4 | import com.nccgroup.loggerplusplus.filterlibrary.FilterLibraryController;
5 |
6 | import javax.swing.*;
7 | import java.awt.*;
8 | import java.awt.event.ActionEvent;
9 | import java.awt.event.ActionListener;
10 | import java.awt.event.WindowEvent;
11 |
12 | /**
13 | * Created by corey on 19/07/17.
14 | */
15 | public class ColorFilterDialog extends JFrame {
16 | private static ColorFilterDialog instance;
17 | private final FilterLibraryController filterLibraryController;
18 | private final ColorFilterTable filterTable;
19 |
20 | public ColorFilterDialog(FilterLibraryController filterLibraryController){
21 | if(instance != null) instance.dispose();
22 | instance = this;
23 | this.filterLibraryController = filterLibraryController;
24 | this.filterTable = new ColorFilterTable(filterLibraryController);
25 | buildDialog();
26 | pack();
27 | }
28 |
29 | private void buildDialog(){
30 | this.setLayout(new BorderLayout());
31 | this.setTitle("Color Filters");
32 | JPanel content = new JPanel(new GridBagLayout());
33 | this.add(content, BorderLayout.CENTER);
34 | final JScrollPane filterListWrapper = new JScrollPane(filterTable);
35 | GridBagConstraints gbcFilterWrapper = new GridBagConstraints();
36 | gbcFilterWrapper.gridx = 0;
37 | gbcFilterWrapper.gridy = 0;
38 | gbcFilterWrapper.weighty = 999;
39 | gbcFilterWrapper.weightx = 999;
40 | gbcFilterWrapper.fill = GridBagConstraints.BOTH;
41 | this.setMinimumSize(filterTable.getMinimumSize());
42 | content.add(filterListWrapper, gbcFilterWrapper);
43 |
44 | gbcFilterWrapper.gridx = 1;
45 | gbcFilterWrapper.weightx = 1;
46 | gbcFilterWrapper.fill = GridBagConstraints.HORIZONTAL;
47 | final JPanel priorityControls = new JPanel(new GridLayout(0,1));
48 | priorityControls.add(new JButton(new AbstractAction("\u25B2") {
49 | @Override
50 | public void actionPerformed(ActionEvent actionEvent) {
51 | filterTable.moveSelectedUp();
52 | }
53 | }));
54 | priorityControls.add(new JButton(new AbstractAction("\u25BC") {
55 | @Override
56 | public void actionPerformed(ActionEvent actionEvent) {
57 | filterTable.moveSelectedDown();
58 | }
59 | }));
60 | content.add(priorityControls, gbcFilterWrapper);
61 |
62 | GridBagConstraints gbcFooter = new GridBagConstraints();
63 | gbcFooter.gridx = 0;
64 | gbcFooter.gridy = 1;
65 | gbcFooter.fill = GridBagConstraints.BOTH;
66 | gbcFooter.weighty = gbcFooter.weightx = 1;
67 | gbcFooter.gridwidth = 2;
68 | JPanel buttonPanel = new JPanel(new BorderLayout());
69 | JButton btnDeleteAll = new JButton("Delete All");
70 | btnDeleteAll.addActionListener(new ActionListener() {
71 | @Override
72 | public void actionPerformed(ActionEvent actionEvent) {
73 | ((ColorFilterTableModel) filterTable.getModel()).removeAll();
74 | }
75 | });
76 | JPanel rightPanel = new JPanel(new BorderLayout());
77 | JButton btnAddFilter = new JButton("Add LogFilter");
78 | btnAddFilter.addActionListener(new ActionListener() {
79 | @Override
80 | public void actionPerformed(ActionEvent actionEvent) {
81 | ((ColorFilterTableModel) filterTable.getModel()).addFilter(new TableColorRule());
82 | }
83 | });
84 | JButton btnClose = new JButton("Close");
85 | btnClose.addActionListener(new ActionListener() {
86 | @Override
87 | public void actionPerformed(ActionEvent actionEvent) {
88 | ColorFilterDialog.this.dispatchEvent(new WindowEvent(ColorFilterDialog.this, WindowEvent.WINDOW_CLOSING));
89 | }
90 | });
91 | rightPanel.add(btnAddFilter, BorderLayout.WEST);
92 | rightPanel.add(btnClose, BorderLayout.EAST);
93 | buttonPanel.add(btnDeleteAll, BorderLayout.WEST);
94 | buttonPanel.add(rightPanel, BorderLayout.EAST);
95 | content.add(buttonPanel, gbcFooter);
96 |
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/util/userinterface/dialog/ColorFilterTable.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.util.userinterface.dialog;
2 |
3 | import com.nccgroup.loggerplusplus.filter.colorfilter.TableColorRule;
4 | import com.nccgroup.loggerplusplus.filterlibrary.FilterLibraryController;
5 | import com.nccgroup.loggerplusplus.util.userinterface.renderer.ButtonRenderer;
6 | import com.nccgroup.loggerplusplus.util.userinterface.renderer.ColorRenderer;
7 | import com.nccgroup.loggerplusplus.util.userinterface.renderer.FilterRenderer;
8 | import com.nccgroup.loggerplusplus.util.userinterface.ColorEditor;
9 |
10 | import javax.swing.*;
11 | import java.awt.*;
12 | import java.awt.event.MouseAdapter;
13 | import java.awt.event.MouseEvent;
14 |
15 | /**
16 | * Created by corey on 19/07/17.
17 | */
18 | public class ColorFilterTable extends JTable {
19 | private final FilterLibraryController filterLibraryController;
20 |
21 | ColorFilterTable(FilterLibraryController filterLibraryController){
22 | this.filterLibraryController = filterLibraryController;
23 | this.setModel(new ColorFilterTableModel(filterLibraryController));
24 | this.setFillsViewportHeight(true);
25 | this.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
26 | this.setAutoCreateRowSorter(false);
27 | this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
28 | this.setRowHeight(25);
29 | ((JComponent) this.getDefaultRenderer(Boolean.class)).setOpaque(true); // to remove the white background of the checkboxes!
30 | ((JComponent) this.getDefaultRenderer(JButton.class)).setOpaque(true);
31 |
32 | this.getColumnModel().getColumn(1).setCellRenderer(new FilterRenderer());
33 | this.getColumnModel().getColumn(2).setCellRenderer(new ColorRenderer(true));
34 | this.getColumnModel().getColumn(2).setCellEditor(new ColorEditor());
35 | this.getColumnModel().getColumn(3).setCellRenderer(new ColorRenderer(true));
36 | this.getColumnModel().getColumn(3).setCellEditor(new ColorEditor());
37 | this.getColumnModel().getColumn(5).setCellRenderer(new ButtonRenderer());
38 |
39 |
40 | this.setDragEnabled(true);
41 | this.setDropMode(DropMode.INSERT);
42 |
43 | int[] minWidths = {100, 250, 50, 50, 100, 100};
44 | for(int i=0; i 0){
68 | ((ColorFilterTableModel) this.getModel()).switchRows(this.getSelectedRow(), this.getSelectedRow()-1);
69 | this.getSelectionModel().setSelectionInterval(this.getSelectedRow()-1, this.getSelectedRow()-1);
70 | TableColorRule filter = ((ColorFilterTableModel) this.getModel()).getFilterAtRow(this.getSelectedRow());
71 | filterLibraryController.updateColorFilter(filter);
72 | }
73 | }
74 | public void moveSelectedDown() {
75 | if(this.getSelectedRow() >= 0 && this.getSelectedRow() < this.getRowCount()){
76 | ((ColorFilterTableModel) this.getModel()).switchRows(this.getSelectedRow(), this.getSelectedRow()+1);
77 | this.getSelectionModel().setSelectionInterval(this.getSelectedRow()+1, this.getSelectedRow()+1);
78 | TableColorRule filter = ((ColorFilterTableModel) this.getModel()).getFilterAtRow(this.getSelectedRow());
79 | filterLibraryController.updateColorFilter(filter);
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/util/userinterface/dialog/TagDialog.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.util.userinterface.dialog;
2 |
3 | import com.nccgroup.loggerplusplus.filter.tag.Tag;
4 | import com.nccgroup.loggerplusplus.filterlibrary.FilterLibraryController;
5 |
6 | import javax.swing.*;
7 | import java.awt.*;
8 | import java.awt.event.ActionEvent;
9 | import java.awt.event.ActionListener;
10 | import java.awt.event.WindowEvent;
11 |
12 | /**
13 | * Created by corey on 19/07/17.
14 | */
15 | public class TagDialog extends JFrame {
16 | private static TagDialog instance;
17 | private final FilterLibraryController filterLibraryController;
18 | private final TagTable filterTable;
19 |
20 | public TagDialog(FilterLibraryController filterLibraryController) {
21 | if (instance != null) instance.dispose();
22 | instance = this;
23 | this.filterLibraryController = filterLibraryController;
24 | this.filterTable = new TagTable(filterLibraryController);
25 | buildDialog();
26 | pack();
27 | }
28 |
29 | private void buildDialog() {
30 | this.setLayout(new BorderLayout());
31 | this.setTitle("Log Tags");
32 | JPanel content = new JPanel(new GridBagLayout());
33 | this.add(content, BorderLayout.CENTER);
34 | final JScrollPane filterListWrapper = new JScrollPane(filterTable);
35 | GridBagConstraints gbcFilterWrapper = new GridBagConstraints();
36 | gbcFilterWrapper.gridx = 0;
37 | gbcFilterWrapper.gridy = 0;
38 | gbcFilterWrapper.weighty = 999;
39 | gbcFilterWrapper.weightx = 999;
40 | gbcFilterWrapper.fill = GridBagConstraints.BOTH;
41 | this.setMinimumSize(filterTable.getMinimumSize());
42 | content.add(filterListWrapper, gbcFilterWrapper);
43 |
44 | gbcFilterWrapper.gridx = 1;
45 | gbcFilterWrapper.weightx = 1;
46 | gbcFilterWrapper.fill = GridBagConstraints.HORIZONTAL;
47 | final JPanel priorityControls = new JPanel(new GridLayout(0, 1));
48 | priorityControls.add(new JButton(new AbstractAction("\u25B2") {
49 | @Override
50 | public void actionPerformed(ActionEvent actionEvent) {
51 | filterTable.moveSelectedUp();
52 | }
53 | }));
54 | priorityControls.add(new JButton(new AbstractAction("\u25BC") {
55 | @Override
56 | public void actionPerformed(ActionEvent actionEvent) {
57 | filterTable.moveSelectedDown();
58 | }
59 | }));
60 | content.add(priorityControls, gbcFilterWrapper);
61 |
62 | GridBagConstraints gbcFooter = new GridBagConstraints();
63 | gbcFooter.gridx = 0;
64 | gbcFooter.gridy = 1;
65 | gbcFooter.fill = GridBagConstraints.BOTH;
66 | gbcFooter.weighty = gbcFooter.weightx = 1;
67 | gbcFooter.gridwidth = 2;
68 | JPanel buttonPanel = new JPanel(new BorderLayout());
69 | JButton btnDeleteAll = new JButton("Delete All");
70 | btnDeleteAll.addActionListener(new ActionListener() {
71 | @Override
72 | public void actionPerformed(ActionEvent actionEvent) {
73 | ((TagTableModel) filterTable.getModel()).removeAll();
74 | }
75 | });
76 | JPanel rightPanel = new JPanel(new BorderLayout());
77 | JButton btnAddFilter = new JButton("Add Tag");
78 | btnAddFilter.addActionListener(new ActionListener() {
79 | @Override
80 | public void actionPerformed(ActionEvent actionEvent) {
81 | ((TagTableModel) filterTable.getModel()).addTag(new Tag());
82 | }
83 | });
84 | JButton btnClose = new JButton("Close");
85 | btnClose.addActionListener(new ActionListener() {
86 | @Override
87 | public void actionPerformed(ActionEvent actionEvent) {
88 | TagDialog.this.dispatchEvent(new WindowEvent(TagDialog.this, WindowEvent.WINDOW_CLOSING));
89 | }
90 | });
91 | rightPanel.add(btnAddFilter, BorderLayout.WEST);
92 | rightPanel.add(btnClose, BorderLayout.EAST);
93 | buttonPanel.add(btnDeleteAll, BorderLayout.WEST);
94 | buttonPanel.add(rightPanel, BorderLayout.EAST);
95 | content.add(buttonPanel, gbcFooter);
96 |
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/util/userinterface/dialog/TagTable.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.util.userinterface.dialog;
2 |
3 | import com.nccgroup.loggerplusplus.filter.tag.Tag;
4 | import com.nccgroup.loggerplusplus.filterlibrary.FilterLibraryController;
5 | import com.nccgroup.loggerplusplus.util.userinterface.ColorEditor;
6 | import com.nccgroup.loggerplusplus.util.userinterface.renderer.ButtonRenderer;
7 | import com.nccgroup.loggerplusplus.util.userinterface.renderer.ColorRenderer;
8 | import com.nccgroup.loggerplusplus.util.userinterface.renderer.FilterRenderer;
9 |
10 | import javax.swing.*;
11 | import java.awt.*;
12 | import java.awt.event.MouseAdapter;
13 | import java.awt.event.MouseEvent;
14 |
15 | /**
16 | * Created by corey on 19/07/17.
17 | */
18 | public class TagTable extends JTable {
19 | private final FilterLibraryController filterLibraryController;
20 |
21 | TagTable(FilterLibraryController filterLibraryController) {
22 | this.filterLibraryController = filterLibraryController;
23 | this.setModel(new TagTableModel(filterLibraryController));
24 | this.setFillsViewportHeight(true);
25 | this.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
26 | this.setAutoCreateRowSorter(false);
27 | this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
28 | this.setRowHeight(25);
29 | ((JComponent) this.getDefaultRenderer(Boolean.class)).setOpaque(true); // to remove the white background of the checkboxes!
30 | ((JComponent) this.getDefaultRenderer(JButton.class)).setOpaque(true);
31 |
32 | this.getColumnModel().getColumn(1).setCellRenderer(new FilterRenderer());
33 | this.getColumnModel().getColumn(2).setCellRenderer(new ColorRenderer(true));
34 | this.getColumnModel().getColumn(2).setCellEditor(new ColorEditor());
35 | this.getColumnModel().getColumn(3).setCellRenderer(new ColorRenderer(true));
36 | this.getColumnModel().getColumn(3).setCellEditor(new ColorEditor());
37 | this.getColumnModel().getColumn(5).setCellRenderer(new ButtonRenderer());
38 |
39 |
40 | this.setDragEnabled(true);
41 | this.setDropMode(DropMode.INSERT);
42 |
43 | int[] minWidths = {100, 250, 100, 100};
44 | for (int i = 0; i < minWidths.length; i++) {
45 | this.getColumnModel().getColumn(i).setMinWidth(minWidths[i]);
46 | }
47 | int[] maxWidths = {9999, 9999, 100, 100};
48 | for (int i = 0; i < maxWidths.length; i++) {
49 | this.getColumnModel().getColumn(i).setMaxWidth(maxWidths[i]);
50 | }
51 | this.setMinimumSize(new Dimension(850, 200));
52 |
53 | final JTable _this = this;
54 | this.addMouseListener(new MouseAdapter() {
55 | @Override
56 | public void mouseReleased(MouseEvent mouseEvent) {
57 | if (SwingUtilities.isLeftMouseButton(mouseEvent)) {
58 | int col = _this.columnAtPoint(mouseEvent.getPoint());
59 | int row = _this.rowAtPoint(mouseEvent.getPoint());
60 | ((TagTableModel) getModel()).onClick(row, col);
61 | }
62 | }
63 | });
64 | }
65 |
66 | public void moveSelectedUp() {
67 | if (this.getSelectedRow() > 0) {
68 | ((TagTableModel) this.getModel()).switchRows(this.getSelectedRow(), this.getSelectedRow() - 1);
69 | this.getSelectionModel().setSelectionInterval(this.getSelectedRow() - 1, this.getSelectedRow() - 1);
70 | Tag filter = ((TagTableModel) this.getModel()).getTagAtRow(this.getSelectedRow());
71 | filterLibraryController.updateTag(filter);
72 | }
73 | }
74 |
75 | public void moveSelectedDown() {
76 | if (this.getSelectedRow() >= 0 && this.getSelectedRow() < this.getRowCount()) {
77 | ((TagTableModel) this.getModel()).switchRows(this.getSelectedRow(), this.getSelectedRow() + 1);
78 | this.getSelectionModel().setSelectionInterval(this.getSelectedRow() + 1, this.getSelectedRow() + 1);
79 | Tag filter = ((TagTableModel) this.getModel()).getTagAtRow(this.getSelectedRow());
80 | filterLibraryController.updateTag(filter);
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/util/userinterface/renderer/BooleanRenderer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.util.userinterface.renderer;
2 |
3 | import javax.swing.*;
4 | import javax.swing.border.Border;
5 | import javax.swing.border.EmptyBorder;
6 | import javax.swing.plaf.UIResource;
7 | import javax.swing.table.TableCellRenderer;
8 | import java.awt.*;
9 |
10 | /**
11 | * Created by corey on 07/09/17.
12 | */
13 | public class BooleanRenderer extends JCheckBox implements TableCellRenderer, UIResource {
14 | private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
15 |
16 | public BooleanRenderer() {
17 | this.setHorizontalAlignment(0);
18 | this.setBorderPainted(true);
19 | this.setOpaque(true);
20 | }
21 |
22 | public Component getTableCellRendererComponent(JTable var1, Object var2, boolean var3, boolean var4, int var5, int var6) {
23 | if(var3) {
24 | this.setForeground(var1.getSelectionForeground());
25 | super.setBackground(var1.getSelectionBackground());
26 | } else {
27 | this.setForeground(var1.getForeground());
28 | this.setBackground(var1.getBackground());
29 | }
30 |
31 | this.setSelected(var2 != null && ((Boolean)var2).booleanValue());
32 | if(var4) {
33 | this.setBorder(UIManager.getBorder("LogTable.focusCellHighlightBorder"));
34 | } else {
35 | this.setBorder(noFocusBorder);
36 | }
37 |
38 | return this;
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/util/userinterface/renderer/ButtonRenderer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.util.userinterface.renderer;
2 |
3 | import javax.swing.*;
4 | import javax.swing.table.TableCellRenderer;
5 | import java.awt.*;
6 |
7 | /**
8 | * Created by corey on 22/08/17.
9 | */
10 | public class ButtonRenderer implements TableCellRenderer {
11 | @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
12 | JButton button = (JButton)value;
13 | button.setOpaque(false);
14 | button.setForeground(table.getForeground());
15 | button.setBackground(UIManager.getColor("Button.background"));
16 | return button;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/util/userinterface/renderer/ColorRenderer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.util.userinterface.renderer;
2 |
3 | /*
4 | * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
5 | * https://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableDialogEditDemoProject/src/components/ColorRenderer.java
6 | */
7 |
8 | import javax.swing.*;
9 | import javax.swing.border.Border;
10 | import javax.swing.table.TableCellRenderer;
11 | import java.awt.*;
12 |
13 | public class ColorRenderer extends JLabel
14 | implements TableCellRenderer {
15 | Border unselectedBorder = null;
16 | Border selectedBorder = null;
17 | boolean isBordered = true;
18 |
19 | public ColorRenderer(boolean isBordered) {
20 | this.isBordered = isBordered;
21 | setOpaque(true);
22 | }
23 |
24 | public Component getTableCellRendererComponent(
25 | JTable table, Object color,
26 | boolean isSelected, boolean hasFocus,
27 | int row, int column) {
28 | Color newColor = (Color)color;
29 | setBackground(newColor);
30 | if (isBordered) {
31 | if (isSelected) {
32 | if (selectedBorder == null) {
33 | selectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
34 | table.getSelectionBackground());
35 | }
36 | setBorder(selectedBorder);
37 | } else {
38 | if (unselectedBorder == null) {
39 | unselectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
40 | table.getBackground());
41 | }
42 | setBorder(unselectedBorder);
43 | }
44 | }
45 | if(newColor != null) {
46 | setToolTipText("RGB value: " + newColor.getRed() + ", "
47 | + newColor.getGreen() + ", "
48 | + newColor.getBlue());
49 | }
50 | return this;
51 | }
52 | }
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/util/userinterface/renderer/FilterRenderer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.util.userinterface.renderer;
2 |
3 | import com.nccgroup.loggerplusplus.filter.FilterExpression;
4 | import com.nccgroup.loggerplusplus.filter.logfilter.LogTableFilter;
5 | import com.nccgroup.loggerplusplus.util.userinterface.dialog.ColorFilterTable;
6 | import com.nccgroup.loggerplusplus.util.userinterface.dialog.ColorFilterTableModel;
7 | import com.nccgroup.loggerplusplus.util.userinterface.dialog.TagTable;
8 | import com.nccgroup.loggerplusplus.util.userinterface.dialog.TagTableModel;
9 |
10 | import javax.swing.*;
11 | import javax.swing.table.DefaultTableCellRenderer;
12 | import java.awt.*;
13 |
14 | /**
15 | * Created by corey on 22/08/17.
16 | */
17 | public class FilterRenderer extends DefaultTableCellRenderer {
18 |
19 | @Override
20 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
21 | Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
22 | boolean validFilter;
23 | if (table instanceof ColorFilterTable) {
24 | validFilter = ((ColorFilterTableModel) table.getModel()).validFilterAtRow(row);
25 | } else if (table instanceof TagTable) {
26 | validFilter = ((TagTableModel) table.getModel()).validFilterAtRow(row);
27 | } else {
28 | validFilter = (value instanceof FilterExpression);
29 | }
30 |
31 | if(validFilter){
32 | c.setBackground(new Color(76,255, 155));
33 | c.setForeground(Color.BLACK);
34 | }else{
35 | c.setBackground(new Color(221, 70, 57));
36 | c.setForeground(Color.WHITE);
37 | }
38 |
39 | return c;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/util/userinterface/renderer/LeftTableCellRenderer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.util.userinterface.renderer;
2 |
3 | import javax.swing.*;
4 | import javax.swing.table.DefaultTableCellRenderer;
5 |
6 | /**
7 | * Created by corey on 07/09/17.
8 | */
9 | public class LeftTableCellRenderer extends DefaultTableCellRenderer {
10 | public LeftTableCellRenderer() {
11 | setHorizontalAlignment(SwingConstants.LEFT);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/nccgroup/loggerplusplus/util/userinterface/renderer/TagRenderer.java:
--------------------------------------------------------------------------------
1 | package com.nccgroup.loggerplusplus.util.userinterface.renderer;
2 |
3 | import com.nccgroup.loggerplusplus.filter.tag.Tag;
4 | import org.jdesktop.swingx.HorizontalLayout;
5 |
6 | import javax.swing.*;
7 | import javax.swing.table.TableCellRenderer;
8 | import java.awt.*;
9 | import java.util.ArrayList;
10 | import java.util.Collection;
11 | import java.util.Collections;
12 | import java.util.Enumeration;
13 |
14 | /**
15 | * Created by corey on 22/08/17.
16 | */
17 | public class TagRenderer implements TableCellRenderer {
18 | @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
19 | JPanel tagWrapper = new JPanel();
20 | tagWrapper.setLayout(new HorizontalLayout(2));
21 | tagWrapper.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
22 |
23 | if(value instanceof Collection){
24 | for (Object o : ((Collection) value).toArray()) {
25 | JButton c = new JButton(((Tag) o).getName());
26 | c.putClientProperty("JButton.buttonType", "roundRect");
27 | c.setMargin(new Insets(7,4,7,4));
28 | c.setBackground(((Tag) o).getBackgroundColor());
29 | c.setForeground(((Tag) o).getForegroundColor());
30 | tagWrapper.add(c);
31 | }
32 | }
33 |
34 | return tagWrapper;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/resources/AboutMain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PortSwigger/logger-plus-plus/6fd5f21b714bb3aef2b34d709b0d05b8ade15d2c/src/main/resources/AboutMain.png
--------------------------------------------------------------------------------
/src/main/resources/GitHubLogoBlack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PortSwigger/logger-plus-plus/6fd5f21b714bb3aef2b34d709b0d05b8ade15d2c/src/main/resources/GitHubLogoBlack.png
--------------------------------------------------------------------------------
/src/main/resources/GitHubLogoWhite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PortSwigger/logger-plus-plus/6fd5f21b714bb3aef2b34d709b0d05b8ade15d2c/src/main/resources/GitHubLogoWhite.png
--------------------------------------------------------------------------------
/src/main/resources/NCCGroup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PortSwigger/logger-plus-plus/6fd5f21b714bb3aef2b34d709b0d05b8ade15d2c/src/main/resources/NCCGroup.png
--------------------------------------------------------------------------------
/src/main/resources/NCCLarge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PortSwigger/logger-plus-plus/6fd5f21b714bb3aef2b34d709b0d05b8ade15d2c/src/main/resources/NCCLarge.png
--------------------------------------------------------------------------------
/src/main/resources/TwitterLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PortSwigger/logger-plus-plus/6fd5f21b714bb3aef2b34d709b0d05b8ade15d2c/src/main/resources/TwitterLogo.png
--------------------------------------------------------------------------------
/src/main/resources/log4j2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/test/java/Test.java:
--------------------------------------------------------------------------------
1 | import com.nccgroup.loggerplusplus.LoggerPlusPlus;
2 |
3 | import java.lang.reflect.Method;
4 | import java.util.ArrayList;
5 | import java.util.Arrays;
6 | import java.util.List;
7 |
8 | public class Test {
9 | public static void main(String[] args) {
10 | try {
11 | Method main = Class.forName("burp.StartBurp").getMethod("main", String[].class);
12 | ArrayList argList = new ArrayList<>(Arrays.stream(args).toList());
13 | argList.add("--developer-extension-class-name=" + LoggerPlusPlus.class.getName());
14 | main.invoke(null, (Object) argList.toArray(new String[]{}));
15 | }catch (Exception e){
16 | System.err.println("Cannot start burp. Check the burp jar is correctly included in the classpath.");
17 | e.printStackTrace();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------