Cygwin で kpcli を使う備忘録

Environment
Photo by hyt.

kpcli ってなに?

私はパスワード等の管理はオープンソースソフトウェアの KeePass で行っています.と言うのも,これだと Windows でも Mac でも Android でも ios でも使えるから.

KeePass Password Safe
KeePass is a free open source password manager. Passwords can be stored in an encrypted database, which can be unlocked ...

これ,GUI のクライアントで使うのが一般的だと思うのですが,いつも Cygwin のターミナルで生活していますので,出来れば CUI で使えると嬉しい.と言うことで,色々探していたのですが,

GitHub - alecsammon/kpcli: Keepass Cli
Keepass Cli. Contribute to alecsammon/kpcli development by creating an account on GitHub.

だと,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 から

をダウンロードしてインストールします.普通は,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";

とりあえずこれで動いてはいますが,現時点で,

  1. 日本語が含まれる PATH の補間等が上手くいかない
  2. 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 辺りの問題かなと当たりを付けたのですが,修正は結構面倒そうなので,まぁいいかと今のところ放置しています.

気が向いたらまたやってみようかな……

タイトルとURLをコピーしました