From: Sergey Matveev <stargrave@stargrave.org>
Date: Sun, 12 Sep 2021 10:49:51 +0000 (+0300)
Subject: More pleasant Tk dialogs
X-Git-Tag: v0.1.0~66
X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=b4e23c13d7b2ea73f8b1167c044a521d540120ad;p=tofuproxy.git

More pleasant Tk dialogs
---

diff --git a/doc/dialog.webp b/doc/dialog.webp
index bff3268..dd19649 100644
Binary files a/doc/dialog.webp and b/doc/dialog.webp differ
diff --git a/tlsauth.go b/tlsauth.go
index 0965335..b980e08 100644
--- a/tlsauth.go
+++ b/tlsauth.go
@@ -51,19 +51,42 @@ func (g *ClientCertificateGetter) get(
 	if tlsCert != nil {
 		return tlsCert, nil
 	}
+	sigSchemes := make([]string, 0, len(cri.SignatureSchemes))
+	for _, ss := range cri.SignatureSchemes {
+		sigSchemes = append(sigSchemes, ss.String())
+	}
 	var b bytes.Buffer
 	b.WriteString(fmt.Sprintf(`
 tk_setPalette grey
 wm title . "TLS client authentication: %s"
 
-label .lVersion -text "Version: %s"
-grib .lVersion
-
 set lb [listbox .lb]
 .lb insert end ""
+grid .lb
+
+proc submit {} {
+    global lb
+    puts [$lb get active]
+    exit
+}
+
+button .submit -text "Use" -command submit
+grid .submit
+
+label .lTLSVersion -text "TLS version: %s"
+grid .lTLSVersion
+
+set sigSchemeRow 0
+foreach sigScheme {%s} {
+    label .lSignatureScheme$sigSchemeRow -text "Signature scheme: $sigScheme"
+    grid .lSignatureScheme$sigSchemeRow
+    incr sigSchemeRow
+}
+
 `,
 		g.host,
 		ucspi.TLSVersion(cri.Version),
+		strings.Join(sigSchemes, " "),
 	))
 
 	ents, err := os.ReadDir(CCerts)
@@ -89,18 +112,7 @@ set lb [listbox .lb]
 		})
 		b.WriteString(fmt.Sprintf(".lb insert end \"%d: %s\"\n", i, cert.Subject))
 	}
-	b.WriteString(`
-grid .lb
-
-proc submit {} {
-    global lb
-    puts [$lb get active]
-    exit
-}
-
-button .submit -text "Use" -command submit
-grid .submit
-`)
+	// ioutil.WriteFile("/tmp/tls-auth-dialog.tcl", b.Bytes(), 0666)
 	cmd := exec.Command(CmdWish)
 	cmd.Stdin = &b
 	out, err := cmd.Output()
diff --git a/verify.go b/verify.go
index f1bb49f..ed98650 100644
--- a/verify.go
+++ b/verify.go
@@ -36,6 +36,93 @@ import (
 	"go.stargrave.org/tofuproxy/fifos"
 )
 
+const VerifyDialog = `
+# host err daneStatus certsTheir certsOur
+
+if {[string length $err] > 0} {
+    set tErr [text .tErr]
+    $tErr insert end $err
+    $tErr configure -wrap word -height 5
+    $tErr configure -state disabled
+    grid .tErr
+}
+
+proc certsDecode {raws} {
+    set certs [list]
+    foreach raw [split $raws] {
+        set lines [list]
+        set lineN 0
+        foreach line [split [binary decode hex $raw] "\n"] {
+            lappend lines [format "%03d %s" $lineN $line]
+            incr lineN
+        }
+        lappend certs [join $lines "\n"]
+    }
+    return $certs
+}
+
+set certsTheir [certsDecode $certsTheir]
+set certsOur [certsDecode $certsOur]
+
+tk_setPalette grey
+wm title . $host
+
+proc paginator {i delta t l certs} {
+    incr i $delta
+    if {$i == [llength $certs]} {
+        set i 0
+    } elseif {$i < 0} {
+        set i [expr {[llength $certs] - 1}]
+    }
+    $t configure -state normal
+    $t delete 1.0 end
+    $t insert end [lindex $certs $i]
+    $t configure -state disabled
+    $l configure -text "[expr {$i + 1}] / [llength $certs]"
+    return $i
+}
+
+proc addCertsWindow {name} {
+    global certs$name t$name sb$name page$name l$name
+    set t [text .t$name]
+    set sb [scrollbar .sb$name -command [list $t yview]]
+    $t configure -wrap word -yscrollcommand [list $sb set]
+    $t configure -state disabled
+    grid $t $sb -sticky nsew
+    set t$name $t
+    set sb$name $t
+
+    frame .fControl$name
+    set l$name [label .lPage$name]
+    button .bNext$name -text "Next" -command "set page$name \[
+        paginator \$page$name +1 \$t$name \$l$name \$certs$name
+    ]"
+    button .bPrev$name -text "Prev" -command "set page$name \[
+        paginator \$page$name -1 \$t$name \$l$name \$certs$name
+    ]"
+    grid .fControl$name
+    grid .lPage$name .bNext$name .bPrev$name -in .fControl$name
+    set page$name [paginator -1 +1 $t [set l$name] [set certs$name]]
+}
+
+addCertsWindow Their
+if {[llength $certsOur] > 0} { addCertsWindow Our }
+frame .fButtons
+set lDANE [label .lDANE]
+if {$daneStatus ne ""} {
+    array set daneColour {ok green bad red}
+    $lDANE configure -bg $daneColour($daneStatus)
+    $lDANE configure -text "DANE-EE: $daneStatus"
+}
+button .bAccept -text "Accept" -bg green -command { exit 10 }
+button .bOnce -text "Once" -bg green -command { exit 11 }
+button .bReject -text "Reject" -bg red -command { exit 12 }
+grid .fButtons
+grid .lDANE .bAccept .bOnce .bReject -in .fButtons
+grid rowconfigure . 0 -weight 1
+grid columnconfigure . 0 -weight 1
+`
+
 var (
 	CmdCerttool = "certtool"
 	CmdWish     = "wish8.6"
@@ -62,16 +149,7 @@ func certInfo(certRaw []byte) string {
 	if err != nil {
 		return err.Error()
 	}
-	lines := make([]string, 0, 128)
-	for i, line := range strings.Split(string(out), "\n") {
-		if strings.Contains(line, "ASCII:") {
-			continue
-		}
-		lines = append(lines, fmt.Sprintf(
-			"%03d %s", i, strings.ReplaceAll(line, `"`, `\"`),
-		))
-	}
-	return strings.Join(lines, "\n")
+	return string(out)
 }
 
 func verifyCert(
@@ -127,66 +205,38 @@ func verifyCert(
 			return nil
 		}
 		var b bytes.Buffer
-		b.WriteString("tk_setPalette grey\n")
-		b.WriteString(fmt.Sprintf("wm title . \"%s\"\n", host))
-
-		if dialErr != nil {
-			b.WriteString(fmt.Sprintf(`set tErr [text .tErr]
-$tErr insert end "%s"
-$tErr configure -wrap word -height 5
-`, dialErr.Error()))
-			b.WriteString("grid .tErr -columnspan 3\n")
+		b.WriteString(fmt.Sprintf("set host \"%s\"\n", host))
+		if dialErr == nil {
+			b.WriteString(fmt.Sprintf("set err \"\"\n"))
+		} else {
+			b.WriteString(fmt.Sprintf("set err \"%s\"\n", dialErr.Error()))
 		}
-
+		var daneStatus string
 		if daneExists {
 			if daneMatched {
-				b.WriteString("label .lDANE -bg green -text \"DANE matched\"\n")
+				daneStatus = "ok"
 			} else {
-				b.WriteString("label .lDANE -bg red -text \"DANE NOT matched\"\n")
+				daneStatus = "bad"
 			}
-			b.WriteString("grid .lDANE\n")
 		}
-
-		var bCerts bytes.Buffer
-		for i, rawCert := range rawCerts {
-			bCerts.WriteString(fmt.Sprintf("Their %d:\n", i))
-			bCerts.WriteString(certInfo(rawCert))
+		b.WriteString(fmt.Sprintf("set daneStatus \"%s\"\n", daneStatus))
+		hexCerts := make([]string, 0, len(rawCerts))
+		for _, rawCert := range rawCerts {
+			hexCerts = append(hexCerts, hex.EncodeToString([]byte(certInfo(rawCert))))
 		}
-		b.WriteString(fmt.Sprintf(`set tTheir [text .tTheir]
-$tTheir insert end "%s"
-set sbTheir [scrollbar .sbTheir -command [list $tTheir yview]]
-$tTheir configure -wrap word -yscrollcommand [list $sbTheir set]
-`, bCerts.String()))
-		b.WriteString("grid $tTheir $sbTheir -sticky nsew -columnspan 3\n")
-
-		if certsOur != nil {
-			bCerts.Reset()
-			for i, cert := range certsOur {
-				bCerts.WriteString(fmt.Sprintf("Our %d:\n", i))
-				bCerts.WriteString(certInfo(cert.Raw))
-			}
-			b.WriteString(fmt.Sprintf(`set tOur [text .tOur]
-$tOur insert end "%s"
-set sbOur [scrollbar .sbOur -command [list $tOur yview]]
-$tOur configure -wrap word -yscrollcommand [list $sbOur set]
-`, bCerts.String()))
-			b.WriteString("grid $tOur $sbOur -sticky nsew -columnspan 3\n")
+		b.WriteString(fmt.Sprintf(
+			"set certsTheir \"%s\"\n", strings.Join(hexCerts, " "),
+		))
+		hexCerts = make([]string, 0, len(certsOur))
+		for _, cert := range certsOur {
+			hexCerts = append(hexCerts, hex.EncodeToString([]byte(certInfo(cert.Raw))))
 		}
-
-		b.WriteString(`
-proc doAccept {} { exit 10 }
-proc doOnce {} { exit 11 }
-proc doReject {} { exit 12 }
-button .bAccept -text "Accept" -bg green -command doAccept
-button .bOnce -text "Once" -bg green -command doOnce
-button .bReject -text "Reject" -bg red -command doReject
-grid .bAccept .bOnce .bReject
-grid rowconfigure . 0 -weight 1
-grid columnconfigure . 0 -weight 1
-`)
-
+		b.WriteString(fmt.Sprintf(
+			"set certsOur \"%s\"\n", strings.Join(hexCerts, " "),
+		))
+		b.WriteString(VerifyDialog)
 		cmd := exec.Command(CmdWish)
-		// ioutil.WriteFile("/tmp/w.tcl", b.Bytes(), 0666)
+		// ioutil.WriteFile("/tmp/verify-dialog.tcl", b.Bytes(), 0666)
 		cmd.Stdin = &b
 		err = cmd.Run()
 		exitError, ok := err.(*exec.ExitError)