package main import ( "context" "errors" "sync" "github.com/go-logr/logr" "github.com/webview/webview" "golang.org/x/oauth2/authhandler" ) func requestUserConsentFunc(ctx context.Context) authhandler.AuthorizationHandler { return func(originalWebUrl string) (string, string, error) { return requestUserConsent(ctx, originalWebUrl) } } func requestUserConsent(ctx context.Context, originalWebUrl string) (code string, state string, err error) { log := logr.FromContextOrDiscard(ctx).WithName("requestUserConsent") log.Info("Asking for user consent", "url", originalWebUrl) proxyServer, err := NewOneAndOneLoginProxy(ctx, "localhost:0") if err != nil { log.Error(err, "Failed to set up local 1&1 login proxy") return "", "", nil } go proxyServer.Listen() defer proxyServer.Teardown() webUrl, err := proxyServer.ConvertURLString(originalWebUrl) if err != nil { log.Error(err, "Failed to convert oauth init URL to proxy URL") return "", "", nil } ctx, cancelFunc := context.WithCancel(ctx) wg := new(sync.WaitGroup) w := webview.New(webviewDebug) defer w.Destroy() w.SetTitle("1&1 Login") w.SetSize(480, 480, webview.HintNone) w.Navigate(webUrl.String()) wg.Add(1) go func() { defer wg.Done() doneC := ctx.Done() select { case values := <-proxyServer.ResponseCodeC(): code = values.Get("code") state = values.Get("state") log.V(1).Info("Got login response", "code", code, "state", state) w.Terminate() case <-doneC: return } }() w.Run() cancelFunc() wg.Wait() // Did webview get terminated before we got a code? // That's the user canceling login. if code == "" { return "", "", errors.New("user canceled login") } return code, state, nil }