Example #1
0
File: utils.go Project: pgpst/pgpst
func connectToRethinkDB(c *cli.Context) (*r.ConnectOpts, *r.Session, bool) {
	opts, err := utils.ParseRethinkDBString(c.GlobalString("rethinkdb"))
	if err != nil {
		writeError(c, err)
		return nil, nil, false
	}
	session, err := r.Connect(opts)
	if err != nil {
		writeError(c, err)
		return nil, nil, false
	}

	return &opts, session, true
}
Example #2
0
func addressesAdd(c *cli.Context) int {
	// Connect to RethinkDB
	_, session, connected := connectToRethinkDB(c)
	if !connected {
		return 1
	}

	// Input struct
	var input struct {
		ID    string `json:"id"`
		Owner string `json:"owner"`
	}

	// Read JSON from stdin
	if c.Bool("json") {
		if err := json.NewDecoder(c.App.Env["reader"].(io.Reader)).Decode(&input); err != nil {
			writeError(c, err)
			return 1
		}
	} else {
		// Buffer stdin
		rd := bufio.NewReader(c.App.Env["reader"].(io.Reader))
		var err error

		// Acquire from interactive input
		fmt.Fprintf(c.App.Writer, "Address: ")
		input.ID, err = rd.ReadString('\n')
		if err != nil {
			writeError(c, err)
			return 1
		}
		input.ID = strings.TrimSpace(input.ID)

		fmt.Fprintf(c.App.Writer, "Owner ID: ")
		input.Owner, err = rd.ReadString('\n')
		if err != nil {
			writeError(c, err)
			return 1
		}
		input.Owner = strings.TrimSpace(input.Owner)
	}

	// First of all, the address. Append domain if it has no such suffix.
	if strings.Index(input.ID, "@") == -1 {
		input.ID += "@" + c.GlobalString("default_domain")
	}

	// And format it
	styledID := utils.NormalizeAddress(input.ID)
	input.ID = utils.RemoveDots(styledID)

	// Then check if it's taken.
	cursor, err := r.Table("addresses").Get(input.ID).Ne(nil).Run(session)
	if err != nil {
		writeError(c, err)
		return 1
	}
	defer cursor.Close()
	var taken bool
	if err := cursor.One(&taken); err != nil {
		writeError(c, err)
		return 1
	}
	if taken {
		writeError(c, fmt.Errorf("Address %s is already taken", input.ID))
		return 1
	}

	// Check if account ID exists
	cursor, err = r.Table("accounts").Get(input.Owner).Ne(nil).Run(session)
	if err != nil {
		writeError(c, err)
	}
	defer cursor.Close()
	var exists bool
	if err := cursor.One(&exists); err != nil {
		writeError(c, err)
		return 1
	}
	if !exists {
		writeError(c, fmt.Errorf("Account %s doesn't exist", input.ID))
		return 1
	}

	// Insert the address into the database
	address := &models.Address{
		ID:           input.ID,
		StyledID:     styledID,
		DateCreated:  time.Now(),
		DateModified: time.Now(),
		Owner:        input.Owner,
	}

	if !c.GlobalBool("dry") {
		if err := r.Table("addresses").Insert(address).Exec(session); err != nil {
			writeError(c, err)
			return 1
		}
	}

	// Write a success message
	fmt.Fprintf(c.App.Writer, "Created a new address - %s\n", address.StyledID)
	return 0
}
Example #3
0
func accountsAdd(c *cli.Context) int {
	// Connect to RethinkDB
	_, session, connected := connectToRethinkDB(c)
	if !connected {
		return 1
	}

	// Input struct
	var input struct {
		MainAddress  string `json:"main_address"`
		Password     string `json:"password"`
		Subscription string `json:"subscription"`
		AltEmail     string `json:"alt_email"`
		Status       string `json:"status"`
	}

	// Read JSON from stdin
	if c.Bool("json") {
		if err := json.NewDecoder(c.App.Env["reader"].(io.Reader)).Decode(&input); err != nil {
			writeError(c, err)
			return 1
		}
	} else {
		// Buffer stdin
		rd := bufio.NewReader(c.App.Env["reader"].(io.Reader))
		var err error

		// Acquire from interactive input
		fmt.Fprint(c.App.Writer, "Main address: ")
		input.MainAddress, err = rd.ReadString('\n')
		if err != nil {
			writeError(c, err)
			return 1
		}
		input.MainAddress = strings.TrimSpace(input.MainAddress)

		fmt.Fprint(c.App.Writer, "Password: "******"Password: "******"Subscription [beta/admin]: ")
		input.Subscription, err = rd.ReadString('\n')
		if err != nil {
			writeError(c, err)
			return 1
		}
		input.Subscription = strings.TrimSpace(input.Subscription)

		fmt.Fprint(c.App.Writer, "Alternative address: ")
		input.AltEmail, err = rd.ReadString('\n')
		if err != nil {
			writeError(c, err)
			return 1
		}
		input.AltEmail = strings.TrimSpace(input.AltEmail)

		fmt.Fprint(c.App.Writer, "Status [inactive/active/suspended]: ")
		input.Status, err = rd.ReadString('\n')
		if err != nil {
			writeError(c, err)
			return 1
		}
		input.Status = strings.TrimSpace(input.Status)
	}

	// Analyze the input

	// First of all, the address. Append domain if it has no such suffix.
	if strings.Index(input.MainAddress, "@") == -1 {
		input.MainAddress += "@" + c.GlobalString("default_domain")
	}

	// And format it
	styledID := utils.NormalizeAddress(input.MainAddress)
	input.MainAddress = utils.RemoveDots(styledID)

	// Then check if it's taken.
	cursor, err := r.Table("addresses").Get(input.MainAddress).Ne(nil).Run(session)
	if err != nil {
		writeError(c, err)
		return 1
	}
	defer cursor.Close()
	var taken bool
	if err := cursor.One(&taken); err != nil {
		writeError(c, err)
		return 1
	}
	if taken {
		writeError(c, fmt.Errorf("Address %s is already taken", input.MainAddress))
		return 1
	}

	// If the password isn't 64 characters long, then hash it.
	var password []byte
	if len(input.Password) != 64 {
		hash := sha256.Sum256([]byte(input.Password))
		password = hash[:]
	} else {
		password, err = hex.DecodeString(input.Password)
		if err != nil {
			writeError(c, err)
			return 1
		}
	}

	// Subscription has to be beta or admin
	if input.Subscription != "beta" && input.Subscription != "admin" {
		writeError(c, fmt.Errorf("Subscription has to be either beta or admin. Got %s.", input.Subscription))
		return 1
	}

	// AltEmail must be an email
	if !govalidator.IsEmail(input.AltEmail) {
		writeError(c, fmt.Errorf("Email %s has an incorrect format", input.AltEmail))
		return 1
	}

	// Status has to be inactive/active/suspended
	if input.Status != "inactive" && input.Status != "active" && input.Status != "suspended" {
		writeError(c, fmt.Errorf("Status has to be either inactive, active or suspended. Got %s.", input.Status))
		return 1
	}

	// Prepare structs to insert
	account := &models.Account{
		ID:           uniuri.NewLen(uniuri.UUIDLen),
		DateCreated:  time.Now(),
		DateModified: time.Now(),
		MainAddress:  input.MainAddress,
		Subscription: input.Subscription,
		AltEmail:     input.AltEmail,
		Status:       input.Status,
	}
	if err := account.SetPassword([]byte(password)); err != nil {
		writeError(c, err)
		return 1
	}

	address := &models.Address{
		ID:           input.MainAddress,
		StyledID:     styledID,
		DateCreated:  time.Now(),
		DateModified: time.Now(),
		Owner:        account.ID,
	}

	var labels []*models.Label
	if account.Status != "inactive" {
		labels = []*models.Label{
			&models.Label{
				ID:           uniuri.NewLen(uniuri.UUIDLen),
				DateCreated:  time.Now(),
				DateModified: time.Now(),
				Owner:        account.ID,
				Name:         "Inbox",
				System:       true,
			},
			&models.Label{
				ID:           uniuri.NewLen(uniuri.UUIDLen),
				DateCreated:  time.Now(),
				DateModified: time.Now(),
				Owner:        account.ID,
				Name:         "Spam",
				System:       true,
			},
			&models.Label{
				ID:           uniuri.NewLen(uniuri.UUIDLen),
				DateCreated:  time.Now(),
				DateModified: time.Now(),
				Owner:        account.ID,
				Name:         "Sent",
				System:       true,
			},
			&models.Label{
				ID:           uniuri.NewLen(uniuri.UUIDLen),
				DateCreated:  time.Now(),
				DateModified: time.Now(),
				Owner:        account.ID,
				Name:         "Starred",
				System:       true,
			},
		}
	}

	// Insert them into database
	if !c.Bool("dry") {
		if err := r.Table("addresses").Insert(address).Exec(session); err != nil {
			writeError(c, err)
			return 1
		}
		if err := r.Table("accounts").Insert(account).Exec(session); err != nil {
			writeError(c, err)
			return 1
		}
		if labels != nil {
			if err := r.Table("labels").Insert(labels).Exec(session); err != nil {
				writeError(c, err)
				return 1
			}
		}
	}

	// Write a success message
	fmt.Fprintf(c.App.Writer, "Created a new account with ID %s\n", account.ID)
	return 0
}