Windowsで動くパスワード管理ツールをJavaFXで作る
Windows上のGUIで動作するパスワード管理ツールを作成しました。
まずは必要最低限の機能を持たせました。
- パスワード名称の一覧表示
- 絞り込み機能
- クリップボードへコピー
経緯について
コロナ過に入ってからずっとリモートワークが続き、Slack等で画面を共有しながら作業することがよくあります。
その際にパスワードをメモからコピーするときにさらけ出してしまうのを防ぎたかったからです。
2画面以上のマルチディスプレイであれば共有していないほうのディスプレイでコピーすれば済むんですが、1画面のためそうはいかず...
またWindowsのアプリケーションでも探してみましたが、有償であったり会員登録が必要であったりと、これといったものが無かったのでJavaFxの勉強がてらに作ってみました。
環境
- Windows10
- vscode
- JDK11
プロジェクト作成
-
vscodeを開き「Ctrl+Shift+P」で「Java:Create Java Project...」を選択
-
Project type に No build tools を選択
-
Project を作成する親フォルダを選択
ここでは C:¥workspace を選択 -
Project名を入力
-
以下のような構成でプロジェクトが作成される
-
実行は右上の > ボタン
Terminalに「Hello, World!」が出力されればひとまずOK
ライブラリ
JavaFX SDKダウンロード
JavaでGUIを実装するためのフレームワークです。
Windows版のSDKをダウンロードします。
https://gluonhq.com/products/javafx/
ダウンロード後解凍し、任意のディレクトリに配置します。
ここでは C:\workspace\password-manager-test\lib\javafx へ配置しました。
JavaFX SDKインポート
- vscodeのエクスプローラーから、Java Projectを開く
- Referenced Libraries → +ボタン
- 配置したディレクトリのlibディレクトリまで移動
- *.jarファイルをすべて選択し、Select Jar Librariesでインポート
jackson-databind JAR
https://jar-download.com/artifacts/com.fasterxml.jackson.core/jackson-databind
パスワードの保存ファイルにjsonを採用し、ObjectMapperを使って読み込みたいため、jackson-databind JARをダウンロードし、JacvFXと同様の手順でインポートします。
実行とデバッグの設定
左側メニューの実行とデバッグから「launch.jsonファイルを作成」をクリックします。
以下のようなJSONファイルが作成されるのでconfigurationsの最終行に varArgs を設定します。
{
// IntelliSense を使用して利用可能な属性を学べます。
// 既存の属性の説明をホバーして表示します。
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Launch App",
"request": "launch",
"mainClass": "App",
"projectName": "password-manager-test_5bebe0f2",
// ↓追加行
"vmArgs": "--module-path \"C:\\workspace\\password-manager-test\\lib\\javafx\\lib\" --add-modules javafx.controls,javafx.fxml"
}
]
}
サンプル動作確認
App.java
以下コードをApp.javaに貼り付けて実行し画面が立ち上がればひとまずOKです。
javafxを使って開発する環境が整いました。
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class App extends Application {
public static void main(String[] args) throws Exception {
launch();
}
@Override
public void start(Stage stage) throws Exception {
Label l = new Label("Hello, World!");
Scene scene = new Scene(new StackPane(l), 640, 480);
stage.setScene(scene);
stage.show();
}
}
実装
アプリケーションの実装
App.java
以下のように修正します。
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class App extends Application {
List<Button> buttonList;
Clipboard clipboard;
public static void main(String[] args) throws Exception {
launch();
}
@Override
public void start(Stage stage) throws Exception {
stage.setTitle("Password Manager");
clipboard = Clipboard.getSystemClipboard();
// Jsonデータの読み込み
String json = "";
for (String buff : Files.readAllLines(Paths.get("C:\\workspace\\password-manager-test\\data.json"))) {
json += buff;
}
// JsonデータをMapへ変換するためのオブジェクト
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> data = mapper.readValue(json, new TypeReference<Map<String,Object>>(){});
// 検索テキストボックスの設定
// Key入力時にリアルタイムで検索する
TextField search = new TextField();
search.setOnKeyTyped(new EventHandler<KeyEvent>(){
@Override
public void handle(KeyEvent e) {
String keyword = search.getText().trim();
for (Button button : buttonList) {
if (button.getText().toLowerCase().contains(keyword.toLowerCase())) {
button.setVisible(true);
button.setManaged(true);
} else {
button.setVisible(false);
button.setManaged(false);
}
}
}
});
// 各種ボタンの設定
// クリック時にパスワードをクリップボードにコピーする
buttonList = new ArrayList<>();
int i = 0;
for (String key : data.keySet()) {
Button button = new Button(key);
button.setId(key);
button.setAlignment(Pos.CENTER_LEFT);
button.setUserData(data.get(key.toString()));
button.setOnAction(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent e) {
Button target = (Button) e.getSource();
ClipboardContent content = new ClipboardContent();;
content.putString(target.getUserData().toString());
clipboard.setContent(content);
}
});
buttonList.add(button);
buttonList.get(i).setPrefWidth(480);
i++;
}
// コントロールをパネルにセット
VBox vBox = new VBox();
vBox.setAlignment(Pos.TOP_CENTER);
vBox.setPadding(new Insets(10, 10, 10, 10));
vBox.getChildren().addAll(search);
vBox.getChildren().addAll(buttonList);
Scene scene = new Scene(new ScrollPane(vBox), -1, 600);
stage.setScene(scene);
stage.show();
}
}
データファイル
data.json
パスワードを保存するJSONファイルです。
単純なMapオブジェクトでKey(名称)とValue(パスワード)の組み合わせで構成しています。
{
"mailaddress@test.com":"test1234"
,"Dev-Server password":"dev1234"
,"CMS password 1":"cmspass1"
,"CMS password 2":"cmspass2"
}
動作確認
アプリケーションを実行するとJSONファイルが読み込まれ登録したパスワードの名称が一覧表示されます。
任意のボタンをクリックするとクリップボードへパスワード(Value)がコピーされるので、冒頭の目的はひとまず達成されました。
このままだとvscodeを閉じたり、workspaceを切り替えるとアプリケーションも終了してしまいます。
何かと不便なので、とりあえず次回これをMavenプロジェクトで作り直したいと思います。
コメント
コメントを投稿