From 75890ee7903a0d2c0febe23ef3ee78411a9b7e31 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E8=AB=8F=E8=A8=AA=E5=AD=90?= Date: Fri, 1 Dec 2023 02:25:27 +0900 Subject: [PATCH] 1.1.0 --- CHANGELOG.md | 7 ++++++ Makefile | 9 ++++--- README.md | 60 +++++++++++++++++++++++++++++++++++++++++++++++ addpass.c | 23 ++++++++++++++---- main.c | 8 +++---- otppass.c | 26 ++++++++++++++++++++ otppass.h | 6 +++++ showpass.c | 13 ++++++++-- sp-completion.zsh | 48 +++++++++++++++++++++++++++++++++++++ yankpass.c | 8 ++++++- 10 files changed, 193 insertions(+), 15 deletions(-) create mode 100644 otppass.c create mode 100644 otppass.h create mode 100644 sp-completion.zsh diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a0d870..0274411 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,9 @@ +# 1.1.0 +* TOTP対応 +* READMEファイルで使い方を詳しく説明する +* zshキャプチャー +* パスワード追加関数を安定化 +* パスワード表示とパスワードのコピー関数で、GNU Passで保存したパスワードの場合は改行を追加しない様に + # 1.0.0 * 最初リリース diff --git a/Makefile b/Makefile index 4c378f5..2a1c062 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,11 @@ NAME=sp -VERSION=1.0.0 +VERSION=1.1.0 # Linux、Haiku、かIllumos = /usr、FreeBSDかOpenBSD = /usr/local、NetBSD = /usr/pkg PREFIX=/usr CC=cc -FILES=main.c showpass.c yankpass.c addpass.c delpass.c listpass.c genpass.c initpass.c +FILES=main.c showpass.c yankpass.c addpass.c delpass.c listpass.c genpass.c initpass.c otppass.c CFLAGS=-Wall -Wextra -g -LDFLAGS=-lgpgme +LDFLAGS=-lgpgme -lcrypto all: ${CC} ${CFLAGS} -o ${NAME} ${FILES} ${LDFLAGS} @@ -25,6 +25,9 @@ install: all cp -f ${NAME} ${DESTDIR}${PREFIX}/bin chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME} +install-zsh: + cp sp-completion.zsh /usr/share/zsh/site-functions/_sp + uninstall: rm -f ${DESTDIR}${PREFIX}/bin/${NAME} diff --git a/README.md b/README.md index 82aa445..d7502a2 100644 --- a/README.md +++ b/README.md @@ -39,3 +39,63 @@ doas gmake install PREFIX=/usr/local ## 初期設定 「gpg -k」でGPG鍵IDを確認して、「sp -i [GPG ID]」を実行して下さい。 + +## 使い方 +### パスワードの作成 +#### 強いパスワードの場合 +```sh +$ sp -g 64 +nSYGSF2lWGCUsqKCRB_~mZm+spaU 0 && pw[len - 1] == '\n') { + pw[len - 1] = '\0'; + } else { + // 掃除 + int c; + while ((c = getchar()) != '\n' && c != EOF); + } + } // 端末設定をもとに戻す tcsetattr(fileno(stdin), TCSANOW, &old); - - // 改行文字を取り消す - pw[strcspn(pw, "\n")] = 0; } void addpass(char* file) { @@ -233,8 +240,14 @@ void addpass(char* file) { char buffer[512]; ssize_t read_bytes; + while ((read_bytes = gpgme_data_read(out, buffer, sizeof(buffer))) > 0) { - fwrite(buffer, 1, read_bytes, gpgfile); + if (fwrite(buffer, 1, (size_t)read_bytes, gpgfile) != (size_t)read_bytes) { + perror("パスワードを書き込みに失敗"); + free(gpgpath); + cleanup(ctx, key[0], in, out); + return; + } } // 掃除 diff --git a/main.c b/main.c index 2dfb3ff..ad3e1c4 100644 --- a/main.c +++ b/main.c @@ -12,11 +12,11 @@ #include "addpass.h" #include "delpass.h" #include "genpass.h" -void otppass(char* file); +#include "otppass.h" void helpme(); const char* sofname = "sp"; -const char* version = "1.0.0"; +const char* version = "1.1.0"; void helpme() { printf("076 sp - シンプルなパスワードマネージャー\n"); @@ -29,7 +29,7 @@ void helpme() { printf("%s -a <パスワード名> :パスワードを追加\n", sofname); printf("%s -d <パスワード名> :パスワードを削除\n", sofname); printf("%s -g <文字数> [risk|secure] :希望文字数でパスワードをランダムに作成する。risk=英数字のみ(不安)、secure=英数字+特別文字(デフォルト)を使用\n", sofname); - /* printf("%s -o <パスワード名>\n :ワンタイムパスワード(TOTP)を表示。存在しなければ、創作する", sofname); */ + printf("%s -o <パスワード名>\n :ワンタイムパスワード(TOTP)を表示。存在しなければ、創作する\n", sofname); printf("%s -h :ヘルプを表示\n", sofname); printf("%s -v :バージョンを表示\n", sofname); } @@ -64,7 +64,7 @@ int main (int argc, char* argv[]) { else if (argc == 4 && strcmp(argv[3], "secure") == 0) genpass(atoi(argv[2]), true); else helpme(); } - else if (argc == 3 && strcmp(argv[1], "-o") == 0) printf("TODO: otp\n"); + else if (argc == 3 && strcmp(argv[1], "-o") == 0) otppass(argv[2]); else if (argc == 2 && strcmp(argv[1], "-v") == 0) printf("%s-%s\n", sofname, version); else helpme(); diff --git a/otppass.c b/otppass.c new file mode 100644 index 0000000..87c2b42 --- /dev/null +++ b/otppass.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include + +unsigned long generate_totp(const unsigned char* secret, size_t keylen) { + unsigned long timestep = time(NULL) / 30; + unsigned char hmacres[20]; + + HMAC(EVP_sha1(), secret, keylen, (unsigned char*)×tep, sizeof(timestep), hmacres, NULL); + + int offset = hmacres[19] & 0xF; + unsigned long trunhash = (hmacres[offset] & 0x7F) << 24 | + (hmacres[offset + 1] & 0xFF) << 16 | + (hmacres[offset + 2] & 0xFF) << 8 | + (hmacres[offset + 3] & 0xFF); + + unsigned long otp = trunhash % 1000000; + return otp; +} + +void otppass(char* file) { + const char* secret = file; + unsigned long otp = generate_totp((unsigned char*)secret, strlen(secret)); + printf("%06lu\n", otp); +} diff --git a/otppass.h b/otppass.h new file mode 100644 index 0000000..b916b09 --- /dev/null +++ b/otppass.h @@ -0,0 +1,6 @@ +#ifndef OTPPASS_H +#define OTPPASS_H + +void otppass(char* file); + +#endif diff --git a/showpass.c b/showpass.c index 9cebc97..76e0007 100644 --- a/showpass.c +++ b/showpass.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -83,9 +84,17 @@ void showpass(char* file) { gpgme_data_seek(out, 0, SEEK_SET); char buffer[512]; ssize_t read_bytes; + bool islastnl = false; + while ((read_bytes = gpgme_data_read(out, buffer, sizeof(buffer) - 1)) > 0) { - buffer[read_bytes] = '\0'; - printf("%s", buffer); + fwrite(buffer, 1, read_bytes, stdout); + if (buffer[read_bytes - 1] == '\n') { + islastnl = true; + } + } + + if (!islastnl) { + putchar('\n'); } // 掃除 diff --git a/sp-completion.zsh b/sp-completion.zsh new file mode 100644 index 0000000..412a735 --- /dev/null +++ b/sp-completion.zsh @@ -0,0 +1,48 @@ +# compdef sp + +_sp () { + local state + local -a options + local -a entries + + _arguments -C \ + '-i[GPGと使ってパスワードストレージを初期設定]: :_sp_complete_keys' \ + '-s[パスワードを表示]: :_sp_complete_entries' \ + '-y[パスワードを表示せずクリップボードにコピーする]: :_sp_complete_entries' \ + '-l[パスワード一覧を表示]' \ + '-a[パスワードを追加]: :_sp_complete_entries' \ + '-d[パスワードを削除]: :_sp_complete_entries' \ + '-g[希望文字数でパスワードをランダムに作成する]: :_sp_complete_entries' \ + '-o[ワンタイムパスワード(TOTP)を表示]: :_sp_complete_entries' \ + '-h[ヘルプを表示]' \ + '-v[バージョンを表示]' \ + '*:: :->subcmds' + + case $state in + subcmds) + _message "no more arguments" + ;; + esac +} + +_sp_cmd_show () { + _sp_complete_entries +} + +_sp_complete_entries() { + _sp_complete_entries_helper -type f +} + +_sp_complete_entries_helper () { + local IFS=$'\n' + local prefix="${SP_DIR:-$HOME/.local/share/sp}" + entries=("${(f)$(find -L "$prefix" \( -name .git -o -name .gpg-id \) -prune -o -type f -print 2>/dev/null | sed -e "s#${prefix}/##" -e 's#\.gpg$##')}") + _describe 'password entries' entries +} + +_sp_complete_keys () { + local IFS=$'\n' + _values 'gpg keys' $(gpg2 --list-secret-keys --with-colons | cut -d : -f 10 | sort -u | sed '/^$/d') +} + +compdef _sp sp diff --git a/yankpass.c b/yankpass.c index e79fc51..b8df4de 100644 --- a/yankpass.c +++ b/yankpass.c @@ -98,12 +98,18 @@ void yankpass(char* file) { char buffer[512]; ssize_t read_bytes; - while ((read_bytes = gpgme_data_read(out, buffer, 511)) > 0) { + + while ((read_bytes = gpgme_data_read(out, buffer, sizeof(buffer))) > 0) { + if (buffer[read_bytes - 1] == '\n') { + read_bytes--; + } fwrite(buffer, 1, read_bytes, pipe); } + pclose(pipe); // 45秒後、クリップボードから削除する + printf("パスワードをクリップボードに追加しました。\n45秒後はクリップボードから取り消されます。\n"); sleep(45); system("echo -n | xclip -selection clipboard"); -- 2.43.0