Beispiel #1
0
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)
}
Beispiel #2
0
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)
	}
}
Beispiel #3
0
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
}
Beispiel #4
0
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
}
Beispiel #5
0
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
}
Beispiel #6
0
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)
}
Beispiel #7
0
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
}
Beispiel #8
0
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)
}
Beispiel #10
0
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")
}
Beispiel #11
0
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
}