diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d22ee8..ff82ea5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `left_margin` config option - Right margin for text (#1) - Desktop entry file +- Option to continue anyway when cert doesn't match TOFU database ### Changed - Connection timeout is 15 seconds (was 5s) diff --git a/NOTES.md b/NOTES.md index c330579..21f747c 100644 --- a/NOTES.md +++ b/NOTES.md @@ -9,4 +9,5 @@ - Text background not reset on ANSI pages - Filed [issue 25](https://gitlab.com/tslocum/cview/-/issues/25) - Modal styling messed up when wrapped - example occurence is the error modal for a long unsupported scheme URL - - Filed [issue 26](https://gitlab.com/tslocum/cview/-/issues/26) \ No newline at end of file + - Filed [issue 26](https://gitlab.com/tslocum/cview/-/issues/26) + - Add some bold back into modal text after this is fixed \ No newline at end of file diff --git a/client/client.go b/client/client.go index c4e9d0e..c223ea7 100644 --- a/client/client.go +++ b/client/client.go @@ -18,7 +18,7 @@ func Fetch(u string) (*gemini.Response, error) { parsed, _ := url.Parse(u) ok := handleTofu(resp.Cert, parsed.Port()) if !ok { - return nil, ErrTofu + return resp, ErrTofu } return resp, err } diff --git a/client/tofu.go b/client/tofu.go index 555ee57..4524a7a 100644 --- a/client/tofu.go +++ b/client/tofu.go @@ -104,3 +104,12 @@ func handleTofu(cert *x509.Certificate, port string) bool { } return false } + +// RemoveTofuEntry invalidates the TOFU entry in the database for the given cert and port. +// This will make any cert for that domain valid. +// +// The port string can be empty, to indicate port 1965. +func RemoveTofuEntry(cert *x509.Certificate, port string) { + tofuStore.Set(idKey(cert.Subject.CommonName, port), "") + tofuStore.WriteConfig() +} diff --git a/display/modals.go b/display/modals.go index 68fd333..8d6b7a1 100644 --- a/display/modals.go +++ b/display/modals.go @@ -1,6 +1,7 @@ package display import ( + "fmt" "strconv" "strings" @@ -35,7 +36,6 @@ var inputCh = make(chan string) var inputModalText string // The current text of the input field in the modal var yesNoModal = cview.NewModal(). - SetBackgroundColor(tcell.ColorPurple). SetButtonBackgroundColor(tcell.ColorNavy). SetButtonTextColor(tcell.ColorWhite). SetTextColor(tcell.ColorWhite). @@ -143,7 +143,26 @@ func Input(prompt string) (string, bool) { // YesNo displays a modal asking a yes-or-no question. func YesNo(prompt string) bool { - yesNoModal.SetText(prompt) + yesNoModal.SetText(prompt).SetBackgroundColor(tcell.ColorPurple) + tabPages.ShowPage("yesno") + tabPages.SendToFront("yesno") + App.SetFocus(yesNoModal) + App.Draw() + + resp := <-yesNoCh + tabPages.SwitchToPage(strconv.Itoa(curTab)) + return resp +} + +// Tofu displays the TOFU warning modal. +// It returns a bool indicating whether the user wants to continue. +func Tofu(host string) bool { + // Reuses yesno modal, with error colour + + yesNoModal.SetBackgroundColor(tcell.ColorMaroon) + yesNoModal.SetText( + fmt.Sprintf("%s's certificate has changed, possibly indicating an security issue. Are you sure you want to continue anyway?", host), + ) tabPages.ShowPage("yesno") tabPages.SendToFront("yesno") App.SetFocus(yesNoModal) diff --git a/display/private.go b/display/private.go index bb6f2e0..586e9ad 100644 --- a/display/private.go +++ b/display/private.go @@ -140,7 +140,7 @@ func setPage(p *structs.Page) { // The second returned item is a bool indicating if page content was displayed. // It returns false for Errors, other protocols, etc. func handleURL(u string) (string, bool) { - defer App.Draw() // Make sure modals get displayed + defer App.Draw() // Just in case //logger.Log.Printf("Sent: %s", u) @@ -178,7 +178,7 @@ func handleURL(u string) (string, bool) { return "", false } if !strings.HasPrefix(u, "gemini") { - Error("Protocol Error", "Only [::b]gemini[::-] and [::b]http[::-] are supported. URL was "+u) + Error("Protocol Error", "Only gemini and HTTP are supported. URL was "+u) bottomBar.SetText(tabMap[curTab].Url) return "", false } @@ -195,7 +195,17 @@ func handleURL(u string) (string, bool) { App.Draw() res, err := client.Fetch(u) - if err != nil { + if err == client.ErrTofu { + if Tofu(parsed.Host) { + // They want to continue anyway + client.RemoveTofuEntry(res.Cert, parsed.Port()) + return handleURL(u) + } + // They don't want to continue + // Set the bar back to original URL + bottomBar.SetText(tabMap[curTab].Url) + return "", false + } else if err != nil { Error("URL Fetch Error", err.Error()) // Set the bar back to original URL bottomBar.SetText(tabMap[curTab].Url)