diff --git a/.github/workflows/maven-tests.yml b/.github/workflows/maven-tests.yml
new file mode 100644
index 0000000..b5fa596
--- /dev/null
+++ b/.github/workflows/maven-tests.yml
@@ -0,0 +1,30 @@
+name: Maven Tests
+
+on:
+ push:
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Set up JDK 17
+ uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+ cache: maven
+
+ - name: Test with Maven
+ run: mvn -B -Dmaven.test.failure.ignore=true test
+
+ - name: Surefire Report
+ uses: dorny/test-reporter@v1
+ if: always()
+ with:
+ name: Maven Tests
+ path: target/surefire-reports/*.xml
+ reporter: java-junit
+ fail-on-error: true
diff --git a/.gitignore b/.gitignore
index a700395..1b846e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,6 +41,7 @@ buildNumber.properties
.classpath
# manually added
+.attach_pid*
out/
*.iml
src/build/
diff --git a/pom.xml b/pom.xml
index 05ac174..9a65d95 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,6 +37,24 @@
maven-resources-plugin
3.3.1
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.10.1
+ test
+
+
+ org.assertj
+ assertj-core
+ 3.24.2
+ test
+
+
+ org.awaitility
+ awaitility
+ 4.2.0
+ test
+
@@ -98,6 +116,10 @@
+
+ maven-surefire-plugin
+ 3.2.3
+
\ No newline at end of file
diff --git a/src/main/java/burp/BurpExtender.java b/src/main/java/burp/BurpExtender.java
index 6ed6b5f..ce073b2 100644
--- a/src/main/java/burp/BurpExtender.java
+++ b/src/main/java/burp/BurpExtender.java
@@ -13,7 +13,7 @@ public class BurpExtender implements IBurpExtender {
public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks) {
try {
MainUI mainUI = new MainUI(callbacks);
- mainUI.initialize();
+ mainUI.initializeUI();
callbacks.setExtensionName(mainUI.getNameExtension());
diff --git a/src/main/java/com/cys4/sensitivediscoverer/MainUI.java b/src/main/java/com/cys4/sensitivediscoverer/MainUI.java
index 3f35606..fef5021 100644
--- a/src/main/java/com/cys4/sensitivediscoverer/MainUI.java
+++ b/src/main/java/com/cys4/sensitivediscoverer/MainUI.java
@@ -29,8 +29,10 @@ public class MainUI implements ITab {
private final Properties configProperties;
private final ScannerOptions scannerOptions;
private JTabbedPane mainPanel;
+ private boolean interfaceInitialized;
public MainUI(IBurpExtenderCallbacks callbacks) throws Exception {
+ this.interfaceInitialized = false;
this.callbacks = callbacks;
// setup stdout/stderr
@@ -50,6 +52,10 @@ public MainUI(IBurpExtenderCallbacks callbacks) throws Exception {
this.extensionsRegexList = RegexSeeder.getExtensionRegexes();
}
+ public boolean isInterfaceInitialized() {
+ return interfaceInitialized;
+ }
+
public ScannerOptions getScannerOptions() {
return scannerOptions;
}
@@ -57,11 +63,11 @@ public ScannerOptions getScannerOptions() {
/**
* Main function that initializes the extension and creates the UI, asynchronously
*/
- public void initialize() {
- SwingUtilities.invokeLater(this::_initialize);
+ public void initializeUI() {
+ SwingUtilities.invokeLater(this::_initializeUI);
}
- private void _initialize() {
+ private void _initializeUI() {
mainPanel = new JTabbedPane();
LoggerTab loggerTab = new LoggerTab(this);
mainPanel.addTab(loggerTab.getTabName(), loggerTab.getPanel());
@@ -72,6 +78,8 @@ private void _initialize() {
callbacks.customizeUiComponent(mainPanel);
callbacks.addSuiteTab(MainUI.this);
+
+ this.interfaceInitialized = true;
}
/**
diff --git a/src/main/java/com/cys4/sensitivediscoverer/RegexSeeder.java b/src/main/java/com/cys4/sensitivediscoverer/RegexSeeder.java
index 703b7a8..3049467 100644
--- a/src/main/java/com/cys4/sensitivediscoverer/RegexSeeder.java
+++ b/src/main/java/com/cys4/sensitivediscoverer/RegexSeeder.java
@@ -34,7 +34,8 @@ private static List fill(String[] regexFiles) {
element.getDescription(),
element.getRegex(),
element.isActive(),
- ProxyItemSection.deserializeSections(element.getSections())))
+ ProxyItemSection.deserializeSections(element.getSections()),
+ element.getTests()))
.collect(Collectors.toList());
}
diff --git a/src/main/java/com/cys4/sensitivediscoverer/model/JsonRegexEntity.java b/src/main/java/com/cys4/sensitivediscoverer/model/JsonRegexEntity.java
index 6ade373..ac39ef4 100644
--- a/src/main/java/com/cys4/sensitivediscoverer/model/JsonRegexEntity.java
+++ b/src/main/java/com/cys4/sensitivediscoverer/model/JsonRegexEntity.java
@@ -14,6 +14,7 @@ public class JsonRegexEntity {
private String regex;
private String description;
private List sections;
+ private List tests;
public JsonRegexEntity() {
}
@@ -33,4 +34,8 @@ public String getDescription() {
public List getSections() {
return sections;
}
+
+ public List getTests() {
+ return tests;
+ }
}
diff --git a/src/main/java/com/cys4/sensitivediscoverer/model/RegexEntity.java b/src/main/java/com/cys4/sensitivediscoverer/model/RegexEntity.java
index 7872602..6f9e5f7 100644
--- a/src/main/java/com/cys4/sensitivediscoverer/model/RegexEntity.java
+++ b/src/main/java/com/cys4/sensitivediscoverer/model/RegexEntity.java
@@ -5,6 +5,7 @@
package com.cys4.sensitivediscoverer.model;
import java.util.EnumSet;
+import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -20,27 +21,34 @@ public class RegexEntity {
private final transient Pattern regexCompiled;
private final String description;
private final EnumSet sections;
+ private final List tests;
private boolean active;
-
public RegexEntity(String description, String regex) throws IllegalArgumentException {
- this(description, regex, true, ProxyItemSection.getDefault());
+ this(description, regex, true, ProxyItemSection.getDefault(), null);
}
public RegexEntity(String description, String regex, boolean active) throws IllegalArgumentException {
- this(description, regex, active, ProxyItemSection.getDefault());
+ this(description, regex, active, ProxyItemSection.getDefault(), null);
}
public RegexEntity(String description, String regex, boolean active, EnumSet sections) {
- if (regex == null || regex.isBlank())
+ this(description, regex, active, sections, null);
+ }
+
+ public RegexEntity(String description, String regex, boolean active, EnumSet sections, List tests) {
+ if (regex == null || regex.isBlank()) {
throw new IllegalArgumentException(getLocaleString("exception-invalidRegex"));
- if (sections == null)
+ }
+ if (sections == null) {
throw new IllegalArgumentException(getLocaleString("exception-invalidSections"));
+ }
this.active = active;
this.description = description;
this.regex = regex;
this.regexCompiled = Pattern.compile(regex);
this.sections = sections;
+ this.tests = tests;
}
public RegexEntity(RegexEntity entity) throws IllegalArgumentException {
@@ -59,6 +67,10 @@ public static Matcher checkRegexEntityFromCSV(String input) {
.matcher(input);
}
+ public List getTests() {
+ return tests;
+ }
+
public boolean isActive() {
return this.active;
}
diff --git a/src/main/resources/regexes/extension_general.json b/src/main/resources/regexes/extension_general.json
index ee0f919..94d4154 100644
--- a/src/main/resources/regexes/extension_general.json
+++ b/src/main/resources/regexes/extension_general.json
@@ -3,384 +3,448 @@
"active": true,
"description": "1Password password manager database file",
"regex": "\\.agilekeychain$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.agilekeychain"]
},
{
"active": true,
"description": "ASP configuration file",
"regex": "\\.asa$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.asa"]
},
{
"active": true,
"description": "Apple Keychain database file",
"regex": "\\.keychain$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.keychain"]
},
{
"active": true,
"description": "Azure service configuration schema file",
"regex": "\\.cscfg$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.cscfg"]
},
{
"active": true,
"description": "Backup file",
"regex": "\\.bak$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.bak"]
},
{
"active": true,
"description": "Certificate file",
"regex": "\\.cer$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.cer"]
},
{
"active": true,
"description": "Certificate file",
"regex": "\\.crt$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.crt"]
},
{
"active": true,
"description": "Certificate file",
"regex": "\\.p7b$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.p7b"]
},
{
"active": true,
"description": "Compressed archive file",
"regex": "\\.zip$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.zip"]
},
{
"active": true,
"description": "Compressed archive file",
"regex": "\\.tar$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.tar"]
},
{
"active": true,
"description": "Compressed archive file",
"regex": "\\.gz$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.gz"]
},
{
"active": true,
"description": "Compressed archive file",
"regex": "\\.tgz$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.tgz"]
},
{
"active": true,
"description": "Compressed archive file",
"regex": "\\.rar$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.rar"]
},
{
"active": true,
"description": "Configuration file",
"regex": "\\.config$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.config"]
},
{
"active": true,
"description": "Day One journal file",
"regex": "\\.dayone$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.dayone"]
},
{
"active": true,
"description": "Document file",
"regex": "\\.docx$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.docx"]
},
{
"active": true,
"description": "Document file",
"regex": "\\.doc$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.doc"]
},
{
"active": true,
"description": "Document file",
"regex": "\\.rtf$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.rtf"]
},
{
"active": true,
"description": "Excel file",
"regex": "\\.xlsx$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.xlsx"]
},
{
"active": true,
"description": "Excel file",
"regex": "\\.xls$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.xls"]
},
{
"active": true,
"description": "Excel file",
"regex": "\\.csv$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.csv"]
},
{
"active": true,
"description": "GnuCash database file",
"regex": "\\.gnucash$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.gnucash"]
},
{
"active": true,
"description": "Include file",
"regex": "\\.inc$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.inc"]
},
{
"active": true,
"description": "Java file",
"regex": "\\.java$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.java"]
},
{
"active": true,
"description": "Java keystore file",
"regex": "\\.jks$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.jks"]
},
{
"active": true,
"description": "KDE Wallet Manager database file",
"regex": "\\.kwallet$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.kwallet"]
},
{
"active": true,
"description": "Little Snitch firewall configuration file",
"regex": "\\.xpl$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.xpl"]
},
{
"active": true,
"description": "Log file",
"regex": "\\.log$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.log"]
},
{
"active": true,
"description": "Microsoft BitLocker Trusted Platform Module password file",
"regex": "\\.tpm$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.tpm"]
},
{
"active": true,
"description": "Microsoft BitLocker recovery key file",
"regex": "\\.bek$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.bek"]
},
{
"active": true,
"description": "Microsoft SQL database file",
"regex": "\\.mdf$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.mdf"]
},
{
"active": true,
"description": "Microsoft SQL server compact database file",
"regex": "\\.sdf$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.sdf"]
},
{
"active": true,
"description": "Network traffic capture file",
"regex": "\\.pcap$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.pcap"]
},
{
"active": true,
"description": "Old file",
"regex": "\\.old$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.old"]
},
{
"active": true,
"description": "OpenVPN client configuration file",
"regex": "\\.ovpn$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.ovpn"]
},
{
"active": true,
"description": "PDF file",
"regex": "\\.pdf$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.pdf"]
},
{
"active": true,
"description": "PHP file",
"regex": "\\.php$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.php"]
},
{
"active": true,
"description": "Password Safe database file",
"regex": "\\.psafe3$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.psafe3"]
},
{
"active": true,
"description": "Potential configuration file",
"regex": "\\.yml$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.yml"]
},
{
"active": true,
"description": "Potential cryptographic key bundle",
"regex": "\\.pkcs12$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.pkcs12"]
},
{
"active": true,
"description": "Potential cryptographic key bundle",
"regex": "\\.p12$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.p12"]
},
{
"active": true,
"description": "Potential cryptographic key bundle",
"regex": "\\.pfx$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.pfx"]
},
{
"active": true,
"description": "Potential PGP public keyring",
"regex": "\\.pkr$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.pkr"]
},
{
"active": true,
"description": "Potential PGP secret keyring",
"regex": "\\.skr$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.skr"]
},
{
"active": true,
"description": "Potential cryptographic key bundle",
"regex": "\\.asc$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.asc"]
},
{
"active": true,
"description": "Potential cryptographic private key",
"regex": "\\.pem$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.pem"]
},
{
"active": true,
"description": "Potential private key",
- "regex": "otr.private_key$",
- "sections": ["req_url"]
+ "regex": "\\.private_key$",
+ "sections": ["req_url"],
+ "tests": ["otr.private_key", "test_file.private_key"]
},
{
"active": true,
"description": "Presentation file",
"regex": "\\.pptx$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.pptx"]
},
{
"active": true,
"description": "Presentation file",
"regex": "\\.ppt$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.ppt"]
},
{
"active": true,
"description": "Python file",
"regex": "\\.py$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.py"]
},
{
"active": true,
"description": "Remote Desktop connection file",
"regex": "\\.rdp$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.rdp"]
},
{
"active": true,
"description": "Ruby On Rails file",
"regex": "\\.rb$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.rb"]
},
{
"active": true,
"description": "SQLite database file",
"regex": "\\.sqlite$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.sqlite"]
},
{
"active": true,
"description": "SQLite3 database file",
"regex": "\\.sqlite3$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.sqlite3"]
},
{
"active": true,
"description": "Sequel Pro MySQL database manager bookmark file",
"regex": "\\.plist$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.plist"]
},
{
"active": true,
"description": "Shell configuration file",
"regex": "\\.exports$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.exports"]
},
{
"active": true,
"description": "Shell configuration file",
"regex": "\\.functions$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.functions"]
},
{
"active": true,
"description": "Shell configuration file",
"regex": "\\.extra$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.extra"]
},
{
"active": true,
"description": "Temporary file",
"regex": "\\.tmp$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.tmp"]
},
{
"active": true,
"description": "Terraform variable config file",
- "regex": "\\terraform.tfvars$",
- "sections": ["req_url"]
+ "regex": "terraform\\.tfvars$",
+ "sections": ["req_url"],
+ "tests": ["terraform.tfvars"]
},
{
"active": true,
"description": "Text file",
"regex": "\\.txt$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.txt"]
},
{
"active": true,
"description": "Tunnelblick VPN configuration file",
"regex": "\\.tblk$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.tblk"]
},
{
"active": true,
"description": "Windows BitLocker full volume encrypted data file",
"regex": "\\.fve$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.fve"]
},
{
"active": true,
"description": "XML file",
"regex": "\\.xml$",
- "sections": ["req_url"]
+ "sections": ["req_url"],
+ "tests": ["test_file.xml"]
}
]
diff --git a/src/main/resources/regexes/regex_general.jsonc b/src/main/resources/regexes/regex_general.jsonc
index 91e6e87..ff17af4 100644
--- a/src/main/resources/regexes/regex_general.jsonc
+++ b/src/main/resources/regexes/regex_general.jsonc
@@ -2,27 +2,51 @@
{
"active": true,
"description": "Encapsulation boundary for data such as keys and certificates",
- "regex": "-----BEGIN"
+ "regex": "-----BEGIN",
+ "tests": [
+ "-----BEGIN CERTIFICATE-----",
+ "-----BEGIN RSA PRIVATE KEY-----",
+ "-----BEGIN PRIVATE KEY-----"
+ ]
},
{
"active": true,
"description": "Generic API Key",
- "regex": "(?i)api.{0,5}key[^&|;?,]{0,32}?['\\\"][a-zA-Z0-9_\\-+=\\/\\\\]{10,}['\\\"]"
+ "regex": "(?i)api.{0,5}key[^&|;?,]{0,32}?['\\\"][a-zA-Z0-9_\\-+=\\/\\\\]{10,}['\\\"]",
+ "tests":[
+ "{backend_api_key:\"ABCDEFGH/12\"}",
+ "{\"apikey_mail\" : 'ABCDEFGH=12'}",
+ "{\"mail_apikey\" : \"ABCDEFGH-12\"}"
+ ]
},
{
"active": true,
"description": "Generic Secret",
- "regex": "(?i)secret[^&|;?,]{0,32}?['\\\"][a-zA-Z0-9_\\-+=\\/\\\\]{10,}['\\\"]"
+ "regex": "(?i)secret[^&|;?,]{0,32}?['\\\"][a-zA-Z0-9_\\-+=\\/\\\\]{10,}['\\\"]",
+ "tests":[
+ "{\"my_secret_key\":\"ABCDEFGH12\"}",
+ "{'my_super_secret' : 'ABCDEFGH-12'}"
+ ]
},
{
// Try to match only IPs and not section numbers of js libraries
"active": true,
"description": "IP Address",
- "regex": "(? generalRegexList = List.of();
+ private final List extensionsRegexList = List.of();
+ private RegexScanner regexScanner;
+ private BurpExtenderCallbacksMock burpExtenderCallbacks;
+ private ExtensionHelpersMock extensionHelpers;
+ private ScannerOptions scannerOptions;
+
+ private static void accept(Integer integer) {
+ }
+
+ private byte[] B(String str) {
+ return str.getBytes(StandardCharsets.UTF_8);
+ }
+
+ private HttpRequestResponseMock HRR(String req, String res) {
+ return new HttpRequestResponseMock(B(req), B(res));
+ }
+
+ @BeforeEach
+ void setUp() {
+ extensionHelpers = new ExtensionHelpersMock();
+ //TODO missing way to test url & headers
+ extensionHelpers.setAnalyzeRequestFunction(httpRequestResponse -> {
+ try {
+ return new RequestInfoMock(List.of(), new URL("https://null"));
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ //TODO missing way to test headers
+ extensionHelpers.setAnalyzeResponseFunction(response -> new ResponseInfoMock(List.of()));
+ extensionHelpers.setBytesToStringFunction(bytes -> new String(bytes, StandardCharsets.UTF_8));
+ burpExtenderCallbacks = new BurpExtenderCallbacksMock();
+ burpExtenderCallbacks.setHelpers(extensionHelpers);
+
+ scannerOptions = new ScannerOptions();
+ scannerOptions.setConfigMaxResponseSize(10000000);
+ scannerOptions.setConfigNumberOfThreads(1);
+ scannerOptions.setFilterInScopeCheckbox(false);
+ scannerOptions.setFilterSkipMaxSizeCheckbox(false);
+ scannerOptions.setFilterSkipMediaTypeCheckbox(false);
+
+ this.regexScanner = new RegexScanner(burpExtenderCallbacks, scannerOptions, generalRegexList, extensionsRegexList);
+ }
+
+ @Test
+ void testAnalysisOfGeneralRegexes() {
+ final List logEntities = new ArrayList<>();
+ final Object loggerLock = new Object();
+
+ // set-up callbacks
+ Consumer itemAnalyzedCallback = RegexScannerTest::accept;
+ Consumer logEntityConsumer = logEntity -> {
+ synchronized (loggerLock) {
+ logEntities.add(logEntity);
+ }
+ };
+ // set-up BurpExtenderCallbacks
+ this.burpExtenderCallbacks.setIsInScopePredicate(url -> true);
+ HttpRequestResponseMock[] proxyHistory = {
+ HRR("testing", "testing")
+ };
+ this.burpExtenderCallbacks.setProxyHistory(proxyHistory);
+
+ // test 1
+ logEntities.clear();
+ this.regexScanner = new RegexScanner(this.burpExtenderCallbacks, this.scannerOptions,
+ List.of(
+ new RegexEntity("Match test string", "test", true, ProxyItemSection.ALL)
+ ),
+ List.of());
+ regexScanner.analyzeProxyHistory(itemAnalyzedCallback, logEntityConsumer);
+ assertThat(logEntities).as("Check count of entries found").hasSize(2);
+
+ // test 2
+ logEntities.clear();
+ this.regexScanner = new RegexScanner(this.burpExtenderCallbacks, this.scannerOptions,
+ List.of(
+ new RegexEntity("Match random string", "random", true, ProxyItemSection.ALL)
+ ),
+ List.of());
+ regexScanner.analyzeProxyHistory(itemAnalyzedCallback, logEntityConsumer);
+ assertThat(logEntities).as("Check count of entries found").hasSize(0);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/cys4/sensitivediscoverer/RegexSeederTest.java b/src/test/java/com/cys4/sensitivediscoverer/RegexSeederTest.java
new file mode 100644
index 0000000..7a63f8d
--- /dev/null
+++ b/src/test/java/com/cys4/sensitivediscoverer/RegexSeederTest.java
@@ -0,0 +1,48 @@
+package com.cys4.sensitivediscoverer;
+
+import com.cys4.sensitivediscoverer.model.RegexEntity;
+import org.assertj.core.api.Condition;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class RegexSeederTest {
+ private final Condition positiveMatch = new Condition<>(s -> !(s.startsWith("!")), "positive match");
+
+ /**
+ * Assert that each regex in the list has at least one test string and also assert that each test string matches correctly
+ * @param regexList The regex list
+ */
+ private void testRegexList(List regexList) {
+ assertThat(regexList)
+ .isNotEmpty()
+ .allSatisfy(regex -> {
+ assertThat(regex.getTests())
+ .as("%s", regex.getDescription())
+ .isNotEmpty()
+ .haveAtLeastOne(positiveMatch)
+ .allSatisfy(s -> {
+ if (s.startsWith("!"))
+ assertThat(s.substring(1))
+ .isNotEmpty()
+ .doesNotContainPattern(regex.getRegexCompiled());
+ else
+ assertThat(s)
+ .isNotEmpty()
+ .containsPattern(regex.getRegexCompiled());
+ });
+ });
+ }
+
+ @Test
+ public void generalRegexesMatching() {
+ testRegexList(RegexSeeder.getGeneralRegexes());
+ }
+
+ @Test
+ public void extensionRegexesMatching() {
+ testRegexList(RegexSeeder.getExtensionRegexes());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/cys4/sensitivediscoverer/mock/BurpExtenderCallbacksMock.java b/src/test/java/com/cys4/sensitivediscoverer/mock/BurpExtenderCallbacksMock.java
new file mode 100644
index 0000000..b8a4e03
--- /dev/null
+++ b/src/test/java/com/cys4/sensitivediscoverer/mock/BurpExtenderCallbacksMock.java
@@ -0,0 +1,515 @@
+package com.cys4.sensitivediscoverer.mock;
+
+import burp.*;
+import org.apache.commons.lang3.NotImplementedException;
+
+import java.awt.*;
+import java.io.File;
+import java.io.OutputStream;
+import java.net.URL;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Predicate;
+
+public class BurpExtenderCallbacksMock implements IBurpExtenderCallbacks {
+ private IExtensionHelpers extensionHelpers;
+ private IHttpRequestResponse[] proxyHistory;
+ private Predicate isInScopePredicate;
+
+ @Override
+ public IExtensionHelpers getHelpers() {
+ return extensionHelpers;
+ }
+
+ public void setHelpers(IExtensionHelpers extensionHelpers) {
+ this.extensionHelpers = extensionHelpers;
+ }
+
+ @Override
+ public IHttpRequestResponse[] getProxyHistory() {
+ return proxyHistory;
+ }
+
+ public void setProxyHistory(IHttpRequestResponse[] proxyHistory) {
+ this.proxyHistory = proxyHistory;
+ }
+
+ @Override
+ public boolean isInScope(URL url) {
+ return isInScopePredicate.test(url);
+ }
+
+ public void setIsInScopePredicate(Predicate isInScopePredicate) {
+ this.isInScopePredicate = isInScopePredicate;
+ }
+
+ @Override
+ public void addSuiteTab(ITab tab) {
+ if (Objects.isNull(tab)) throw new IllegalArgumentException("Tab is null");
+ }
+
+ @Override
+ public void customizeUiComponent(Component component) {
+ }
+
+ @Override
+ public OutputStream getStdout() {
+ return System.out;
+ }
+
+ @Override
+ public OutputStream getStderr() {
+ return System.err;
+ }
+
+ @Override
+ public ITextEditor createTextEditor() {
+ return new TextEditorMock();
+ }
+
+ @Override
+ public void setExtensionName(String s) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void printOutput(String s) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void printError(String s) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void registerExtensionStateListener(IExtensionStateListener iExtensionStateListener) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List getExtensionStateListeners() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void removeExtensionStateListener(IExtensionStateListener iExtensionStateListener) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void registerHttpListener(IHttpListener iHttpListener) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List getHttpListeners() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void removeHttpListener(IHttpListener iHttpListener) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void registerProxyListener(IProxyListener iProxyListener) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List getProxyListeners() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void removeProxyListener(IProxyListener iProxyListener) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void registerScannerListener(IScannerListener iScannerListener) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List getScannerListeners() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void removeScannerListener(IScannerListener iScannerListener) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void registerScopeChangeListener(IScopeChangeListener iScopeChangeListener) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List getScopeChangeListeners() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void removeScopeChangeListener(IScopeChangeListener iScopeChangeListener) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void registerContextMenuFactory(IContextMenuFactory iContextMenuFactory) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List getContextMenuFactories() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void removeContextMenuFactory(IContextMenuFactory iContextMenuFactory) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void registerMessageEditorTabFactory(IMessageEditorTabFactory iMessageEditorTabFactory) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List getMessageEditorTabFactories() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void removeMessageEditorTabFactory(IMessageEditorTabFactory iMessageEditorTabFactory) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void registerScannerInsertionPointProvider(IScannerInsertionPointProvider iScannerInsertionPointProvider) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List getScannerInsertionPointProviders() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void removeScannerInsertionPointProvider(IScannerInsertionPointProvider iScannerInsertionPointProvider) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void registerScannerCheck(IScannerCheck iScannerCheck) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List getScannerChecks() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void removeScannerCheck(IScannerCheck iScannerCheck) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void registerIntruderPayloadGeneratorFactory(IIntruderPayloadGeneratorFactory iIntruderPayloadGeneratorFactory) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List getIntruderPayloadGeneratorFactories() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void removeIntruderPayloadGeneratorFactory(IIntruderPayloadGeneratorFactory iIntruderPayloadGeneratorFactory) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void registerIntruderPayloadProcessor(IIntruderPayloadProcessor iIntruderPayloadProcessor) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List getIntruderPayloadProcessors() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void removeIntruderPayloadProcessor(IIntruderPayloadProcessor iIntruderPayloadProcessor) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void registerSessionHandlingAction(ISessionHandlingAction iSessionHandlingAction) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List getSessionHandlingActions() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void removeSessionHandlingAction(ISessionHandlingAction iSessionHandlingAction) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void unloadExtension() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void removeSuiteTab(ITab iTab) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IMessageEditor createMessageEditor(IMessageEditorController iMessageEditorController, boolean b) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public String[] getCommandLineArguments() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void saveExtensionSetting(String s, String s1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public String loadExtensionSetting(String s) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void sendToRepeater(String s, int i, boolean b, byte[] bytes, String s1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void sendToIntruder(String s, int i, boolean b, byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void sendToIntruder(String s, int i, boolean b, byte[] bytes, List list) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void sendToComparer(byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void sendToSpider(URL url) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IScanQueueItem doActiveScan(String s, int i, boolean b, byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IScanQueueItem doActiveScan(String s, int i, boolean b, byte[] bytes, List list) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void doPassiveScan(String s, int i, boolean b, byte[] bytes, byte[] bytes1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IHttpRequestResponse makeHttpRequest(IHttpService iHttpService, byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IHttpRequestResponse makeHttpRequest(IHttpService iHttpService, byte[] bytes, boolean b) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] makeHttpRequest(String s, int i, boolean b, byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] makeHttpRequest(String s, int i, boolean b, byte[] bytes, boolean b1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] makeHttp2Request(IHttpService iHttpService, List list, byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] makeHttp2Request(IHttpService iHttpService, List list, byte[] bytes, boolean b) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] makeHttp2Request(IHttpService iHttpService, List list, byte[] bytes, boolean b, String s) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void includeInScope(URL url) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void excludeFromScope(URL url) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void issueAlert(String s) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IHttpRequestResponse[] getSiteMap(String s) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IScanIssue[] getScanIssues(String s) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void generateScanReport(String s, IScanIssue[] iScanIssues, File file) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public List getCookieJarContents() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void updateCookieJar(ICookie iCookie) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void addToSiteMap(IHttpRequestResponse iHttpRequestResponse) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void restoreState(File file) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void saveState(File file) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public Map saveConfig() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void loadConfig(Map map) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public String saveConfigAsJson(String... strings) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void loadConfigFromJson(String s) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void setProxyInterceptionEnabled(boolean b) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public String[] getBurpVersion() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public String getExtensionFilename() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public boolean isExtensionBapp() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void exitSuite(boolean b) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public ITempFile saveToTempFile(byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IHttpRequestResponsePersisted saveBuffersToTempFiles(IHttpRequestResponse iHttpRequestResponse) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IHttpRequestResponseWithMarkers applyMarkers(IHttpRequestResponse iHttpRequestResponse, List list, List list1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public String getToolName(int i) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void addScanIssue(IScanIssue iScanIssue) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IBurpCollaboratorClientContext createBurpCollaboratorClientContext() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public String[][] getParameters(byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public String[] getHeaders(byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void registerMenuItem(String s, IMenuItemHandler iMenuItemHandler) {
+ throw new NotImplementedException();
+ }
+}
diff --git a/src/test/java/com/cys4/sensitivediscoverer/mock/ExtensionHelpersMock.java b/src/test/java/com/cys4/sensitivediscoverer/mock/ExtensionHelpersMock.java
new file mode 100644
index 0000000..5d140c1
--- /dev/null
+++ b/src/test/java/com/cys4/sensitivediscoverer/mock/ExtensionHelpersMock.java
@@ -0,0 +1,172 @@
+package com.cys4.sensitivediscoverer.mock;
+
+import burp.*;
+import org.apache.commons.lang3.NotImplementedException;
+
+import java.net.URL;
+import java.util.List;
+import java.util.function.Function;
+
+public class ExtensionHelpersMock implements IExtensionHelpers {
+ Function analyzeRequestFunction;
+ Function analyzeResponseFunction;
+ Function bytesToStringFunction;
+
+ @Override
+ public IRequestInfo analyzeRequest(IHttpRequestResponse iHttpRequestResponse) {
+ return analyzeRequestFunction.apply(iHttpRequestResponse);
+ }
+
+ public void setAnalyzeRequestFunction(Function analyzeRequestFunction) {
+ this.analyzeRequestFunction = analyzeRequestFunction;
+ }
+
+ @Override
+ public IResponseInfo analyzeResponse(byte[] bytes) {
+ return analyzeResponseFunction.apply(bytes);
+ }
+
+ public void setAnalyzeResponseFunction(Function analyzeResponseFunction) {
+ this.analyzeResponseFunction = analyzeResponseFunction;
+ }
+
+ @Override
+ public String bytesToString(byte[] bytes) {
+ return bytesToStringFunction.apply(bytes);
+ }
+
+ public void setBytesToStringFunction(Function bytesToStringFunction) {
+ this.bytesToStringFunction = bytesToStringFunction;
+ }
+
+
+ @Override
+ public IRequestInfo analyzeRequest(IHttpService iHttpService, byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IRequestInfo analyzeRequest(byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IParameter getRequestParameter(byte[] bytes, String s) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public String urlDecode(String s) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public String urlEncode(String s) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] urlDecode(byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] urlEncode(byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] base64Decode(String s) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] base64Decode(byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public String base64Encode(String s) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public String base64Encode(byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] stringToBytes(String s) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public int indexOf(byte[] bytes, byte[] bytes1, boolean b, int i, int i1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] buildHttpMessage(List list, byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] buildHttpRequest(URL url) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] addParameter(byte[] bytes, IParameter iParameter) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] removeParameter(byte[] bytes, IParameter iParameter) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] updateParameter(byte[] bytes, IParameter iParameter) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] toggleRequestMethod(byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IHttpService buildHttpService(String s, int i, String s1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IHttpService buildHttpService(String s, int i, boolean b) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IParameter buildParameter(String s, String s1, byte b) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IHttpHeader buildHeader(String s, String s1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IScannerInsertionPoint makeScannerInsertionPoint(String s, byte[] bytes, int i, int i1) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IResponseVariations analyzeResponseVariations(byte[]... bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IResponseKeywords analyzeResponseKeywords(List list, byte[]... bytes) {
+ throw new NotImplementedException();
+ }
+}
diff --git a/src/test/java/com/cys4/sensitivediscoverer/mock/HttpRequestResponseMock.java b/src/test/java/com/cys4/sensitivediscoverer/mock/HttpRequestResponseMock.java
new file mode 100644
index 0000000..f11e169
--- /dev/null
+++ b/src/test/java/com/cys4/sensitivediscoverer/mock/HttpRequestResponseMock.java
@@ -0,0 +1,66 @@
+package com.cys4.sensitivediscoverer.mock;
+
+import burp.IHttpRequestResponse;
+import burp.IHttpService;
+import org.apache.commons.lang3.NotImplementedException;
+
+public class HttpRequestResponseMock implements IHttpRequestResponse {
+ byte[] request;
+ byte[] response;
+ IHttpService httpServiceMock = new HttpServiceMock();
+
+ public HttpRequestResponseMock(byte[] request, byte[] response) {
+ this.request = request;
+ this.response = response;
+ }
+
+ @Override
+ public byte[] getRequest() {
+ return this.request;
+ }
+
+ @Override
+ public void setRequest(byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public IHttpService getHttpService() {
+ return this.httpServiceMock;
+ }
+
+ @Override
+ public void setHttpService(IHttpService iHttpService) {
+ this.httpServiceMock = iHttpService;
+ }
+
+ @Override
+ public byte[] getResponse() {
+ return this.response;
+ }
+
+ @Override
+ public void setResponse(byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public String getComment() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void setComment(String s) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public String getHighlight() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void setHighlight(String s) {
+ throw new NotImplementedException();
+ }
+}
diff --git a/src/test/java/com/cys4/sensitivediscoverer/mock/HttpServiceMock.java b/src/test/java/com/cys4/sensitivediscoverer/mock/HttpServiceMock.java
new file mode 100644
index 0000000..307fd4a
--- /dev/null
+++ b/src/test/java/com/cys4/sensitivediscoverer/mock/HttpServiceMock.java
@@ -0,0 +1,21 @@
+package com.cys4.sensitivediscoverer.mock;
+
+import burp.IHttpService;
+
+public class HttpServiceMock implements IHttpService {
+
+ @Override
+ public String getHost() {
+ return "test.com";
+ }
+
+ @Override
+ public int getPort() {
+ return 443;
+ }
+
+ @Override
+ public String getProtocol() {
+ return "https";
+ }
+}
diff --git a/src/test/java/com/cys4/sensitivediscoverer/mock/RequestInfoMock.java b/src/test/java/com/cys4/sensitivediscoverer/mock/RequestInfoMock.java
new file mode 100644
index 0000000..12190ba
--- /dev/null
+++ b/src/test/java/com/cys4/sensitivediscoverer/mock/RequestInfoMock.java
@@ -0,0 +1,51 @@
+package com.cys4.sensitivediscoverer.mock;
+
+import burp.IParameter;
+import burp.IRequestInfo;
+
+import java.net.URL;
+import java.util.List;
+
+public class RequestInfoMock implements IRequestInfo {
+ List headers;
+ URL url;
+
+ public RequestInfoMock(List headers, URL url) {
+ this.headers = headers;
+ this.url = url;
+ }
+
+ @Override
+ public URL getUrl() {
+ return this.url;
+ }
+
+ @Override
+ public List getHeaders() {
+ return this.headers;
+ }
+
+ @Override
+ public int getBodyOffset() {
+ // request only contains the body. The headers are set manually
+ return 0;
+ }
+
+ @Override
+ public byte getContentType() {
+ // don't care
+ return 0;
+ }
+
+ @Override
+ public String getMethod() {
+ // don't care
+ return null;
+ }
+
+ @Override
+ public List getParameters() {
+ // don't care
+ return null;
+ }
+}
diff --git a/src/test/java/com/cys4/sensitivediscoverer/mock/ResponseInfoMock.java b/src/test/java/com/cys4/sensitivediscoverer/mock/ResponseInfoMock.java
new file mode 100644
index 0000000..2ce0939
--- /dev/null
+++ b/src/test/java/com/cys4/sensitivediscoverer/mock/ResponseInfoMock.java
@@ -0,0 +1,49 @@
+package com.cys4.sensitivediscoverer.mock;
+
+import burp.ICookie;
+import burp.IResponseInfo;
+
+import java.util.List;
+
+public class ResponseInfoMock implements IResponseInfo {
+ List headers;
+
+ public ResponseInfoMock(List headers) {
+ this.headers = headers;
+ }
+
+ @Override
+ public List getHeaders() {
+ return this.headers;
+ }
+
+ @Override
+ public int getBodyOffset() {
+ // response only contains the body. The headers are set manually
+ return 0;
+ }
+
+ @Override
+ public short getStatusCode() {
+ // don't care
+ return 200;
+ }
+
+ @Override
+ public List getCookies() {
+ // don't care
+ return null;
+ }
+
+ @Override
+ public String getStatedMimeType() {
+ // don't care
+ return "TEST";
+ }
+
+ @Override
+ public String getInferredMimeType() {
+ // don't care
+ return "TEST";
+ }
+}
diff --git a/src/test/java/com/cys4/sensitivediscoverer/mock/TextEditorMock.java b/src/test/java/com/cys4/sensitivediscoverer/mock/TextEditorMock.java
new file mode 100644
index 0000000..ee5ef7a
--- /dev/null
+++ b/src/test/java/com/cys4/sensitivediscoverer/mock/TextEditorMock.java
@@ -0,0 +1,49 @@
+package com.cys4.sensitivediscoverer.mock;
+
+import burp.ITextEditor;
+import org.apache.commons.lang3.NotImplementedException;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class TextEditorMock implements ITextEditor {
+ @Override
+ public Component getComponent() {
+ return new JPanel();
+ }
+
+ @Override
+ public void setEditable(boolean b) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] getText() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void setText(byte[] bytes) {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public boolean isTextModified() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public byte[] getSelectedText() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public int[] getSelectionBounds() {
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void setSearchExpression(String s) {
+ throw new NotImplementedException();
+ }
+}
diff --git a/src/test/java/com/cys4/sensitivediscoverer/model/RegexEntityTest.java b/src/test/java/com/cys4/sensitivediscoverer/model/RegexEntityTest.java
new file mode 100644
index 0000000..1bc4480
--- /dev/null
+++ b/src/test/java/com/cys4/sensitivediscoverer/model/RegexEntityTest.java
@@ -0,0 +1,81 @@
+package com.cys4.sensitivediscoverer.model;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.EnumSet;
+import java.util.regex.Matcher;
+
+import static org.assertj.core.api.Assertions.*;
+
+class RegexEntityTest {
+
+ @Test
+ void testInvalidRegexConstructor() {
+ assertThatExceptionOfType(IllegalArgumentException.class)
+ .isThrownBy(() -> new RegexEntity("desc", ""));
+ assertThatExceptionOfType(IllegalArgumentException.class)
+ .isThrownBy(() -> new RegexEntity("desc", null));
+ assertThatNoException().isThrownBy(() -> new RegexEntity("desc", "^regex$"));
+ }
+
+ @Test
+ void testInvalidSectionsConstructor() {
+ assertThatExceptionOfType(IllegalArgumentException.class)
+ .isThrownBy(() ->
+ new RegexEntity("desc", "^regex$", true, null));
+ assertThatNoException()
+ .isThrownBy(() ->
+ new RegexEntity("desc", "^regex$", true, EnumSet.of(ProxyItemSection.RES_BODY, ProxyItemSection.REQ_BODY)));
+ }
+
+ @Test
+ void testDefaultRegexIsActive() {
+ RegexEntity entity = new RegexEntity("desc", "regex");
+ assertThat(entity.isActive()).isTrue();
+ }
+
+ @Test
+ void testActiveFlag() {
+ RegexEntity entity;
+
+ entity = new RegexEntity("desc", "regex", true);
+ assertThat(entity.isActive()).isTrue();
+
+ entity = new RegexEntity("desc", "regex", false);
+ assertThat(entity.isActive()).isFalse();
+
+ entity = new RegexEntity("desc", "regex", true);
+ entity.setActive(false);
+ assertThat(entity.isActive()).isFalse();
+ entity.setActive(true);
+ assertThat(entity.isActive()).isTrue();
+ }
+
+ @Test
+ void checkRegexEntityFromCSV() {
+ Matcher csvMatcher = RegexEntity.checkRegexEntityFromCSV("\"description\",\"regex\",\"SECTION_1,SECTION_2\"");
+ assertThat(csvMatcher.find()).isTrue();
+ assertThat(csvMatcher.groupCount()).isEqualTo(3);
+ assertThat(csvMatcher.group(1)).isEqualTo("description");
+ assertThat(csvMatcher.group(2)).isEqualTo("regex");
+ assertThat(csvMatcher.group(3)).isEqualTo("SECTION_1,SECTION_2");
+ }
+
+ @Test
+ void getSectionsHumanReadable() {
+ RegexEntity entity;
+ EnumSet sections;
+
+ sections = ProxyItemSection.ALL;
+ entity = new RegexEntity("desc", "regex", true, sections);
+ assertThat(entity.getSectionsHumanReadable()).isEqualTo("REQ[URL, Headers, Body], RES[Headers, Body]");
+
+ sections = EnumSet.of(ProxyItemSection.RES_BODY);
+ entity = new RegexEntity("desc", "regex", true, sections);
+ assertThat(entity.getSectionsHumanReadable()).isEqualTo("RES[Body]");
+
+ sections = EnumSet.of(ProxyItemSection.REQ_HEADERS, ProxyItemSection.REQ_BODY);
+ entity = new RegexEntity("desc", "regex", true, sections);
+ assertThat(entity.getSectionsHumanReadable()).isEqualTo("REQ[Headers, Body]");
+ }
+}
\ No newline at end of file