kpcli ってなに?
私はパスワード等の管理はオープンソースソフトウェアの KeePass で行っています.と言うのも,これだと Windows でも Mac でも Android でも ios でも使えるから.
これ,GUI のクライアントで使うのが一般的だと思うのですが,いつも Cygwin のターミナルで生活していますので,出来れば CUI で使えると嬉しい.と言うことで,色々探していたのですが,
だと,perl スクリプトなので何とかなりそう.と言うことで,実際に入れてみた作業記録なのですが,正直
とっても面倒です!
前提
Cygwin は導入済みとしておきます.また,基本的に,Cygwin を UTF-8 で使っているとしておきます.なお,SJIS でも,少しの変更で何とかなるんではないかと思いますが,これは試していません.
必要な perl のライブラリの整備
まず,結構大量に perl のパッケージを準備しないといけません.おまけに,Cygwin の標準パッケージ管理システムから入れられないものも多い.
まずは,Cygwin の標準パッケージに含まれているもので入れないといけないのは,
- perl-Term-ReadLine-Gnu
- perl-TermReadKey
- perl-Clone
- perl-Capture-Tiny
- perl-File-Remove
- perl-Module-ScanDeps
- perl-YAML-tiny
- perl-XML-Parser
です.これは setup-x86_64.exe もしくは,setup-x86.exe から導入してください.
次に,perl の Module の総本山の CPAN から
- Crypt-Rijndael-1.13.tar.gz
- Sort-Naturally-1.03.tar.gz
- File-KeePass-2.03.tar.gz
- Term-ShellUI-0.92.tar.gz
- Module-Install-1.18.tar.gz
- Win32-Clipboard-0.58.tar.gz
- Clipboard-0.13.tar.gz
をダウンロードしてインストールします.普通は,cpan とか cpanm とか使って入れるのだと思いますが,私の場合は /usr/local 以下にパッケージをインストールしたかったのと,cpan でこのディレクトリ以下にインストールする方法がいまいちよく分からなかったので,あえて,手作業で入れています.要するに「古い」入れ方ですね.
どれもほとんど手順は同じですが,その詳細は以下の通りです.
Crypt-Rijndael-1.13.tar.gz
$ cd /usr/local/src $ tar -zxvf Crypt-Rijndael-1.13.tar.gz $ cd Crypt-Rijndael-1.13 $ perl Makefile.PL PREFIX=/usr/local $ make $ make test $ make install
Sort-Naturally-1.03.tar.gz
$ cd /usr/local/src $ tar -zxvf Sort-Naturally-1.03.tar.gz $ cd Sort-Naturally-1.03 $ perl Makefile.PL PREFIX=/usr/local $ make $ make test $ make install
File-KeePass-2.03.tar.gz
$ cd /usr/local/src $ tar -zxvf File-KeePass-2.03.tar.gz $ cd File-KeePass-2.03 $ perl Makefile.PL PREFIX=/usr/local $ make $ make test $ make install
Term-ShellUI-0.92.tar.gz
$ cd /usr/local/src $ tar -zxvf Term-ShellUI-0.92.tar.gz $ cd Term-ShellUI-0.92 $ perl Makefile.PL PREFIX=/usr/local $ make $ make test $ make install
Module-Install-1.18.tar.gz
$ cd /usr/local/src $ tar -zxvf Module-Install-1.18.tar.gz $ cd Module-Install-1.18 $ perl Makefile.PL PREFIX=/usr/local $ make $ make test $ make install
Win32-Clipboard-0.58.tar.gz
$ cd /usr/local/src $ tar -zxvf Win32-Clipboard-0.58.tar.gz $ cd Win32-Clipboard-0.58 $ perl Makefile.PL PREFIX=/usr/local $ make $ make test $ make install
Clipboard-0.13.tar.gz
$ cd /usr/local/src $ tar -zxvf Clipboard-0.13.tar.gz $ cd Clipboard-0.13 $ perl Makefile.PL PREFIX=/usr/local $ make $ make test $ make install
これで準備が整いました.
kpcli の導入
kpcli は単なる perl のスクリプトで,単一のファイルで出来ています.だから,導入は
$ cd /usr/local/bin $ wget https://raw.githubusercontent.com/alecsammon/kpcli/master/kpcli.pl $ chmod +x kpcli.pl
で終了なのですが,このままだと,日本語の取り扱いに問題があります.これを何とかする為に,kpcli.pl の書き換えを行うのですが,Quick Hack なことに注意してください.
オリジナルとの差分は以下の通り.
$ diff -up kpcli.pl.orig kpcli.pl --- kpcli.pl 2017-10-27 21:32:54.526836700 +0900 +++ /usr/local/bin/kpcli.pl 2017-10-27 20:35:16.494521400 +0900 @@ -15,6 +15,12 @@ # ########################################################################### +use Encode; +use utf8; +binmode STDIN, ':encoding(utf8)'; +binmode STDOUT, ':encoding(utf8)'; +binmode STDERR, ':encoding(utf8)'; + # The required perl modules use strict; # core use version; # core @@ -831,7 +837,7 @@ sub cli_pwck { } my @targets = (); - my $target = $params->{args}->[0]; + my $target = decode_utf8($params->{args}->[0]); # Start by trying to find a single entity with the paramter given. # If no single entity is found then try to find entities based on # assuming that the path given is a group. @@ -1009,7 +1015,7 @@ sub cli_cd { if (recent_sigint()) { return undef; } # Bail on SIGINT - my $raw_pathstr = $params->{args}->[0]; + my $raw_pathstr = decode_utf8($params->{args}->[0]); # "cd ." if ($raw_pathstr =~ m/^[.]$/) { return; # nothing to do @@ -1158,7 +1164,7 @@ sub cli_find($) { print "Find only supports searching for one word.\n"; return; } - $search_str = $ARGV[0]; + $search_str = decode_utf8($ARGV[0]); } } @@ -1419,7 +1425,7 @@ sub cli_xN($$) { } # Find the entry that the user wants to copy to the clipboard from. - my $target = $params->{args}->[0]; + my $target = decode_utf8($params->{args}->[0]); my $ent=find_target_entity_by_number_or_path($target); if (! defined($ent)) { print "Don't see an entry at path: $target\n"; @@ -1461,7 +1467,7 @@ sub cli_rm($) { return; } - my $target = $params->{args}->[0]; + my $target = decode_utf8($params->{args}->[0]); my $ent=find_target_entity_by_number_or_path($target); if (! defined($ent)) { print "Don't see an entry at path: $target\n"; @@ -1555,7 +1561,7 @@ sub cli_rename($$) { return; } - my $target_dir = $params->{args}->[0]; + my $target_dir = decode_utf8($params->{args}->[0]); my $dir_normalized=normalize_path_string($target_dir); my $grp=undef; if (defined($state->{all_grp_paths_fwd}->{$dir_normalized})) { @@ -1939,7 +1945,7 @@ sub cli_edit { return; } - my $target = $params->{args}->[0]; + my $target = decode_utf8($params->{args}->[0]); my $ent=find_target_entity_by_number_or_path($target); if (! defined($ent)) { print "Don't see an entry at path: $target\n"; @@ -2509,8 +2515,8 @@ sub cli_new($) { my $new_title=''; # If the user gave us a path (that may include the new title) in args[0], # then we have to first rationalize that path. - if (defined($params->{args}->[0])) { - $new_path = $params->{args}->[0]; + if (defined(decode_utf8($params->{args}->[0]))) { + $new_path = decode_utf8($params->{args}->[0]); # Insure that $new_path is absolute if ($new_path !~ m/^\/+$/) { $new_path = get_pwd() . '/' . $new_path; @@ -3057,7 +3063,7 @@ sub cli_rmdir($) { return; } - my $raw_pathstr=$params->{'args'}->[0]; + my $raw_pathstr=decode_utf8($params->{'args'}->[0]); my ($path,$grp_name) = normalize_and_split_raw_path($raw_pathstr); # Make sure the group exists. @@ -3121,7 +3127,7 @@ sub cli_mkdir($) { return; } - my $raw_pathstr = $params->{args}->[0]; + my $raw_pathstr = decode_utf8($params->{args}->[0]); my ($path,$newdir) = normalize_and_split_raw_path($raw_pathstr); # Make sure the group doesn't already exist. @@ -3420,7 +3426,7 @@ sub cli_attach { return; } - my $target = $params->{args}->[0]; + my $target = decode_utf8($params->{args}->[0]); my $ent=find_target_entity_by_number_or_path($target); if (! defined($ent)) { print "Don't see an entry at path: $target\n";
とりあえずこれで動いてはいますが,現時点で,
- 日本語が含まれる PATH の補間等が上手くいかない
- history が文字化けする
等の問題点が残っています.
kpcli の使い方
単に,kpcli.pl と打つだけです.以下の様な感じで使えます.
$ kpcli.pl KeePass CLI (kpcli) v3.0 is ready for operation. Type 'help' for a description of available commands. Type 'help <command>' for details on individual commands. kpcli:/> open password_file.kdbx Please provide the master password: ************************* kpcli:/> ls === Groups === テスト/ kpcli:/> cl テスト === Entries === 0. test site 1 kpcli:/テスト> show 0 Title: test site 1 Uname: hyt Pass: *********** URL: http://www.google.com Notes: kpcli:/テスト>
かなり直感的に使えますし,分からないときは「 ?」 で各コマンドのヘルプが表示されます.特に便利なのが find で,
kpcli:/> find TESTSITE Searching for "TESTSITE" ... - 1 matches found and placed into /_found/ Would you like to show this entry? [y/N] Path: /テスト/ Title: TESTSITE Uname: hyt Pass: ******** URL: https://testsite Notes: kpcli:/>
の様に表示されるので,あとは,
- xp: Copy password to clipboard
- xu: Copy username to clipboard
- xw: Copy URL (www) to clipboard
等を適宜使えば OKです.
おわりに
KeePass のデータベースにコマンドラインからアクセスするプログラムって,探すと幾つか出てくるのですが,KeePass の ver 1 系列のデータベースしかアクセスできなかったり,使い方が良く分からない,もしくは,使い難かったりするものが多くてイマイチでした.
kpcli もそのままだと日本語が使えなかったので,どんなもんかと思ってましたが,単一ファイルで出来た perl のスクリプトなので,何とかなるかなとやってみたのが本備忘録です.
なお,現在,上手くいっていない部分も直そうかと少しチャレンジして,Term::ShellUI 辺りの問題かなと当たりを付けたのですが,修正は結構面倒そうなので,まぁいいかと今のところ放置しています.
気が向いたらまたやってみようかな……