func configFromDir(dir string) (config, error) { l, err := readLegacyConfigFile(filepath.Join(dir, legacyConfigFile)) if err != nil && !stackerr.HasUnderlying(err, stackerr.MatcherFunc(os.IsNotExist)) { return nil, err } if l != nil { // legacy config format projectConfig := &projectConfig{ Type: legacyParseFormat, Parse: &parseProjectConfig{ JSSDK: l.Global.ParseVersion, }, ParserEmail: l.Global.ParserEmail, } applications := l.Applications if applications == nil { applications = make(map[string]*parseAppConfig) } return &parseConfig{ Applications: applications, projectConfig: projectConfig, }, nil } canonicalize := func(err error) error { if err == nil { return nil } if stackerr.HasUnderlying(err, stackerr.MatcherFunc(os.IsNotExist)) { return stackerr.New("Command must be run inside a Parse project.") } return err } // current config format p, err := readProjectConfigFile(filepath.Join(dir, parseProject)) if err != nil { return nil, canonicalize(err) } configFile := filepath.Join(dir, parseLocal) switch p.Type { case parseFormat: c, err := readParseConfigFile(configFile) if err != nil { return nil, canonicalize(err) } if c.Applications == nil { c.Applications = make(map[string]*parseAppConfig) } c.projectConfig = p return c, nil } return nil, stackerr.Newf("Unknown project type: %d.", p.Type) }
func (c *HerokuConfig) PrettyPrintApps(e *Env) { apps := c.Applications defaultApp := c.GetDefaultApp() var appNames []string for appName := range apps { appNames = append(appNames, appName) } sort.Strings(appNames) if len(appNames) == 0 { return } fmt.Fprintln( e.Out, "The following apps are associated with cloud code in the current directory:", ) for _, appName := range appNames { if appName == DefaultKey { continue } if defaultApp == appName { fmt.Fprint(e.Out, "* ") } else { fmt.Fprint(e.Out, " ") } fmt.Fprintf(e.Out, "%s", appName) config, _ := apps[appName] if config.GetLink() != "" { fmt.Fprintf(e.Out, " -> %s", config.GetLink()) } herokuAppName, err := FetchHerokuAppName(config.HerokuAppID, e) if err != nil { if stackerr.HasUnderlying(err, stackerr.MatcherFunc(HerokuAppNotFound)) { herokuAppName = "" } else { herokuAppName = config.HerokuAppID } } fmt.Fprintf(e.Out, " (%q)\n", herokuAppName) } }
func (l *login) authUser(e *env) error { _, err := l.authUserWithToken(e) if err == nil { return nil } // user never created an account key: educate them if stackerr.HasUnderlying(err, stackerr.MatcherFunc(os.IsNotExist)) { fmt.Fprintln( e.Out, `We've changed the way the CLI works. To save time logging in, you should create an account key. `) } apps := &apps{} fmt.Fprintln( e.Out, `Type "parse configure accountkey" to create a new account key. Read more at: https://parse.com/docs/js/guide#command-line-account-keys Please login to Parse using your email and password.`, ) for i := 0; i < numRetries; i++ { err := l.populateCreds(e) if err != nil { return err } apps.login.credentials = l.credentials _, err = apps.restFetchApps(e) if err == nil { return nil } if i == numRetries-1 && err != nil { return err } if err != errAuth { fmt.Fprintf(e.Err, "Got error: %s", errorString(e, err)) } fmt.Fprintf(e.Err, "%s\nPlease try again...\n", err) l.credentials.password = "" } return errAuth }
func (l *login) authUserWithToken(e *env) (string, error) { _, tokenCredentials, err := l.getTokenCredentials(e, e.ParserEmail) if err != nil { if stackerr.HasUnderlying(err, stackerr.MatcherFunc(accessKeyNotFound)) { fmt.Fprintln(e.Err, errorString(e, err)) } return "", err } email, err := l.authToken(e, tokenCredentials.token) if err != nil { fmt.Fprintf(e.Err, "Account key could not be used.\nError: %s\n\n", errorString(e, err)) return "", err } l.credentials = *tokenCredentials return email, nil }
func (l *Login) AuthUser(e *Env, strict bool) error { _, err := l.AuthUserWithToken(e, strict) if err == nil { return nil } if strict { return err } if !stackerr.HasUnderlying(err, stackerr.MatcherFunc(accountKeyNotConfigured)) { fmt.Fprintln( e.Out, `Type "parse configure accountkey" to create a new account key. Read more at: https://parse.com/docs/cloudcode/guide#command-line-account-keys Please login to Parse using your email and password.`, ) } apps := &Apps{} for i := 0; i < numRetries; i++ { err := l.populateCreds(e) if err != nil { return err } apps.Login.Credentials = l.Credentials _, err = apps.RestFetchApps(e) if err == nil { return nil } if i == numRetries-1 && err != nil { return err } if err != errAuth { fmt.Fprintf(e.Err, "Got error: %s", ErrorString(e, err)) } fmt.Fprintf(e.Err, "%s\nPlease try again...\n", err) l.Credentials.Password = "" } return errAuth }
func (h *herokuLink) herokuAppNames(ids []string, e *parsecli.Env) (nameIDs, []string, error) { var wg errgroup.Group wg.Add(len(ids)) maxParallel := make(chan struct{}, maxRequests) var ( ret nameIDs deletedLinks []string retMutex sync.Mutex deletedLinksMutex sync.Mutex ) getAppName := func(id string) { defer func() { wg.Done() <-maxParallel }() appName, err := parsecli.FetchHerokuAppName(id, e) if err != nil { if stackerr.HasUnderlying(err, stackerr.MatcherFunc(parsecli.HerokuAppNotFound)) { deletedLinksMutex.Lock() defer deletedLinksMutex.Unlock() deletedLinks = append(deletedLinks, id) return } wg.Error(err) // ignore error if corresponding heroku app was deleted return } retMutex.Lock() defer retMutex.Unlock() ret = append(ret, nameID{id: id, name: appName}) } for _, id := range ids { go getAppName(id) } err := wg.Wait() sort.Sort(ret) return ret, deletedLinks, stackerr.Wrap(err) }
func configFromDir(dir string) (config, error) { l, err := readLegacyConfigFile(filepath.Join(dir, legacyConfigFile)) if err != nil { if stackerr.HasUnderlying(err, stackerr.MatcherFunc(os.IsNotExist)) { return nil, stackerr.New("Command must be run in a directory containing a Parse project.") } return nil, err } projectConfig := &projectConfig{ Type: legacy, Parse: &parseProjectConfig{JSSDK: l.Global.ParseVersion}, } applications := l.Applications if applications == nil { applications = make(map[string]*parseAppConfig) } return &parseConfig{ Applications: applications, projectConfig: projectConfig, }, nil }
func (l *Login) AuthUserWithToken(e *Env, strict bool) (string, error) { _, tokenCredentials, err := l.GetTokenCredentials(e, e.ParserEmail) if err != nil { // user never created an account key: educate them if stackerr.HasUnderlying(err, stackerr.MatcherFunc(os.IsNotExist)) { if strict { fmt.Fprintln( e.Out, `To proceed further, you must configure an account key. `, ) } else { fmt.Fprintln( e.Out, `We've changed the way the CLI works. To save time logging in, you should create an account key. `, ) } fmt.Fprintln( e.Out, `Type "parse configure accountkey" to create a new account key. Read more at: https://parse.com/docs/cloudcode/guide#command-line-account-keys`) return "", stackerr.New("Account key not configured") } return "", err } email, err := l.AuthToken(e, tokenCredentials.Token) if err != nil { fmt.Fprintf(e.Err, "Account key could not be used.\nError: %s\n\n", ErrorString(e, err)) return "", err } l.Credentials = *tokenCredentials return email, nil }
func (c *configureCmd) accountKey(e *env) error { token, err := c.login.helpCreateToken(e) if err != nil { return err } email, err := c.login.authToken(e, token) if err != nil { fmt.Fprintln(e.Err, "Could not store credentials. Please try again.\n") return err } if c.isDefault { email = "" } var l login if c.tokenReader != nil { l.tokenReader = c.tokenReader } foundEmail, creds, err := l.getTokenCredentials(e, email) if stackerr.HasUnderlying(err, stackerr.MatcherFunc(os.IsNotExist)) && !c.isDefault { fmt.Fprintln( e.Out, ` Looks like you have not configured the default account key yet. Note that "parse new" and "parse list" can automatically pick up a default key if present. Otherwise, you'll have to explicitly set the PARSER_EMAIL environment variable for it to know which account key to use. Further, if the command line tool cannot find an account key for a configured email it will try to use the default account key To configure the default account key use: "parse configure accountkey -d"`, ) } if creds != nil { if c.isDefault { fmt.Fprintln( e.Err, "Note: this operation will overwrite the default account key", ) } else if foundEmail { fmt.Fprintf( e.Err, `Note: this operation will overwrite the account key: %q for email: %q `, last4(token), email, ) } } err = c.login.storeCredentials(e, email, &credentials{token: token}) if err == nil { if c.isDefault { fmt.Fprintln(e.Out, "Successfully stored default account key.") } else { fmt.Fprintf(e.Out, "Successfully stored account key for: %q.\n", email) } } return stackerr.Wrap(err) }
func GetLinkedHerokuAppConfig(app *parsecli.App, e *parsecli.Env) (bool, *parsecli.HerokuAppConfig, error) { h := &herokuLink{parseAppID: app.ApplicationID} apps, err := h.getAppLinks(e) if err != nil { return false, nil, err } if len(apps) == 0 { randomName := getRandomAppName(app) appName := randomName for i := 0; i < 3; i++ { if appName == randomName { fmt.Fprintf(e.Out, `Let's create a new Heroku app in which server code will be run. The Heroku app will be named: %q Note that this can be changed later using Heroku API or Dashboard. `, randomName, ) } else { appName = h.getHerokuAppName(e) } id, err := h.createNewLink(e, appName) if err == nil { return true, &parsecli.HerokuAppConfig{ ParseAppID: app.ApplicationID, HerokuAppID: id, }, nil } if i == 2 { return false, nil, err } switch { case stackerr.HasUnderlying(err, stackerr.MatcherFunc(herokuAppNameTaken)): fmt.Fprintf(e.Err, "App name %s already taken.\nPlease try again...\n\n", appName) appName = "" case stackerr.HasUnderlying(err, stackerr.MatcherFunc(herokuAccountNotLinked)): fmt.Fprintf(e.Err, `Looks like you have not yet linked your Heroku Account to your Parse account. Trying to open %q in the browser. Please click "Link Heroku" button at the bottom. `, linkHerokuURL, ) appName = randomName err := open.Run(linkHerokuURL) if err != nil { fmt.Fprintf(e.Err, `Sorry, we couldn’t open the browser for you. Go to %q and click the "Link Heroku" button to link your Heroku account to Parse. `, linkHerokuURL, ) } fmt.Fprintf(e.Out, "Press ENTER when you are done linking your Heroku account to Parse: ") var discard string fmt.Fscanf(e.In, "%s\n", &discard) default: return false, nil, err } } } if len(apps) == 1 { return false, &parsecli.HerokuAppConfig{ ParseAppID: app.ApplicationID, HerokuAppID: apps[0].id, }, nil } // NOTE: this part of code will not be used for now for r := 0; r < 3; r++ { selected, err := selectHerokuApp(apps, e) if err != nil { fmt.Fprintf(e.Err, "error: %s.\nPlease try again...\n", parsecli.ErrorString(e, err)) continue } if selected.id != "" { return false, &parsecli.HerokuAppConfig{ ParseAppID: app.ApplicationID, HerokuAppID: selected.id, }, nil } id, err := h.createNewLink(e, selected.name) if err != nil { return false, nil, err } return false, &parsecli.HerokuAppConfig{ ParseAppID: app.ApplicationID, HerokuAppID: id, }, nil } return false, nil, stackerr.New("failed to selected an heroku app in 3 attempts") }
func (c *configureCmd) accountKey(e *parsecli.Env) error { token, err := c.login.HelpCreateToken(e) if err != nil { return err } email, err := c.login.AuthToken(e, token) if err != nil { fmt.Fprintln(e.Err, "Could not store credentials. Please try again.\n") return err } if c.isDefault { email = "" } var l parsecli.Login if c.tokenReader != nil { l.TokenReader = c.tokenReader } foundEmail, creds, err := l.GetTokenCredentials(e, email) firstEverConfigure := false if stackerr.HasUnderlying(err, stackerr.MatcherFunc(os.IsNotExist)) && !c.isDefault { firstEverConfigure = true } if creds != nil { if c.isDefault { fmt.Fprintln( e.Err, "Note: this operation will overwrite the default account key", ) } else if foundEmail { fmt.Fprintf( e.Err, `Note: this operation will overwrite the account key: %q for email: %q `, parsecli.Last4(token), email, ) } } err = c.login.StoreCredentials(e, email, &parsecli.Credentials{Token: token}) if err == nil { if c.isDefault { fmt.Fprintln(e.Out, "Successfully stored default account key.") } else { fmt.Fprintf(e.Out, "Successfully stored account key for: %q.\n", email) } } if err != nil { fmt.Fprintln(e.Err, "Could not save account key.") return stackerr.Wrap(err) } if firstEverConfigure { fmt.Fprintln( e.Out, ` Looks like this is the first time you have configured an account key. Note that "parse new" and "parse list" can automatically pick up a default key if present. Otherwise, you'll have to explicitly set the PARSER_EMAIL common.Environment variable for them to pick the correct account key. Further, if the command line tool cannot find an account key for a configured email it will try to use the default account key. Hence, we are automatically configuring the default account key to be the same as current account key. `, ) err = c.login.StoreCredentials(e, "", &parsecli.Credentials{Token: token}) if err != nil { fmt.Fprintln(e.Err, "Could not save account key.") return stackerr.Wrap(err) } fmt.Fprintln(e.Out, `Successfully configured the default account key. To change the default account key in future use: "parse configure accountkey -d" `) } return nil }