setup.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package cmd
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "time"
  7. "github.com/spf13/cobra"
  8. "github.com/usememos/memos/common/util"
  9. "github.com/usememos/memos/store"
  10. "github.com/usememos/memos/store/db"
  11. "golang.org/x/crypto/bcrypt"
  12. )
  13. var (
  14. setupCmdFlagHostUsername = "host-username"
  15. setupCmdFlagHostPassword = "host-password"
  16. setupCmd = &cobra.Command{
  17. Use: "setup",
  18. Short: "Make initial setup for memos",
  19. Run: func(cmd *cobra.Command, _ []string) {
  20. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  21. defer cancel()
  22. hostUsername, err := cmd.Flags().GetString(setupCmdFlagHostUsername)
  23. if err != nil {
  24. fmt.Printf("failed to get owner username, error: %+v\n", err)
  25. return
  26. }
  27. hostPassword, err := cmd.Flags().GetString(setupCmdFlagHostPassword)
  28. if err != nil {
  29. fmt.Printf("failed to get owner password, error: %+v\n", err)
  30. return
  31. }
  32. db := db.NewDB(profile)
  33. if err := db.Open(ctx); err != nil {
  34. fmt.Printf("failed to open db, error: %+v\n", err)
  35. return
  36. }
  37. store := store.New(db.DBInstance, profile)
  38. if err := ExecuteSetup(ctx, store, hostUsername, hostPassword); err != nil {
  39. fmt.Printf("failed to setup, error: %+v\n", err)
  40. return
  41. }
  42. },
  43. }
  44. )
  45. func init() {
  46. setupCmd.Flags().String(setupCmdFlagHostUsername, "", "Owner username")
  47. setupCmd.Flags().String(setupCmdFlagHostPassword, "", "Owner password")
  48. rootCmd.AddCommand(setupCmd)
  49. }
  50. func ExecuteSetup(ctx context.Context, store *store.Store, hostUsername, hostPassword string) error {
  51. s := setupService{store: store}
  52. return s.Setup(ctx, hostUsername, hostPassword)
  53. }
  54. type setupService struct {
  55. store *store.Store
  56. }
  57. func (s setupService) Setup(ctx context.Context, hostUsername, hostPassword string) error {
  58. if err := s.makeSureHostUserNotExists(ctx); err != nil {
  59. return err
  60. }
  61. if err := s.createUser(ctx, hostUsername, hostPassword); err != nil {
  62. return fmt.Errorf("create user: %w", err)
  63. }
  64. return nil
  65. }
  66. func (s setupService) makeSureHostUserNotExists(ctx context.Context) error {
  67. hostUserType := store.RoleHost
  68. existedHostUsers, err := s.store.ListUsers(ctx, &store.FindUser{Role: &hostUserType})
  69. if err != nil {
  70. return fmt.Errorf("find user list: %w", err)
  71. }
  72. if len(existedHostUsers) != 0 {
  73. return errors.New("host user already exists")
  74. }
  75. return nil
  76. }
  77. func (s setupService) createUser(ctx context.Context, hostUsername, hostPassword string) error {
  78. userCreate := &store.User{
  79. Username: hostUsername,
  80. // The new signup user should be normal user by default.
  81. Role: store.RoleHost,
  82. Nickname: hostUsername,
  83. OpenID: util.GenUUID(),
  84. }
  85. if len(userCreate.Username) < 3 {
  86. return fmt.Errorf("username is too short, minimum length is 3")
  87. }
  88. if len(userCreate.Username) > 32 {
  89. return fmt.Errorf("username is too long, maximum length is 32")
  90. }
  91. if len(hostPassword) < 3 {
  92. return fmt.Errorf("password is too short, minimum length is 3")
  93. }
  94. if len(hostPassword) > 512 {
  95. return fmt.Errorf("password is too long, maximum length is 512")
  96. }
  97. if len(userCreate.Nickname) > 64 {
  98. return fmt.Errorf("nickname is too long, maximum length is 64")
  99. }
  100. if userCreate.Email != "" {
  101. if len(userCreate.Email) > 256 {
  102. return fmt.Errorf("email is too long, maximum length is 256")
  103. }
  104. if !util.ValidateEmail(userCreate.Email) {
  105. return fmt.Errorf("invalid email format")
  106. }
  107. }
  108. passwordHash, err := bcrypt.GenerateFromPassword([]byte(hostPassword), bcrypt.DefaultCost)
  109. if err != nil {
  110. return fmt.Errorf("failed to hash password: %w", err)
  111. }
  112. userCreate.PasswordHash = string(passwordHash)
  113. if _, err := s.store.CreateUser(ctx, userCreate); err != nil {
  114. return fmt.Errorf("failed to create user: %w", err)
  115. }
  116. return nil
  117. }