utils.go (8188B)
1 package utils 2 3 import ( 4 "dkforest/pkg/config" 5 "dkforest/pkg/database" 6 "dkforest/pkg/managers" 7 "dkforest/pkg/utils" 8 "errors" 9 "fmt" 10 "github.com/labstack/echo" 11 "github.com/sirupsen/logrus" 12 ) 13 14 func GetZeroUser(db *database.DkfDB) database.User { 15 zeroUser, err := db.GetUserByUsername(config.NullUsername) 16 utils.LogErr(err) 17 return zeroUser 18 } 19 20 func ZeroSendMsg(db *database.DkfDB, recipientID database.UserID, msg string) { 21 zeroUser := GetZeroUser(db) 22 _, _ = db.CreateMsg(msg, msg, "", config.GeneralRoomID, zeroUser.ID, &recipientID, false) 23 } 24 25 func RootAdminNotify(db *database.DkfDB, msg string) { 26 rootAdminID := database.UserID(config.RootAdminID) 27 ZeroSendMsg(db, rootAdminID, msg) 28 } 29 30 func SendNewChessGameMessages(db *database.DkfDB, key, roomKey string, roomID database.RoomID, zeroUser, player1, player2 database.User) { 31 // Send game link to players 32 getPlayerMsg := func(opponent database.User) (raw string, msg string) { 33 raw = `Chess game against ` + string(opponent.Username) 34 msg = `<a href="/chess/` + key + `" rel="noopener noreferrer" target="_blank">Chess game against ` + string(opponent.Username) + `</a>` 35 return 36 } 37 raw, msg := getPlayerMsg(player2) 38 _, _ = db.CreateMsg(raw, msg, roomKey, roomID, zeroUser.ID, &player1.ID, false) 39 raw, msg = getPlayerMsg(player1) 40 _, _ = db.CreateMsg(raw, msg, roomKey, roomID, zeroUser.ID, &player2.ID, false) 41 42 // Send notifications to chess games subscribers 43 raw = `Chess game: ` + string(player1.Username) + ` VS ` + string(player2.Username) 44 msg = `<a href="/chess/` + key + `" rel="noopener noreferrer" target="_blank">Chess game: ` + string(player1.Username) + ` VS ` + string(player2.Username) + `</a>` 45 46 activeUsers := managers.ActiveUsers.GetActiveUsers() 47 activeUsersIDs := make([]database.UserID, len(activeUsers)) 48 for idx, activeUser := range activeUsers { 49 activeUsersIDs[idx] = activeUser.UserID 50 } 51 52 users, _ := db.GetOnlineChessSubscribers(activeUsersIDs) 53 for _, user := range users { 54 if user.ID == player1.ID || user.ID == player2.ID { 55 continue 56 } 57 // Make a copy of user ID, otherwise next iteration will overwrite the pointer 58 // and change data that was sent previously in the pubsub later on 59 userID := user.ID 60 _, _ = db.CreateMsg(raw, msg, roomKey, roomID, zeroUser.ID, &userID, false) 61 } 62 } 63 64 func DoParseUsernamePtr(v string) *database.Username { 65 if v == "" { 66 return nil 67 } 68 username := database.Username(v) 69 return &username 70 } 71 72 func GetUserIDFromUsername(db *database.DkfDB, u string) *database.UserID { 73 username := DoParseUsernamePtr(u) 74 if username == nil { 75 return nil 76 } 77 userID, err := db.GetUserIDByUsername(*username) 78 if err != nil { 79 return nil 80 } 81 return &userID 82 } 83 84 func DoParsePmDisplayMode(v string) database.PmDisplayMode { 85 p, err := utils.ParseInt64(v) 86 if err != nil { 87 return database.PmNoFilter 88 } 89 switch p { 90 case 1: 91 return database.PmOnly 92 case 2: 93 return database.PmNone 94 default: 95 return database.PmNoFilter 96 } 97 } 98 99 func Parse[T ~int64](v string) (out T, err error) { 100 p, err := utils.ParseInt64(v) 101 if err != nil { 102 return out, err 103 } 104 return T(p), nil 105 } 106 107 func DoParse[T ~int64](v string) (out T) { 108 out, _ = Parse[T](v) 109 return 110 } 111 112 func ParseUserID(v string) (database.UserID, error) { 113 return Parse[database.UserID](v) 114 } 115 116 func DoParseUserID(v string) (out database.UserID) { 117 return DoParse[database.UserID](v) 118 } 119 120 func ParseRoomID(v string) (database.RoomID, error) { 121 return Parse[database.RoomID](v) 122 } 123 124 func DoParseRoomID(v string) (out database.RoomID) { 125 return DoParse[database.RoomID](v) 126 } 127 128 func SelfHellBan(db *database.DkfDB, user *database.User, msg string) { 129 db.NewAudit(*user, fmt.Sprintf("hellban %s #%d %s", user.Username, user.ID, msg)) 130 user.HellBan(db) 131 managers.ActiveUsers.UpdateUserHBInRooms(managers.NewUserInfo(user)) 132 } 133 134 func Kick(db *database.DkfDB, kicked, kickedBy database.User, purge, silent bool) error { 135 if kicked.IsHellbanned { 136 silent = true 137 } 138 return kick(db, kicked, kickedBy, silent, purge, "") 139 } 140 141 func SilentKick(db *database.DkfDB, kicked, kickedBy database.User) error { 142 return kick(db, kicked, kickedBy, true, true, "") 143 } 144 145 func SelfKick(db *database.DkfDB, kicked database.User, silent bool, msg string) error { 146 return kick(db, kicked, kicked, silent, true, msg) 147 } 148 149 func kick(db *database.DkfDB, kicked, kickedBy database.User, silent, purge bool, msg string) error { 150 if !kicked.Verified { 151 return errors.New("user already kicked") 152 } 153 // Can't kick a vetted user (unless admin) 154 if !kickedBy.IsAdmin && kicked.Vetted { 155 return errors.New("cannot kick a vetted user") 156 } 157 // Can't kick another moderator (unless admin) 158 if !kickedBy.IsAdmin && kicked.IsModerator() { 159 return errors.New("cannot kick another moderator") 160 } 161 // Can't kick yourself as a moderator/admin 162 if (kicked.IsAdmin || kicked.IsModerator()) && kickedBy.ID == kicked.ID { 163 return errors.New("cannot kick yourself") 164 } 165 166 db.NewAudit(kickedBy, fmt.Sprintf("kick %s #%d %s", kicked.Username, kicked.ID, msg)) 167 kicked.SetVerified(db, false) 168 169 // Remove user from the user cache 170 managers.ActiveUsers.RemoveUser(kicked.ID) 171 172 if purge { 173 // Purge user messages 174 if err := db.DeleteUserChatMessages(kicked.ID); err != nil { 175 logrus.Error(err) 176 } 177 database.MsgPubSub.Pub(database.RefreshTopic, database.ChatMessageType{Typ: database.ForceRefresh}) 178 } else { 179 database.MsgPubSub.Pub("refresh_"+string(kicked.Username), database.ChatMessageType{Typ: database.ForceRefresh}) 180 } 181 182 // If user is HB, do not display system message 183 if !silent { 184 // Display kick message 185 db.CreateKickMsg(kicked, kickedBy) 186 } 187 188 return nil 189 } 190 191 func GetRoomAndKey(db *database.DkfDB, c echo.Context, roomName string) (database.ChatRoom, string, error) { 192 roomKey := "" 193 room, err := db.GetChatRoomByName(roomName) 194 if err != nil { 195 return room, roomKey, errors.New("room not found") 196 } 197 hasAccess, roomKey := room.HasAccess(c) 198 if !hasAccess { 199 return room, roomKey, errors.New("forbidden") 200 } 201 return room, roomKey, nil 202 } 203 204 var ErrPMDenied = errors.New("you cannot pm/inbox this user") 205 var Err20Msgs = errors.New("you need 20 public messages to unlock PMs/Inbox; or be whitelisted") 206 var ErrOther20Msgs = errors.New("dest user must be whitelisted or have 20 public messages") 207 208 func CanUserPmOther(db *database.DkfDB, user, other database.User, roomIsPrivate bool) (skipInbox bool, err error) { 209 errPMDenied := ErrPMDenied 210 211 if user.ID == other.ID { 212 return false, errors.New("cannot /pm yourself") 213 } 214 215 if db.IsUserPmWhitelisted(user.ID, other.ID) { 216 return false, nil 217 } 218 219 switch other.PmMode { 220 case database.PmModeWhitelist: 221 // We are in whitelist mode, and user is not whitelisted 222 return false, errPMDenied 223 224 case database.PmModeStandard: 225 if !user.CanSendPM() { 226 // In private rooms, can send PM but inboxes will be skipped if not enough public messages 227 if roomIsPrivate { 228 return true, nil 229 } 230 // Need at least 20 public messages to send PM in a public room 231 return false, Err20Msgs 232 } 233 234 // User on blacklist cannot PM/Inbox 235 if db.IsUserPmBlacklisted(user.ID, other.ID) { 236 return false, errPMDenied 237 } 238 // Other doesn't want PM from new users 239 if !user.AccountOldEnough() && other.BlockNewUsersPm { 240 return false, errPMDenied 241 } 242 243 if !other.CanSendPM() { 244 if db.IsUserPmWhitelisted(other.ID, user.ID) { 245 return true, nil 246 } 247 // In private rooms, can send PM but inboxes will be skipped if not enough public messages 248 if roomIsPrivate { 249 return true, nil 250 } 251 return false, ErrOther20Msgs 252 } 253 254 return false, nil 255 } 256 257 // Should never go here 258 return false, nil 259 } 260 261 // VerifyMsgAuth returns either or not authUser is allowed to see msg 262 func VerifyMsgAuth(db *database.DkfDB, msg *database.ChatMessage, authUserID database.UserID, isModerator bool) bool { 263 // Verify moderators channel authorization 264 if msg.Moderators && !isModerator { 265 return false 266 } 267 // Verify group authorization 268 if msg.GroupID != nil { 269 userGroupsIDs, _ := db.GetUserRoomGroupsIDs(authUserID, msg.RoomID) 270 if !utils.InArr(*msg.GroupID, userGroupsIDs) { 271 return false 272 } 273 } 274 // verify PM authorization 275 if msg.IsPm() { 276 if msg.UserID != authUserID && *msg.ToUserID != authUserID { 277 return false 278 } 279 } 280 return true 281 }