mirror of
				https://github.com/usememos/memos.git
				synced 2025-11-01 01:06:04 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			142 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package cmd
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/pkg/errors"
 | |
| 	"github.com/spf13/cobra"
 | |
| 	"golang.org/x/crypto/bcrypt"
 | |
| 
 | |
| 	"github.com/usememos/memos/common/util"
 | |
| 	"github.com/usememos/memos/store"
 | |
| 	"github.com/usememos/memos/store/db/sqlite"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	setupCmdFlagHostUsername = "host-username"
 | |
| 	setupCmdFlagHostPassword = "host-password"
 | |
| 	setupCmd                 = &cobra.Command{
 | |
| 		Use:   "setup",
 | |
| 		Short: "Make initial setup for memos",
 | |
| 		Run: func(cmd *cobra.Command, _ []string) {
 | |
| 			ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 | |
| 			defer cancel()
 | |
| 
 | |
| 			hostUsername, err := cmd.Flags().GetString(setupCmdFlagHostUsername)
 | |
| 			if err != nil {
 | |
| 				fmt.Printf("failed to get owner username, error: %+v\n", err)
 | |
| 				return
 | |
| 			}
 | |
| 
 | |
| 			hostPassword, err := cmd.Flags().GetString(setupCmdFlagHostPassword)
 | |
| 			if err != nil {
 | |
| 				fmt.Printf("failed to get owner password, error: %+v\n", err)
 | |
| 				return
 | |
| 			}
 | |
| 
 | |
| 			driver, err := sqlite.NewDB(profile)
 | |
| 			if err != nil {
 | |
| 				fmt.Printf("failed to create db driver, error: %+v\n", err)
 | |
| 				return
 | |
| 			}
 | |
| 			if err := driver.Migrate(ctx); err != nil {
 | |
| 				fmt.Printf("failed to migrate db, error: %+v\n", err)
 | |
| 				return
 | |
| 			}
 | |
| 
 | |
| 			store := store.New(driver, profile)
 | |
| 			if err := ExecuteSetup(ctx, store, hostUsername, hostPassword); err != nil {
 | |
| 				fmt.Printf("failed to setup, error: %+v\n", err)
 | |
| 				return
 | |
| 			}
 | |
| 		},
 | |
| 	}
 | |
| )
 | |
| 
 | |
| func init() {
 | |
| 	setupCmd.Flags().String(setupCmdFlagHostUsername, "", "Owner username")
 | |
| 	setupCmd.Flags().String(setupCmdFlagHostPassword, "", "Owner password")
 | |
| 
 | |
| 	rootCmd.AddCommand(setupCmd)
 | |
| }
 | |
| 
 | |
| func ExecuteSetup(ctx context.Context, store *store.Store, hostUsername, hostPassword string) error {
 | |
| 	s := setupService{store: store}
 | |
| 	return s.Setup(ctx, hostUsername, hostPassword)
 | |
| }
 | |
| 
 | |
| type setupService struct {
 | |
| 	store *store.Store
 | |
| }
 | |
| 
 | |
| func (s setupService) Setup(ctx context.Context, hostUsername, hostPassword string) error {
 | |
| 	if err := s.makeSureHostUserNotExists(ctx); err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if err := s.createUser(ctx, hostUsername, hostPassword); err != nil {
 | |
| 		return errors.Wrap(err, "create user")
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (s setupService) makeSureHostUserNotExists(ctx context.Context) error {
 | |
| 	hostUserType := store.RoleHost
 | |
| 	existedHostUsers, err := s.store.ListUsers(ctx, &store.FindUser{Role: &hostUserType})
 | |
| 	if err != nil {
 | |
| 		return errors.Wrap(err, "find user list")
 | |
| 	}
 | |
| 
 | |
| 	if len(existedHostUsers) != 0 {
 | |
| 		return errors.New("host user already exists")
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (s setupService) createUser(ctx context.Context, hostUsername, hostPassword string) error {
 | |
| 	userCreate := &store.User{
 | |
| 		Username: hostUsername,
 | |
| 		// The new signup user should be normal user by default.
 | |
| 		Role:     store.RoleHost,
 | |
| 		Nickname: hostUsername,
 | |
| 	}
 | |
| 
 | |
| 	if len(userCreate.Username) < 3 {
 | |
| 		return errors.New("username is too short, minimum length is 3")
 | |
| 	}
 | |
| 	if len(userCreate.Username) > 32 {
 | |
| 		return errors.New("username is too long, maximum length is 32")
 | |
| 	}
 | |
| 	if len(hostPassword) < 3 {
 | |
| 		return errors.New("password is too short, minimum length is 3")
 | |
| 	}
 | |
| 	if len(hostPassword) > 512 {
 | |
| 		return errors.New("password is too long, maximum length is 512")
 | |
| 	}
 | |
| 	if len(userCreate.Nickname) > 64 {
 | |
| 		return errors.New("nickname is too long, maximum length is 64")
 | |
| 	}
 | |
| 	if userCreate.Email != "" {
 | |
| 		if len(userCreate.Email) > 256 {
 | |
| 			return errors.New("email is too long, maximum length is 256")
 | |
| 		}
 | |
| 		if !util.ValidateEmail(userCreate.Email) {
 | |
| 			return errors.New("invalid email format")
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	passwordHash, err := bcrypt.GenerateFromPassword([]byte(hostPassword), bcrypt.DefaultCost)
 | |
| 	if err != nil {
 | |
| 		return errors.Wrap(err, "failed to hash password")
 | |
| 	}
 | |
| 
 | |
| 	userCreate.PasswordHash = string(passwordHash)
 | |
| 	if _, err := s.store.CreateUser(ctx, userCreate); err != nil {
 | |
| 		return errors.Wrap(err, "failed to create user")
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 |