資格情報マネージャ読み書きプログラムをNode.jsで作成する
VBA等のスクリプト系は、Windowsの資格情報マネージャに格納されてる情報を直接取得する事が出来ません。かといって、Web API等のアクセスに必要な情報を直書きしたり、そのままレジストリに書き込んで読み書きでは不安です。
そこで今回、Node.js + Keytar + nexeでexeを作成し、コマンドラインの標準出力でVBA側にパスワードを渡す手法を考えてみました。
※正直言って実用的じゃないので、素直に暗号化モジュール使って、暗号/複合を実装したほうがなんぼもマシだと思います
リンク
今回使用するモジュール
今回は、Node.jsにコマンドライン引数を渡して処理し、返り値をDOS窓の標準出力を取得する形で手に入れます。
ソースコード
Node.js側コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
"use strict" //モジュールの読み込み const fs = require('fs'); const keytar = require('keytar'); const commandLineArgs = require('command-line-args'); //コマンドラインオプションを構築 const optionDefinitions = [ { name: 'userid', alias: 'u', type: String }, { name: 'setpass', alias: 's', type: String }, { name: 'getpass', alias: 'g', type: String } ]; const args = commandLineArgs(optionDefinitions); //引数に応じて処理を分岐 var userid = args.userid; if(userid == undefined){ //User ID指定がないので処理を終了 return 0; } //サービス名を構築する var servicename = "kintone_" + userid; //-gオプションの値を取得する var tempargs = args.getpass; if(tempargs == undefined){ //getじゃないのでsetなのか判定 tempargs = args.setpass; if(tempargs == undefined){ //オプション指定がないので処理を終了 return 0; }else{ //パスワードセットの処理を実行 setPassword(servicename,userid,tempargs,function(ret){ console.log(ret); return ret; }); } }else{ //パスワードゲットの処理を実行 getPassword(servicename,userid,function (ret){ console.log(ret); return ret; }) } //パスワードを取得する処理 function getPassword(servicename,userid,callback){ const secret = keytar.getPassword(servicename,userid); secret.then((result) => { return result; }) .then(function(data) { callback(data); return data; }) } //パスワードをセットする処理 function setPassword(servicename,userid,pass,callback){ //パスワードを保存する keytar.setPassword(servicename,userid,pass); //処理完了 callback(1); return 1; } |
- optionDefinitionsにて、コマンドライン引数オプションの-sと-u、-gの場合の処理を用意しています。
- コマンドラインとして、node index.js -u ユーザID -s パスワードとすると、パスワードを資格情報マネージャにセットします。
- コマンドラインとして、node index.js -u ユーザID -g ユーザIDとすると、パスワードを資格情報マネージャからゲットします。
- -gの時の処理、-sの時の処理それぞれを条件分岐で作成します。
- setPasswordでkeytarを使ってパスワードをセットします。
- getPasswordでkeytarを使ってパスワードをゲットします。
- keytar自体、非同期で実行されるので、callbackやthenなどを利用して値を取得後に標準出力で出すようにコードを記述する必要があります。
- servicenameは、利用するウェブサービス等の名称と組み合わせる何か(例えばUser ID)で組み立てます。これを元に資格情報マネージャにセットしたり、取得したりします。
VBA側コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Sub credmanexe() 'WSHの用意 Dim WSH, wExec, sCmd As String, Result As String Set WSH = CreateObject("WScript.Shell") //コマンドラインの組み立てと実行 sCmd = ThisWorkbook.Path & "\creden.exe -u ユーザID -g ユーザID" Set wExec = WSH.Exec("%ComSpec% /c " & sCmd) //ステータスを見てループ Do While wExec.Status = 0 DoEvents Loop //標準出力内容を取得してメッセージボックスで表示 Result = wExec.StdOut.ReadAll MsgBox Result //終了処理 Set wExec = Nothing Set WSH = Nothing End Sub |
- WSHを利用してexecにてコマンドラインを実行しています(今回はとりあえずパスワードの取得の部分だけ)
- StdOut.ReadAllにて標準出力(console.log())に出力された内容を取得しています。
- コマンドプロンプトの画面はexecの場合、非表示に出来ません。しかし、Runの場合今度は標準出力を取得できません。
- VBSを利用したコマンドプロンプト非表示のテクニックがあるので、こちらを利用すると尚良いでしょう。
- パスワード取得とパスワードセットの2つのルーチンに対して、今回のコードを組み込んでおきます。
単一実行ファイルを作成する
Node.js 18よりSingle executable applicationsという機能が装備され、標準で単独実行ファイルが作成できるようになりました。結果pkgはプロジェクト終了となっています。よって、以下のエントリーの単一実行ファイルを作成するを参考に、Node18以降はexeファイルを作成することが可能です。