package ui import ( "strconv" "gioui.org/layout" "gioui.org/widget" "gioui.org/widget/material" "git.wxccs.org/iceking2nd/winauth-go/internal/authenticator" "git.wxccs.org/iceking2nd/winauth-go/internal/global" "git.wxccs.org/iceking2nd/winauth-go/internal/i18n" ) // addHOTPDialog asks for {Name, Base32 secret, starting counter}. type addHOTPDialog struct { nameEd widget.Editor secretEd widget.Editor counterEd widget.Editor showSec widget.Bool okBtn widget.Clickable cancelBtn widget.Clickable errorMsg string } func newAddHOTPDialog() *addHOTPDialog { d := &addHOTPDialog{} d.nameEd.SingleLine = true d.secretEd.SingleLine = true d.secretEd.Mask = '*' d.counterEd.SingleLine = true d.counterEd.SetText("0") return d } func (d *addHOTPDialog) Layout( gtx layout.Context, th *material.Theme, onDone func(authenticator.Authenticator, string), ) layout.Dimensions { const fn = "internal.ui.addHOTPDialog.Layout" if d.showSec.Update(gtx) { if d.showSec.Value { d.secretEd.Mask = 0 } else { d.secretEd.Mask = '*' } } if d.okBtn.Clicked(gtx) { secret := d.secretEd.Text() if secret == "" { d.errorMsg = i18n.T("msg_empty_secret") } else { counter, err := strconv.ParseUint(d.counterEd.Text(), 10, 64) if err != nil { d.errorMsg = i18n.T("msg_invalid_counter") } else { h := authenticator.NewHOTPAuthenticator() if err := h.Enroll(secret, counter); err != nil { global.Log.WithField("func", fn).WithError(err).Warn("enroll failed") d.errorMsg = i18n.T("msg_invalid_secret") } else { name := d.nameEd.Text() if name == "" { name = i18n.T("vendor_hotp") } onDone(h, name) return layout.Dimensions{Size: gtx.Constraints.Max} } } } } if d.cancelBtn.Clicked(gtx) { onDone(nil, "") return layout.Dimensions{Size: gtx.Constraints.Max} } body := func(gtx layout.Context) layout.Dimensions { return layout.Flex{Axis: layout.Vertical}.Layout(gtx, layout.Rigid(labeledEditor(th, i18n.T("label_name"), &d.nameEd, i18n.T("vendor_hotp"))), layout.Rigid(labeledEditor(th, i18n.T("label_secret_key"), &d.secretEd, "ABCDEF...")), layout.Rigid(labeledEditor(th, i18n.T("label_counter"), &d.counterEd, "0")), layout.Rigid(material.CheckBox(th, &d.showSec, i18n.T("label_show_secret")).Layout), layout.Rigid(errorLabel(th, d.errorMsg)), ) } return modalCard(gtx, th, i18n.T("dialog_add_hotp_title"), i18n.T("btn_ok"), i18n.T("btn_cancel"), &d.okBtn, &d.cancelBtn, body) }