パスワードマネージャー
煩雑になりがちなサービスのIDとパスワードを一元管理しましょう!
シェルスクリプトで、簡易なパスワードマネージャーをつくりました。GnuPGを使って、暗号化しています。
環境
- MAC OS
- シェルスクリプト
- ターミナル
ご利用方法
1. GnuPGをインストール/設定
- GnuPG: ファイルを暗号化するための無料ソフトウェアです。
- 下記のコマンドを実行すると、インストールできます。(MAC, Linux環境)
sudo apt install gnupg
2. password_manager.zshをダウンロード
- GitHubリポジト(https://github.com/oshibas/apprentice/tree/main/week3-4/quest) の「<>code」プルダウンから、「Download Zip」をクリック。
3. password_manager.zshを実行
- 下記のコマンドを入力してください。
- ファイルに実行権限を付与し、ファイルを起動します。
chmod +x password_manager.sh
./password_manager.sh
4. 動作内容
- あなたのGPGキーで設定したメールアドレスを入力してください。
- 次の選択肢から入力してください(Add Password/Get Password/Exit)
- 終了したい場合は、 exit と入力してください。
パスワードマネージャーの作り方
難易度別に、3段階をふみました。
ステップ1: パスワードを保存しよう!
ステップ2: パスワードを検索しよう!
ステップ3: パスワードを暗号化しよう!
ステップ1: パスワードを保存しよう!
内容
パスワードを保存する処理
仕様
以下の情報をファイルに保存する。
シェルスクリプトを実行するたび、入力された情報がファイルに追記される。
- サービス名
- ユーザー名
- パスワード
実行時のアウトプット
パスワードマネージャーへようこそ!
サービス名を入力してください:
ユーザー名を入力してください:
パスワードを入力してください:
# 入力が完了したら
Thank you!
ステップ1のbash
#!/bin/bash
echo "パスワードマネージャーへようこそ!"
echo "サービス名を入力してください:"
# サービス名をservice_name変数に代入する
read service_name
echo "ユーザー名を入力してください:"
# ユーザー名をusername変数に代入する
read username
echo "パスワードを入力してください:"
# -s: 入力されたパスワードを表示させない
read -s password
# ユーザーの入力をpass.txtに書き込む
echo "$service_name:$username:$password" >> pass.txt
echo "Thank you!"
ポイント
宣言文:
はじめに、bashで書きますよ~!という宣言文を入れます。
「シェバング」というそうです。
#!/bin/bash
実行時にテキストを表示:
echo
コマンド
例:echo "パスワードマネージャーへようこそ!"
ユーザーから受け取った文字列を、変数に代入:
read
コマンド <変数名>
ここではサービス名を受け取り、代入します。
例:read service_name
変数を別のテキストファイルに書き込む:
echo <$変数名>:<$変数名>:<$変数名> >> <テキストファイル名>
:
を変数名にはさむと、複数の変数を1行に結合します。
>>
このファイルに書き込んでね!という意味の、「リダイレクト演算子」というものです。
例:echo "$service_name:$username:$password" >> pass.txt
ステップ2: パスワードを検索しよう!
内容: パスワードを保存し、検索する
処理
仕様
下記のステップ1の使用に加えて、検索機能を追加しました。
選択式の質問が表示され、ユーザーの入力に応じて分岐処理を行う。
シェルスクリプトを実行するたび、入力された情報がファイルに追記される。
- サービス名
- ユーザー名
- パスワード
実行時のアウトプット
パスワードマネージャーへようこそ!
次の選択肢から入力してください(Add Password/Get Password/Exit):
# Add Password が入力された場合
サービス名を入力してください:
ユーザー名を入力してください:
パスワードを入力してください:
パスワードの追加は成功しました。
次の選択肢から入力してください(Add Password/Get Password/Exit):
# Get Password が入力された場合
サービス名を入力してください:
## サービス名が保存されていなかった場合
そのサービスは登録されていません。
## サービス名が保存されていた場合
サービス名:hoge
ユーザー名:fuga
パスワード:piyo
次の選択肢から入力してください(Add Password/Get Password/Exit):
# Exit が入力された場合
Thank you!
## プログラムが終了
# Add Password/Get Password/Exit 以外が入力された場合
入力が間違えています。Add Password/Get Password/Exit から入力してください。
ステップ2のbash
#!/bin/bash
# 無限ループ内でユーザーにメニューを表示し、選択肢に応じて適切な処理を行う
while true; do
echo "パスワードマネージャーへようこそ!"
echo "次の選択肢から入力してください(Add Password/Get Password/Exit):"
# ユーザーからの入力を受け取り、choice変数に代入する
read choice
case $choice in
"Add Password")
read -p "サービス名を入力してください: " serviceName
read -p "ユーザー名を入力してください: " userName
# -s: 入力されたパスワードを表示させない
read -s -p "パスワードを入力してください: " password
# 入力された情報をpasswords.txtファイルに追記する
echo "$serviceName:$userName:$password" >> passwords.txt
echo "パスワードの追加は成功しました。"
;;
"Get Password")
read -p "サービス名を入力してください: " serviceName
# serviceNameに対応するpassをpasswords.txtファイルから取得
password=$(grep "^$serviceName:" passwords.txt | cut -d: -f3)
if [ -z "$password" ]; then
echo "そのサービスは登録されていません。"
else
echo "サービス名:$serviceName"
# サービス名に対応するユーザー名を表示
echo "ユーザー名:$(grep "^$serviceName:" passwords.txt | cut -d: -f2)"
# サービス名に対応するパスワードを表示
echo "パスワード:$password"
fi
;;
"Exit")
echo "Thank you!"
exit
;;
*)
echo "入力が間違えています。Add Password/Get Password/Exitから入力してください。"
;;
esac
done
ポイント
while文:
while 条件式
do
コマンド
done
while true; do
から始まる行は、無限ループを表しています。
ずっとtrue
(真)なので、「条件を満たしている間は同じ処理を繰り返す(無限にループしちゃうよ!)」という意味です。
ユーザーの入力を変数に代入:
read choice
の行は、ユーザーからの入力を受け取り、その入力を choice
変数に代入するもの。
case文:
case 値 in
条件・値1 ) コマンド1 ;;
条件・値2 ) コマンド2 ;;
条件・値3 ) コマンド3 ;;
esac
;;
を忘れないでね。
choice
の値に応じて、下記のいずれかの処理を行う。
- Add Password
- Get Password
- Exit
case
文の中で、各処理を実装しています。
Add Password の場合:
read
コマンドを使用してサービス名、ユーザー名、パスワードをユーザーに入力させ、それらの情報を passwords.txt
に追記するためのコマンドを実行。
echo
コマンドを使用してパスワードの追加が成功したことをユーザーに通知します。
Get Password の場合:
read
コマンドを使用してサービス名をユーザーに入力させ、それに対応するパスワードを passwords.txt
ファイルから取得し、それをユーザーに表示するためのコマンドを実行します。
grep
コマンドと cut
コマンドを使用して、serviceName
に対応する行を passwords.txt
から取得し、パスワードを取り出します。
grep
コマンドは、指定された正規表現に一致するテキスト行を検索するために使用されます。
cut
コマンドは、テキストファイルから行、フィールド、バイトなどの指定されたセクションを抽出するために使用されます。
grep "^$serviceName:" passwords.txt
は、passwords.txt
ファイル内で$serviceName
で始まる行を検索し、cut -d: -f3
はその行から3番目のフィールド(パスワード)を抽出しています。
ステップ3: パスワードを暗号化しよう!
内容
パスワードを暗号化する処理をほどこしました。
仕様
以下の情報をファイルに保存します。
シェルスクリプトを実行するたび、入力された情報がファイルに追記されます。
- サービス名
- ユーザー名
- パスワード
ステップ3のbash
#!/bin/bash
# 無限ループ内でユーザーにメニューを表示し、選択肢に応じて適切な処理を行う
while true; do
echo "パスワードマネージャーへようこそ!"
echo "終了したい場合は Exit と入力してください。"
echo "あなたのGPGキーで設定したメールアドレスを入力してください。"
# ユーザーからの入力を受け取り、gpg_email変数に代入する。
read gpg_email
# 「?」演算子: 変数が設定されていない場合にエラーメッセージを表示。
gpg_email="${gpg_email:?GPGのメールアドレスを設定してください。}"
echo "次の選択肢から入力してください(Add Password/Get Password/Exit):"
read choice
case $choice in
"Add Password")
# -pオプションでメッセージ(プロンプト)を表示
# ユーザーからの入力を受け取り、変数に代入する
read -p "サービス名を入力してください: " serviceName
# 空文字の場合、エラーメッセージを表示する
serviceName="${serviceName:?サービス名を設定してください。}"
read -p "ユーザー名を入力してください: " userName
userName="${userName:?ユーザー名を設定してください。}"
# -s: 入力されたパスワードを表示させない
read -s -p "パスワードを入力してください: " password
password="${password:?パスワードを設定してください。}"
# 復号化したデータを一時ファイルに保存
# 標準エラー出力(2)を/dev/nullに捨てる。つまり、エラーメッセージを表示しない。
gpg -d password.gpg > password.txt 2> /dev/null
# パスワードをpassword.txtに書き込む
echo "$serviceName:$userName:$password" >> passwords.txt
# 入力ファイルを暗号化して出力ファイルに保存する
gpg -r "$gpg_email" -e -o password.gpg password.txt
echo "パスワードの追加は成功しました。"
# ;; 各処理の終了を示す。省略可能。
;;
"Get Password")
read -p "サービス名を入力してください: " serviceName
# 復号化したデータを一時ファイルに保存
gpg -d password.gpg > password.txt 2> /dev/null
# serviceNameに対応するpassをpasswords.txtファイルから取得
# cut -d: -f3: 「:」で区切られた3番目のフィールド(パスワード)を取得
password=$(grep "^$serviceName:" passwords.txt | cut -d: -f3)
if [ -z "$password" ]; then
echo "そのサービスは登録されていません。"
else
echo "サービス名:$serviceName"
# サービス名に対応するユーザー名を表示
# cut -d: -f2: 「:」で区切られた2番目のフィールド(ユーザー名)を取得。
echo "ユーザー名:$(grep "^$serviceName:" passwords.txt | cut -d: -f2)"
# サービス名に対応するパスワードを表示。
echo "パスワード:$password"
fi
;;
"Exit")
echo "Thank you!"
exit
;;
# *)どの値にも一致しなかった場合の処理
*)
echo "入力が間違えています。Add Password/Get Password/Exitから入力してください。"
;;
# case文の終了を示す。esac=caseを逆読みしてる。
esac
# whileループの終了を示す。
done
# 一時ファイルを削除する。
rm password.txt
ポイント
- ユーザーのGPGキーを、コマンド入力から受け取ります。
- 空文字を入力した場合、エラーメッセージを表示します。
- セキュリティを強化。