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"));