package user import ( "encoding/base64" "encoding/json" "strings" "time" "git.umbach.dev/app-idea/rest-api/modules/database" "git.umbach.dev/app-idea/rest-api/modules/rabbitmq" "git.umbach.dev/app-idea/rest-api/modules/structs" "github.com/gofiber/fiber/v2" "github.com/google/uuid" log "github.com/sirupsen/logrus" "golang.org/x/crypto/bcrypt" ) type RegisterInput struct { Username string `json:"username"` Email string `json:"email"` Password string `json:"password"` Hashtag string `json:"hashtag"` LanguageId int `json:"languageId"` } func NewUser(c *fiber.Ctx) error { // swagger:operation POST /users User usersNewUser // --- // summary: Create new user // produces: // - application/json // parameters: // - name: username // in: query // description: username of the user (length 3-30) // type: string // required: true // - name: email // in: query // description: email of the user (length 3-255) // type: string // required: true // - name: password // in: query // description: password (base64) of the user (length 6-250) // type: string // required: true // - name: hashtag // in: query // description: hashtag of the client (length 2-6, UPPERCASE (Letters, Numbers)) // type: string // - name: avatar_url // in: query // description: avatar url of the client // type: string // - name: location // in: query // description: location of the client (length 1-20) (for example Frankfurt) // type: string // responses: // '201': // description: user created // "$ref": "#/definitions/User" // '400': // description: format is not correct // '422': // description: username, email or/and hashtag already assigned var input RegisterInput if err := c.BodyParser(&input); err != nil { log.Debugln("bodyParser failed:", err) return c.SendStatus(fiber.StatusBadRequest) } decodedPassword, err := base64.StdEncoding.DecodeString(input.Password) if err != nil { log.Debugln("base64 decoding failed:", err) return c.SendStatus(fiber.StatusBadRequest) } input.Password = string(decodedPassword) if !isUsernameValid(input.Username) || !isEmailValid(input.Email) || !isPasswordValid(input.Password) { return c.SendStatus(fiber.StatusForbidden) } user := structs.User{Email: input.Email} db := database.DB if !isEmailAvailable(db, user.Email) { return c.SendStatus(fiber.StatusUnprocessableEntity) } if input.Hashtag == "" { input.Hashtag, err = generateRandomHashtag(db, 6) if err != nil { return c.SendStatus(fiber.StatusInternalServerError) } } else if !isHashtagValid(db, 1, input.Hashtag) { return c.SendStatus(fiber.StatusUnprocessableEntity) } hashedPassword, err := bcrypt.GenerateFromPassword([]byte(input.Password), bcrypt.DefaultCost) if err != nil { log.Warnln("Failed to bcrypt password", err) return c.SendStatus(fiber.StatusInternalServerError) } now := time.Now() user.Id = strings.Replace(uuid.New().String(), "-", "", -1) user.Hashtag = input.Hashtag user.Name = input.Username user.Password = string(hashedPassword) user.LanguageId = input.LanguageId user.State = 1 user.LastLogin = now user.CreatedAt = now res := db.Create(&user) if res.Error != nil { log.Warnln("Failed to insert user to db:", res.Error) return c.SendStatus(fiber.StatusInternalServerError) } // account activation via email userActivationId, err := createUserActivation(user.Id) if err != nil { return c.SendStatus(fiber.StatusInternalServerError) } type JsonMessage struct { Key string `json:"k"` Mail string `json:"m"` TemplateId int `json:"t"` LanguageId int `json:"l"` BodyData *json.RawMessage `json:"d"` } bodyData := json.RawMessage(`{"name": "` + user.Name + `", "email": "` + user.Email + `", "url": "http://localhost:3000/api/v1/user/activate/` + userActivationId + `"}`) js := JsonMessage{Key: "mykey", Mail: "app@roese.dev", TemplateId: 0, LanguageId: user.LanguageId, BodyData: &bodyData} reqBody, err := json.MarshalIndent(&js, "", "\t") if err != nil { log.Infoln("error reqBody", err) } rabbitmq.Publish(string(reqBody)) /*resp, err := http.Post(cfg.Mail.Host+"/send", "application/json", bytes.NewBuffer(reqBody)) if err != nil { log.Infoln("err http post", err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Infoln("err reading body", err) } log.Infoln("body", body) log.Infoln("StatusCode", resp.StatusCode)*/ sessionId, err := createUserSession(db, user.Id, c.IP(), string(c.Context().UserAgent())) if err != nil { return c.SendStatus(fiber.StatusInternalServerError) } expires := getUserSessionExpiresTime() c.Cookie(&fiber.Cookie{Name: "session_id", Value: sessionId, Secure: true, HTTPOnly: true, Expires: expires}) c.Cookie(&fiber.Cookie{Name: "username", Value: input.Username, Secure: true, Expires: expires}) c.Cookie(&fiber.Cookie{Name: "user_hashtag", Value: input.Hashtag, Secure: true, Expires: expires}) log.Debugln("user created", user) return c.SendStatus(fiber.StatusCreated) }