Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion callback.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"context"
"crypto/subtle"
"errors"
"fmt"
"html"
Expand Down Expand Up @@ -97,7 +98,7 @@ func startCallbackServer(ctx context.Context, port int, expectedState string,
}

state := q.Get("state")
if state != expectedState {
if subtle.ConstantTimeCompare([]byte(state), []byte(expectedState)) == 0 {
sanitized := "Authorization failed. Possible security issue detected."
writeCallbackPage(w, false, sanitized)
sendResult(callbackResult{
Expand Down
23 changes: 12 additions & 11 deletions tui/flow_renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@ import (
"charm.land/lipgloss/v2"
)

// ANSI escape sequences for terminal control.
const (
ansiClearScreen = "\033[H\033[2J"
ansiClearToEnd = "\033[J"
ansiHideCursor = "\033[999;999H"
)

// FlowRenderer manages rendering of the unified flow view without running a full Bubble Tea program
type FlowRenderer struct {
model *UnifiedFlowModel
spinnerFrame int
spinnerChars []rune
lastContent string // Track last rendered content to avoid unnecessary redraws
contentDirty bool // Flag to indicate if content needs redraw
inProgressStepIdx int // Index of the in-progress step for spinner updates
hasInProgressStep bool // Whether there's a step in progress
Expand Down Expand Up @@ -91,7 +97,7 @@ func (r *FlowRenderer) NextSpinner() string {
// RenderHeader renders and prints the header
func (r *FlowRenderer) RenderHeader() {
// Clear screen and move to top
fmt.Print("\033[H\033[2J")
fmt.Print(ansiClearScreen)

var b strings.Builder

Expand Down Expand Up @@ -179,18 +185,14 @@ func (r *FlowRenderer) UpdateDisplay() {

currentContent := b.String()

// Move cursor to after header
headerLines := r.headerLines

// Move to position after header
fmt.Printf("\033[%d;0H", headerLines)
fmt.Printf("\033[%d;0H", r.headerLines)
// Clear from cursor to end of screen
fmt.Print("\033[J")
fmt.Print(ansiClearToEnd)

// Print new content
fmt.Print(currentContent)

r.lastContent = currentContent
r.contentDirty = false
}

Expand All @@ -201,8 +203,7 @@ func (r *FlowRenderer) updateSpinnerOnly() {
}

// Calculate the line number for the in-progress step
headerLines := r.headerLines
stepLine := headerLines + r.inProgressStepIdx
stepLine := r.headerLines + r.inProgressStepIdx

// Render the spinner character
spinnerStyle := lipgloss.NewStyle().Foreground(colorPrimary)
Expand All @@ -213,7 +214,7 @@ func (r *FlowRenderer) updateSpinnerOnly() {
// Print just the spinner character
fmt.Print(spinnerChar)
// Move cursor back to end (to avoid cursor showing)
fmt.Print("\033[999;999H")
fmt.Print(ansiHideCursor)
}

// renderDeviceCodeInfo renders the device code information box
Expand Down
Loading