setup.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. package cmd
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. "github.com/pkg/errors"
  7. "github.com/spf13/cobra"
  8. "golang.org/x/crypto/bcrypt"
  9. "github.com/usememos/memos/internal/util"
  10. "github.com/usememos/memos/store"
  11. "github.com/usememos/memos/store/db/sqlite"
  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. driver, err := sqlite.NewDB(profile)
  33. if err != nil {
  34. fmt.Printf("failed to create db driver, error: %+v\n", err)
  35. return
  36. }
  37. if err := driver.Migrate(ctx); err != nil {
  38. fmt.Printf("failed to migrate db, error: %+v\n", err)
  39. return
  40. }
  41. store := store.New(driver, profile)
  42. if err := ExecuteSetup(ctx, store, hostUsername, hostPassword); err != nil {
  43. fmt.Printf("failed to setup, error: %+v\n", err)
  44. return
  45. }
  46. },
  47. }
  48. )
  49. func init() {
  50. setupCmd.Flags().String(setupCmdFlagHostUsername, "", "Owner username")
  51. setupCmd.Flags().String(setupCmdFlagHostPassword, "", "Owner password")
  52. rootCmd.AddCommand(setupCmd)
  53. }
  54. func ExecuteSetup(ctx context.Context, store *store.Store, hostUsername, hostPassword string) error {
  55. s := setupService{store: store}
  56. return s.Setup(ctx, hostUsername, hostPassword)
  57. }
  58. type setupService struct {
  59. store *store.Store
  60. }
  61. func (s setupService) Setup(ctx context.Context, hostUsername, hostPassword string) error {
  62. if err := s.makeSureHostUserNotExists(ctx); err != nil {
  63. return err
  64. }
  65. if err := s.createUser(ctx, hostUsername, hostPassword); err != nil {
  66. return errors.Wrap(err, "create user")
  67. }
  68. return nil
  69. }
  70. func (s setupService) makeSureHostUserNotExists(ctx context.Context) error {
  71. hostUserType := store.RoleHost
  72. existedHostUsers, err := s.store.ListUsers(ctx, &store.FindUser{Role: &hostUserType})
  73. if err != nil {
  74. return errors.Wrap(err, "find user list")
  75. }
  76. if len(existedHostUsers) != 0 {
  77. return errors.New("host user already exists")
  78. }
  79. return nil
  80. }
  81. func (s setupService) createUser(ctx context.Context, hostUsername, hostPassword string) error {
  82. userCreate := &store.User{
  83. Username: hostUsername,
  84. // The new signup user should be normal user by default.
  85. Role: store.RoleHost,
  86. Nickname: hostUsername,
  87. }
  88. if len(userCreate.Username) < 3 {
  89. return errors.New("username is too short, minimum length is 3")
  90. }
  91. if len(userCreate.Username) > 32 {
  92. return errors.New("username is too long, maximum length is 32")
  93. }
  94. if len(hostPassword) < 3 {
  95. return errors.New("password is too short, minimum length is 3")
  96. }
  97. if len(hostPassword) > 512 {
  98. return errors.New("password is too long, maximum length is 512")
  99. }
  100. if len(userCreate.Nickname) > 64 {
  101. return errors.New("nickname is too long, maximum length is 64")
  102. }
  103. if userCreate.Email != "" {
  104. if len(userCreate.Email) > 256 {
  105. return errors.New("email is too long, maximum length is 256")
  106. }
  107. if !util.ValidateEmail(userCreate.Email) {
  108. return errors.New("invalid email format")
  109. }
  110. }
  111. passwordHash, err := bcrypt.GenerateFromPassword([]byte(hostPassword), bcrypt.DefaultCost)
  112. if err != nil {
  113. return errors.Wrap(err, "failed to hash password")
  114. }
  115. userCreate.PasswordHash = string(passwordHash)
  116. if _, err := s.store.CreateUser(ctx, userCreate); err != nil {
  117. return errors.Wrap(err, "failed to create user")
  118. }
  119. return nil
  120. }