func (repo *repository) DetectApiRootAndSetAccessToken(values url.Values) (apiRoot string, err error) { if repo.URL.Host == "github.com" { apiRoot = "https://api.github.com" return } if v, ok := repo.Config[repo.URL.Host]; ok { apiRoot = v.ApiRoot values.Add("access_token", v.AccessToken) return } sc := SiteConfig{repo.URL.Host, "", ""} msg := fmt.Sprintf("Please input github API root path for '%s' (such as 'https://api.github.com') :", repo.URL.Host) apiRoot, err = ask.Ask(msg, false) if err != nil { return } sc.ApiRoot = strings.TrimLeft(apiRoot, "/") sc.AccessToken, err = repo.NewAccessToken(sc.Host, sc.ApiRoot) if err != nil { err = util.LyciaError("failed to generate new access token: " + err.Error()) return } repo.Config[repo.URL.Host] = sc err = repo.Config.Save() if err != nil { err = util.LyciaError("failed to save config: " + err.Error()) return } values.Add("access_token", sc.AccessToken) return }
func (repo *repository) NewAccessToken(host string, apiRoot string) (accessToken string, err error) { username, err := ask.Ask(fmt.Sprintf("Please input username for '%s':", host), false) if err != nil { return } password, err := ask.Ask(fmt.Sprintf("Please input password for '%s':", host), true) if err != nil { return } reqBody := fmt.Sprintf(`{"scopes":["repo"],"note":"lycia %s"}`, time.Now()) req, err := repo.NewPostRequest(username, password, apiRoot+"/authorizations", reqBody) if err != nil { return } client := &http.Client{} res, err := client.Do(req) if err != nil { return } if res.StatusCode == 401 { if v := res.Header.Get("X-Github-Otp"); strings.HasPrefix(v, "required;") { var otp string otp, err = ask.Ask("Please input two-factor authentication code:", false) if err != nil { return } req, err = repo.NewPostRequest(username, password, apiRoot+"/authorizations", reqBody) if err != nil { return } req.Header.Add("X-Github-Otp", otp) res, err = client.Do(req) if err != nil { return } } else { err = util.LyciaError("Bad credentials") return } } else if res.StatusCode != 200 && res.StatusCode != 201 { err = util.LyciaError(fmt.Sprintf("Unknown status: %s", res.Status)) return } defer res.Body.Close() decoder := json.NewDecoder(res.Body) var authorizations Authorizations if err = decoder.Decode(&authorizations); err != nil { return } if authorizations.HashedToken != "" { accessToken = authorizations.HashedToken } else if authorizations.Token != "" { accessToken = authorizations.Token } else { err = util.LyciaError("cannot detect HashedToken") } return }