238 lines
6.1 KiB
Go
238 lines
6.1 KiB
Go
package socketclients
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"janex/admin-dashboard-backend/modules/cache"
|
|
"janex/admin-dashboard-backend/modules/database"
|
|
"janex/admin-dashboard-backend/modules/structs"
|
|
"janex/admin-dashboard-backend/modules/utils"
|
|
"time"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
func BroadcastMessage(sendSocketMessage structs.SendSocketMessage) {
|
|
for _, client := range cache.GetSocketClients() {
|
|
client.SendMessage(sendSocketMessage)
|
|
}
|
|
}
|
|
|
|
func BroadcastMessageExceptUserSessionId(ignoreUserSessionId string, sendSocketMessage structs.SendSocketMessage) {
|
|
for _, client := range cache.GetSocketClients() {
|
|
if client.SessionId != ignoreUserSessionId {
|
|
client.SendMessage(sendSocketMessage)
|
|
}
|
|
}
|
|
}
|
|
|
|
func UpdateConnectedUsers(userId string) {
|
|
var user structs.User
|
|
|
|
database.DB.First(&user, "id = ?", userId)
|
|
|
|
BroadcastMessage(structs.SendSocketMessage{
|
|
Cmd: utils.SentCmdUpdateConnectedUsers,
|
|
Body: struct {
|
|
WebSocketUsersCount int
|
|
UserId string
|
|
ConnectionStatus uint8
|
|
LastOnline time.Time
|
|
}{
|
|
WebSocketUsersCount: len(cache.GetSocketClients()),
|
|
UserId: userId,
|
|
ConnectionStatus: isUserGenerallyConnected(userId),
|
|
LastOnline: user.LastOnline,
|
|
},
|
|
})
|
|
}
|
|
|
|
func SendMessageToUser(userId string, ignoreUserSessionId string, sendSocketMessage structs.SendSocketMessage) {
|
|
for _, client := range cache.GetSocketClients() {
|
|
if client.UserId == userId && client.SessionId != ignoreUserSessionId {
|
|
client.SendMessage(sendSocketMessage)
|
|
}
|
|
}
|
|
}
|
|
|
|
// This close all connections that are connected with one session id.
|
|
// For example when a user has two browser tabs opened
|
|
func CloseAllUserSessionConnections(sessionId string) {
|
|
for _, client := range cache.GetSocketClients() {
|
|
if client.SessionId == sessionId {
|
|
client.SendSessionClosedMessage()
|
|
}
|
|
}
|
|
}
|
|
|
|
func GetUserSessions(userId string) []structs.UserSessionSocket {
|
|
var userSessions []structs.UserSession
|
|
|
|
database.DB.Where("user_id = ?", userId).Find(&userSessions)
|
|
|
|
var userSessionsSocket []structs.UserSessionSocket
|
|
|
|
socketClients := cache.GetSocketClients()
|
|
|
|
for _, userSession := range userSessions {
|
|
userSessionsSocket = append(userSessionsSocket, structs.UserSessionSocket{
|
|
IdForDeletion: userSession.IdForDeletion,
|
|
UserAgent: userSession.UserAgent,
|
|
ConnectionStatus: isUserSessionConnected(userSession.Id, socketClients),
|
|
LastUsed: userSession.LastUsed,
|
|
ExpiresAt: userSession.ExpiresAt,
|
|
})
|
|
}
|
|
|
|
return userSessionsSocket
|
|
}
|
|
|
|
func UpdateUserSessionsForUser(userId string, ignoreUserSessionId string) {
|
|
GetUserSessions(userId)
|
|
|
|
SendMessageToUser(userId, ignoreUserSessionId, structs.SendSocketMessage{
|
|
Cmd: utils.SentCmdUpdateUserSessions,
|
|
Body: GetUserSessions(userId),
|
|
})
|
|
}
|
|
|
|
func isUserSessionConnected(userSessionId string, socketClients []*structs.SocketClient) uint8 {
|
|
for _, socketClient := range socketClients {
|
|
if socketClient.SessionId == userSessionId {
|
|
return 1
|
|
}
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
// Used to determine if a user is connected regardless of the session used
|
|
func isUserGenerallyConnected(userId string) uint8 {
|
|
for _, socketClient := range cache.GetSocketClients() {
|
|
if socketClient.UserId == userId {
|
|
return 1
|
|
}
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
// Get all users from database.
|
|
// This is used in the UI to display all users.
|
|
func GetAllUsers() []structs.AllUsers {
|
|
var users []structs.User
|
|
var allUsers []structs.AllUsers
|
|
|
|
database.DB.Find(&users)
|
|
|
|
for _, user := range users {
|
|
allUsers = append(allUsers, structs.AllUsers{
|
|
Id: user.Id,
|
|
Avatar: user.Avatar,
|
|
Username: user.Username,
|
|
ConnectionStatus: isUserGenerallyConnected(user.Id),
|
|
LastOnline: user.LastOnline,
|
|
})
|
|
}
|
|
|
|
return allUsers
|
|
}
|
|
|
|
func GetAllScanners() []structs.Scanner {
|
|
var scanners []structs.Scanner
|
|
var allScanners []structs.Scanner
|
|
|
|
database.DB.Find(&scanners)
|
|
|
|
for _, scanner := range scanners {
|
|
// clear session to prevent leaking and sending to ui
|
|
scanner.Session = ""
|
|
|
|
allScanners = append(allScanners, scanner)
|
|
}
|
|
|
|
return allScanners
|
|
}
|
|
|
|
func isUsernameAvailable(username string) bool {
|
|
var user structs.User
|
|
database.DB.Select("username").Where("username = ?", username).Find(&user)
|
|
|
|
return user.Username == ""
|
|
}
|
|
|
|
func isEmailAvailable(email string) bool {
|
|
var user structs.User
|
|
database.DB.Select("email").Where("email = ?", email).Find(&user)
|
|
|
|
return user.Email == ""
|
|
}
|
|
|
|
func UpdateUserProfile(userId string, changes map[string]interface{}) {
|
|
log.Debug().Msgf("changes: %v", changes)
|
|
|
|
var user structs.User
|
|
var updates = make(map[string]interface{})
|
|
|
|
// TODO: validate length of username and email
|
|
|
|
if changes["username"] != nil {
|
|
username := changes["username"].(string)
|
|
|
|
if isUsernameAvailable(username) {
|
|
user.Username = username
|
|
updates["Username"] = username
|
|
}
|
|
}
|
|
|
|
if changes["email"] != nil {
|
|
email := changes["email"].(string)
|
|
|
|
if isEmailAvailable(email) {
|
|
user.Email = email
|
|
updates["Email"] = email
|
|
}
|
|
}
|
|
|
|
if changes["password"] != nil {
|
|
log.Debug().Msg("update password")
|
|
password := changes["password"].(string)
|
|
|
|
decodedPassword, err := base64.StdEncoding.DecodeString(changes["password"].(string))
|
|
|
|
if err != nil {
|
|
log.Error().Msg("Failed to decode base64 password, err: " + err.Error())
|
|
}
|
|
|
|
if utils.IsPasswordLengthValid(password) {
|
|
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), decodedPassword); err != nil {
|
|
log.Error().Msg("Incorrect password")
|
|
}
|
|
}
|
|
|
|
// TODO: logout all client user sessions
|
|
}
|
|
|
|
log.Debug().Msgf("len %v", len(changes))
|
|
|
|
// TODO: dont sent change message if user changed password
|
|
if len(changes) > 0 {
|
|
// TODO: update user last updated timestamp
|
|
database.DB.Model(&structs.User{}).Where("id = ?", userId).Updates(user)
|
|
|
|
if changes["username"] != nil || changes["email"] != nil {
|
|
BroadcastMessage(structs.SendSocketMessage{
|
|
Cmd: utils.SentCmdUserProfileUpdated,
|
|
Body: struct {
|
|
UserId string
|
|
Changes map[string]interface{}
|
|
}{
|
|
UserId: userId,
|
|
Changes: updates,
|
|
},
|
|
})
|
|
}
|
|
}
|
|
// TODO: sent feedback back to user for ui notification message
|
|
}
|