diff --git a/pam/integration-tests/testdata/tapes/cli/qr_code.tape b/pam/integration-tests/testdata/tapes/cli/qr_code.tape index ca2d621420..eeb529c881 100644 --- a/pam/integration-tests/testdata/tapes/cli/qr_code.tape +++ b/pam/integration-tests/testdata/tapes/cli/qr_code.tape @@ -47,17 +47,17 @@ Show Hide Enter -Sleep 300ms +Sleep 800ms Show Hide Enter -Sleep 300ms +Sleep 800ms Show Hide Enter -Sleep 300ms +Sleep 800ms Show Hide diff --git a/pam/integration-tests/testdata/tapes/cli/qr_code_quick_regenerate.tape b/pam/integration-tests/testdata/tapes/cli/qr_code_quick_regenerate.tape index 9aaa4141d8..85ac5c0191 100644 --- a/pam/integration-tests/testdata/tapes/cli/qr_code_quick_regenerate.tape +++ b/pam/integration-tests/testdata/tapes/cli/qr_code_quick_regenerate.tape @@ -52,8 +52,8 @@ Sleep 300ms Show Hide -Enter@1ms 50 -Sleep 10s +Enter@1ms 800 +Sleep 3s Show Sleep 300ms diff --git a/pam/internal/adapter/qrcodemodel.go b/pam/internal/adapter/qrcodemodel.go index 3162d2496b..8bd1a62fc0 100644 --- a/pam/internal/adapter/qrcodemodel.go +++ b/pam/internal/adapter/qrcodemodel.go @@ -1,23 +1,30 @@ package adapter import ( + "context" "fmt" "os" "strings" + "time" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" "github.com/muesli/termenv" "github.com/skip2/go-qrcode" "github.com/ubuntu/authd" + "github.com/ubuntu/authd/internal/log" ) var centeredStyle = lipgloss.NewStyle().Align(lipgloss.Center, lipgloss.Top) +// reselectionRateLimit is the amount of time (in ms) that we wait before regenerating the qrcode. +const reselectionRateLimit = int64(300) + // qrcodeModel is the form layout type to allow authenticating and return a challenge. type qrcodeModel struct { - label string - buttonModel *buttonModel + label string + buttonModel *buttonModel + selectionTimestamp int64 content string code string @@ -39,12 +46,13 @@ func newQRCodeModel(content, code, label, buttonLabel string, wait bool) (qrcode } return qrcodeModel{ - label: label, - buttonModel: button, - content: content, - code: code, - qrCode: qrCode, - wait: wait, + label: label, + buttonModel: button, + selectionTimestamp: time.Now().UnixMilli(), + content: content, + code: code, + qrCode: qrCode, + wait: wait, }, nil } @@ -73,6 +81,12 @@ func (m qrcodeModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if m.buttonModel == nil { return m, nil } + now := time.Now().UnixMilli() + if now-m.selectionTimestamp < reselectionRateLimit { + log.Debug(context.TODO(), "Button press ignored, too fast!") + return m, nil + } + m.selectionTimestamp = now return m, sendEvent(reselectAuthMode{}) } }