~sotirisp/kindleto

ea858373ce22c7d56946ca6be1090bc205eb916b — Sotiris Papatheodorou 3 months ago dcf264e
Use go-gemini function to escape Gemini queries
3 files changed, 8 insertions(+), 12 deletions(-)

M gemini/gemini.go
M gemini/gemtext.go
M handlers.go
M gemini/gemini.go => gemini/gemini.go +1 -7
@@ 37,12 37,6 @@ var reGemResponseHeader *regexp.Regexp = regexp.MustCompile(`^\d{2} (.*)\r\n`)
var reLang *regexp.Regexp = regexp.MustCompile(`\blang=([\w-]+)`)
var reStatus *regexp.Regexp = regexp.MustCompile(`\d\d .*`)

// GeminiQueryEscape returns a URL query string with "+" replaced by "%2O",
// as requred in secion 1.2 Gemini URI scheme of the Gemini specification.
func GeminiQueryEscape(q string) string {
	return strings.ReplaceAll(url.PathEscape(q), "+", "%2B")
}

// ProxyGemini finds the Gemini content at u.
func ProxyGemini(w http.ResponseWriter, r *http.Request, u *url.URL) (*url.URL, error) {
	var err error


@@ 172,7 166,7 @@ func ProxyGemini(w http.ResponseWriter, r *http.Request, u *url.URL) (*url.URL, 
				err = fmt.Errorf("ProxyGemini: client certificated disabled by --hours option (meta: %s)", response.Meta)
				break
			}
			http.Redirect(w, r, "/certificate?url="+GeminiQueryEscape(u.String()), http.StatusFound)
			http.Redirect(w, r, "/certificate?url="+gemini.QueryEscape(u.String()), http.StatusFound)
		default: // Client certificat not autorized, not valid, etc.
			err = fmt.Errorf("ProxyGemini: %s", response.Meta)
		}

M gemini/gemtext.go => gemini/gemtext.go +2 -1
@@ 7,6 7,7 @@ package gemini
import (
	"bufio"
	"fmt"
	"git.sr.ht/~adnano/go-gemini"
	"html"
	"io"
	"log"


@@ 99,7 100,7 @@ func gemtextToHTML(w http.ResponseWriter, u *url.URL, rd *bufio.Reader, td templ
			linkURLString = linkURL.String()
			io.WriteString(w, `<a href="`)
			if linkURL.Scheme == "gemini" || linkURL.Scheme == "finger" {
				io.WriteString(w, `/?url=`+GeminiQueryEscape(linkURLString))
				io.WriteString(w, `/?url=`+gemini.QueryEscape(linkURLString))
			} else {
				io.WriteString(w, linkURLString)
			}

M handlers.go => handlers.go +5 -4
@@ 7,6 7,7 @@ package main
import (
	"errors"
	"fmt"
	gogemini "git.sr.ht/~adnano/go-gemini"
	"io"
	"log"
	"net/http"


@@ 119,7 120,7 @@ func clientCertificateRequired(w http.ResponseWriter, r *http.Request) {
			http.Error(w, "Internal Server Error", 500)
		}
		certificates.CreateClientCert(u, r.FormValue("name"), certificates.StringToDuration(r.FormValue("duration")))
		http.Redirect(w, r, "/?url="+gemini.GeminiQueryEscape(r.FormValue("url")), http.StatusFound)
		http.Redirect(w, r, "/?url="+gogemini.QueryEscape(r.FormValue("url")), http.StatusFound)
	} else {
		if util.LogLevel > 0 {
			log.Println("clientCertificateRequired: handler accessed without URL in POST or GET")


@@ 175,12 176,12 @@ func proxy(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodPost && r.FormValue("url") != "" {
		targetURL = strings.SplitN(r.FormValue("url"), "?", 2)[0]
		if r.FormValue("input") != "" {
			targetURL = targetURL + "?" + gemini.GeminiQueryEscape(r.FormValue("input"))
			targetURL = targetURL + "?" + gogemini.QueryEscape(r.FormValue("input"))
			if util.LogLevel > 1 {
				log.Println("proxy: submitting Gemini input:", targetURL)
			}
		} else if r.FormValue("secret") != "" {
			targetURL = targetURL + "?" + gemini.GeminiQueryEscape(r.FormValue("secret"))
			targetURL = targetURL + "?" + gogemini.QueryEscape(r.FormValue("secret"))
			if util.LogLevel > 1 {
				log.Printf("proxy: submitting Gemini sensitive input: %s?REDACTED_SECRET", r.FormValue("url"))
			}


@@ 188,7 189,7 @@ func proxy(w http.ResponseWriter, r *http.Request) {
			targetURL = r.FormValue("url")
		}

		http.Redirect(w, r, "/?url="+gemini.GeminiQueryEscape(targetURL), http.StatusFound)
		http.Redirect(w, r, "/?url="+gogemini.QueryEscape(targetURL), http.StatusFound)
	}

	if r.URL.Query().Get("url") == "" {