WaitForBrowserCallback lauches a new HTTP server listening on the provided address and waits for a request. Once received, the code is extracted from the query string (if any), and returned it to the caller.
(addr string)
| 12 | // address and waits for a request. Once received, the code is extracted from |
| 13 | // the query string (if any), and returned it to the caller. |
| 14 | func WaitForBrowserCallback(addr string) (code string, state string, err error) { |
| 15 | type callback struct { |
| 16 | code string |
| 17 | state string |
| 18 | err string |
| 19 | errDescription string |
| 20 | } |
| 21 | |
| 22 | cbCh := make(chan *callback) |
| 23 | errCh := make(chan error) |
| 24 | |
| 25 | m := http.NewServeMux() |
| 26 | s := &http.Server{Addr: addr, Handler: m} |
| 27 | |
| 28 | m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { |
| 29 | cb := &callback{ |
| 30 | code: r.URL.Query().Get("code"), |
| 31 | state: r.URL.Query().Get("state"), |
| 32 | err: r.URL.Query().Get("error"), |
| 33 | errDescription: r.URL.Query().Get("error_description"), |
| 34 | } |
| 35 | |
| 36 | if cb.code == "" { |
| 37 | _, _ = w.Write([]byte(resultPage("Login Failed", |
| 38 | "Failed to extract code from request, please try authenticating again.", |
| 39 | "error-denied"))) |
| 40 | } else { |
| 41 | _, _ = w.Write([]byte(resultPage("Login Successful", |
| 42 | "You can close the window and go back to the CLI to see the user info and tokens.", |
| 43 | "success-lock"))) |
| 44 | } |
| 45 | |
| 46 | cbCh <- cb |
| 47 | }) |
| 48 | |
| 49 | go func() { |
| 50 | if err := s.ListenAndServe(); err != nil && err != http.ErrServerClosed { |
| 51 | errCh <- err |
| 52 | } |
| 53 | }() |
| 54 | |
| 55 | select { |
| 56 | case cb := <-cbCh: |
| 57 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) |
| 58 | defer cancel() |
| 59 | defer func(c context.Context) { _ = s.Shutdown(ctx) }(ctx) |
| 60 | |
| 61 | var err error |
| 62 | if cb.err != "" { |
| 63 | err = fmt.Errorf("%s: %s", cb.err, cb.errDescription) |
| 64 | } |
| 65 | return cb.code, cb.state, err |
| 66 | case err := <-errCh: |
| 67 | return "", "", err |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | //go:embed data/result-page.html |