Changed file structure
parent
663ab5f2f2
commit
7220ffdcd2
|
@ -0,0 +1,65 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.umbach.dev/app-idea/rest-api/modules/database"
|
||||
"git.umbach.dev/app-idea/rest-api/modules/structs"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func createUserActivation(userId string) (string, error) {
|
||||
userActivationId, err := generateRandomString(16, 1)
|
||||
|
||||
if err != nil {
|
||||
log.Warnln("Failed to generate random string")
|
||||
return "", err
|
||||
}
|
||||
|
||||
db := database.DB
|
||||
|
||||
db.Create(structs.UserActivation{Id: userActivationId, UserId: userId, Expires: getUserActivationExpiresTime()})
|
||||
|
||||
return userActivationId, nil
|
||||
}
|
||||
|
||||
func deleteExpiredUserActivations(db *gorm.DB) {
|
||||
var res string
|
||||
|
||||
db.Raw("DELETE FROM user_activations WHERE expires < ?", time.Now()).Scan(&res)
|
||||
}
|
||||
|
||||
func ActivateUser(c *fiber.Ctx) error {
|
||||
// swagger:operation POST /user/activate/:id User activation
|
||||
// ---
|
||||
// summary: Activate user
|
||||
// responses:
|
||||
// '200':
|
||||
// description: User was activated
|
||||
// '401':
|
||||
// description: Activation Id is incorrect or expired
|
||||
|
||||
db := database.DB
|
||||
|
||||
deleteExpiredUserActivations(db)
|
||||
|
||||
userActivation := structs.UserActivation{Id: c.Params("id")}
|
||||
|
||||
db.Select("user_id").Where("id = ?", c.Params("id")).Find(&userActivation)
|
||||
|
||||
if userActivation.UserId == "" {
|
||||
return c.SendStatus(fiber.StatusUnauthorized)
|
||||
}
|
||||
|
||||
db.Delete(userActivation)
|
||||
|
||||
db.Model(structs.User{Id: userActivation.UserId}).Update("state", 0)
|
||||
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
}
|
||||
|
||||
func getUserActivationExpiresTime() time.Time {
|
||||
return time.Now().Add(time.Minute * time.Duration(cfg.Settings.Expires.UserActivation))
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"git.umbach.dev/app-idea/rest-api/modules/database"
|
||||
"git.umbach.dev/app-idea/rest-api/modules/structs"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
type LoginInput struct {
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
func Login(c *fiber.Ctx) error {
|
||||
// swagger:operation POST /user/login User userLogin
|
||||
// ---
|
||||
// summary: Login a user
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: username or email
|
||||
// in: query
|
||||
// description: username or email
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: password
|
||||
// in: query
|
||||
// description: password (base64) of the user
|
||||
// type: string
|
||||
// required: true
|
||||
// responses:
|
||||
// '200':
|
||||
// description: login success
|
||||
// '401':
|
||||
// description: login credentials not correct
|
||||
|
||||
var input LoginInput
|
||||
|
||||
if err := c.BodyParser(&input); err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
log.Println(input)
|
||||
|
||||
if input.Username != "" && /*!isValid(input.Username, 3, 30) */ !isUsernameValid(input.Username) || input.Email != "" && !isEmailValid(input.Email) || input.Username == "" && input.Email == "" || input.Password == "" {
|
||||
log.Info("bad")
|
||||
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)
|
||||
|
||||
db := database.DB
|
||||
user := structs.User{}
|
||||
|
||||
if input.Username != "" {
|
||||
db.Select("id, hashtag, password").Where("name = ?", input.Username).Find(&user)
|
||||
} else {
|
||||
db.Select("id, hashtag, name, password").Where("email = ?", input.Email).Find(&user)
|
||||
}
|
||||
|
||||
if user.Name == "" && user.Email == "" {
|
||||
return c.SendStatus(fiber.StatusUnauthorized)
|
||||
}
|
||||
|
||||
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(input.Password))
|
||||
|
||||
if err != nil {
|
||||
log.Warnln("Failed to comapare bcrypt password", err)
|
||||
return c.SendStatus(fiber.StatusUnauthorized)
|
||||
}
|
||||
|
||||
sessionId, err := createUserSession(database.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})
|
||||
if user.Name != "" {
|
||||
c.Cookie(&fiber.Cookie{Name: "name", Value: user.Name, Secure: true, Expires: expires})
|
||||
}
|
||||
c.Cookie(&fiber.Cookie{Name: "hashtag", Value: user.Hashtag, Secure: true, Expires: expires})
|
||||
|
||||
return c.SendStatus(fiber.StatusCreated)
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
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)
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"git.umbach.dev/app-idea/rest-api/modules/database"
|
||||
"git.umbach.dev/app-idea/rest-api/modules/structs"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
ua "github.com/mileusna/useragent"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func isSessionIdValid(sessionId string) bool {
|
||||
deleteExpiredSessions(database.DB)
|
||||
|
||||
var res string
|
||||
var db = database.DB
|
||||
|
||||
db.Raw("SELECT session_id FROM sessions WHERE session_id = ?", sessionId).Scan(&res)
|
||||
|
||||
if res == "" {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func deleteSession(db *sql.DB, sessionId string) {
|
||||
_, err := db.Exec("DELETE FROM sessions WHERE session_id = ?", sessionId)
|
||||
|
||||
if err != nil {
|
||||
log.Warnln("err deleting session:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func deleteExpiredSessions(db *gorm.DB) {
|
||||
var res string
|
||||
|
||||
db.Raw("DELETE FROM sessions WHERE expires < ?", time.Now()).Scan(&res)
|
||||
}
|
||||
|
||||
func createUserSession(db *gorm.DB, userId string, ip string, userAgent string) (string, error) {
|
||||
sessionId, err := generateRandomString(32, 1)
|
||||
|
||||
if err != nil {
|
||||
log.Warnln("Failed to generate user session:", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
ua := ua.Parse(userAgent)
|
||||
session := structs.Session{UserId: userId, SessionId: sessionId, IP: ip, UserAgent: ua.OS + " " + ua.Name, LastLogin: time.Now(), Expires: getUserSessionExpiresTime()}
|
||||
|
||||
res := db.Create(&session)
|
||||
|
||||
if res.Error != nil {
|
||||
log.Warnln("failed to create session:", res.Error)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return sessionId, nil
|
||||
}
|
||||
|
||||
func getUserSessionExpiresTime() time.Time {
|
||||
return time.Now().Add(time.Hour * time.Duration(cfg.Settings.Expires.UserSession))
|
||||
}
|
||||
|
||||
func SessionIdCheck(c *fiber.Ctx) error {
|
||||
sessionId := c.Cookies("session_id")
|
||||
|
||||
if sessionId == "" {
|
||||
return fiber.ErrUnauthorized
|
||||
}
|
||||
|
||||
valid := isSessionIdValid(sessionId)
|
||||
|
||||
if valid {
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
return fiber.ErrUnauthorized
|
||||
}
|
|
@ -2,202 +2,21 @@ package user
|
|||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"git.umbach.dev/app-idea/rest-api/modules/config"
|
||||
"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"
|
||||
ua "github.com/mileusna/useragent"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var cfg = &config.Cfg
|
||||
|
||||
type LoginInput 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 LoginInput
|
||||
|
||||
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)
|
||||
|
||||
log.Debugln("lgId", input.LanguageId)
|
||||
|
||||
user.LanguageId = input.LanguageId
|
||||
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
|
||||
|
||||
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": "https://roese.dev/activate/1234567890"}`)
|
||||
|
||||
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 := getExpiresTime()
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func generateRandomString(n int, t int) (string, error) {
|
||||
var letters string
|
||||
|
||||
|
@ -305,156 +124,47 @@ func isEmailAvailable(db *gorm.DB, email string) bool {
|
|||
}
|
||||
}
|
||||
|
||||
func SessionIdCheck(c *fiber.Ctx) error {
|
||||
sessionId := c.Cookies("session_id")
|
||||
func getUserIdBySessionId(sessionId string) (string, error) {
|
||||
db := database.DB
|
||||
session := structs.Session{}
|
||||
|
||||
if sessionId == "" {
|
||||
return fiber.ErrUnauthorized
|
||||
}
|
||||
db.Select("user_id").Where("session_id = ?", sessionId).Find(&session)
|
||||
|
||||
valid := isSessionIdValid(sessionId)
|
||||
|
||||
if valid {
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
return fiber.ErrUnauthorized
|
||||
return session.UserId, nil
|
||||
}
|
||||
|
||||
func isSessionIdValid(sessionId string) bool {
|
||||
deleteExpiredSessions(database.DB)
|
||||
func GetUser(c *fiber.Ctx) error {
|
||||
log.Infoln("body", c.Body())
|
||||
|
||||
var res string
|
||||
var db = database.DB
|
||||
|
||||
db.Raw("SELECT session_id FROM sessions WHERE session_id = ?", sessionId).Scan(&res)
|
||||
|
||||
if res == "" {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func deleteSession(db *sql.DB, sessionId string) {
|
||||
_, err := db.Exec("DELETE FROM sessions WHERE session_id = ?", sessionId)
|
||||
|
||||
if err != nil {
|
||||
log.Warnln("err deleting session:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func deleteExpiredSessions(db *gorm.DB) {
|
||||
var res string
|
||||
|
||||
db.Raw("DELETE FROM sessions WHERE expires < ?", time.Now()).Scan(&res)
|
||||
}
|
||||
|
||||
func createUserSession(db *gorm.DB, userId string, ip string, userAgent string) (string, error) {
|
||||
sessionId, err := generateRandomString(32, 1)
|
||||
|
||||
if err != nil {
|
||||
log.Warnln("Failed to generate user session:", err)
|
||||
return "", err
|
||||
type Input struct {
|
||||
Val []string `json:"val"`
|
||||
}
|
||||
|
||||
ua := ua.Parse(userAgent)
|
||||
session := structs.Session{UserId: userId, SessionId: sessionId, IP: ip, UserAgent: ua.OS + " " + ua.Name, LastLogin: time.Now(), Expires: getExpiresTime()}
|
||||
log.Infoln("arr", string(c.Body()))
|
||||
|
||||
res := db.Create(&session)
|
||||
|
||||
if res.Error != nil {
|
||||
log.Warnln("failed to create session:", res.Error)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return sessionId, nil
|
||||
}
|
||||
|
||||
func getExpiresTime() time.Time {
|
||||
return time.Now().Add(time.Hour * time.Duration(cfg.Settings.ExpiredTime))
|
||||
}
|
||||
|
||||
func Login(c *fiber.Ctx) error {
|
||||
// swagger:operation POST /user/login User userLogin
|
||||
// ---
|
||||
// summary: Login a user
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: username or email
|
||||
// in: query
|
||||
// description: username or email
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: password
|
||||
// in: query
|
||||
// description: password (base64) of the user
|
||||
// type: string
|
||||
// required: true
|
||||
// responses:
|
||||
// '200':
|
||||
// description: login success
|
||||
// '401':
|
||||
// description: login credentials not correct
|
||||
|
||||
var input LoginInput
|
||||
var input Input
|
||||
|
||||
if err := c.BodyParser(&input); err != nil {
|
||||
log.Infoln("bad", input)
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
log.Println(input)
|
||||
log.Infoln("test", strings.Join(input.Val, ","))
|
||||
|
||||
if input.Username != "" && /*!isValid(input.Username, 3, 30) */ !isUsernameValid(input.Username) || input.Email != "" && !isEmailValid(input.Email) || input.Username == "" && input.Email == "" || input.Password == "" {
|
||||
log.Info("bad")
|
||||
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)
|
||||
log.Println("input", input)
|
||||
|
||||
db := database.DB
|
||||
user := structs.User{}
|
||||
|
||||
if input.Username != "" {
|
||||
db.Select("id, hashtag, password").Where("name = ?", input.Username).Find(&user)
|
||||
} else {
|
||||
db.Select("id, hashtag, name, password").Where("email = ?", input.Email).Find(&user)
|
||||
}
|
||||
|
||||
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(input.Password))
|
||||
|
||||
if err != nil {
|
||||
log.Warnln("Failed to comapare bcrypt password", err)
|
||||
return c.SendStatus(fiber.StatusUnauthorized)
|
||||
}
|
||||
|
||||
sessionId, err := createUserSession(database.DB, user.Id, c.IP(), string(c.Context().UserAgent()))
|
||||
userId, err := getUserIdBySessionId(c.Cookies("session_id"))
|
||||
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
expires := getExpiresTime()
|
||||
user := structs.User{}
|
||||
|
||||
c.Cookie(&fiber.Cookie{Name: "session_id", Value: sessionId, Secure: true, HTTPOnly: true, Expires: expires})
|
||||
if user.Name != "" {
|
||||
c.Cookie(&fiber.Cookie{Name: "name", Value: user.Name, Secure: true, Expires: expires})
|
||||
}
|
||||
c.Cookie(&fiber.Cookie{Name: "hashtag", Value: user.Hashtag, Secure: true, Expires: expires})
|
||||
db.Table("users").Select(strings.Join(input.Val, ",")).First(&user, "id = ?", userId)
|
||||
|
||||
return c.SendStatus(fiber.StatusCreated)
|
||||
}
|
||||
|
||||
func GetUser(c *fiber.Ctx) error {
|
||||
return c.SendString("user")
|
||||
return c.JSON(&user)
|
||||
}
|
||||
|
||||
func GetUsers(c *fiber.Ctx) error {
|
||||
|
|
Loading…
Reference in New Issue