コミットを比較

...

47 コミット

作成者 SHA1 メッセージ 日付
守矢諏訪子 8084424b16 ごめん 2024-05-25 17:45:15 +09:00
守矢諏訪子 35fef77fef ごめん 2024-05-25 17:43:43 +09:00
守矢諏訪子 f64a68ddf2 TODOっていらん 2024-05-25 17:57:41 +09:00
守矢諏訪子 eed1ed1361 やはり成功だった 2024-05-25 17:40:41 +09:00
守矢諏訪子 45dc3ac6dc Merge pull request 'パスワードがなくなるまで削除したら、ディレクトリも削除する様に' (#17) from delpass into master
Reviewed-on: #17
2024-05-25 17:30:42 +09:00
守矢諏訪子 f652e8d5d6 Merge branch 'master' of gitler.moe:suwako/sp into delpass 2024-05-25 17:15:25 +09:00
守矢諏訪子 26c0d00954 そっか、spの場合はCHANGELOG.mdを変更する事が不要 2024-05-22 18:38:52 +09:00
守矢諏訪子 af6d9c174f 使い方の修正 2024-05-22 18:38:07 +09:00
守矢諏訪子 43f463ba75 WIP: パスワードがなくなるまで削除したら、ディレクトリも削除する様に 2024-05-22 12:27:35 +09:00
守矢諏訪子 cf7147a90f segfault 2024-05-22 10:35:22 +09:00
守矢諏訪子 c1e344ac71 manpageを細かくに 2024-05-22 10:34:56 +09:00
守矢諏訪子 6a5b916d29 パスワード作成関数のデフォルトな長さは64に 2024-05-22 10:26:42 +09:00
守矢諏訪子 5f7cb70922 . 2024-05-22 03:53:43 +09:00
守矢諏訪子 69ef928b4b ヘルプの表示の削除 2024-05-22 03:27:52 +09:00
守矢諏訪子 0668578cbd ソースコードは綺麗に、OTPのバグの修正、表示のバグの修正 2024-05-22 03:13:29 +09:00
守矢諏訪子 58793174a4 uname -m 2024-04-30 21:07:41 +09:00
守矢諏訪子 aac723e78c NetBSD向けのリリースコマンドの追加 2024-04-16 18:06:04 +09:00
守矢諏訪子 284abb1fad Merge branch 'v1.3.0' of gitler.moe:suwako/sp into v1.3.0 2024-04-16 13:34:13 +09:00
守矢諏訪子 fe286d22ce 忘れた 2024-04-16 13:33:38 +09:00
守矢諏訪子 2e5e0b61b2 ごめん 2024-04-16 13:09:01 +09:00
守矢諏訪子 a5c6e3fe54 最新ルールに従い 2024-04-16 13:06:34 +09:00
守矢諏訪子 6f7eeaa45c Merge branch 'make-release-linux' of gitler.moe:suwako/sp into v1.3.0 2024-04-16 12:31:45 +09:00
守矢諏訪子 386bac6792 Linux向けのリリースコマンドの追加 2024-04-16 12:30:37 +09:00
守矢諏訪子 5003ea13bc FreeBSD向けのリリースコマンドの追加 2024-04-16 12:27:59 +09:00
守矢諏訪子 61271640e7 ごみ 2024-04-16 00:52:48 +09:00
守矢諏訪子 51c119e794 . 2024-04-16 00:48:28 +09:00
守矢諏訪子 1f997af2c1 Merge pull request 'OpenBSD向けリリースコマンドの追加' (#11) from make-release-openbsd into v1.3.0
Reviewed-on: #11
2024-04-16 00:46:38 +09:00
守矢諏訪子 417423417c Merge branch 'v1.3.0' of gitler.moe:suwako/sp into make-release-openbsd 2024-04-16 00:46:09 +09:00
守矢諏訪子 1e3ce35091 Merge pull request 'bsdmake' (#10) from bsdmake into v1.3.0
Reviewed-on: #10
2024-04-16 00:44:19 +09:00
守矢諏訪子 a29867337e OpenBSD向けリリースコマンドの追加 2024-04-16 00:43:13 +09:00
守矢諏訪子 8ea7ebd47d GPLv2 → ISC 2024-04-16 00:40:50 +09:00
守矢諏訪子 7add5ffa21 GNU Make → BSD Make 2024-04-16 00:39:52 +09:00
守矢諏訪子 0aaf5f12b2 最新ルールに従う様に 2024-02-03 19:37:46 +09:00
守矢諏訪子 297b9766dd ごめん 2024-02-03 00:30:26 +09:00
守矢諏訪子 e6defe3271 MANページを追加 2024-02-03 00:17:50 +09:00
守矢諏訪子 461b952da7 英訳の追加 2024-02-02 12:15:58 +09:00
守矢諏訪子 ffa3590ec7 . 2024-02-01 17:13:24 +09:00
守矢諏訪子 53a5739fa4 zsh対応の修正 2024-02-01 17:04:11 +09:00
守矢諏訪子 3976c11d91 パスワード変更機能性の追加 2024-02-01 17:01:15 +09:00
守矢諏訪子 a4f76ab2d9 パスワード削除機能性で、パスワードが存在ないかどうか確認 2024-02-01 16:50:03 +09:00
守矢諏訪子 e0d792f5c3 パスワード追加機能性で、パスワードが既に存在するかどうか確認 2024-02-01 16:45:52 +09:00
守矢諏訪子 a7d6f12c46 . 2024-02-01 16:20:53 +09:00
守矢諏訪子 330722bb68 パスワードの長さの延長 2024-02-01 16:14:57 +09:00
守矢諏訪子 f68a09c490 makeを実行したら、バイナリがもっと小さくなる 2024-02-01 16:01:47 +09:00
守矢諏訪子 55543618e5 やっとTOTP機能性を修正した 2024-02-01 16:01:25 +09:00
守矢諏訪子 c42f23f79f OpenBSDでのコンパイラーが発生された問題を修正した 2023-12-01 13:26:30 +09:00
守矢諏訪子 000e111406 make install-zsh部分を修正 2023-12-01 12:41:36 +09:00
36個のファイルの変更1525行の追加688行の削除

3
.gitignore vendored
ファイルの表示

@ -1,4 +1,5 @@
sp sp
.ccls-cache .ccls-cache
*.o *.o
*.tar.gz release
*.core

ファイルの表示

@ -1,3 +1,33 @@
# 1.3.0
* 英訳の追加
* GNU Make → BSD Make
* GPLv2 → ISC
* OpenBSD向けのリリースコマンドの追加
* FreeBSD向けのリリースコマンドの追加
* Linux向けのリリースコマンドの追加
* 最新ルールに従い
* NetBSD向けのリリースコマンドの追加
* OpenBSD 7.5でTOTPの修正 (ヌル終端文字列のバグ)
* ヘルプの表示の削除 (manpageをご利用下さい)
* パスワード作成関数のデフォルトな長さは64に
* manpageを細かくに
* パスワードがなくなるまで削除したら、ディレクトリも削除する様に
# 1.2.0
* やっとTOTP機能性を修正した
* makeを実行したら、バイナリがもっと小さくなる
* パスワードの長さの延長
* パスワード追加機能性で、パスワードが既に存在するかどうか確認
* パスワード削除機能性で、パスワードが存在ないかどうか確認
* パスワード変更機能性の追加
* zsh対応の修正
# 1.1.2
* OpenBSDでのコンパイラーが発生された問題を修正した
# 1.1.1
* make install-zsh部分を修正
# 1.1.0 # 1.1.0
* TOTP対応 * TOTP対応
* READMEファイルで使い方を詳しく説明する * READMEファイルで使い方を詳しく説明する

ファイルの表示

@ -0,0 +1,14 @@
Copyright © 2004-2011 by Internet Systems Consortium, Inc. ("ISC")
Copyright © 2018-2024 by 076.moe
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

ファイルの表示

@ -1,33 +1,80 @@
NAME=sp UNAME_S != uname -s
VERSION=1.1.0 UNAME_M != uname -m
# Linux、Haiku、かIllumos = /usr、FreeBSDかOpenBSD = /usr/local、NetBSD = /usr/pkg
PREFIX=/usr NAME != cat main.c | grep "const char \*sofname" | awk '{print $$5}' | \
CC=cc sed "s/\"//g" | sed "s/;//"
FILES=main.c showpass.c yankpass.c addpass.c delpass.c listpass.c genpass.c initpass.c otppass.c VERSION != cat main.c | grep "const char \*version" | awk '{print $$5}' | \
CFLAGS=-Wall -Wextra -g sed "s/\"//g" | sed "s/;//"
LDFLAGS=-lgpgme -lcrypto PREFIX = /usr/local
MANPREFIX = ${PREFIX}/man
.if ${UNAME_S} == "FreeBSD"
MANPREFIX = ${PREFIX}/share/man
.elif ${UNAME_S} == "Linux"
PREFIX = /usr
MANPREFIX = ${PREFIX}/share/man
.elif ${UNAME_S} == "NetBSD"
PREFIX = /usr/pkg
MANPREFIX = ${PREFIX}/share/man
.endif
CC = cc
FILES = main.c src/*.c
CFLAGS = -Wall -Wextra -O3 -I${PREFIX}/include -L${PREFIX}/lib
.if ${UNAME_S} == "NetBSD"
CFLAGS += -I/usr/local/include -L/usr/local/lib -I/usr/include -L/usr/lib
.endif
LDFLAGS = -lgpgme -lcrypto
all: all:
${CC} ${CFLAGS} -o ${NAME} ${FILES} ${LDFLAGS} ${CC} ${CFLAGS} -o ${NAME} ${FILES} ${LDFLAGS}
strip ${NAME}
clean: clean:
rm -f ${NAME} rm -f ${NAME}
dist: clean dist: clean
mkdir -p ${NAME}-${VERSION} mkdir -p release/src ${NAME}-${VERSION}
cp -R LICENSE.txt Makefile README.md CHANGELOG.md\ cp -R LICENSE.txt Makefile README.md CHANGELOG.md \
sp-completion.zsh\ ${NAME}-completion.zsh ${NAME}.1 main.c src ${NAME}-${VERSION}
*.c *.h ${NAME}-${VERSION} tar zcfv release/src/${NAME}-${VERSION}.tar.gz ${NAME}-${VERSION}
tar zcfv ${NAME}-${VERSION}.tar.gz ${NAME}-${VERSION}
rm -rf ${NAME}-${VERSION} rm -rf ${NAME}-${VERSION}
release-openbsd:
mkdir -p release/bin
${CC} ${CFLAGS} -o release/bin/${NAME}-${VERSION}-openbsd-${UNAME_M} ${FILES} \
-static -lgpgme -lcrypto -lc -lassuan -lgpg-error -lintl -liconv
strip release/bin/${NAME}-${VERSION}-openbsd-${UNAME_M}
release-freebsd:
mkdir -p release/bin
${CC} ${CFLAGS} -o release/bin/${NAME}-${VERSION}-freebsd-${UNAME_M} ${FILES} \
-static -lgpgme -lcrypto -lc -lassuan -lgpg-error -lthr -lintl
strip release/bin/${NAME}-${VERSION}-freebsd-${UNAME_M}
release-netbsd:
mkdir -p release/bin
${CC} ${CFLAGS} -o release/bin/${NAME}-${VERSION}-netbsd-${UNAME_M} ${FILES} \
-static -lgpgme -lcrypto -lcrypt -lc -lassuan -lgpg-error -lintl
strip release/bin/${NAME}-${VERSION}-netbsd-${UNAME_M}
release-linux:
mkdir -p release/bin
${CC} ${CFLAGS} -o release/bin/${NAME}-${VERSION}-linux-${UNAME_M} ${FILES} \
-static -lgpgme -lcrypto -lc -lassuan -lgpg-error
strip release/bin/${NAME}-${VERSION}-linux-${UNAME_M}
install: all install: all
mkdir -p ${DESTDIR}${PREFIX}/bin mkdir -p ${DESTDIR}${PREFIX}/bin
cp -f ${NAME} ${DESTDIR}${PREFIX}/bin cp -f ${NAME} ${DESTDIR}${PREFIX}/bin
chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME} chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME}
mkdir -p ${DESTDIR}${MANPREFIX}/man1
sed "s/VERSION/${VERSION}/g" < ${NAME}.1 > ${DESTDIR}${MANPREFIX}/man1/${NAME}.1
chmod 644 ${DESTDIR}${MANPREFIX}/man1/${NAME}.1
install-zsh: install-zsh:
cp sp-completion.zsh /usr/share/zsh/site-functions/_sp cp sp-completion.zsh ${DESTDIR}${PREFIX}/share/zsh/site-functions/_sp
uninstall: uninstall:
rm -f ${DESTDIR}${PREFIX}/bin/${NAME} rm -f ${DESTDIR}${PREFIX}/bin/${NAME}

ファイルの表示

@ -6,6 +6,7 @@
```sh ```sh
doas prt-get depinst gpgme gnupg pinentry doas prt-get depinst gpgme gnupg pinentry
doas make install doas make install
doas make install-zsh
``` ```
又は 又は
@ -23,18 +24,21 @@ prt-get depinst sp
```sh ```sh
doas pacman -S base-devel gpgme gnupg pinentry doas pacman -S base-devel gpgme gnupg pinentry
doas make install doas make install
doas make install-zsh
``` ```
### OpenBSD ### OpenBSD
```sh ```sh
doas pkg_add gmake gpgme gnupg pinentry doas pkg_add gmake gpgme gnupg pinentry
doas gmake install PREFIX=/usr/local doas gmake install PREFIX=/usr/local
doas gmake install-zsh PREFIX=/usr/local
``` ```
### FreeBSD ### FreeBSD
```sh ```sh
doas pkg install gmake gpgme gnupg pinentry doas pkg install gmake gpgme gnupg pinentry
doas gmake install PREFIX=/usr/local doas gmake install PREFIX=/usr/local
doas gmake install-zsh PREFIX=/usr/local
``` ```
## 初期設定 ## 初期設定
@ -85,8 +89,10 @@ $ sp -d 076.moe/suwako
## TOTP(ワンタイムパスワード) ## TOTP(ワンタイムパスワード)
### QRコードから ### QRコードから
QRコードをダウンロードし、zbarimgを使用して「QR-Code:」以降の部分をコピーし、spに追加して下さい。\ QRコードをダウンロードし、zbarimgを使用して「QR-Code:」以降の部分をコピーし、
`sp -a`を実行すると、「パスワード」を聞かれますが、TOTPの場合は「otpauth://」から始まる文字列をコピペして下さい。 spに追加して下さい。\
`sp -a`を実行すると、「パスワード」を聞かれますが、
TOTPの場合は「otpauth://」から始まる文字列をコピペして下さい。
```sh ```sh
$ zbarimg -q gitler.png $ zbarimg -q gitler.png
QR-Code:otpauth://totp/Gitler%20%28gitler.moe%29:suwako?algorithm=SHA1&digits=6&issuer=Gitler%20%28gitler.moe%29&period=30&secret= QR-Code:otpauth://totp/Gitler%20%28gitler.moe%29:suwako?algorithm=SHA1&digits=6&issuer=Gitler%20%28gitler.moe%29&period=30&secret=

259
addpass.c
ファイルの表示

@ -1,259 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <locale.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <gpgme.h>
#include <termios.h>
#include "addpass.h"
void cleanup(gpgme_ctx_t ctx, gpgme_key_t key, gpgme_data_t in, gpgme_data_t out) {
gpgme_data_release(in);
gpgme_data_release(out);
gpgme_release(ctx);
gpgme_key_release(key);
}
int mkdir_r(const char *path, mode_t mode) {
char tmp[256];
char *p = NULL;
size_t len;
snprintf(tmp, sizeof(tmp), "%s", path);
len = strlen(tmp);
if (tmp[len - 1] == '/') {
tmp[len - 1] = 0; // 最後の「/」文字を取り消す
}
for (p = tmp + 1; *p; p++) {
if (*p == '/') {
*p = 0; // 最後の「/」文字を取り消す
if (mkdir(tmp, mode) != 0 && errno != EEXIST) return -1;
*p = '/'; // また追加
}
}
if (mkdir(tmp, mode) != 0 && errno != EEXIST) {
return -1;
}
return 0;
}
void getpasswd(char* prompt, char*pw, size_t pwlen) {
struct termios old, new;
printf("%s", prompt);
// 端末設定を受け取る
tcgetattr(fileno(stdin), &old);
new = old;
// echoを無効にして
new.c_lflag &= ~ECHO;
tcsetattr(fileno(stdin), TCSANOW, &new);
// パスワードを読み込む
if (fgets(pw, pwlen, stdin) != NULL) {
// あれば、改行を取り消す
size_t len = strlen(pw);
if (len > 0 && pw[len - 1] == '\n') {
pw[len - 1] = '\0';
} else {
// 掃除
int c;
while ((c = getchar()) != '\n' && c != EOF);
}
}
// 端末設定をもとに戻す
tcsetattr(fileno(stdin), TCSANOW, &old);
}
void addpass(char* file) {
char pass[100];
char knin[100];
// パスワードを受け取る
getpasswd("パスワード: ", pass, sizeof(pass));
puts("");
getpasswd("パスワード(確認用): ", knin, sizeof(knin));
puts("");
// パスワードが一致するかどうか確認
if (strcmp(pass, knin) != 0) {
fprintf(stderr, "パスワードが一致していません。終了…\n");
return;
}
// パスワードを保存する
gpgme_ctx_t ctx;
gpgme_error_t err;
gpgme_key_t key[2] = {NULL, NULL};
gpgme_data_t in, out;
FILE *gpgfile;
// GPGMEライブラリを設置
setlocale(LC_ALL, "");
gpgme_check_version(NULL);
gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
// GPGMEを創作
err = gpgme_new(&ctx);
if (err) {
fprintf(stderr, "GPGMEを創作に失敗%s\n", gpgme_strerror(err));
return;
}
// GPGMEは非対話的モードに設定
err = gpgme_set_pinentry_mode(ctx, GPGME_PINENTRY_MODE_LOOPBACK);
if (err) {
fprintf(stderr, "pinentryモードを設定に失敗 %s\n", gpgme_strerror(err));
gpgme_release(ctx);
return;
}
// パスワードからデータオブジェクトを創作
err = gpgme_data_new_from_mem(&in, pass, strlen(pass), 0);
if (err) {
fprintf(stderr, "データオブジェクトを創作に失敗: %s\n", gpgme_strerror(err));
gpgme_release(ctx);
return;
}
gpgme_data_new(&out);
// パスを準備
char* homedir = getenv("HOME");
if (homedir == NULL) {
perror("ホームディレクトリを受取に失敗。");
return;
}
char* basedir = "/.local/share/sp/";
char* ext = ".gpg";
// 鍵を受け取る
char keypath[256];
snprintf(keypath, sizeof(keypath), "%s%s%s", homedir, basedir, ".gpg-id");
keypath[sizeof(keypath) - 1] = '\0';
FILE* keyfile = fopen(keypath, "rb");
if (keyfile == NULL) {
perror(".gpg-idファイルを開くに失敗。");
printf("失敗したパス: %s\n", keypath);
return;
}
char* keyid = malloc(100);
if (!fgets(keyid, 100, keyfile)) {
perror("鍵IDを読込に失敗。");
fclose(keyfile);
free(keyid);
return;
}
keyid[strcspn(keyid, "\n")] = 0;
fclose(keyfile);
err = gpgme_get_key(ctx, keyid, &key[0], 0);
if (err) {
fprintf(stderr, "鍵を受取に失敗: %s\n", gpgme_strerror(err));
free(keyid);
return;
}
if (key[0] == NULL) {
fprintf(stderr, "エラー鍵はNULLです。\n");
free(keyid);
return;
}
free(keyid);
// 暗号化
err = gpgme_op_encrypt(ctx, &key[0], GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
if (err) {
fprintf(stderr, "暗号化に失敗: %s\n", gpgme_strerror(err));
cleanup(ctx, key[0], in, out);
return;
}
// 暗号化したタイルを開く
int alllen = snprintf(NULL, 0, "%s%s%s%s", homedir, basedir, file, ext) + 1;
char* gpgpath = malloc(alllen);
if (gpgpath == NULL) {
cleanup(ctx, key[0], in, out);
perror("メモリを割当に失敗。");
return;
}
// ディレクトリを創作
char dirpath[512];
snprintf(dirpath, sizeof(dirpath), "%s%s%s", homedir, basedir, file);
dirpath[sizeof(dirpath) - 1] = '\0';
char* lastsla = strrchr(dirpath, '/');
if (lastsla != NULL) {
*lastsla = '\0';
if (mkdir_r(dirpath, 0755) != 0) {
free(gpgpath);
cleanup(ctx, key[0], in, out);
perror("ディレクトリを創作に失敗。");
return;
}
}
snprintf(gpgpath, alllen, "%s%s%s%s", homedir, basedir, file, ext);
struct stat statbuf;
if (stat(gpgpath, &statbuf) == 0) {
free(gpgpath);
cleanup(ctx, key[0], in, out);
fprintf(stderr, "パスワードは既に存在しています。\n");
return;
}
gpgfile = fopen(gpgpath, "wb");
if (gpgfile == NULL) {
perror("ファイルを開くに失敗。");
printf("失敗したパス: %s\n", gpgpath);
free(gpgpath);
cleanup(ctx, key[0], in, out);
return;
}
// データが保存したかどうか確認
ssize_t encrypted_data_size = gpgme_data_seek(out, 0, SEEK_END);
if (encrypted_data_size <= 0) {
fprintf(stderr, "データを保存に失敗。\n");
fclose(gpgfile);
free(gpgpath);
cleanup(ctx, key[0], in, out);
return;
}
// 復号化したパスワードを表示する
gpgme_data_seek(out, 0, SEEK_SET);
char buffer[512];
ssize_t read_bytes;
while ((read_bytes = gpgme_data_read(out, buffer, sizeof(buffer))) > 0) {
if (fwrite(buffer, 1, (size_t)read_bytes, gpgfile) != (size_t)read_bytes) {
perror("パスワードを書き込みに失敗");
free(gpgpath);
cleanup(ctx, key[0], in, out);
return;
}
}
// 掃除
fclose(gpgfile);
free(gpgpath);
cleanup(ctx, key[0], in, out);
printf("パスワードを保存出来ました。\n");
}

ファイルの表示

@ -1,9 +0,0 @@
#ifndef ADDPASS_H
#define ADDPASS_H
#include <sys/stat.h>
int mkdir_r(const char *path, mode_t mode);
void addpass(char* file);
#endif

ファイルの表示

@ -1,42 +0,0 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include "delpass.h"
int delpass(char* file) {
// パスを準備
char pwfile[512];
char* homedir = getenv("HOME");
if (homedir == NULL) {
perror("ホームディレクトリを受取に失敗。");
return -1;
}
char* basedir = "/.local/share/sp/";
char* ext = ".gpg";
int needed = snprintf(pwfile, sizeof(pwfile), "%s%s%s%s", homedir, basedir, file, ext);
if (needed >= (int)sizeof(pwfile)) {
fprintf(stderr, "エラー:パスが長すぎる。\n");
return -1;
}
// 削除を確認する
printf("パスワード「%s」を本当に削除する事が宜しいでしょうか? (y/N): ", file);
int confirm = getchar();
if (confirm != 'y' && confirm != 'Y') {
printf("削除しませんでした。\n");
return -1;
}
int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
if (unlink(pwfile) == -1) {
perror("パスワードを削除出来ませんですた。");
return -1;
}
printf("パスワードを削除しました。\n");
return -1;
}

ファイルの表示

@ -1,29 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "genpass.h"
void genpass(int count, bool issecure) {
const char* charset_risky = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
const char* charset_secure = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()=~-^\\|_@`[{]};:+*<>,./?";
const char* charset = issecure ? charset_secure : charset_risky;
FILE *fp = fopen("/dev/random", "rb");
if (fp == NULL) {
perror("/dev/randomを開けられませんでした。");
exit(EXIT_FAILURE);
}
char password[count + 1];
for (int i = 0; i < count; i++) {
unsigned char key;
fread(&key, sizeof(key), 1, fp);
password[i] = charset[key % strlen(charset)];
}
password[count] = '\0';
fclose(fp);
printf("%s\n", password);
}

ファイルの表示

@ -1,50 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include "initpass.h"
#include "addpass.h"
void initpass(char* gpgid) {
char* homedir = getenv("HOME");
if (homedir == NULL) {
perror("ホームディレクトリを受取に失敗。");
return;
}
char* basedir = "/.local/share/sp/";
char dirpath[256];
snprintf(dirpath, sizeof(dirpath), "%s%s", homedir, basedir);
if (mkdir_r(dirpath, 0755) != 0 && errno != EEXIST) {
perror("ディレクトリを作成に失敗。");
return;
}
char gpgidpath[512];
snprintf(gpgidpath, sizeof(gpgidpath), "%s/.gpg-id", dirpath);
struct stat statbuf;
if (stat(gpgidpath, &statbuf) == 0) {
fprintf(stderr, ".gpg-idファイルは既に存在します。\n");
return;
}
FILE* gpgidfile = fopen(gpgidpath, "w");
if (gpgidfile == NULL) {
perror(".gpg-idファイルを書き込めません。");
fclose(gpgidfile);
return;
}
if (fputs(gpgid, gpgidfile) == EOF) {
fprintf(stderr, ".gpg-idファイルへの書き込みに失敗しました。\n");
fclose(gpgidfile);
return;
}
fclose(gpgidfile);
printf("初期設定に完了しました。");
}

ファイルの表示

@ -1,51 +0,0 @@
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
#include "listpass.h"
void listpass(char* basePath, int level) {
struct dirent* entry;
DIR* dir = opendir(basePath);
if (!dir) {
perror("ディレクトリを開けられません。");
return;
}
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
char path[1000];
int needed = snprintf(path, sizeof(path), "%s/%s", basePath, entry->d_name);
if (needed >= (int)sizeof(path) || needed < 0) {
fprintf(stderr, "エラー:パスが長すぎる、又は長さを受取に失敗。");
continue;
}
struct stat statbuf;
if (stat(path, &statbuf) == -1) {
perror("ファイル状況を読込に失敗。");
continue;
}
for (int i = 0; i < level; i++) {
printf(" ");
}
if (S_ISDIR(statbuf.st_mode)) {
printf("|-- %s\n", entry->d_name);
listpass(path, level + 1);
} else if (S_ISREG(statbuf.st_mode)) {
char* filename = entry->d_name;
char* ext = strstr(filename, ".gpg");
if (ext) {
*ext = '\0';
}
printf("|-- %s\n", filename);
}
}
}
closedir(dir);
}

159
main.c
ファイルの表示

@ -1,72 +1,119 @@
#include <stdio.h> #include "src/common.h"
#include <string.h> #include "src/initpass.h"
#include <stdlib.h> #include "src/showpass.h"
#include <stdbool.h> #include "src/yankpass.h"
#include "src/listpass.h"
#include "src/addpass.h"
#include "src/delpass.h"
#include "src/genpass.h"
#include "src/otppass.h"
#include <gpgme.h> const char *sofname = "sp";
const char *version = "1.3.0";
#include "initpass.h" void usage() {
#include "showpass.h" printf("%s-%s\nusage: %s [-adegilosvy]\n", sofname, version, sofname);
#include "yankpass.h"
#include "listpass.h"
#include "addpass.h"
#include "delpass.h"
#include "genpass.h"
#include "otppass.h"
void helpme();
const char* sofname = "sp";
const char* version = "1.1.0";
void helpme() {
printf(" sp - シンプルなパスワードマネージャー\n");
printf("https://076.moe/ | https://gitler.moe/suwako/sp\n\n");
printf("使い方:\n");
printf("%s -i <gpg-id> GPGと使ってパスワードストレージを初期設定\n", sofname);
printf("%s -s <パスワード名> :パスワードを表示\n", sofname);
printf("%s -y <パスワード名> :パスワードを表示せずクリップボードにコピーする\n", sofname);
printf("%s -l :パスワード一覧を表示\n", sofname);
printf("%s -a <パスワード名> :パスワードを追加\n", sofname);
printf("%s -d <パスワード名> :パスワードを削除\n", sofname);
printf("%s -g <文字数> [risk|secure] 希望文字数でパスワードをランダムに作成する。risk英数字のみ(不安)、secure英数字特別文字(デフォルト)を使用\n", sofname);
printf("%s -o <パスワード名>\n ワンタイムパスワード(TOTP)を表示。存在しなければ、創作する\n", sofname);
printf("%s -h :ヘルプを表示\n", sofname);
printf("%s -v :バージョンを表示\n", sofname);
} }
int main (int argc, char* argv[]) { char *getfullpath(char *arg) {
char *lang = getlang();
char *homedir = getenv("HOME");
if (homedir == NULL) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to getting home directory");
else perror("ホームディレクトリを受取に失敗");
return NULL;
}
char *basedir = "/.local/share/sp/";
size_t fullPathLen;
char *fullPath;
if (arg != NULL) {
fullPathLen = strlen(homedir) + strlen(basedir) + strlen(arg) + 5;
} else {
fullPathLen = strlen(homedir) + strlen(basedir);
}
fullPath = (char *)malloc(fullPathLen);
if (fullPath == NULL) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to allocating memory");
else perror("メモリの役割に失敗");
free(fullPath);
free(homedir);
return NULL;
}
if (arg != NULL) {
snprintf(fullPath, fullPathLen, "%s%s%s.gpg", homedir, basedir, arg);
} else {
snprintf(fullPath, fullPathLen, "%s%s", homedir, basedir);
}
return fullPath;
}
int main(int argc, char *argv[]) {
if (argc < 2) { if (argc < 2) {
helpme(); usage();
return 0; return 0;
} }
if (argc == 3 && strcmp(argv[1], "-i") == 0) initpass(argv[2]); if (strcmp(argv[1], "-g") == 0) {
else if (argc == 3 && strcmp(argv[1], "-s") == 0) showpass(argv[2]); if (argc > 4) {
else if (argc == 3 && strcmp(argv[1], "-y") == 0) yankpass(argv[2]); usage();
else if (argc == 2 && strcmp(argv[1], "-l") == 0) { return 1;
char basePath[512];
char* homedir = getenv("HOME");
if (homedir == NULL) {
perror("ホームディレクトリを受取に失敗。");
return -1;
} }
char* basedir = "/.local/share/sp/"; if (argc == 2) genpass(64, true);
snprintf(basePath, sizeof(basePath), "%s%s", homedir, basedir); else if (argc == 3) genpass(atoi(argv[2]), true);
else if (argc == 4 && strcmp(argv[3], "risk") == 0)
genpass(atoi(argv[2]), false);
else if (argc == 4 && strcmp(argv[3], "secure") == 0)
genpass(atoi(argv[2]), true);
listpass(basePath, 0); return 0;
} }
else if (argc == 3 && strcmp(argv[1], "-a") == 0) addpass(argv[2]);
else if (argc == 3 && strcmp(argv[1], "-d") == 0) delpass(argv[2]); if (argc == 3) {
else if (strcmp(argv[1], "-g") == 0) { if (strcmp(argv[1], "-i") == 0) initpass(argv[2]);
if (argc == 3) genpass(atoi(argv[2]), true); else if (strcmp(argv[1], "-s") == 0) {
else if (argc == 4 && strcmp(argv[3], "risk") == 0) genpass(atoi(argv[2]), false); const char *pass = showpass(argv[2]);
else if (argc == 4 && strcmp(argv[3], "secure") == 0) genpass(atoi(argv[2]), true); if (pass == NULL) return -1;
else helpme(); printf("%s\n", pass);
}
else if (strcmp(argv[1], "-y") == 0) yankpass(argv[2]);
else if (strcmp(argv[1], "-a") == 0) addpass(argv[2]);
else if (strcmp(argv[1], "-d") == 0) delpass(argv[2], 0);
else if (strcmp(argv[1], "-e") == 0) {
delpass(argv[2], 1);
addpass(argv[2]);
} else if (strcmp(argv[1], "-o") == 0) {
char *fullPath = getfullpath(argv[2]);
if (fullPath == NULL) return -1;
otppass(fullPath);
free(fullPath);
} else {
usage();
return 1;
}
} else if (argc == 2) {
char *basePath = getfullpath(NULL);
if (basePath == NULL) return -1;
if (strcmp(argv[1], "-l") == 0) listpass(basePath, 0);
else if (strcmp(argv[1], "-v") == 0) printf("%s-%s\n", sofname, version);
else {
usage();
free(basePath);
return 1;
}
free(basePath);
} else {
usage();
return 1;
} }
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();
return 0; return 0;
} }

ファイルの表示

@ -1,26 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <openssl/hmac.h>
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*)&timestep, 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);
}

ファイルの表示

@ -1,102 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <locale.h>
#include <gpgme.h>
#include "showpass.h"
void clean_up(gpgme_ctx_t ctx, gpgme_data_t in, gpgme_data_t out, FILE* gpgfile, char* gpgpath) {
if (gpgfile) fclose(gpgfile);
if (gpgpath) free(gpgpath);
gpgme_data_release(in);
gpgme_data_release(out);
gpgme_release(ctx);
}
void showpass(char* file) {
gpgme_ctx_t ctx;
gpgme_error_t err;
gpgme_data_t in, out;
FILE *gpgfile;
// GPGMEライブラリを設置
setlocale(LC_ALL, "");
gpgme_check_version(NULL);
gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
// GPGMEを創作
err = gpgme_new(&ctx);
if (err) {
fprintf(stderr, "GPGMEを創作に失敗%s\n", gpgme_strerror(err));
return;
}
// OpenPGPプロトコールを設定
gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
// 暗号化したタイルを開く
char* homedir = getenv("HOME");
if (homedir == NULL) {
perror("ホームディレクトリを受取に失敗。");
return;
}
char* basedir = "/.local/share/sp/";
char* ext = ".gpg";
int alllen = snprintf(NULL, 0, "%s%s%s%s", homedir, basedir, file, ext) + 1;
char* gpgpath = malloc(alllen);
if (gpgpath == NULL) {
perror("メモリを割当に失敗。");
return;
}
sprintf(gpgpath, "%s%s%s%s", homedir, basedir, file, ext);
gpgfile = fopen(gpgpath, "rb");
if (gpgfile == NULL) {
perror("ファイルを開くに失敗。");
printf("失敗したパス: %s\n", gpgpath);
free(gpgpath);
return;
}
if (gpgme_data_new_from_stream(&in, gpgfile) != GPG_ERR_NO_ERROR || gpgme_data_new(&out) != GPG_ERR_NO_ERROR) {
fprintf(stderr, "GPGMEデータオブジェクトを創作に失敗。\n");
clean_up(ctx, in, out, gpgfile, gpgpath);
return;
}
// データオブジェクトを創作
gpgme_data_new(&out);
// 復号化して
err = gpgme_op_decrypt(ctx, in, out);
if (err) {
fprintf(stderr, "復号化に失敗: %s\n", gpgme_strerror(err));
// 掃除
clean_up(ctx, in, out, gpgfile, gpgpath);
return;
}
// 復号化したパスワードを表示する
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) {
fwrite(buffer, 1, read_bytes, stdout);
if (buffer[read_bytes - 1] == '\n') {
islastnl = true;
}
}
if (!islastnl) {
putchar('\n');
}
// 掃除
clean_up(ctx, in, out, gpgfile, gpgpath);
}

ファイルの表示

@ -1,28 +1,48 @@
# compdef sp #compdef sp
#autoload
_sp () { _sp () {
local state local cmd
local -a options if (( CURRENT > 2)); then
local -a entries cmd=${words[2]}
curcontext="${curcontext%:*:*}:pass-$cmd"
_arguments -C \ (( CURRENT-- ))
'-i[GPGと使ってパスワードストレージを初期設定]: :_sp_complete_keys' \ shift words
'-s[パスワードを表示]: :_sp_complete_entries' \ case "${cmd}" in
'-y[パスワードを表示せずクリップボードにコピーする]: :_sp_complete_entries' \ -i)
'-l[パスワード一覧を表示]' \ _sp_complete_keys
'-a[パスワードを追加]: :_sp_complete_entries' \ ;;
'-d[パスワードを削除]: :_sp_complete_entries' \ -i|-y|-d|-a|-e|-o)
'-g[希望文字数でパスワードをランダムに作成する]: :_sp_complete_entries' \ _sp_complete_entries_helper
'-o[ワンタイムパスワード(TOTP)を表示]: :_sp_complete_entries' \ ;;
'-h[ヘルプを表示]' \ -g)
'-v[バージョンを表示]' \ local -a subcommands
'*:: :->subcmds' subcommands=(
"secure:英数字+特別文字(デフォルト)"
case $state in "risk:英数字のみ(不安)"
subcmds) )
_message "no more arguments" ;;
;; -s)
esac _sp_cmd_show
;;
esac
else
local -a subcommands
subcommands=(
"-i:GPGと使ってパスワードストレージを初期設定"
"-s:パスワードを表示"
"-y:パスワードを表示せずクリップボードにコピーする"
"-l:パスワード一覧を表示"
"-a:パスワードを追加"
"-d:パスワードを削除"
"-e:パスワードを変更"
"-g:希望文字数でパスワードをランダムに作成する。risk英数字のみ(不安)、secure英数字特別文字(デフォルト)を使用"
"-o:ワンタイムパスワード(TOTP)を表示。存在しなければ、創作する"
"-h:ヘルプを表示"
"-v:バージョンを表示"
)
_sp_cmd_show
fi
} }
_sp_cmd_show () { _sp_cmd_show () {
@ -35,9 +55,9 @@ _sp_complete_entries() {
_sp_complete_entries_helper () { _sp_complete_entries_helper () {
local IFS=$'\n' local IFS=$'\n'
local prefix="${SP_DIR:-$HOME/.local/share/sp}" local prefix
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$##')}") zstyle -s ":completion:${curcontext}:" prefix prefix || prefix="${SP_DIR:-$HOME/.local/share/sp}"
_describe 'password entries' entries _values -C 'passwords' ${$(find -L "$prefix" \( -name .git -o -name .gpg-id \) -prune -o $@ -print 2>/dev/null | sed -e "s#${prefix}/\{0,1\}##" -e 's#\.gpg##' -e 's#\\#\\\\#g' -e 's#:#\\:#g' | sort):-""}
} }
_sp_complete_keys () { _sp_complete_keys () {
@ -45,4 +65,4 @@ _sp_complete_keys () {
_values 'gpg keys' $(gpg2 --list-secret-keys --with-colons | cut -d : -f 10 | sort -u | sed '/^$/d') _values 'gpg keys' $(gpg2 --list-secret-keys --with-colons | cut -d : -f 10 | sort -u | sed '/^$/d')
} }
compdef _sp sp _sp

172
sp.1 ノーマルファイル
ファイルの表示

@ -0,0 +1,172 @@
.TH SP 1 VERSION
.SH NAME
sp - Simple Password Manager
.br
.B sp
[-i] [-i \fI\,gpg-id\fR] [-adeosy \fI\,password\fR] [-g \fI\,length\fR [\fI\,secure\fR|\fI\,risk\fR]]
.SH 説明
.PP
シンプルなパスワードマネージャー。
.TP
\fB\,a\fR \fI\,password\fR
パスワードを追加
.TP
\fB\,d\fR \fI\,password\fR
パスワードを削除
.TP
\fB\,e\fR \fI\,password\fR
パスワードを変更
.TP
\fB\,g\fR \fI,length\fR \fI,risk|secure\fR
希望文字数でパスワードをランダムに作成する。
.br
デフォルトな長さは64文字です。
.br
secure英数字特別文字(デフォルト)を使用
.br
risk英数字のみ(不安)を使用
.TP
\fB\,i\fR \fI\,gpg-id\fR
GPGと使ってパスワードストレージを初期設定
.TP
\fB\,l\fR
パスワード一覧を表示
.TP
\fB\,o\fR \fI\,password\fR
ワンタイムパスワード(TOTP)を表示。存在しなければ、創作する
.TP
\fB\,s\fR \fI\,password\fR
パスワードを表示
.TP
\fB\,v\fR
バージョンを表示
.TP
\fB\,y\fR \fI\,password\fR
パスワードを表示せずクリップボードにコピーする
.SH LANGUAGE
デフォルトの言語は日本語ですが、英語で利用するには、
.br
「.zshrc」、「.bashrc」等ファイルで「SP_LANG=en」を追加して下さい。
.SH EXAMPLES
\&...
$ sp -i 12345678901234567890ABCDEFABCDEF1234ABCD
.br
初期設定に完了しました。
$ cat ~/.local/share/sp/.gpg-id
.br
12345678901234567890ABCDEFABCDEF1234ABCD
.ED
\&...
$ sp -a 076.moe/nitori
.br
パスワード:
.br
パスワード(確認用):
.br
パスワードを保存出来ました
$ sp -s 076.moe/nitori
.br
kyuuri
$ sp -d 076.moe/nitori
.br
パスワード「076.moe/nitori」を本当に削除する事が宜しいでしょうか? (y/N): y
.br
パスワードを削除しました
.br
$ sp -s 076.moe/nitori
.br
ファイルを開くに失敗: No such file or directory
.ED
\&...
$ sp -a 076.moe/nitori
.br
パスワード:
.br
パスワード(確認用):
.br
パスワードを保存出来ました
$ sp -s 076.moe/nitori
.br
kyuuri
$ sp -a 076.moe/nitori
.br
パスワードが既に存在しています。
.br
変更するには、「 sp -e 076.moe/nitori 」を実行して下さい。
$ SP_LANG=en sp -a 076.moe/nitori
.br
Password already exist.
.br
For edit, please run ' sp -e 076.moe/nitori '.
$ sp -e 076.moe/nitori
.br
パスワード:
.br
パスワード(確認用):
.br
パスワードを保存出来ました
$ sp -s 076.moe/nitori
.br
kappa
.ED
\&...
$ sp -g
.br
\5C'F6=8r&:OO=P?{Ry-3d4%z#7Hki}965l`j2xJSRoHQkvj^nz+YPx4g74yu_OT
$ sp -g 12
.br
{%#upiPiayqZ
$ sp -g 12 risk
.br
iwxoumJC9wZH
.ED
\&...
$ doas pkg_add zbar
.br
quirks-7.14 signed on 2024-05-21T22:52:07Z
.br
zbar-0.23.90p2: ok
$ zbarimg -q --raw Untitled.png
.br
otpauth://totp/GitHub:TechnicalSuwako?secret=ABCDEFGHIJKLMNOP&issuer=GitHub
$ sp -a github.com/2fa
.br
パスワード:
.br
パスワード(確認用):
.br
パスワードを保存出来ました
$ sp -s github.com/2fa
.br
otpauth://totp/GitHub:TechnicalSuwako?secret=ABCDEFGHIJKLMNOP&issuer=GitHub
$ sp -o github.com/2fa
.br
123456
.Ed
.SH AUTHORS
.PP
テクニカル諏訪子

301
src/addpass.c ノーマルファイル
ファイルの表示

@ -0,0 +1,301 @@
#include "addpass.h"
void cleanup(gpgme_ctx_t ctx, gpgme_key_t key, gpgme_data_t in, gpgme_data_t out) {
gpgme_data_release(in);
gpgme_data_release(out);
gpgme_release(ctx);
gpgme_key_release(key);
}
void getpasswd(char *prompt, char *pw, size_t pwlen) {
struct termios old, new;
printf("%s", prompt);
// 端末設定を受け取る
tcgetattr(fileno(stdin), &old);
new = old;
// echoを無効にして
new.c_lflag &= ~ECHO;
tcsetattr(fileno(stdin), TCSANOW, &new);
// パスワードを読み込む
if (fgets(pw, pwlen, stdin) != NULL) {
// あれば、改行を取り消す
size_t len = strlen(pw);
if (len > 0 && pw[len - 1] == '\n') {
pw[len - 1] = '\0';
} else {
// 掃除
int c;
while ((c = getchar()) != '\n' && c != EOF);
}
}
// 端末設定をもとに戻す
tcsetattr(fileno(stdin), TCSANOW, &old);
}
void addpass(char *file) {
char *lang = getlang();
// パスを準備
char *homedir = getenv("HOME");
if (homedir == NULL) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to retrieving home directory");
else perror("ホームディレクトリを受取に失敗");
return;
}
char *basedir = "/.local/share/sp/";
char *ext = ".gpg";
char pass[256];
char knin[256];
int alllen = snprintf(NULL, 0, "%s%s%s%s", homedir, basedir, file, ext) + 1;
char *gpgpathchk = malloc(alllen);
if (gpgpathchk == NULL) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to allocating memory");
else perror("メモリを割当に失敗");
return;
}
// ファイルが既に存在するかどうか確認
snprintf(gpgpathchk, alllen, "%s%s%s%s", homedir, basedir, file, ext);
if (access(gpgpathchk, F_OK) != -1) {
if (strncmp(lang, "en", 2) == 0)
fprintf(
stderr,
"Password already exist.\nFor edit, please run ' sp -e %s '.\n",
file
);
else
fprintf(
stderr,
"%s\n変更するには、「 sp -e %s 」を実行して下さい。\n",
"パスワードが既に存在しています。",
file
);
free(gpgpathchk);
return;
}
free(gpgpathchk);
// パスワードを受け取る
if (strncmp(lang, "en", 2) == 0)
getpasswd("Password: ", pass, sizeof(pass));
else getpasswd("パスワード: ", pass, sizeof(pass));
puts("");
if (strncmp(lang, "en", 2) == 0)
getpasswd("Password (for verification): ", knin, sizeof(knin));
else getpasswd("パスワード(確認用): ", knin, sizeof(knin));
puts("");
// パスワードが一致するかどうか確認
if (strcmp(pass, knin) != 0) {
if (strncmp(lang, "en", 2) == 0)
perror("Password does not match. Ending...");
else perror("パスワードが一致していません。終了…");
return;
}
// パスワードを保存する
gpgme_ctx_t ctx;
gpgme_error_t err;
gpgme_key_t key[2] = {NULL, NULL};
gpgme_data_t in, out;
FILE *gpgfile;
// GPGMEライブラリを設置
setlocale(LC_ALL, "");
gpgme_check_version(NULL);
gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
// GPGMEを創作
err = gpgme_new(&ctx);
if (err) {
if (strncmp(lang, "en", 2) == 0)
fprintf(stderr, "Failed to generating GPGME: %s\n", gpgme_strerror(err));
else fprintf(stderr, "GPGMEを創作に失敗%s\n", gpgme_strerror(err));
return;
}
// GPGMEは非対話的モードに設定
err = gpgme_set_pinentry_mode(ctx, GPGME_PINENTRY_MODE_LOOPBACK);
if (err) {
if (strncmp(lang, "en", 2) == 0)
fprintf(stderr, "Failed to setting pinentry mode: %s\n", gpgme_strerror(err));
else fprintf(stderr, "pinentryモードを設定に失敗 %s\n", gpgme_strerror(err));
gpgme_release(ctx);
return;
}
// パスワードからデータオブジェクトを創作
err = gpgme_data_new_from_mem(&in, pass, strlen(pass), 0);
if (err) {
if (strncmp(lang, "en", 2) == 0)
fprintf(stderr, "Failed to making data object: %s\n", gpgme_strerror(err));
else
fprintf(stderr, "データオブジェクトを創作に失敗: %s\n", gpgme_strerror(err));
gpgme_release(ctx);
return;
}
gpgme_data_new(&out);
// 鍵を受け取る
char keypath[256];
snprintf(keypath, sizeof(keypath), "%s%s%s", homedir, basedir, ".gpg-id");
keypath[sizeof(keypath) - 1] = '\0';
FILE* keyfile = fopen(keypath, "rb");
if (keyfile == NULL) {
if (strncmp(lang, "en", 2) == 0) {
perror("Failed to opening .gpg-id file");
fprintf(stderr, "Failed path: %s\n", keypath);
} else {
perror(".gpg-idファイルを開くに失敗");
fprintf(stderr, "失敗したパス: %s\n", keypath);
}
return;
}
char *keyid = malloc(256);
if (!fgets(keyid, 256, keyfile)) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to reading key ID");
else perror("鍵IDを読込に失敗");
fclose(keyfile);
free(keyid);
return;
}
keyid[strcspn(keyid, "\n")] = 0;
fclose(keyfile);
err = gpgme_get_key(ctx, keyid, &key[0], 0);
if (err) {
if (strncmp(lang, "en", 2) == 0)
fprintf(stderr, "Failed to getting key: %s\n", gpgme_strerror(err));
else fprintf(stderr, "鍵を受取に失敗: %s\n", gpgme_strerror(err));
free(keyid);
return;
}
if (key[0] == NULL) {
if (strncmp(lang, "en", 2) == 0) perror("Error: Key is NULL");
else perror("エラー鍵はNULLです");
free(keyid);
return;
}
free(keyid);
// 暗号化
err = gpgme_op_encrypt(ctx, &key[0], GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
if (err) {
if (strncmp(lang, "en", 2) == 0)
fprintf(stderr, "Failed to encrypt: %s\n", gpgme_strerror(err));
else fprintf(stderr, "暗号化に失敗: %s\n", gpgme_strerror(err));
cleanup(ctx, key[0], in, out);
return;
}
// 暗号化したタイルを開く
char *gpgpath = malloc(alllen);
if (gpgpath == NULL) {
cleanup(ctx, key[0], in, out);
if (strncmp(lang, "en", 2) == 0)
perror("Failed to allocating memory");
else perror("メモリを割当に失敗");
return;
}
// ディレクトリを創作
char dirpath[512];
snprintf(dirpath, sizeof(dirpath), "%s%s%s", homedir, basedir, file);
dirpath[sizeof(dirpath) - 1] = '\0';
char *lastsla = strrchr(dirpath, '/');
if (lastsla != NULL) {
*lastsla = '\0';
if (mkdir_r(dirpath, 0755) != 0) {
free(gpgpath);
cleanup(ctx, key[0], in, out);
if (strncmp(lang, "en", 2) == 0)
perror("Failed to constructing directory");
else perror("ディレクトリを創作に失敗");
return;
}
}
snprintf(gpgpath, alllen, "%s%s%s%s", homedir, basedir, file, ext);
struct stat statbuf;
if (stat(gpgpath, &statbuf) == 0) {
free(gpgpath);
cleanup(ctx, key[0], in, out);
if (strncmp(lang, "en", 2) == 0)
perror("Password is already exist");
else perror("パスワードは既に存在しています");
return;
}
gpgfile = fopen(gpgpath, "wb");
if (gpgfile == NULL) {
if (strncmp(lang, "en", 2) == 0) {
perror("Failed to opening file.");
fprintf(stderr, "Failed path: %s\n", gpgpath);
} else {
perror("ファイルを開くに失敗。");
fprintf(stderr, "失敗したパス: %s\n", gpgpath);
}
free(gpgpath);
cleanup(ctx, key[0], in, out);
return;
}
// データが保存したかどうか確認
ssize_t encrypted_data_size = gpgme_data_seek(out, 0, SEEK_END);
if (encrypted_data_size <= 0) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to saving the data");
else perror("データを保存に失敗");
fclose(gpgfile);
free(gpgpath);
cleanup(ctx, key[0], in, out);
return;
}
// 復号化したパスワードを表示する
gpgme_data_seek(out, 0, SEEK_SET);
char buffer[512];
ssize_t read_bytes;
while ((read_bytes = gpgme_data_read(out, buffer, sizeof(buffer))) > 0) {
if (fwrite(buffer, 1, (size_t)read_bytes, gpgfile) != (size_t)read_bytes) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to writing password");
else perror("パスワードを書き込みに失敗");
free(gpgpath);
cleanup(ctx, key[0], in, out);
return;
}
}
// 掃除
fclose(gpgfile);
free(gpgpath);
cleanup(ctx, key[0], in, out);
if (strncmp(lang, "en", 2) == 0)
puts("I could save the password");
else puts("パスワードを保存出来ました");
}

13
src/addpass.h ノーマルファイル
ファイルの表示

@ -0,0 +1,13 @@
#ifndef ADDPASS_H
#define ADDPASS_H
#include <locale.h>
#include <unistd.h>
#include <termios.h>
#include "common.h"
void addpass(char *file);
#endif

44
src/base32.c ノーマルファイル
ファイルの表示

@ -0,0 +1,44 @@
#include <string.h>
#include "base32.h"
int char_to_val(char c) {
const char *base32_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
char *ptr = strchr(base32_alphabet, c);
return ptr ? ptr - base32_alphabet : -1;
}
unsigned char *base32_decode(const char *encoded, size_t *out_len) {
size_t encoded_len = strlen(encoded);
size_t padding = 0;
for (int i = encoded_len - 1; i >= 0 && encoded[i] == '='; --i) {
++padding;
}
*out_len = (encoded_len - padding) * 5 / 8;
if (*out_len == 0) return NULL;
unsigned char *decoded = malloc(*out_len);
if (!decoded) return NULL;
int buffer = 0, bits_left = 0, count = 0;
for (size_t i = 0; i < encoded_len - padding; ++i) {
int val = char_to_val(encoded[i]);
if (val < 0) {
free(decoded);
return NULL;
}
buffer <<= 5;
buffer |= val;
bits_left += 5;
if (bits_left >= 8) {
decoded[count++] = (unsigned char) (buffer >> (bits_left - 8));
bits_left -= 8;
}
}
*out_len = count;
return decoded;
}

8
src/base32.h ノーマルファイル
ファイルの表示

@ -0,0 +1,8 @@
#ifndef BASE32_H
#define BASE32_H
#include <stdlib.h>
unsigned char *base32_decode(const char *encoded, size_t *out_len);
#endif

37
src/common.c ノーマルファイル
ファイルの表示

@ -0,0 +1,37 @@
#include "common.h"
char *getlang() {
char *lang = NULL;
lang = getenv("SP_LANG");
if (lang == NULL) lang = "ja";
return lang;
}
int mkdir_r(const char *path, mode_t mode) {
char tmp[256];
char *p = NULL;
size_t len;
snprintf(tmp, sizeof(tmp), "%s", path);
len = strlen(tmp);
if (tmp[len - 1] == '/') {
tmp[len - 1] = 0; // 最後の「/」文字を取り消す
}
for (p = tmp + 1; *p; p++) {
if (*p == '/') {
*p = 0; // 最後の「/」文字を取り消す
if (mkdir(tmp, mode) != 0 && errno != EEXIST) return -1;
*p = '/'; // また追加
}
}
if (mkdir(tmp, mode) != 0 && errno != EEXIST) {
return -1;
}
return 0;
}

16
src/common.h ノーマルファイル
ファイルの表示

@ -0,0 +1,16 @@
#ifndef COMMON_H
#define COMMON_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <errno.h>
#include <gpgme.h>
char *getlang();
int mkdir_r(const char *path, mode_t mode);
#endif

180
src/delpass.c ノーマルファイル
ファイルの表示

@ -0,0 +1,180 @@
#include <unistd.h>
#include <dirent.h>
#include "common.h"
#include "delpass.h"
int delcnt(const char *str, char delimiter) {
int count = 0;
while (*str) {
if (*str == delimiter) {
count++;
}
str++;
}
return count;
}
char **explode(const char *str, char delimiter, int *numtokens) {
int count = delcnt(str, delimiter) + 1;
*numtokens = count;
char **tokens = malloc(count * sizeof(char *));
if (tokens == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
char *strcopy = strdup(str);
if (strcopy == NULL) {
perror("strdup");
exit(EXIT_FAILURE);
}
char *token = strtok(strcopy, &delimiter);
int i = 0;
while (token != NULL) {
tokens[i] = strdup(token);
if (tokens[i] == NULL) {
perror("strdup");
exit(EXIT_FAILURE);
}
i++;
token = strtok(NULL, &delimiter);
}
free(strcopy);
return tokens;
}
void freetokens(char **tokens, int numtokens) {
for (int i = 0; i < numtokens; i++) {
free(tokens[i]);
}
free(tokens);
}
int delpass(char *file, int force) {
char *lang = getlang();
// パスを準備
char pwfile[512];
char *homedir = getenv("HOME");
if (homedir == NULL) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to getting home directory");
else perror("ホームディレクトリを受取に失敗");
return -1;
}
char *basedir = "/.local/share/sp/";
char *ext = ".gpg";
int alllen = snprintf(NULL, 0, "%s%s%s%s", homedir, basedir, file, ext) + 1;
char *gpgpathchk = malloc(alllen);
if (gpgpathchk == NULL) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to allocating memory");
else perror("メモリを割当に失敗");
return -1;
}
// ファイルが既に存在するかどうか確認
snprintf(gpgpathchk, alllen, "%s%s%s%s", homedir, basedir, file, ext);
if (access(gpgpathchk, F_OK) != 0) {
if (strncmp(lang, "en", 2) == 0)
perror("Password does not exist");
else perror("パスワードが存在しません");
free(gpgpathchk);
return -1;
}
free(gpgpathchk);
int needed = snprintf(
pwfile,
sizeof(pwfile),
"%s%s%s%s",
homedir,
basedir,
file,
ext
);
if (needed >= (int)sizeof(pwfile)) {
if (strncmp(lang, "en", 2) == 0)
perror("Error: Path is too long");
else perror("エラー:パスが長すぎる");
return -1;
}
// 削除を確認する
if (force == 0) { // パスワードの変更の場合、確認は不要
if (strncmp(lang, "en", 2) == 0)
printf("Is it really good if I delete the password '%s'? (y/N): ", file);
printf("パスワード「%s」を本当に削除する事が宜しいでしょうか? (y/N): ", file);
int confirm = getchar();
if (confirm != 'y' && confirm != 'Y') {
if (strncmp(lang, "en", 2) == 0) puts("Not deleted");
else puts("削除しませんでした");
return -1;
}
int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
}
if (unlink(pwfile) == -1) {
if (strncmp(lang, "en", 2) == 0)
perror("Password cannot be delete");
else perror("パスワードを削除出来ませんですた");
return -1;
}
// 空のディレクトリの場合
int numt;
char **tokens = explode(file, '/', &numt);
char basepath[1024];
char passpath[1024];
snprintf(basepath, sizeof(basepath), "%s%s", homedir, basedir);
snprintf(passpath, sizeof(passpath), "%s%s%s", homedir, basedir, tokens[0]);
char *ls = strrchr(basepath, '/');
if (ls != NULL) {
*ls = '\0';
}
for (int i = 1; i < numt; i++) {
if (i == (numt-1)) continue;
strncat(passpath, "/", sizeof(passpath) - strlen(passpath) - 1);
strncat(passpath, tokens[i], sizeof(passpath) - strlen(passpath) - 1);
}
for (int i = numt - 1; i >= 0; i--) {
// ~/.local/share/sp を削除したら危険
if (strncmp(passpath, basepath, sizeof(passpath)) == 0) {
break;
}
// ディレクトリが空じゃない場合、削除を止める
if (rmdir(passpath) == -1) {
break;
}
char *last_slash = strrchr(passpath, '/');
if (last_slash != NULL) {
*last_slash = '\0';
}
}
freetokens(tokens, numt);
// sp -e の場合、「パスワードを削除しました」って要らない
if (force == 1) return 0;
if (strncmp(lang, "en", 2) == 0) puts("Deleted password");
else puts("パスワードを削除しました");
return 0;
}

ファイルの表示

@ -1,6 +1,6 @@
#ifndef DELPASS_H #ifndef DELPASS_H
#define DELPASS_H #define DELPASS_H
int delpass(char* file); int delpass(char *file, int force);
#endif #endif

32
src/genpass.c ノーマルファイル
ファイルの表示

@ -0,0 +1,32 @@
#include "common.h"
#include "genpass.h"
void genpass(int count, bool issecure) {
char *lang = getlang();
const char *charset_risky =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
const char *charset_secure =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"#$%&'()=~-^\\|_@`[{]};:+*<>,./?";
const char *charset = issecure ? charset_secure : charset_risky;
FILE *fp = fopen("/dev/random", "rb");
if (fp == NULL) {
if (strncmp(lang, "en", 2) == 0)
perror("Could not opening /dev/random");
else perror("/dev/randomを開けられませんでした");
exit(EXIT_FAILURE);
}
char password[count + 1];
for (int i = 0; i < count; i++) {
unsigned char key;
fread(&key, sizeof(key), 1, fp);
password[i] = charset[key % strlen(charset)];
}
password[count] = '\0';
fclose(fp);
printf("%s\n", password);
}

ファイルの表示

58
src/initpass.c ノーマルファイル
ファイルの表示

@ -0,0 +1,58 @@
#include "common.h"
#include "initpass.h"
void initpass(char *gpgid) {
char *lang = getlang();
char *homedir = getenv("HOME");
if (homedir == NULL) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to getting home directory.");
else perror("ホームディレクトリを受取に失敗。");
return;
}
char *basedir = "/.local/share/sp/";
char dirpath[256];
snprintf(dirpath, sizeof(dirpath), "%s%s", homedir, basedir);
if (mkdir_r(dirpath, 0755) != 0 && errno != EEXIST) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to creating directory.");
else perror("ディレクトリを作成に失敗。");
return;
}
char gpgidpath[512];
snprintf(gpgidpath, sizeof(gpgidpath), "%s/.gpg-id", dirpath);
struct stat statbuf;
if (stat(gpgidpath, &statbuf) == 0) {
if (strncmp(lang, "en", 2) == 0)
perror(".gpg-id file is already exist.");
else perror(".gpg-idファイルは既に存在します。");
return;
}
FILE *gpgidfile = fopen(gpgidpath, "w");
if (gpgidfile == NULL) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to writing .gpg-id file.");
else perror(".gpg-idファイルを書き込めません。");
fclose(gpgidfile);
return;
}
if (fputs(gpgid, gpgidfile) == EOF) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to writing .gpg-id file.");
else perror(".gpg-idファイルへの書き込みに失敗しました。");
fclose(gpgidfile);
return;
}
fclose(gpgidfile);
if (strncmp(lang, "en", 2) == 0)
puts("First time setup was complete.");
else puts("初期設定に完了しました。");
}

ファイルの表示

56
src/listpass.c ノーマルファイル
ファイルの表示

@ -0,0 +1,56 @@
#include <dirent.h>
#include "common.h"
#include "listpass.h"
void listpass(char *basePath, int level) {
char *lang = getlang();
struct dirent *entry;
DIR* dir = opendir(basePath);
if (!dir) {
if (strncmp(lang, "en", 2) == 0)
perror("Could not opening directory");
else perror("ディレクトリを開けられません");
return;
}
while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
char path[1000];
int needed = snprintf(path, sizeof(path), "%s/%s", basePath, entry->d_name);
if (needed >= (int)sizeof(path) || needed < 0) {
if (strncmp(lang, "en", 2) == 0)
perror("Error: Path is too long, or failed to getting lenth");
else perror("エラー:パスが長すぎる、又は長さを受取に失敗");
continue;
}
struct stat statbuf;
if (stat(path, &statbuf) == -1) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to reading file status");
else perror("ファイル状況を読込に失敗");
continue;
}
for (int i = 0; i < level; i++) {
printf(" ");
}
if (S_ISDIR(statbuf.st_mode)) {
printf("|-- %s\n", entry->d_name);
listpass(path, level + 1);
} else if (S_ISREG(statbuf.st_mode)) {
char *filename = entry->d_name;
char *ext = strstr(filename, ".gpg");
if (ext) *ext = '\0';
printf("|-- %s\n", filename);
}
}
closedir(dir);
}

ファイルの表示

@ -1,6 +1,6 @@
#ifndef LISTPASS_H #ifndef LISTPASS_H
#define LISTPASS_H #define LISTPASS_H
void listpass(char* basePath, int level); void listpass(char *basePath, int level);
#endif #endif

159
src/otppass.c ノーマルファイル
ファイルの表示

@ -0,0 +1,159 @@
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include "base32.h"
#include "common.h"
#include "otppass.h"
unsigned char *extract_secret(const char *otpauth_url, size_t *decoded_len) {
char *lang = getlang();
const char *secret_start = strstr(otpauth_url, "secret=");
if (!secret_start) {
if (strncmp(lang, "en", 2) == 0)
perror("In the middle of the OTPAuth URL, could not found secret");
else perror("OTPAuth URLの中に、シークレットを見つけられませんでした");
return NULL;
}
secret_start += 7;
const char *secret_end = strchr(secret_start, '&');
if (!secret_end) {
if (secret_start[0] != '\0') {
secret_end = secret_start + strlen(secret_start);
} else {
secret_end = secret_start;
}
}
if (secret_end < secret_start) {
if (strncmp(lang, "en", 2) == 0)
perror("Illegal secret range");
else perror("不正なシークレットの距離");
return NULL;
}
size_t secret_len = secret_end - secret_start;
char *secret_encoded = (char *)malloc(secret_len + 1);
if (secret_encoded == NULL) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to allocating memory");
else perror("メモリの役割に失敗");
return NULL;
}
strncpy(secret_encoded, secret_start, secret_len);
secret_encoded[secret_len] = '\0';
unsigned char *secret_decoded = base32_decode(secret_encoded, decoded_len);
free(secret_encoded);
if (!secret_decoded) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to decrypting of the BASE32");
else perror("BASE32の復号化に失敗");
return NULL;
}
return secret_decoded;
}
uint32_t generate_totp(const char *secret, uint64_t counter) {
counter = htobe64(counter);
unsigned char hash[SHA_DIGEST_LENGTH];
HMAC(
EVP_sha1(),
secret,
strlen(secret),
(unsigned char *)&counter,
sizeof(counter),
hash,
NULL
);
int offset = hash[SHA_DIGEST_LENGTH - 1] & 0x0F;
uint32_t truncated_hash =
(hash[offset] & 0x7F) << 24 |
(hash[offset + 1] & 0xFF) << 16 |
(hash[offset + 2] & 0xFF) << 8 |
(hash[offset + 3] & 0xFF);
return truncated_hash % 1000000;
}
void otppass(char *file) {
char *lang = getlang();
gpgme_ctx_t ctx;
gpgme_error_t err;
gpgme_data_t in, out;
size_t secret_len;
gpgme_check_version(NULL);
err = gpgme_new(&ctx);
if (err) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to generating the GPG");
else perror("GPGMEを創作に失敗");
exit(1);
}
err = gpgme_data_new_from_file(&in, file, 1);
if (err) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to reading the GPG file");
else perror("GPGファイルを読込に失敗");
exit(1);
}
err = gpgme_data_new(&out);
if (err) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to reading the GPG data");
else perror("GPGデータを読込に失敗");
exit(1);
}
err = gpgme_op_decrypt(ctx, in, out);
if (err) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to decrypting the GPG");
else perror("GPGを復号化に失敗");
exit(1);
}
char *secret = gpgme_data_release_and_get_mem(out, &secret_len);
if (!secret) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to getting the GPG");
else perror("GPGを受取に失敗");
exit(1);
}
secret[secret_len] = '\0';
size_t decoded_len;
unsigned char *secret_decoded = extract_secret(secret, &decoded_len);
if (!secret_decoded) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to decoding or exporting secret");
else perror("シークレットの抽出又はデコードに失敗しました");
free(secret);
exit(1);
}
secret_decoded[decoded_len] = '\0';
time_t current_time = time(NULL);
uint64_t counter = current_time / 30;
uint32_t otp = generate_totp((const char *)secret_decoded, counter);
gpgme_data_release(in);
gpgme_release(ctx);
gpgme_free(secret);
free(secret_decoded);
printf("%06d\n", otp);
}

ファイルの表示

137
src/showpass.c ノーマルファイル
ファイルの表示

@ -0,0 +1,137 @@
#include <locale.h>
#include "common.h"
#include "showpass.h"
void clean_up(
gpgme_ctx_t ctx,
gpgme_data_t in,
gpgme_data_t out,
FILE *gpgfile,
char *gpgpath
) {
if (gpgfile) fclose(gpgfile);
if (gpgpath) free(gpgpath);
gpgme_data_release(in);
gpgme_data_release(out);
gpgme_release(ctx);
}
const char *showpass(char *file) {
char *lang = getlang();
gpgme_ctx_t ctx;
gpgme_error_t err;
gpgme_data_t in = NULL, out = NULL;
FILE *gpgfile;
// GPGMEライブラリを設置
setlocale(LC_ALL, "");
gpgme_check_version(NULL);
gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
// GPGMEを創作
err = gpgme_new(&ctx);
if (err) {
if (strncmp(lang, "en", 2) == 0)
fprintf(stderr, "Failed to generating GPGME: %s\n", gpgme_strerror(err));
else fprintf(stderr, "GPGMEを創作に失敗%s\n", gpgme_strerror(err));
return NULL;
}
// OpenPGPプロトコールを設定
gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
// 暗号化したタイルを開く
char *homedir = getenv("HOME");
if (homedir == NULL) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to getting home directory");
else perror("ホームディレクトリを受取に失敗");
return NULL;
}
char *basedir = "/.local/share/sp/";
char *ext = ".gpg";
int alllen = snprintf(NULL, 0, "%s%s%s%s", homedir, basedir, file, ext) + 1;
char *gpgpath = malloc(alllen);
if (gpgpath == NULL) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to allocating memeory");
else perror("メモリを割当に失敗");
return NULL;
}
snprintf(gpgpath, alllen, "%s%s%s%s", homedir, basedir, file, ext);
gpgfile = fopen(gpgpath, "rb");
if (gpgfile == NULL) {
if (strncmp(lang, "en", 2) == 0) {
perror("Failed to opening file");
} else {
perror("ファイルを開くに失敗");
}
free(gpgpath);
return NULL;
}
// ファイルからinデータオブジェクトを創作
if (gpgme_data_new_from_stream(&in, gpgfile) != GPG_ERR_NO_ERROR) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to generating the GPGME data object");
else perror("GPGMEデータオブジェクトを創作に失敗");
clean_up(ctx, in, out, gpgfile, gpgpath);
return NULL;
}
// outデータオブジェクトを創作
if (gpgme_data_new(&out) != GPG_ERR_NO_ERROR) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to generating the GPGME data object");
else perror("GPGMEデータオブジェクトを創作に失敗");
clean_up(ctx, in, out, gpgfile, gpgpath);
return NULL;
}
// データオブジェクトを創作
gpgme_data_new(&out);
// 復号化して
err = gpgme_op_decrypt(ctx, in, out);
if (err) {
if (strncmp(lang, "en", 2) == 0)
fprintf(stderr, "Failed to decrypting: %s\n", gpgme_strerror(err));
else fprintf(stderr, "復号化に失敗: %s\n", gpgme_strerror(err));
// 掃除
clean_up(ctx, in, out, gpgfile, gpgpath);
return NULL;
}
// 復号化したパスワードを表示する
gpgme_data_seek(out, 0, SEEK_SET);
char buffer[512];
char *res = malloc(512 * sizeof(char));
if (res == NULL) {
if (strncmp(lang, "en", 2) == 0)
perror("Failed to allocating memory");
else perror("メモリを役割に失敗");
clean_up(ctx, in, out, gpgfile, gpgpath);
return NULL;
}
ssize_t read_bytes;
int i = 0;
while ((read_bytes = gpgme_data_read(out, buffer, sizeof(buffer) - 1)) > 0) {
memcpy(res + i, buffer, read_bytes);
i += read_bytes;
}
res[i] = '\0';
if (res[i-1] == '\n') res[i-1] = '\0';
// 掃除
clean_up(ctx, in, out, gpgfile, gpgpath);
return res;
}

ファイルの表示

@ -1,6 +1,6 @@
#ifndef SHOWPASS_H #ifndef SHOWPASS_H
#define SHOWPASS_H #define SHOWPASS_H
void showpass(char* file); const char *showpass(char *file);
#endif #endif

ファイルの表示

@ -1,17 +1,18 @@
#include <stdio.h>
#include <stdlib.h>
#include <locale.h> #include <locale.h>
#include <unistd.h> #include <unistd.h>
#include <gpgme.h> #include "common.h"
#include "yankpass.h" #include "yankpass.h"
#include "showpass.h" #include "showpass.h"
void yankpass(char* file) { void yankpass(char *file) {
char *lang = getlang();
// Xセッションではない場合(例えば、SSH、TTY、Gayland等)、showpass()を実行して // Xセッションではない場合(例えば、SSH、TTY、Gayland等)、showpass()を実行して
if (getenv("DISPLAY") == NULL) { if (getenv("DISPLAY") == NULL) {
printf("Xセッションではありませんので、「sp -s」を実行します。\n"); if (strncmp(lang, "en", 2) == 0)
puts("There is no X session, so executing 'sp -s'.");
else puts("Xセッションではありませんので、「sp -s」を実行します。");
showpass(file); showpass(file);
return; return;
} }
@ -29,7 +30,9 @@ void yankpass(char* file) {
// GPGMEを創作 // GPGMEを創作
err = gpgme_new(&ctx); err = gpgme_new(&ctx);
if (err) { if (err) {
fprintf(stderr, "GPGMEを創作に失敗%s\n", gpgme_strerror(err)); if (strncmp(lang, "en", 2) == 0)
fprintf(stderr, "Failed to generating GPGME: %s\n", gpgme_strerror(err));
else fprintf(stderr, "GPGMEを創作に失敗%s\n", gpgme_strerror(err));
return; return;
} }
@ -39,7 +42,9 @@ void yankpass(char* file) {
// 暗号化したタイルを開く // 暗号化したタイルを開く
char* homedir = getenv("HOME"); char* homedir = getenv("HOME");
if (homedir == NULL) { if (homedir == NULL) {
perror("ホームディレクトリを受取に失敗。"); if (strncmp(lang, "en", 2) == 0)
perror("Failed to getting home directory");
else perror("ホームディレクトリを受取に失敗");
return; return;
} }
@ -48,15 +53,22 @@ void yankpass(char* file) {
int alllen = snprintf(NULL, 0, "%s%s%s%s", homedir, basedir, file, ext) + 1; int alllen = snprintf(NULL, 0, "%s%s%s%s", homedir, basedir, file, ext) + 1;
char* gpgpath = malloc(alllen); char* gpgpath = malloc(alllen);
if (gpgpath == NULL) { if (gpgpath == NULL) {
perror("メモリを割当に失敗。"); if (strncmp(lang, "en", 2) == 0)
perror("Failed to allocating memory");
else perror("メモリを割当に失敗");
return; return;
} }
sprintf(gpgpath, "%s%s%s%s", homedir, basedir, file, ext); snprintf(gpgpath, alllen, "%s%s%s%s", homedir, basedir, file, ext);
gpgfile = fopen(gpgpath, "rb"); gpgfile = fopen(gpgpath, "rb");
if (gpgfile == NULL) { if (gpgfile == NULL) {
perror("ファイルを開くに失敗。"); if (strncmp(lang, "en", 2) == 0) {
printf("失敗したパス: %s\n", gpgpath); perror("Failed to opening the file");
fprintf(stderr, "Failed path: %s\n", gpgpath);
} else {
perror("ファイルを開くに失敗");
fprintf(stderr, "失敗したパス: %s\n", gpgpath);
}
free(gpgpath); free(gpgpath);
return; return;
} }
@ -68,7 +80,9 @@ void yankpass(char* file) {
// 復号化して // 復号化して
err = gpgme_op_decrypt(ctx, in, out); err = gpgme_op_decrypt(ctx, in, out);
if (err) { if (err) {
fprintf(stderr, "復号化に失敗: %s\n", gpgme_strerror(err)); if (strncmp(lang, "en", 2) == 0)
fprintf(stderr, "Failed to decryption: %s\n", gpgme_strerror(err));
else fprintf(stderr, "復号化に失敗: %s\n", gpgme_strerror(err));
// 掃除 // 掃除
fclose(gpgfile); fclose(gpgfile);
@ -89,7 +103,9 @@ void yankpass(char* file) {
gpgme_data_release(in); gpgme_data_release(in);
gpgme_data_release(out); gpgme_data_release(out);
gpgme_release(ctx); gpgme_release(ctx);
perror("クリップボードを見つけられませんでした。"); if (strncmp(lang, "en", 2) == 0)
perror("Could not found a clipboard");
else perror("クリップボードを見つけられませんでした");
return; return;
} }
@ -109,7 +125,18 @@ void yankpass(char* file) {
pclose(pipe); pclose(pipe);
// 45秒後、クリップボードから削除する // 45秒後、クリップボードから削除する
printf("パスワードをクリップボードに追加しました。\n45秒後はクリップボードから取り消されます。\n"); if (strncmp(lang, "en", 2) == 0)
printf(
"%s\n%s\n",
"Added password to the clipboard.",
"I will take it away from the clipboard after 45 second."
);
else
printf(
"%s\n%s\n",
"パスワードをクリップボードに追加しました。",
"45秒後はクリップボードから取り消されます。"
);
sleep(45); sleep(45);
system("echo -n | xclip -selection clipboard"); system("echo -n | xclip -selection clipboard");

ファイルの表示

@ -1,6 +1,6 @@
#ifndef YANKPASS_H #ifndef YANKPASS_H
#define YANKPASS_H #define YANKPASS_H
void yankpass(char* file); void yankpass(char *file);
#endif #endif