Completed
Push — main ( c7f647...178139 )
by Yume
14s queued 13s
created

controllers.IsConnected   A

Complexity

Conditions 3

Size

Total Lines 37
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 23
nop 1
dl 0
loc 37
rs 9.328
c 0
b 0
f 0
1
package controllers
2
3
import (
4
	"fmt"
5
	"github.com/memnix/memnixrest/app/auth"
6
	"github.com/memnix/memnixrest/pkg/database"
7
	"github.com/memnix/memnixrest/pkg/logger"
8
	"github.com/memnix/memnixrest/pkg/models"
9
	"github.com/memnix/memnixrest/pkg/queries"
10
	"github.com/memnix/memnixrest/pkg/utils"
11
	"net/http"
12
	"strconv"
13
	"strings"
14
	"time"
15
16
	"github.com/gofiber/fiber/v2"
17
	"github.com/golang-jwt/jwt"
18
	"golang.org/x/crypto/bcrypt"
19
)
20
21
// Register function to create a new user
22
// @Description Create a new user
23
// @Summary creates a new user
24
// @Tags Auth
25
// @Produce json
26
// @Param credentials body models.RegisterStruct true "Credentials"
27
// @Success 200 {object} models.User
28
// @Failure 403 "Forbidden"
29
// @Router /v1/register [post]
30
func Register(c *fiber.Ctx) error {
31
	db := database.DBConn // DB Conn
32
33
	var data models.RegisterStruct // Data object
34
35
	if err := c.BodyParser(&data); err != nil {
36
		return err
37
	} // Parse body
38
39
	// Register checks
40
	if len(data.Password) > utils.MaxPasswordLen || len(data.Username) > utils.MaxUsernameLen || len(data.Email) > utils.MaxEmailLen {
41
		log := logger.CreateLog(fmt.Sprintf("Error on register: %s - %s", data.Username, data.Email), logger.LogBadRequest).SetType(logger.LogTypeWarning).AttachIDs(0, 0, 0)
42
		_ = log.SendLog()
43
		return queries.RequestError(c, http.StatusForbidden, utils.ErrorRequestFailed)
44
	}
45
46
	password, _ := bcrypt.GenerateFromPassword([]byte(data.Password), 10) // Hash password
47
	user := models.User{
48
		Username: data.Username,
49
		Email:    strings.ToLower(data.Email),
50
		Password: password,
51
	} // Create object
52
53
	//TODO: manual checking for unique username and email
54
	if err := db.Create(&user).Error; err != nil {
55
		log := logger.CreateLog(fmt.Sprintf("Error on register: %s - %s", data.Username, data.Email), logger.LogAlreadyUsedEmail).SetType(logger.LogTypeWarning).AttachIDs(user.ID, 0, 0)
56
		_ = log.SendLog()
57
		return queries.RequestError(c, http.StatusForbidden, utils.ErrorAlreadyUsedEmail)
58
	} // Add user to DB
59
60
	// Create log
61
	log := logger.CreateLog(fmt.Sprintf("Register: %s - %s", user.Username, user.Email), logger.LogUserRegister).SetType(logger.LogTypeInfo).AttachIDs(user.ID, 0, 0)
62
	_ = log.SendLog() // Send log
63
64
	return c.JSON(user) // Return user
65
}
66
67
// Login function to log in a user and return access with fresh token
68
// @Description Login the user and return a fresh token
69
// @Summary logins user and return a fresh token
70
// @Tags Auth
71
// @Produce json
72
// @Param credentials body models.LoginStruct true "Credentials"
73
// @Success 200 {object} models.LoginResponse
74
// @Failure 400 "Incorrect password or email"
75
// @Failure 500 "Internal error"
76
// @Router /v1/login [post]
77
func Login(c *fiber.Ctx) error {
78
	db := database.DBConn // DB Conn
79
80
	var data models.LoginStruct // Data object
81
82
	if err := c.BodyParser(&data); err != nil {
83
		return err
84
	} // Parse body
85
86
	var user models.User // User object
87
88
	db.Where("email = ?", strings.ToLower(data.Email)).First(&user) // Get user
89
90
	// handle error
91
	if user.ID == 0 { // default ID when return nil
92
		// Create log
93
		log := logger.CreateLog(fmt.Sprintf("Error on login: %s", data.Email), logger.LogIncorrectEmail).SetType(logger.LogTypeWarning).AttachIDs(user.ID, 0, 0)
94
		_ = log.SendLog()                // Send log
95
		c.Status(fiber.StatusBadRequest) // BadRequest Status
96
		// return error message as Json object
97
		return c.JSON(models.LoginResponse{
98
			Message: "Incorrect email or password !",
99
			Token:   "",
100
		})
101
	}
102
103
	// Check password
104
	if err := bcrypt.CompareHashAndPassword(user.Password, []byte(data.Password)); err != nil {
105
		c.Status(fiber.StatusBadRequest) // BadRequest Status
106
		log := logger.CreateLog(fmt.Sprintf("Error on login: %s", data.Email), logger.LogIncorrectPassword).SetType(logger.LogTypeWarning).AttachIDs(user.ID, 0, 0)
107
		_ = log.SendLog() // Send log
108
		// return error message as Json object
109
		return c.JSON(models.LoginResponse{
110
			Message: "Incorrect email or password !",
111
			Token:   "",
112
		})
113
	}
114
115
	// Create token
116
	claims := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{
117
		Issuer:    strconv.Itoa(int(user.ID)),
118
		ExpiresAt: time.Now().Add(time.Hour * 336).Unix(), // 14 day
119
	}) // expires after 2 weeks
120
121
	token, err := claims.SignedString([]byte(auth.SecretKey)) // Sign token
122
	if err != nil {
123
		log := logger.CreateLog(fmt.Sprintf("Error on login: %s", err.Error()), logger.LogLoginError).SetType(logger.LogTypeError).AttachIDs(user.ID, 0, 0)
124
		_ = log.SendLog()                         // Send log
125
		c.Status(fiber.StatusInternalServerError) // InternalServerError Status
126
		// return error message as Json object
127
		return c.JSON(models.LoginResponse{
128
			Message: "Incorrect email or password !",
129
			Token:   "",
130
		})
131
	}
132
133
	log := logger.CreateLog(fmt.Sprintf("Login: %s - %s", user.Username, user.Email), logger.LogUserLogin).SetType(logger.LogTypeInfo).AttachIDs(user.ID, 0, 0)
134
	_ = log.SendLog() // Send log
135
136
	// return token as Json object
137
	return c.JSON(models.LoginResponse{
138
		Message: "Login Succeeded",
139
		Token:   token,
140
	})
141
}
142
143
// User function to get connected user
144
// @Description Get connected user
145
// @Summary  gets connected user
146
// @Tags Auth
147
// @Produce json
148
// @Success 200 {object} models.ResponseAuth
149
// @Failure 401 "Forbidden"
150
// @Security Beaver
151
// @Router /v1/user [get]
152
func User(c *fiber.Ctx) error {
153
	// statusCode, response := IsConnected(c) // Check if connected
154
155
	user := new(models.PublicUser)
156
157
	localUser, ok := c.Locals("user").(models.User)
158
	if !ok {
159
		return queries.RequestError(c, http.StatusUnauthorized, utils.ErrorForbidden)
160
	}
161
162
	user.Set(&localUser) // Set user
163
164
	responseUser := models.ResponsePublicAuth{
165
		Success: true,
166
		Message: "User is connected",
167
		User:    *user,
168
	}
169
170
	return c.Status(fiber.StatusOK).JSON(responseUser) // Return response
171
}
172
173
// Logout function to log user logout
174
// @Description Logout the user and create a record in the log
175
// @Summary logouts the user
176
// @Tags Auth
177
// @Produce json
178
// @Success 200 "Success"
179
// @Failure 401 "Forbidden"
180
// @Security Beaver
181
// @Router /v1/logout [post]
182
func Logout(c *fiber.Ctx) error {
183
	user, ok := c.Locals("user").(models.User)
184
	if !ok {
185
		return queries.RequestError(c, http.StatusUnauthorized, utils.ErrorForbidden)
186
	}
187
188
	// Create log
189
	log := logger.CreateLog(fmt.Sprintf("Logout: %s - %s", user.Username, user.Email), logger.LogUserLogout).SetType(logger.LogTypeInfo).AttachIDs(user.ID, 0, 0)
190
	_ = log.SendLog()
191
192
	// Return response with success
193
	return c.JSON(fiber.Map{
194
		"message": "successfully logged out !",
195
		"token":   "",
196
	})
197
}
198