Unverified Commit abce381f authored by Lemon-miaow's avatar Lemon-miaow
Browse files

fix(tui): wrap the one-time setup URL so narrow terminals can't truncate it

The setup URL carries a 43-char token and overruns 80 columns; the TUI
renderer clipped it. Break it at the query '=' boundary (token on its own
line) with a shared wrapDisplayURL helper used by both the Owner wizard and
the mc-bind wizard; unit test pins the no-loss concatenation.
parent a415246a
Loading
Loading
Loading
Loading
+5 −1
Changes for cmd/felis/tui_mc_bind.go: 5 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -207,7 +207,11 @@ func (m *mcBindModel) doneView() string {
		if box.Len() > 0 {
			box.WriteString("\n")
		}
		box.WriteString(tuiLabel.Render("setup URL  ") + "\n" + tuiPassword.Render(m.setupTokenURL) + "\n\n")
		box.WriteString(tuiLabel.Render("setup URL  ") + "\n")
		for _, line := range wrapDisplayURL(m.setupTokenURL, 70) {
			box.WriteString(tuiPassword.Render(line) + "\n")
		}
		box.WriteString("\n")
		box.WriteString(tuiWarn.Render("Open this URL to complete passwordless login setup.\nIt is shown only once."))
	}
	if m.auditWarning != "" {
+5 −1
Changes for cmd/felis/tui_owner.go: 5 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -420,7 +420,11 @@ func (m *ownerModel) doneView() string {
	var box strings.Builder
	box.WriteString(tuiLabel.Render("username  ") + m.username + "\n")
	if m.setupTokenURL != "" {
		box.WriteString("\n" + tuiLabel.Render("setup URL  ") + "\n" + tuiPassword.Render(m.setupTokenURL) + "\n\n")
		box.WriteString("\n" + tuiLabel.Render("setup URL  ") + "\n")
		for _, line := range wrapDisplayURL(m.setupTokenURL, 70) {
			box.WriteString(tuiPassword.Render(line) + "\n")
		}
		box.WriteString("\n")
		box.WriteString(tuiWarn.Render("Open this URL to complete passwordless login setup. It is shown only once."))
	}
	if m.auditWarning != "" {
+27 −0
Changes for cmd/felis/tui_widgets.go: 27 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -29,6 +29,33 @@ func tuiSeparator() string {
	return tuiHint.Render(strings.Repeat("─", 70))
}

// wrapDisplayURL breaks a long URL into lines no wider than width so the TUI
// renderer never truncates it on a narrow terminal — the one-time setup URL
// carries a 43-char token and overruns 80 columns. It prefers breaking right
// after a '=' or '/' inside the window (the token then lands on its own line)
// and hard-wraps only when no boundary is available. Lines concatenate back to
// the original string.
func wrapDisplayURL(u string, width int) []string {
	if width <= 0 {
		width = 70
	}
	var lines []string
	for len(u) > width {
		cut := width
		if i := strings.LastIndexByte(u[:width], '='); i >= 0 && i >= width/2 {
			cut = i + 1
		} else if i := strings.LastIndexByte(u[:width], '/'); i >= 0 && i >= width/2 {
			cut = i + 1
		}
		lines = append(lines, u[:cut])
		u = u[cut:]
	}
	if u != "" {
		lines = append(lines, u)
	}
	return lines
}

// tuiStepRail renders a breadcrumb of wizard stages. Steps before `current`
// render as done, `current` is highlighted, and later steps are dimmed.
func tuiStepRail(steps []string, current int) string {
+26 −0
Changes for cmd/felis/tui_widgets_test.go: 26 added lines, 0 removed lines.
Original line number Diff line number Diff line
package main

import (
	"strings"
	"testing"
)

func TestWrapDisplayURL(t *testing.T) {
	u := "https://op.console.example.net/setup?token=" + strings.Repeat("A", 43)
	lines := wrapDisplayURL(u, 70)
	if got := strings.Join(lines, ""); got != u {
		t.Fatalf("concatenated lines = %q, want the original URL back", got)
	}
	for i, l := range lines {
		if len(l) > 70 {
			t.Errorf("line %d is %d cols wide: %q", i, len(l), l)
		}
	}
	if len(lines) < 2 || !strings.HasSuffix(lines[0], "token=") {
		t.Fatalf("want the first line to end at the 'token=' boundary, got %q", lines)
	}
	short := "https://a/b"
	if got := wrapDisplayURL(short, 70); len(got) != 1 || got[0] != short {
		t.Errorf("short URL should pass through unsplit, got %q", got)
	}
}