(ctx context.Context, cmd *cobra.Command)
| 95 | } |
| 96 | |
| 97 | func runLogin(ctx context.Context, cmd *cobra.Command) (err error) { |
| 98 | accountsURL := env.GetEnvOrDefault("CLOUDQUERY_ACCOUNTS_URL", defaultAccountsURL) |
| 99 | |
| 100 | mux := http.NewServeMux() |
| 101 | refreshToken := "" |
| 102 | gotToken := make(chan struct{}) |
| 103 | var once gosync.Once |
| 104 | mux.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) { |
| 105 | once.Do(func() { |
| 106 | refreshToken = r.URL.Query().Get("token") |
| 107 | close(gotToken) |
| 108 | }) |
| 109 | http.Redirect(w, r, accountsURL+"/success-close", http.StatusSeeOther) |
| 110 | }) |
| 111 | mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { |
| 112 | w.WriteHeader(http.StatusOK) |
| 113 | fmt.Fprint(w, "OK") |
| 114 | }) |
| 115 | listener, err := net.Listen("tcp", ":0") |
| 116 | if err != nil { |
| 117 | return fmt.Errorf("failed to listen: %w", err) |
| 118 | } |
| 119 | server := http.Server{ |
| 120 | Handler: mux, |
| 121 | Addr: listener.Addr().String(), |
| 122 | } |
| 123 | |
| 124 | var serverErr error |
| 125 | go func() { |
| 126 | if err := server.Serve(listener); err != nil { |
| 127 | if !errors.Is(err, http.ErrServerClosed) { |
| 128 | serverErr = fmt.Errorf("failed to serve: %w", err) |
| 129 | } |
| 130 | } |
| 131 | }() |
| 132 | localServerURL := "http://localhost:" + strconv.Itoa(listener.Addr().(*net.TCPAddr).Port) |
| 133 | if err := waitForServer(ctx, localServerURL+"/health"); err != nil { |
| 134 | return err |
| 135 | } |
| 136 | |
| 137 | url := accountsURL + "?returnTo=" + localServerURL + "/callback" |
| 138 | if err := browser.OpenURL(url); err != nil { |
| 139 | fmt.Printf("Failed to open browser. Please open %s manually and paste the token below:\n", accountsURL) |
| 140 | |
| 141 | stdinFd := int(os.Stdin.Fd()) |
| 142 | if !term.IsTerminal(stdinFd) { |
| 143 | return errors.New("reading from non-terminal stdin is not supported. Hint: Consider setting an api key with the `CLOUDQUERY_API_KEY` env variable") |
| 144 | } |
| 145 | |
| 146 | oldState, err := term.MakeRaw(stdinFd) |
| 147 | if err != nil { |
| 148 | return fmt.Errorf("failed setting stdin to raw mode: %w", err) |
| 149 | } |
| 150 | tty := term.NewTerminal(os.Stdin, "") |
| 151 | refreshToken, err = tty.ReadLine() |
| 152 | _ = term.Restore(stdinFd, oldState) |
| 153 | |
| 154 | if err != nil { |
no test coverage detected