commit - 12472189518006a105ca309e5443be98a646b8a1
commit + 5a39f5931f4b5be1d57d75c7f25cff8adae5f235
blob - 00c6e94de447c08d07ccb19a922584839ab9e024
blob + cd2a4d10283bf4ad5deabc320552d4c15cff03a3
--- certs.c
+++ certs.c
/* client certificate */
struct ccert {
- char *line; /* fields below points inside here */
char *host;
char *port;
char *path;
char *cert;
};
-static struct cert_store {
+static struct cstore {
struct ccert *certs;
size_t len;
size_t cap;
-} cert_store;
+} cert_store, temp_store;
char **identities;
static size_t id_len, id_cap;
}
static int
-certs_store_add(const char *l)
+certs_store_add(struct cstore *cstore, const char *host, const char *port,
+ const char *path, const char *cert)
{
- size_t newcap;
- void *t;
- char *line, *host, *port, *path, *cert;
+ struct ccert *c;
+ void *t;
+ size_t newcap;
- if ((line = strdup(l)) == NULL)
- return (-1);
+ if (cstore->len == cstore->cap) {
+ newcap = cstore->cap + 8;
+ t = reallocarray(cstore->certs, newcap,
+ sizeof(*cstore->certs));
+ if (t == NULL)
+ return (-1);
+ cstore->certs = t;
+ cstore->cap = newcap;
+ }
- host = line;
- while (isspace((unsigned char)*host))
- ++host;
+ c = &cstore->certs[cstore->len];
+ if ((c->host = strdup(host)) == NULL ||
+ (c->port = strdup(port)) == NULL ||
+ (c->path = strdup(path)) == NULL ||
+ (c->cert = strdup(cert)) == NULL) {
+ free(c->host);
+ free(c->port);
+ free(c->path);
+ free(c->cert);
+ memset(c, 0, sizeof(*c));
+ }
+ cstore->len++;
- if (*host == '#') {
- free(line);
+ return (0);
+}
+
+static int
+certs_store_parse_line(struct cstore *cstore, char *line)
+{
+ char *host, *port, *path, *cert;
+
+ while (isspace((unsigned char)*line))
+ ++line;
+ if (*line == '#' || *line == '\0')
return (0);
- }
+ host = line;
+
port = host + strcspn(host, " \t");
if (*port == '\0')
- goto err;
+ return (-1);
*port++ = '\0';
while (isspace((unsigned char)*port))
++port;
path = port + strcspn(port, " \t");
if (*path == '\0')
- goto err;
+ return (-1);
*path++ = '\0';
while (isspace((unsigned char)*path))
++path;
cert = path + strcspn(path, " \t");
if (*cert == '\0')
- goto err;
+ return (-1);
*cert++ = '\0';
while (isspace((unsigned char)*cert))
++cert;
if (*cert == '\0')
- goto err;
+ return (-1);
- if (cert_store.len == cert_store.cap) {
- newcap = cert_store.cap + 8;
- t = reallocarray(cert_store.certs, newcap,
- sizeof(*cert_store.certs));
- if (t == NULL)
- goto err;
- cert_store.certs = t;
- cert_store.cap = newcap;
- }
-
- cert_store.certs[cert_store.len].line = line;
- cert_store.certs[cert_store.len].host = host;
- cert_store.certs[cert_store.len].port = port;
- cert_store.certs[cert_store.len].path = path;
- cert_store.certs[cert_store.len].cert = cert;
- cert_store.len++;
-
- return (0);
-
- err:
- free(line);
- return (-1);
+ return (certs_store_add(cstore, host, port, path, cert));
}
int
if (line[linelen - 1] == '\n')
line[--linelen] = '\0';
- if (certs_store_add(line) == -1) {
+ if (certs_store_parse_line(&cert_store, line) == -1) {
fclose(fp);
free(line);
return (-1);
return (cpath[-1] == '/');
}
-const char *
-cert_for(struct iri *iri)
+static struct ccert *
+find_cert_for(struct cstore *cstore, struct iri *iri)
{
struct ccert *c;
size_t i;
- for (i = 0; i < cert_store.len; ++i) {
- c = &cert_store.certs[i];
+ for (i = 0; i < cstore->len; ++i) {
+ c = &cstore->certs[i];
if (!strcmp(c->host, iri->iri_host) &&
!strcmp(c->port, iri->iri_portstr) &&
path_under(c->path, iri->iri_path))
- return (c->cert);
+ return (c);
}
return (NULL);
}
+const char *
+cert_for(struct iri *iri)
+{
+ struct ccert *c;
+
+ if ((c = find_cert_for(&temp_store, iri)) != NULL)
+ return (c->cert);
+ if ((c = find_cert_for(&cert_store, iri)) != NULL)
+ return (c->cert);
+ return (NULL);
+}
+
+static int
+write_cert_file(void)
+{
+ struct ccert *c;
+ FILE *fp;
+ char sfn[PATH_MAX];
+ size_t i;
+ int fd, r;
+
+ strlcpy(sfn, certs_file_tmp, sizeof(sfn));
+ if ((fd = mkstemp(sfn)) == -1 ||
+ (fp = fdopen(fd, "w")) == NULL) {
+ if (fd != -1) {
+ unlink(sfn);
+ close(fd);
+ }
+ return (-1);
+ }
+
+ for (i = 0; i < cert_store.len; ++i) {
+ c = &cert_store.certs[i];
+ if (c->cert == NULL)
+ continue;
+
+ r = fprintf(fp, "%s\t%s\t%s\t%s\n", c->host, c->port,
+ c->path, c->cert);
+ if (r < 0) {
+ fclose(fp);
+ unlink(sfn);
+ return (-1);
+ }
+ }
+
+ if (ferror(fp)) {
+ fclose(fp);
+ unlink(sfn);
+ return (-1);
+ }
+
+ if (fclose(fp) == EOF) {
+ unlink(sfn);
+ return (-1);
+ }
+
+ if (rename(sfn, certs_file) == -1) {
+ unlink(sfn);
+ return (-1);
+ }
+
+ return (0);
+}
+
int
+cert_save_for(const char *cert, struct iri *i, int persist)
+{
+ struct cstore *cstore;
+ struct ccert *c;
+ char *d;
+
+ cstore = persist ? &cert_store : &temp_store;
+
+ if ((c = find_cert_for(cstore, i)) != NULL) {
+ if ((d = strdup(cert)) == NULL)
+ return (-1);
+
+ free(c->cert);
+ c->cert = d;
+
+ return (0);
+ }
+
+ if (certs_store_add(cstore, i->iri_host, i->iri_portstr, i->iri_path,
+ cert) == -1)
+ return (-1);
+
+ qsort(cert_store.certs, cert_store.len, sizeof(*cert_store.certs),
+ certs_cmp);
+
+ if (persist && write_cert_file() == -1)
+ return (-1);
+
+ return (0);
+}
+
+int
cert_open(const char *cert)
{
char path[PATH_MAX];
blob - 02ed3f170e25607b1fa02036f749359c51db5996
blob + 3512f77a2d20b2adb66315efa49e2a2f15052ba3
--- certs.h
+++ certs.h
int certs_init(const char *);
const char *ccert(const char *);
const char *cert_for(struct iri *);
+int cert_save_for(const char *, struct iri *, int);
int cert_open(const char *);
int cert_new(const char *, const char *, const char *, int);
blob - f0bf316ca2ca85c7efad6ecfa3d4bc3f73e22cb5
blob + 8a32941b4aad1fa405ae08f275800dd1c45b6693
--- cmd.c
+++ cmd.c
{
load_url_in_tab(current_tab, "..", NULL, LU_MODE_NOCACHE);
}
+
+void
+cmd_use_certificate(struct buffer *buffer)
+{
+ GUARD_RECURSIVE_MINIBUFFER();
+
+ enter_minibuffer(sensible_self_insert, uc_select, exit_minibuffer,
+ NULL, compl_uc, NULL, 1);
+ strlcpy(ministate.prompt, "Select certificate: ",
+ sizeof(ministate.prompt));
+}
blob - c215bb0e2afa6871f4f93d31fd8c9224af20a3a8
blob + 5f194e9f36baf000919951aaf3efe24470856f86
--- cmd.h
+++ cmd.h
CMD(cmd_toggle_help, "Toggle side window with help.");
CMD(cmd_toggle_pre_wrap, "Toggle the wrapping of preformatted blocks.");
CMD(cmd_up, "Go up one level.");
+CMD(cmd_use_certificate, "Use a certificate for the current page.");
CMD(cmd_write_buffer, "Save the current page to the disk.");
blob - f6243324b8c79bb4caa3af734dd71f9c490da953
blob + ded602c8ff80b3d4913b94345460da61c038babd
--- compl.c
+++ compl.c
/*
- * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
+ * Copyright (c) 2021, 2024 Omar Polo <op@omarpolo.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
#include <stdlib.h>
+#include "certs.h"
#include "compl.h"
#include "hist.h"
#include "telescope.h"
*line = TAILQ_NEXT(l, lines);
return text;
}
+
+/*
+ * Provide completions for use-certificate
+ */
+const char *
+compl_uc(void **data, void **ret, const char **descr)
+{
+ const char ***state = (const char ***)data;
+
+ /* first time: init the state */
+ if (*state == NULL)
+ *state = (const char **)identities;
+
+ if (**state == NULL)
+ return NULL;
+
+ /* XXX filling descr too would be nice */
+ return *((*state)++);
+}
blob - c2d3ddef9936e81d473da6e75de86d4af340c7e3
blob + 3fbb6ecf9ea517f229c1381d0b0ae97faf0c71c0
--- compl.h
+++ compl.h
/*
- * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
+ * Copyright (c) 2021, 2024 Omar Polo <op@omarpolo.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
const char *compl_ls(void **, void **, const char **);
const char *compl_swiper(void **, void **, const char **);
const char *compl_toc(void **, void **, const char **);
+const char *compl_uc(void **, void **, const char **);
#endif
blob - e9606e181d1cb50517cabfd4d25d55fc9d872828
blob + b05beff923e24cff4ab21a19147baaa6fb5db07b
--- minibuffer.c
+++ minibuffer.c
#include <stdlib.h>
#include <string.h>
+#include "certs.h"
#include "fs.h"
#include "hist.h"
#include "iri.h"
}
static void
+save_cert_for_site_cb(int r, struct tab *tab)
+{
+ cert_save_for(tab->client_cert, &tab->iri, r);
+}
+
+void
+uc_select(void)
+{
+ const char *name;
+
+ name = minibuffer_compl_text();
+ if (!strcmp(name, "Generate new certificate")) {
+ message("Not implemented yet!");
+ return;
+ }
+
+ if ((current_tab->client_cert = ccert(name)) == NULL) {
+ message("Certificate %s not found", name);
+ return;
+ }
+
+ exit_minibuffer();
+
+ yornp("Always use this cert on this page?", save_cert_for_site_cb,
+ current_tab);
+}
+
+static void
yornp_self_insert(void)
{
if (thiskey.key != 'y' && thiskey.key != 'n') {
blob - d993896dd79343bae46a2ba6dc48362c4b802c8a
blob + 693f6b6e018dab5defaa9c193f993d8496332733
--- minibuffer.h
+++ minibuffer.h
void ls_select(void);
void swiper_select(void);
void toc_select(void);
+void uc_select(void);
void enter_minibuffer(void(*)(void), void(*)(void), void(*)(void),
struct hist *, complfn *, void *, int);
blob - c50a70155a36fb4151dc2ecd9f8e6e49345412d1
blob + 6e35e4e642563038362b5bad6eaf81a619958a40
--- telescope.c
+++ telescope.c
LU_MODE_NOCACHE);
} else { /* 4x, 5x & 6x */
load_page_from_str(tab, err_pages[tab->code]);
+ if (tab->code >= 60)
+ cmd_use_certificate(&tab->buffer);
}
}