Commit Diff


commit - 9fedd923db07f03084a4efadf960020480d0db80
commit + a2fd3805b0807d0e85411613df26bd6dcaed01ce
blob - e1e2f6100e6e2893f2f672f01835563a2a24528f
blob + 38c23eb99a604a05c94508b2afdc5c1baf64681b
--- ChangeLog
+++ ChangeLog
@@ -1,5 +1,7 @@
 2021-07-06  Omar Polo  <op@omarpolo.com>
 
+	* telescope.c (handle_check_cert_user_choice): fix two bug: don't crash when there's a certificate mismatch and after saving the cert, before choosing to persist it, the page gets redirected.  Now when the user accept a certificate, is treated as temporary saved for the whole session.
+
 	* defaults.c (load_default_keys): bind M-prior/next (M-pageup/pagedown) to tab-previous and tab-next
 
 2021-07-05  Omar Polo  <op@omarpolo.com>
blob - 0242dd56c8199241ef26e40d82bcb0729755dd80
blob + 7c7f77a1f4e1fbe7110be914331bfaf7aea92664
--- telescope.c
+++ telescope.c
@@ -26,11 +26,11 @@ static void		 die(void) __attribute__((__noreturn__));
 static struct tab	*tab_by_id(uint32_t);
 static void		 handle_imsg_err(struct imsg*, size_t);
 static void		 handle_imsg_check_cert(struct imsg*, size_t);
-static void		 handle_check_cert_user_choice(int, unsigned int);
-static void		 handle_maybe_save_new_cert(int, unsigned int);
+static void		 handle_check_cert_user_choice(int, struct tab *);
+static void		 handle_maybe_save_new_cert(int, struct tab *);
 static void		 handle_imsg_got_code(struct imsg*, size_t);
 static void		 handle_imsg_got_meta(struct imsg*, size_t);
-static void		 handle_maybe_save_page(int, unsigned int);
+static void		 handle_maybe_save_page(int, struct tab *);
 static void		 handle_save_page_path(const char *, unsigned int);
 static void		 handle_imsg_file_opened(struct imsg*, size_t);
 static void		 handle_imsg_buf(struct imsg*, size_t);
@@ -140,7 +140,13 @@ handle_imsg_check_cert(struct imsg *imsg, size_t datal
 		tofu_res = !strcmp(hash, e->hash);
 
 	if (tofu_res) {
-		tab->trust = e->verified ? TS_VERIFIED : TS_TRUSTED;
+		if (e->verified == -1)
+			tab->trust = TS_TEMP_TRUSTED;
+		else if (e->verified == 1)
+			tab->trust = TS_VERIFIED;
+		else
+			tab->trust = TS_TRUSTED;
+
 		imsg_compose(netibuf, IMSG_CERT_STATUS, imsg->hdr.peerid, 0, -1,
 		    &tofu_res, sizeof(tofu_res));
 		imsg_flush(netibuf);
@@ -150,39 +156,42 @@ handle_imsg_check_cert(struct imsg *imsg, size_t datal
 		if ((tab->cert = strdup(hash)) == NULL)
 			die();
 		ui_yornp("Certificate mismatch.  Proceed?",
-		    handle_check_cert_user_choice, tab->id);
+		    handle_check_cert_user_choice, tab);
 	}
 }
 
 static void
-handle_check_cert_user_choice(int accept, unsigned int tabid)
+handle_check_cert_user_choice(int accept, struct tab *tab)
 {
-	struct tab *tab;
-
-	tab = tab_by_id(tabid);
-
-	imsg_compose(netibuf, IMSG_CERT_STATUS, tabid, 0, -1,
+	imsg_compose(netibuf, IMSG_CERT_STATUS, tab->id, 0, -1,
 	    &accept, sizeof(accept));
 	imsg_flush(netibuf);
 
-	if (accept)
+	if (accept) {
+		/*
+		 * trust the certificate for this session only.  If
+		 * the page results in a redirect while we're asking
+		 * the user to save, we'll end up with an invalid
+		 * tabid (one request == one tab id) and crash.  It
+		 * also makes sense to save it for the current session
+		 * if the user accepted it.
+		 */
+		tofu_temp_trust(&certs, tab->uri.host, tab->uri.port, tab->cert);
+
 		ui_yornp("Save the new certificate?",
-		    handle_maybe_save_new_cert, tabid);
-	else {
+		    handle_maybe_save_new_cert, tab);
+	} else {
 		free(tab->cert);
 		tab->cert = NULL;
 	}
 }
 
 static void
-handle_maybe_save_new_cert(int accept, unsigned int tabid)
+handle_maybe_save_new_cert(int accept, struct tab *tab)
 {
-	struct tab *tab;
 	struct tofu_entry *e;
 	const char *host, *port;
 
-	tab = tab_by_id(tabid);
-
 	if (tab->proxy != NULL) {
 		host = tab->proxy->host;
 		port = tab->proxy->port;
@@ -284,7 +293,7 @@ handle_imsg_got_meta(struct imsg *imsg, size_t datalen
 		} else {
 			load_page_from_str(tab, err_pages[UNKNOWN_TYPE_OR_CSET]);
 			ui_yornp("Can't display page, wanna save?",
-			    handle_maybe_save_page, tab->id);
+			    handle_maybe_save_page, tab);
 		}
 	} else if (tab->code < 40) { /* 3x */
 		tab->redirect_count++;
@@ -301,12 +310,12 @@ handle_imsg_got_meta(struct imsg *imsg, size_t datalen
 }
 
 static void
-handle_maybe_save_page(int dosave, unsigned int tabid)
+handle_maybe_save_page(int dosave, struct tab *tab)
 {
 	if (dosave)
-		ui_read("Save to path", handle_save_page_path, tabid);
+		ui_read("Save to path", handle_save_page_path, tab->id);
 	else
-		stop_tab(tab_by_id(tabid));
+		stop_tab(tab);
 }
 
 static void
blob - 0fa19093d9bea18e148c18178e4e1df77a2d3600
blob + 54c23576691a715aa722570bb81528d86e78b7ec
--- telescope.h
+++ telescope.h
@@ -174,6 +174,7 @@ struct parser {
 enum trust_state {
 	TS_UNKNOWN,
 	TS_UNTRUSTED,
+	TS_TEMP_TRUSTED,
 	TS_TRUSTED,
 	TS_VERIFIED,
 };
@@ -383,6 +384,7 @@ void			 tofu_init(struct ohash*, unsigned int, ptrdiff
 struct tofu_entry	*tofu_lookup(struct ohash*, const char*, const char*);
 void			 tofu_add(struct ohash*, struct tofu_entry*);
 void			 tofu_update(struct ohash*, struct tofu_entry*);
+void			 tofu_temp_trust(struct ohash *, const char *, const char *, const char *);
 
 /* ui.c */
 extern int	 body_lines;
@@ -499,7 +501,7 @@ void		 ui_toggle_side_window(void);
 void		 ui_schedule_redraw(void);
 void		 ui_require_input(struct tab*, int);
 void		 ui_read(const char*, void(*)(const char*, unsigned int), unsigned int);
-void		 ui_yornp(const char*, void (*)(int, unsigned int), unsigned int);
+void		 ui_yornp(const char*, void (*)(int, struct tab *), struct tab *);
 void		 ui_end(void);
 
 /* utf.8 */
blob - b474a99d2639bb8390a3b0ec64e782783a93d344
blob + 6be7ec6fe0393108c660c9508e739cfe58beba2d
--- tofu.c
+++ tofu.c
@@ -96,3 +96,23 @@ tofu_update(struct ohash *h, struct tofu_entry *e)
 		free(e);
 	}
 }
+
+void
+tofu_temp_trust(struct ohash *h, const char *host, const char *port,
+    const char *hash)
+{
+	struct tofu_entry *e;
+
+	if ((e = calloc(1, sizeof(*e))) == NULL)
+                abort();
+
+        strlcpy(e->domain, host, sizeof(e->domain));
+	if (*port != '\0' && strcmp(port, "1965")) {
+		strlcat(e->domain, ":", sizeof(e->domain));
+		strlcat(e->domain, port, sizeof(e->domain));
+	}
+	strlcpy(e->hash, hash, sizeof(e->hash));
+	e->verified = -1;
+
+	tofu_update(h, e);
+}
blob - e8aa4f0a5a8bb9205f2f9116ec2fb1d8059df8f6
blob + c7b26c92c942ee917b5c9aa274f41084d0862f82
--- ui.c
+++ ui.c
@@ -104,8 +104,8 @@ static uint32_t		 tab_counter;
 
 static char	keybuf[64];
 
-static void (*yornp_cb)(int, unsigned int);
-static unsigned int yornp_data;
+static void (*yornp_cb)(int, struct tab *);
+static struct tab *yornp_data;
 
 static void (*read_cb)(const char*, unsigned int);
 static unsigned int read_data;
@@ -906,6 +906,7 @@ trust_status_char(enum trust_state ts)
 	switch (ts) {
 	case TS_UNKNOWN:	return 'u';
 	case TS_UNTRUSTED:	return '!';
+	case TS_TEMP_TRUSTED:	return '!';
 	case TS_TRUSTED:	return 'v';
 	case TS_VERIFIED:	return 'V';
 	default:		return 'X';
@@ -1479,8 +1480,8 @@ ui_require_input(struct tab *tab, int hide)
 }
 
 void
-ui_yornp(const char *prompt, void (*fn)(int, unsigned int),
-    unsigned int data)
+ui_yornp(const char *prompt, void (*fn)(int, struct tab *),
+    struct tab *data)
 {
 	size_t len;