Merge pull request #1 from wbrawner/cracker-factory

Implement CrackerFactory
This commit is contained in:
William Brawner 2018-04-18 21:01:38 -05:00 committed by GitHub
commit ed4098983a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 63 additions and 63 deletions

View file

@ -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 distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View file

@ -16,6 +16,7 @@
package com.wbrawner.keecrack.cli; package com.wbrawner.keecrack.cli;
import com.wbrawner.keecrack.lib.Code; import com.wbrawner.keecrack.lib.Code;
import com.wbrawner.keecrack.lib.CrackerFactory;
import com.wbrawner.keecrack.lib.KeeCrack; import com.wbrawner.keecrack.lib.KeeCrack;
import com.wbrawner.keecrack.lib.view.CrackingView; import com.wbrawner.keecrack.lib.view.CrackingView;
import net.sourceforge.argparse4j.ArgumentParsers; import net.sourceforge.argparse4j.ArgumentParsers;
@ -71,7 +72,7 @@ public class Main {
Namespace res = parser.parseArgs(args); Namespace res = parser.parseArgs(args);
isVerbose = res.getBoolean("verbose"); isVerbose = res.getBoolean("verbose");
isIncremental = res.getBoolean("incremental"); isIncremental = res.getBoolean("incremental");
KeeCrack keeCrack = KeeCrack.getInstance(); KeeCrack keeCrack = new CrackerFactory().getCracker(true);
keeCrack.setCrackingView(new CLICrackingView()); keeCrack.setCrackingView(new CLICrackingView());
String databasePath = res.getString("database"); String databasePath = res.getString("database");

View file

@ -16,6 +16,7 @@
package com.wbrawner.keecrack.gui; package com.wbrawner.keecrack.gui;
import com.wbrawner.keecrack.lib.Code; import com.wbrawner.keecrack.lib.Code;
import com.wbrawner.keecrack.lib.CrackerFactory;
import com.wbrawner.keecrack.lib.KeeCrack; import com.wbrawner.keecrack.lib.KeeCrack;
import com.wbrawner.keecrack.lib.view.CrackingView; import com.wbrawner.keecrack.lib.view.CrackingView;
import javafx.application.Platform; import javafx.application.Platform;
@ -41,10 +42,11 @@ public class CrackingController implements Initializable, CrackingView {
private Label timeElapsed; private Label timeElapsed;
private Stage stage; private Stage stage;
private KeeCrack keeCrack;
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
final KeeCrack keeCrack = KeeCrack.getInstance(); keeCrack = new CrackerFactory().getCracker(true);
keeCrack.setCrackingView(this); keeCrack.setCrackingView(this);
new Thread(keeCrack::attack).start(); new Thread(keeCrack::attack).start();
} }
@ -88,7 +90,6 @@ public class CrackingController implements Initializable, CrackingView {
} }
private void onClose() { private void onClose() {
KeeCrack keeCrack = KeeCrack.getInstance();
keeCrack.abort(); keeCrack.abort();
keeCrack.setCrackingView(null); keeCrack.setCrackingView(null);
} }

View file

@ -16,6 +16,7 @@
package com.wbrawner.keecrack.gui; package com.wbrawner.keecrack.gui;
import com.wbrawner.keecrack.lib.Code; import com.wbrawner.keecrack.lib.Code;
import com.wbrawner.keecrack.lib.CrackerFactory;
import com.wbrawner.keecrack.lib.KeeCrack; import com.wbrawner.keecrack.lib.KeeCrack;
import com.wbrawner.keecrack.lib.view.FormView; import com.wbrawner.keecrack.lib.view.FormView;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@ -48,7 +49,6 @@ public class MainController implements Initializable, FormView {
private TextField wordlist; private TextField wordlist;
@FXML @FXML
private Button crackButton; private Button crackButton;
@FXML
private ToggleGroup wordlistType; private ToggleGroup wordlistType;
@FXML @FXML
private RadioButton wordlistFile; private RadioButton wordlistFile;
@ -57,10 +57,10 @@ public class MainController implements Initializable, FormView {
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
keeCrack = KeeCrack.getInstance(); keeCrack = new CrackerFactory().getCracker(true);
keeCrack.setFormView(this); keeCrack.setFormView(this);
database.setOnMouseClicked(event -> { database.setOnMouseClicked(event -> {
if (KeeCrack.getInstance().isCracking()) { if (keeCrack.isCracking()) {
return; return;
} }
@ -69,7 +69,7 @@ public class MainController implements Initializable, FormView {
}); });
key.setOnMouseClicked(event -> { key.setOnMouseClicked(event -> {
if (KeeCrack.getInstance().isCracking()) { if (keeCrack.isCracking()) {
return; return;
} }
@ -81,7 +81,7 @@ public class MainController implements Initializable, FormView {
crackButton.setOnMouseClicked(event -> { crackButton.setOnMouseClicked(event -> {
try { try {
if (KeeCrack.getInstance().isCracking()) { if (keeCrack.isCracking()) {
return; return;
} }
Stage stage = new Stage(); Stage stage = new Stage();
@ -107,13 +107,16 @@ public class MainController implements Initializable, FormView {
e.printStackTrace(); e.printStackTrace();
} }
}); });
if (wordlistType == null)
wordlistType = new ToggleGroup();
wordlistFile.setToggleGroup(wordlistType);
wordlistPattern.setToggleGroup(wordlistType);
wordlistType.selectedToggleProperty().addListener((observableValue, oldToggle, newToggle) -> wordlistType.selectedToggleProperty().addListener((observableValue, oldToggle, newToggle) ->
updateWordListHandler()); updateWordListHandler());
if (keeCrack.getDatabaseFile() != null) if (keeCrack.getDatabaseFile() != null)
onDatabaseFileSet(keeCrack.getDatabaseFile().getName()); onDatabaseFileSet(keeCrack.getDatabaseFile().getName());
if (keeCrack.getKeyFile() != null) if (keeCrack.getKeyFile() != null)
onKeyFileSet(keeCrack.getKeyFile().getName());
if (keeCrack.getWordListName() != null) if (keeCrack.getWordListName() != null)
onWordListSet(keeCrack.getWordListName()); onWordListSet(keeCrack.getWordListName());
} }
@ -127,7 +130,7 @@ public class MainController implements Initializable, FormView {
new FileChooser.ExtensionFilter(description, extensions) new FileChooser.ExtensionFilter(description, extensions)
); );
Stage stage = new Stage(); Stage stage = new Stage();
stage.setOnHidden(e -> KeeCrack.getInstance().setFormView(null)); stage.setOnHidden(e -> keeCrack.setFormView(null));
return fileChooser.showOpenDialog(stage); return fileChooser.showOpenDialog(stage);
} }
@ -137,7 +140,7 @@ public class MainController implements Initializable, FormView {
wordlist.setEditable(false); wordlist.setEditable(false);
wordlist.setCursor(Cursor.HAND); wordlist.setCursor(Cursor.HAND);
wordlist.setOnMouseClicked(event -> { wordlist.setOnMouseClicked(event -> {
if (KeeCrack.getInstance().isCracking()) { if (keeCrack.isCracking()) {
return; return;
} }
File wordlistFile = getFile("Text Files", "txt"); File wordlistFile = getFile("Text Files", "txt");

View file

@ -69,12 +69,8 @@
<HBox.margin> <HBox.margin>
<Insets left="20.0"/> <Insets left="20.0"/>
</HBox.margin> </HBox.margin>
<toggleGroup>
<ToggleGroup fx:id="wordlistType"/>
</toggleGroup>
</RadioButton> </RadioButton>
<RadioButton fx:id="wordlistFile" selected="true" text="From File" <RadioButton fx:id="wordlistFile" selected="true" text="From File">
toggleGroup="wordlistType">
<HBox.margin> <HBox.margin>
<Insets left="20.0"/> <Insets left="20.0"/>
</HBox.margin> </HBox.margin>

View file

@ -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();
}
}

View file

@ -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 * 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 * KeeCrack instance directly, but rather call {@link CrackerFactory#getCracker(boolean)}. To begin, you should set the
* cracking view with {@link #setFormView(FormView)} and {@link #setCrackingView(CrackingView)} respectively. These * form view and cracking view with {@link #setFormView(FormView)} and {@link #setCrackingView(CrackingView)}
* views will be responsible for displaying information like error messages and status updates. The cracking will * respectively. These views will be responsible for displaying information like error messages and status updates.
* work without these, though it's highly recommended to set them prior to beginning. The database and wordlist must * The cracking will work without these, though it's highly recommended to set them prior to beginning. The database
* be set, while the key file is also optional. If either of the required parameters are missing, the * 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 #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 * {@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 * 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. * first parameter will be null.
*/ */
public class KeeCrack { public class KeeCrack {
private static final AtomicReference<KeeCrack> singleton = new AtomicReference<>(null);
private final Object keyFileLock = new Object(); private final Object keyFileLock = new Object();
private final AtomicBoolean isCracking = new AtomicBoolean(false); private final AtomicBoolean isCracking = new AtomicBoolean(false);
/** /**
@ -65,27 +64,10 @@ public class KeeCrack {
private WordList wordList; private WordList wordList;
private int guessCount = 0; 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 * To get an instance of the class, use the {@link CrackerFactory}
* calling this
*/ */
public void reset() { KeeCrack() {
setDatabaseFile(null);
setKeyFile(null);
setWordListFile(null);
setCrackingView(null);
setFormView(null);
} }
public void abort() { public void abort() {

View file

@ -21,13 +21,9 @@ import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.time.Duration; 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.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@ -41,30 +37,14 @@ public class KeeCrackTest {
public void setUp() { public void setUp() {
mockCrackingView = mock(CrackingView.class); mockCrackingView = mock(CrackingView.class);
mockFormView = mock(FormView.class); mockFormView = mock(FormView.class);
keeCrack = KeeCrack.getInstance(); keeCrack = new CrackerFactory().getCracker(false);
} }
@After @After
public void tearDown() { public void tearDown() {
keeCrack.reset();
Utils.rmdir(Utils.getTmpDir()); 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 @Test
public void abortTest() throws IOException { public void abortTest() throws IOException {
keeCrack.setDatabaseFile(Utils.getDatabase("123456.kdbx")); keeCrack.setDatabaseFile(Utils.getDatabase("123456.kdbx"));