diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..857bcc0 --- /dev/null +++ b/src/main.c @@ -0,0 +1,3 @@ +int main(int argc, const char *argv[]) { + return 0; +} diff --git a/src/sekrits.c b/src/sekrits.c new file mode 100644 index 0000000..57b3048 --- /dev/null +++ b/src/sekrits.c @@ -0,0 +1,92 @@ +#include +#include +#include + +#include "sekrits.h" + +/// SEKRITS CODE + +struct sekrits_node { + struct sekrits_node *next; + char *name; + char *value; +}; + +struct sekrits { + struct sekrits_node *root; +}; + +int sekrits_create_from_filename(struct sekrits **ppsekrits, const char *filename) { + FILE *stream = fopen(filename, "r"); + if (stream == NULL) { + perror("couldn't open file"); + return SEKRITS_ERROR; + } + int result = sekrits_create_from_file(ppsekrits, stream); + fclose(stream); + return result; +} + +/* used to define how long a sekrit line is allowed to be (this includes the + * sekrit name and value) */ +#define SEKRIT_MAX_LINE_LEN 8096 + +int sekrits_create_from_file(struct sekrits **ppsekrits, FILE *file) { + struct sekrits *out = (struct sekrits *)malloc(sizeof(struct sekrits)); + if (file == NULL) { + return SEKRITS_ERROR; + } + char sekrit_buf[SEKRIT_MAX_LINE_LEN] = {0}; + char *line_end; + size_t line_num = 0; + while ((line_end = fgets(sekrit_buf, SEKRIT_MAX_LINE_LEN, file)) != NULL) { + ++line_num; + ssize_t total_len = line_end - sekrit_buf; + char *iter; + for (iter = sekrit_buf; iter < line_end; ++iter) { + if (*iter == '\\') { + ++iter; + continue; + } else if (*iter == '=') { + *iter = '\0'; + ++iter; + break; + } + } + char *name = sekrit_buf; + size_t name_len = iter - sekrit_buf; + char *value = iter; + size_t value_len = line_end - iter; +// char name_buf[SEKRIT_MAX_LINE_LEN] = {0}; +// char value_buf[SEKRIT_MAX_LINE_LEN] = {0}; +// char terminator = 0; +// int read_bytes = 0; +// do { +// int res = sscanf(file, "%[^\\=]%n%[\=]c%s", name_buf, &read_bytes, ); +// } while (res != 2); + }; + *ppsekrits = out; + return SEKRITS_OK; +} + +int sekrits_destroy(struct sekrits *thing) { + if (thing != NULL) { + free(thing); + } + return SEKRITS_OK; +} +int sekrits_fetch(const struct sekrits *, const char *name, char *buf, size_t len); + +const char *sekrits_get(struct sekrits *secrets, const char *name) { + if (secrets == NULL) { + return NULL; + } + struct sekrits_node *curr = secrets->root; + while (curr != NULL) { + if (strcmp(curr->name, name)) { + return curr->value; + } + curr = curr->next; + }; + return NULL; +} diff --git a/src/sekrits.h b/src/sekrits.h new file mode 100644 index 0000000..1f4f07e --- /dev/null +++ b/src/sekrits.h @@ -0,0 +1,30 @@ +#ifndef WTFTRAINS_SEKRITS_H +#define WTFTRAINS_SEKRITS_H + +/** + * Library for loading/storing secrets encoded as simple NAME=VALUE, + * newline-delimited pairs in a text file. + */ + +#define SEKRITS_ERROR -1 +#define SEKRITS_OK 0 + +/* opaque struct for storing sekrit information */ +struct sekrits; + +/* load a secret store from an opened file handle */ +int sekrits_create_from_file(struct sekrits **, FILE *file); +/* load a secret store from a filename */ +int sekrits_create_from_filename(struct sekrits **, const char *filename); +/* destroys an object created with sekrits_create_* */ +int sekrits_destroy(struct sekrits *); + +/* lists all of the names */ +int sekrits_list_names(const struct sekrits *, char ** names, size_t len); +/* fetches one specific value, given a name */ +int sekrits_fetch(const struct sekrits *, const char *name, char *buf, size_t len); + +/* convenience function to get the value of a sekrit */ +const char *sekrits_get(struct sekrits *secrets, const char *name); + +#endif // WTFTRAINS_SEKRITS_H diff --git a/tests/check_sekrits.c b/tests/check_sekrits.c new file mode 100644 index 0000000..1404be3 --- /dev/null +++ b/tests/check_sekrits.c @@ -0,0 +1,68 @@ +#include +#include +#include + +#include "../src/sekrits.h" + +START_TEST(test_create_from_file) { + const char *cases[] ={ + "hello=true", + "OK=FINE\n", + "notok" + }; + for (int i = 0; i < sizeof(cases); ++ i) { + struct sekrits *secrets = NULL; + FILE *data = fmemopen((char *)cases[i], strlen(cases[i]) + 1, "r"); + ck_assert_msg( + sekrits_create_from_file(&secrets, data) == SEKRITS_OK, + "Was expecting valid secret data to load from %s", cases[i] + ); + sekrits_destroy(secrets); + fclose(data); + } +} +END_TEST + +START_TEST(test_create_from_file_neg) { + const char *cases[] ={ + "notok" + }; + for (int i = 0; i < sizeof(cases); ++ i) { + printf("running case"); + struct sekrits *secrets = NULL; + FILE *data = fmemopen((char *)cases[i], strlen(cases[i]) + 1, "r"); + ck_assert_msg( + sekrits_create_from_file(&secrets, data) == SEKRITS_ERROR, + "Was expecting invalid secret data to load from %s", cases[i] + ); + sekrits_destroy(secrets); + fclose(data); + } +} +END_TEST + +Suite * sekrits_suite(void) { + TCase *tc_create_file; + tc_create_file = tcase_create("create_from_file"); + tcase_add_test(tc_create_file, test_create_from_file); + + TCase *tc_create_file_neg; + tc_create_file_neg = tcase_create("create_from_file_neg"); + tcase_add_test(tc_create_file_neg, test_create_from_file_neg); + + Suite *s = suite_create("sekrits"); + suite_add_tcase(s, tc_create_file); + suite_add_tcase(s, tc_create_file_neg); + return s; +} + +int main(void) { + int number_failed; + SRunner *srunner = srunner_create(sekrits_suite()); + + srunner_run_all(srunner, CK_VERBOSE); + number_failed = srunner_ntests_failed(srunner); + srunner_free(srunner); + + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +}