aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsinanmohd <sinan@sinanmohd.com>2024-04-09 22:24:15 +0530
committersinanmohd <sinan@sinanmohd.com>2024-04-09 22:25:30 +0530
commit4fcff492c978e1d355373978170dac5ebdef26cd (patch)
treee9092427f6a0a3995ee970f7b2b842efecab2f5c
parentd926dd0ae80ab3823c5d0d4ee024353b28a4412f (diff)
pass/ls: init
-rw-r--r--README.md4
-rw-r--r--include/libnpass/libnpass.h20
-rw-r--r--meson.build1
-rw-r--r--src/libnpass/libnpass.c170
-rw-r--r--src/npass/npass.c71
5 files changed, 261 insertions, 5 deletions
diff --git a/README.md b/README.md
index 14b85f6..410b608 100644
--- a/README.md
+++ b/README.md
@@ -8,9 +8,9 @@ section.
Todo
----
-- [ ] cmdline
+- [x] cmdline
- [x] pass init
- - [ ] pass ls
+ - [x] pass ls
- [x] pass rm
- [x] pass add
- [x] pass gen
diff --git a/include/libnpass/libnpass.h b/include/libnpass/libnpass.h
index ac7423a..130954d 100644
--- a/include/libnpass/libnpass.h
+++ b/include/libnpass/libnpass.h
@@ -1,4 +1,6 @@
#include <stdio.h>
+#include <dirent.h>
+#include <linux/limits.h>
typedef enum {
PASS_GEN_DIGIT = 0,
@@ -6,6 +8,24 @@ typedef enum {
PASS_GEN_GRAPH = 2,
} pass_gen_t;
+typedef enum {
+ PASS_STORE_DIR = 0,
+ PASS_STORE_ENC = 1,
+ PASS_STORE_INV = 2,
+} pass_store_t;
+
+struct store {
+ char name[NAME_MAX];
+ pass_store_t type;
+};
+
+DIR *openstore(const char *spath);
+int readstore(DIR *dirp, struct store *s);
+int readstore_all(const char *path, struct store **stor);
+
+pass_store_t pass_store_type(const char *spath);
+int pass_store_cmp(const void *vp1, const void *vp2);
+
int pass_init(const char *fpr);
int pass_cat(FILE *out, const char *path);
int pass_add(const char *path, const char *pass, size_t n);
diff --git a/meson.build b/meson.build
index ff77d19..0384579 100644
--- a/meson.build
+++ b/meson.build
@@ -12,6 +12,7 @@ project(
add_project_arguments(
[
'-D_POSIX_C_SOURCE=200809L',
+ '-D_DEFAULT_SOURCE',
'-Wvla',
],
language: 'c',
diff --git a/src/libnpass/libnpass.c b/src/libnpass/libnpass.c
index aa1a285..37fc40c 100644
--- a/src/libnpass/libnpass.c
+++ b/src/libnpass/libnpass.c
@@ -7,6 +7,7 @@
#include <libgen.h>
#include <termios.h>
#include <stdio.h>
+#include <dirent.h>
#include "libnpass/libnpass.h"
#include "libnpass/gpg.h"
@@ -14,8 +15,8 @@
#include "util.h"
-#define DEF_PASS_DIR "pass"
-#define FPR_MAX 256
+#define DEF_PASS_DIR "pass"
+#define FPR_MAX NAME_MAX
static char pass_dir[PATH_MAX] = {0};
const char *pass_gen_set[] = {
@@ -32,6 +33,7 @@ const char *pass_gen_set[] = {
};
int set_pass_dir(void);
+int is_storeobj(struct dirent *dir);
int set_pass_dir(void) {
const char *env;
@@ -59,6 +61,170 @@ int set_pass_dir(void) {
return 1;
}
+int pass_store_cmp(const void *vp1, const void *vp2) {
+ struct store *sp1, *sp2;
+
+ sp1 = (struct store *) vp1;
+ sp2 = (struct store *) vp2;
+ return strcmp(sp1->name, sp2->name);
+}
+
+int is_storeobj(struct dirent *dir) {
+ int r;
+ char *s;
+
+ switch (dir->d_type) {
+ case DT_DIR:
+ r = strcmp(dir->d_name, ".");
+ if (r)
+ r = strcmp(dir->d_name, "..");
+
+ return r;
+ break;
+ case DT_REG:
+ s = strrchr(dir->d_name, '.');
+ if (!s)
+ return 0;
+
+ r = strcmp(s, ".gpg");
+ return (r == 0);
+ break;
+ default:
+ return 0;
+ break;
+ }
+}
+
+pass_store_t pass_store_type(const char *spath) {
+ int r;
+ struct stat sbuf;
+ char abs_path[PATH_MAX];
+
+ r = set_pass_dir();
+ if (r)
+ err_ret(PASS_STORE_INV, "PASSWORD_STORE_DIR not set");
+
+ r = snprintf(abs_path, sizeof(abs_path) - 1, "%s/%s",
+ pass_dir, spath);
+ if (r >= (int) sizeof(abs_path))
+ err_ret(PASS_STORE_INV, "path exceeded PATH_MAX");
+ r = stat(abs_path, &sbuf);
+ if (!r && (sbuf.st_mode & S_IFMT) == S_IFDIR)
+ return PASS_STORE_DIR;
+
+ r = snprintf(abs_path, sizeof(abs_path) - 1, "%s/%s.gpg",
+ pass_dir, spath);
+ if (r >= (int) sizeof(abs_path))
+ err_ret(PASS_STORE_INV, "path exceeded PATH_MAX");
+ r = stat(abs_path, &sbuf);
+ if (r)
+ err_ret(PASS_STORE_INV, "%s", strerror(errno));
+
+ if ((sbuf.st_mode & S_IFMT) == S_IFREG) {
+ return PASS_STORE_ENC;
+ } else {
+ err_ret(PASS_STORE_INV, "%s is not a regular file", abs_path);
+ }
+}
+
+DIR *openstore(const char *spath) {
+ int r;
+ DIR *d;
+ const char *path;
+ char abs_path[PATH_MAX];
+
+ r = set_pass_dir();
+ if (r)
+ err_ret(NULL, "PASSWORD_STORE_DIR not set");
+
+ if (spath) {
+ r = snprintf(abs_path, sizeof(abs_path) - 1, "%s/%s",
+ pass_dir, spath);
+ if (r >= (int) sizeof(abs_path))
+ err_ret(NULL, "path exceeded PATH_MAX");
+
+ path = abs_path;
+ } else {
+ path = pass_dir;
+ }
+
+ d = opendir(path);
+ if (!d)
+ err_ret(NULL, "%s", strerror(errno));
+
+ return d;
+}
+
+int readstore(DIR *dirp, struct store *s) {
+ struct dirent *dir;
+
+ errno = 0;
+
+ while ((dir = readdir(dirp))) {
+ if (is_storeobj(dir))
+ break;
+ }
+
+ if (!dir) {
+ if (errno != 0)
+ err_ret(1, "%s", strerror(errno));
+
+ return EOF;
+ }
+
+ strncpy(s->name , dir->d_name, sizeof(s->name));
+ switch (dir->d_type) {
+ case DT_DIR:
+ s->type = PASS_STORE_DIR;
+ break;
+ case DT_REG:
+ /* this is safe since is_storeobj()
+ * rejects files without .gpg suffix */
+ *(strrchr(s->name, '.')) = '\0';
+ s->type = PASS_STORE_ENC;
+ break;
+ default:
+ s->type = PASS_STORE_INV;
+ break;
+ }
+
+ return 0;
+}
+
+int readstore_all(const char *path, struct store **stor) {
+ int r;
+ void *p;
+ size_t i;
+ DIR *dirp;
+ size_t len = PATH_MAX;
+
+ *stor = malloc(sizeof(struct store) * len);
+ if (!*stor)
+ err_ret(-1, "%s", strerror(errno));
+
+ dirp = openstore(path);
+ if (!dirp) {
+ free(*stor);
+ return -1;
+ };
+
+ for (i = 0; !(r = readstore(dirp, *stor + i)); i++) {
+ if (i < len - 1)
+ continue;
+
+ len *= 2;
+ p = realloc(*stor, sizeof(**stor) * len);
+ if (!p) {
+ free(*stor);
+ err_ret(-1, "%s", strerror(errno));
+ } else {
+ *stor = p;
+ }
+ }
+
+ return i;
+}
+
int pass_init(const char *fpr)
{
int r;
diff --git a/src/npass/npass.c b/src/npass/npass.c
index a055317..0b5f792 100644
--- a/src/npass/npass.c
+++ b/src/npass/npass.c
@@ -7,12 +7,22 @@
#include "libnpass/libnpass.h"
#include "util.h"
-#define invalid_usage_err_ret() err_ret(1, "invalid usage, try pass help")
+#define invalid_usage_err_ret() \
+ err_ret(1, "invalid usage, try pass help")
+
+#define BLUE "\e[0;34m"
+#define NCOL "\e[0m"
+
+typedef enum {
+ DEPTH_ITS_OVER = 0,
+ DEPTH_NOT_OVER = 1,
+} depth_state_t;
void print_usage(void);
int cat(const char *path);
int add(const char *path);
int gen(int argc, char *argv[]);
+int ls(const char *path, size_t depth, depth_state_t *depth_state);
void print_usage(void)
{
@@ -46,6 +56,60 @@ int cat(const char *path)
return r;
}
+int ls(const char *path, size_t depth, depth_state_t *depth_state) {
+ void *p;
+ char *prefix;
+ int i, j, len;
+ struct store *stor;
+ char new_path[PATH_MAX];
+ static size_t depth_state_len = NAME_MAX;
+
+ len = readstore_all(path, &stor);
+ if (len < 0)
+ return 1;
+
+ if (!depth) {
+ depth_state = malloc(sizeof(depth_state_t) * depth_state_len);
+ puts((path) ? path : "Password Store");
+ } else if (depth == depth_state_len - 1) {
+ depth_state_len *= 2;
+ p = realloc(stor, sizeof(depth_state[0]) * len);
+ if (!p)
+ err_ret(1, "%s", strerror(errno));
+ depth_state = p;
+ }
+
+ qsort(stor, len, sizeof(stor[0]), pass_store_cmp);
+ for (i = 0; i < len; i++) {
+ if (i == len - 1) {
+ prefix = "└──";
+ depth_state[depth] = DEPTH_ITS_OVER;
+ } else {
+ prefix = "├──";
+ depth_state[depth] = DEPTH_NOT_OVER;
+ }
+
+ for (j = 0; (size_t) j < depth; j++)
+ printf("%s ", (depth_state[j]) == DEPTH_ITS_OVER ? " " : "│");
+
+ if (stor[i].type == PASS_STORE_DIR) {
+ printf("%s %s%s%s\n", prefix, BLUE, stor[i].name, NCOL);
+
+ snprintf(new_path, sizeof(new_path) - 1, "%s/%s",
+ (path) ? path : "", stor[i].name);
+ ls(new_path, depth + 1, depth_state);
+ } else {
+ printf("%s %s\n", prefix, stor[i].name);
+ }
+ }
+
+ if (!depth)
+ free(depth_state);
+ free(stor);
+
+ return 0;
+}
+
int add(const char *path)
{
char *p1 = NULL, *p2 = NULL;
@@ -153,6 +217,11 @@ int main(int argc, char *argv[])
invalid_usage_err_ret();
r = pass_init(argv[1]);
+ } else if (!strcmp("ls", *argv)) {
+ if (argc > 2)
+ invalid_usage_err_ret();
+
+ r = ls(argv[1], 0, NULL);
} else if (!strcmp("cat", *argv)) {
if (argc != 2)
invalid_usage_err_ret();