diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 33ec7bf..feb5e19 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,4 +1,5 @@
-#Sun Apr 15 14:52:35 CDT 2018
+# suppress inspection "UnusedProperty" for whole file
+#Wed Apr 18 08:19:13 CDT 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
diff --git a/keecrack-cli/src/main/java/com/wbrawner/keecrack/cli/Main.java b/keecrack-cli/src/main/java/com/wbrawner/keecrack/cli/Main.java
index 8c7e307..aa7803a 100644
--- a/keecrack-cli/src/main/java/com/wbrawner/keecrack/cli/Main.java
+++ b/keecrack-cli/src/main/java/com/wbrawner/keecrack/cli/Main.java
@@ -16,6 +16,7 @@
package com.wbrawner.keecrack.cli;
import com.wbrawner.keecrack.lib.Code;
+import com.wbrawner.keecrack.lib.CrackerFactory;
import com.wbrawner.keecrack.lib.KeeCrack;
import com.wbrawner.keecrack.lib.view.CrackingView;
import net.sourceforge.argparse4j.ArgumentParsers;
@@ -71,7 +72,7 @@ public class Main {
Namespace res = parser.parseArgs(args);
isVerbose = res.getBoolean("verbose");
isIncremental = res.getBoolean("incremental");
- KeeCrack keeCrack = KeeCrack.getInstance();
+ KeeCrack keeCrack = new CrackerFactory().getCracker(true);
keeCrack.setCrackingView(new CLICrackingView());
String databasePath = res.getString("database");
diff --git a/keecrack-gui/src/main/java/com/wbrawner/keecrack/gui/CrackingController.java b/keecrack-gui/src/main/java/com/wbrawner/keecrack/gui/CrackingController.java
index 47dd4af..28fdf7b 100644
--- a/keecrack-gui/src/main/java/com/wbrawner/keecrack/gui/CrackingController.java
+++ b/keecrack-gui/src/main/java/com/wbrawner/keecrack/gui/CrackingController.java
@@ -16,6 +16,7 @@
package com.wbrawner.keecrack.gui;
import com.wbrawner.keecrack.lib.Code;
+import com.wbrawner.keecrack.lib.CrackerFactory;
import com.wbrawner.keecrack.lib.KeeCrack;
import com.wbrawner.keecrack.lib.view.CrackingView;
import javafx.application.Platform;
@@ -41,10 +42,11 @@ public class CrackingController implements Initializable, CrackingView {
private Label timeElapsed;
private Stage stage;
+ private KeeCrack keeCrack;
@Override
public void initialize(URL location, ResourceBundle resources) {
- final KeeCrack keeCrack = KeeCrack.getInstance();
+ keeCrack = new CrackerFactory().getCracker(true);
keeCrack.setCrackingView(this);
new Thread(keeCrack::attack).start();
}
@@ -88,7 +90,6 @@ public class CrackingController implements Initializable, CrackingView {
}
private void onClose() {
- KeeCrack keeCrack = KeeCrack.getInstance();
keeCrack.abort();
keeCrack.setCrackingView(null);
}
diff --git a/keecrack-gui/src/main/java/com/wbrawner/keecrack/gui/MainController.java b/keecrack-gui/src/main/java/com/wbrawner/keecrack/gui/MainController.java
index 93404f0..bb8a207 100644
--- a/keecrack-gui/src/main/java/com/wbrawner/keecrack/gui/MainController.java
+++ b/keecrack-gui/src/main/java/com/wbrawner/keecrack/gui/MainController.java
@@ -16,6 +16,7 @@
package com.wbrawner.keecrack.gui;
import com.wbrawner.keecrack.lib.Code;
+import com.wbrawner.keecrack.lib.CrackerFactory;
import com.wbrawner.keecrack.lib.KeeCrack;
import com.wbrawner.keecrack.lib.view.FormView;
import javafx.fxml.FXML;
@@ -48,7 +49,6 @@ public class MainController implements Initializable, FormView {
private TextField wordlist;
@FXML
private Button crackButton;
- @FXML
private ToggleGroup wordlistType;
@FXML
private RadioButton wordlistFile;
@@ -57,10 +57,10 @@ public class MainController implements Initializable, FormView {
@Override
public void initialize(URL location, ResourceBundle resources) {
- keeCrack = KeeCrack.getInstance();
+ keeCrack = new CrackerFactory().getCracker(true);
keeCrack.setFormView(this);
database.setOnMouseClicked(event -> {
- if (KeeCrack.getInstance().isCracking()) {
+ if (keeCrack.isCracking()) {
return;
}
@@ -69,7 +69,7 @@ public class MainController implements Initializable, FormView {
});
key.setOnMouseClicked(event -> {
- if (KeeCrack.getInstance().isCracking()) {
+ if (keeCrack.isCracking()) {
return;
}
@@ -81,7 +81,7 @@ public class MainController implements Initializable, FormView {
crackButton.setOnMouseClicked(event -> {
try {
- if (KeeCrack.getInstance().isCracking()) {
+ if (keeCrack.isCracking()) {
return;
}
Stage stage = new Stage();
@@ -107,13 +107,16 @@ public class MainController implements Initializable, FormView {
e.printStackTrace();
}
});
+ if (wordlistType == null)
+ wordlistType = new ToggleGroup();
+ wordlistFile.setToggleGroup(wordlistType);
+ wordlistPattern.setToggleGroup(wordlistType);
wordlistType.selectedToggleProperty().addListener((observableValue, oldToggle, newToggle) ->
updateWordListHandler());
if (keeCrack.getDatabaseFile() != null)
onDatabaseFileSet(keeCrack.getDatabaseFile().getName());
if (keeCrack.getKeyFile() != null)
- onKeyFileSet(keeCrack.getKeyFile().getName());
if (keeCrack.getWordListName() != null)
onWordListSet(keeCrack.getWordListName());
}
@@ -127,7 +130,7 @@ public class MainController implements Initializable, FormView {
new FileChooser.ExtensionFilter(description, extensions)
);
Stage stage = new Stage();
- stage.setOnHidden(e -> KeeCrack.getInstance().setFormView(null));
+ stage.setOnHidden(e -> keeCrack.setFormView(null));
return fileChooser.showOpenDialog(stage);
}
@@ -137,7 +140,7 @@ public class MainController implements Initializable, FormView {
wordlist.setEditable(false);
wordlist.setCursor(Cursor.HAND);
wordlist.setOnMouseClicked(event -> {
- if (KeeCrack.getInstance().isCracking()) {
+ if (keeCrack.isCracking()) {
return;
}
File wordlistFile = getFile("Text Files", "txt");
diff --git a/keecrack-gui/src/main/resources/fxml/main.fxml b/keecrack-gui/src/main/resources/fxml/main.fxml
index e8b4347..41cff57 100644
--- a/keecrack-gui/src/main/resources/fxml/main.fxml
+++ b/keecrack-gui/src/main/resources/fxml/main.fxml
@@ -69,12 +69,8 @@
-
-
-
-
+
diff --git a/keecrack-lib/src/main/java/com/wbrawner/keecrack/lib/CrackerFactory.java b/keecrack-lib/src/main/java/com/wbrawner/keecrack/lib/CrackerFactory.java
new file mode 100644
index 0000000..cccdc8c
--- /dev/null
+++ b/keecrack-lib/src/main/java/com/wbrawner/keecrack/lib/CrackerFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2018 William Brawner
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.wbrawner.keecrack.lib;
+
+/**
+ * Class responsible for acquiring a {@link KeeCrack} instance
+ */
+public class CrackerFactory {
+ private static final Object singletonLock = new Object();
+ private static KeeCrack singleton;
+
+ public KeeCrack getCracker(boolean asSingleton) {
+ if (asSingleton) {
+ synchronized (singletonLock) {
+ if (singleton == null) {
+ singleton = new KeeCrack();
+ }
+ return singleton;
+ }
+ }
+ return new KeeCrack();
+ }
+}
diff --git a/keecrack-lib/src/main/java/com/wbrawner/keecrack/lib/KeeCrack.java b/keecrack-lib/src/main/java/com/wbrawner/keecrack/lib/KeeCrack.java
index aca7177..305c00b 100644
--- a/keecrack-lib/src/main/java/com/wbrawner/keecrack/lib/KeeCrack.java
+++ b/keecrack-lib/src/main/java/com/wbrawner/keecrack/lib/KeeCrack.java
@@ -31,11 +31,11 @@ import java.util.concurrent.atomic.AtomicReference;
/**
* The main class responsible for handling the brute forcing of the KeePass database. You do not contruct the
- * KeeCrack instance directly, but rather call {@link #getInstance()}. To begin, you should set the form view and
- * cracking view with {@link #setFormView(FormView)} and {@link #setCrackingView(CrackingView)} respectively. These
- * views will be responsible for displaying information like error messages and status updates. The cracking will
- * work without these, though it's highly recommended to set them prior to beginning. The database and wordlist must
- * be set, while the key file is also optional. If either of the required parameters are missing, the
+ * KeeCrack instance directly, but rather call {@link CrackerFactory#getCracker(boolean)}. To begin, you should set the
+ * form view and cracking view with {@link #setFormView(FormView)} and {@link #setCrackingView(CrackingView)}
+ * respectively. These views will be responsible for displaying information like error messages and status updates.
+ * The cracking will work without these, though it's highly recommended to set them prior to beginning. The database
+ * and wordlist must be set, while the key file is also optional. If either of the required parameters are missing, the
* {@link #attack()} operation will abort, sending either {@link Code#ERROR_INVALID_DATABASE_FILE} or
* {@link Code#ERROR_INVALID_WORD_LIST}, respectively. The word list can either be a pattern, in which case
* incremental guessing will take place, or a file, in which case each line of the file will be considered a password
@@ -49,7 +49,6 @@ import java.util.concurrent.atomic.AtomicReference;
* first parameter will be null.
*/
public class KeeCrack {
- private static final AtomicReference singleton = new AtomicReference<>(null);
private final Object keyFileLock = new Object();
private final AtomicBoolean isCracking = new AtomicBoolean(false);
/**
@@ -65,27 +64,10 @@ public class KeeCrack {
private WordList wordList;
private int guessCount = 0;
- private KeeCrack() {
- }
-
- public static KeeCrack getInstance() {
- if (singleton.get() == null) {
- singleton.set(new KeeCrack());
- }
-
- return singleton.get();
- }
-
/**
- * Call this to reset the state of the KeeCrack instance. Note that you will need to set the views again after
- * calling this
+ * To get an instance of the class, use the {@link CrackerFactory}
*/
- public void reset() {
- setDatabaseFile(null);
- setKeyFile(null);
- setWordListFile(null);
- setCrackingView(null);
- setFormView(null);
+ KeeCrack() {
}
public void abort() {
diff --git a/keecrack-lib/src/test/java/com/wbrawner/keecrack/lib/KeeCrackTest.java b/keecrack-lib/src/test/java/com/wbrawner/keecrack/lib/KeeCrackTest.java
index e131add..bfc5e35 100644
--- a/keecrack-lib/src/test/java/com/wbrawner/keecrack/lib/KeeCrackTest.java
+++ b/keecrack-lib/src/test/java/com/wbrawner/keecrack/lib/KeeCrackTest.java
@@ -21,13 +21,9 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import java.io.File;
import java.io.IOException;
import java.time.Duration;
-import static junit.framework.TestCase.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
@@ -41,30 +37,14 @@ public class KeeCrackTest {
public void setUp() {
mockCrackingView = mock(CrackingView.class);
mockFormView = mock(FormView.class);
- keeCrack = KeeCrack.getInstance();
+ keeCrack = new CrackerFactory().getCracker(false);
}
@After
public void tearDown() {
- keeCrack.reset();
Utils.rmdir(Utils.getTmpDir());
}
- @Test
- public void resetTest() {
- keeCrack.setDatabaseFile(new File("Database"));
- keeCrack.setKeyFile(new File("Keyfile"));
- keeCrack.setWordListPattern("Some pattern");
- assertNotNull(keeCrack.getDatabaseFile());
- assertNotNull(keeCrack.getKeyFile());
- assertNotNull(keeCrack.getWordList());
- keeCrack.reset();
- assertNull(keeCrack.getDatabaseFile());
- assertNull(keeCrack.getKeyFile());
- assertNull(keeCrack.getWordList());
- assertFalse(keeCrack.isCracking());
- }
-
@Test
public void abortTest() throws IOException {
keeCrack.setDatabaseFile(Utils.getDatabase("123456.kdbx"));