~callum/gmisub

0b9d768073f85c95e1ae36e3351205ab4e7c2eb7 — Callum Brown 1 year, 8 months ago b84a238
Update to use new bearssl version of gmni
4 files changed, 28 insertions(+), 21 deletions(-)

M Makefile
M README.md
M gmisub.1.scd
M gmisub.c
M Makefile => Makefile +1 -1
@@ 8,7 8,7 @@ SCDOC=scdoc
CPPFLAGS=-Iinclude -MMD -MP
CFLAGS=-Wall
LDFLAGS=-Llib
LDLIBS=-lssl -lcrypto -lgmni
LDLIBS=-lgmni -lbearssl

BUILDDIR=build


M README.md => README.md +1 -1
@@ 18,9 18,9 @@ It takes a list of Gemini URLs and extracts the feed entries. These are output t
Dependencies:

- A POSIX-like system and a C11 compiler
- OpenSSL
- [scdoc](https://git.sr.ht/~sircmpwn/scdoc)
- [gmni](https://git.sr.ht/~sircmpwn/gmni)
- [BearSSL](https://www.bearssl.org/) (Dependency of gmni)

```
$ git clone https://git.sr.ht/~callum/gmisub

M gmisub.1.scd => gmisub.1.scd +1 -1
@@ 22,7 22,7 @@ _output_path_ is the file which the generated aggregate will be written to.

*gmisub* uses *gmni*(1)'s TOFU system. If a domain has an associated
certificate fingerprint already stored in the known_hosts file (probably at
~/.local/share/gemini/known_hosts) then the received certificate will be
~/.local/share/gmni/known_hosts) then the received certificate will be
verified. If not, the received certificate will be trusted once but will not
be added to the known_hosts file.


M gmisub.c => gmisub.c +25 -18
@@ 5,7 5,8 @@
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <openssl/err.h>
#include <fcntl.h>
#include <bearssl.h>
#include <gmni/gmni.h>
#include <gmni/tofu.h>



@@ 69,6 70,19 @@ tofu_callback(enum tofu_error error, const char *fingerprint,


/* From gmnlm.c */
static int
resp_read(void *state, void *buf, size_t nbyte)
{
	struct gemini_response *resp = state;
	if (resp->sc) {
		return br_sslio_read(&resp->body, buf, nbyte);
	} else {
		return read(resp->fd, buf, nbyte);
	}
}


/* From gmnlm.c */
static char *
trim_ws(char *in)
{


@@ 191,8 205,9 @@ main(int argc, char *argv[])
	}

	// Open config file
	FILE *config_fp = fopen(argv[argc-2], "r");
	if (!config_fp) {
	// Use open() system call because of how gmni's parser works
	int config_fd = open(argv[argc-2], O_RDONLY);
	if (config_fd < 0) {
		fprintf(stderr, "Failed to open config file for reading: %s.\n", argv[1]);
		return 1;
	}


@@ 232,21 247,14 @@ main(int argc, char *argv[])
	struct tofu_config cfg;
	// Trust certificate without looking at known_hosts
	cfg.action = TOFU_TRUST_ONCE;
	SSL_load_error_strings();
	ERR_load_crypto_strings();
	opts.ssl_ctx = SSL_CTX_new(TLS_method());
	gemini_tofu_init(&cfg.tofu, opts.ssl_ctx, &tofu_callback, &cfg);
	gemini_tofu_init(&cfg.tofu, &tofu_callback, &cfg);

	// Make a gmni response from the config file
	struct gemini_response config_resp;
	BIO *file = BIO_new_fp(config_fp, BIO_CLOSE);
	config_resp.bio = BIO_new(BIO_f_buffer());
	BIO_push(config_resp.bio, file);
	config_resp.meta = strdup("text/gemini");
	config_resp.status = GEMINI_STATUS_SUCCESS;
	config_resp.fd = -1;
	config_resp.ssl = NULL;
	config_resp.ssl_ctx = NULL;
	config_resp.fd = config_fd;
	config_resp.sc = NULL;

	// Initialise dates with a value so it can be realloced in insert_date
	int *dates = malloc(sizeof(int));


@@ 262,14 270,14 @@ main(int argc, char *argv[])
	// Parse config file
	struct gemini_parser config_parser;
	struct gemini_token config_tok;
	gemini_parser_init(&config_parser, config_resp.bio);
	gemini_parser_init(&config_parser, &resp_read, &config_resp);
	while (gemini_parser_next(&config_parser, &config_tok) == 0) {
		// Make requests and output links
		if (token_is_good_link(config_tok)) {
			// Get gemlog index page
			fprintf(stdout, "Attempting request to %s\n", config_tok.link.url);
			struct gemini_response resp;
			enum gemini_result r = gemini_request(config_tok.link.url, &opts, &resp);
			enum gemini_result r = gemini_request(config_tok.link.url, &opts, &cfg.tofu, &resp);
			if (bad_response(r, &resp)) {
				gemini_response_finish(&resp);
				fprintf(stdout, "Skipping due to failed request.\n\n");


@@ 295,7 303,7 @@ main(int argc, char *argv[])
			// Parse gemlog index page
			struct gemini_parser p;
			struct gemini_token tok;
			gemini_parser_init(&p, resp.bio);
			gemini_parser_init(&p, &resp_read, &resp);
			while (gemini_parser_next(&p, &tok) == 0) {
				if (!title_seen && token_is_heading(tok, 1)) {
					feed_title = trim_ws(tok.heading.title);


@@ 449,8 457,7 @@ finish:
	free(entry_groups);
	gemini_token_finish(&config_tok);
	gemini_parser_finish(&config_parser);
	gemini_response_finish(&config_resp); // Closes config_fp
	gemini_response_finish(&config_resp); // Closes config_fd
	gemini_tofu_finish(&cfg.tofu);
	SSL_CTX_free(opts.ssl_ctx);
	return 0;
}