admin.go (27966B)
1 package handlers 2 3 import ( 4 dutils "dkforest/pkg/database/utils" 5 "dkforest/pkg/managers" 6 "dkforest/pkg/web/handlers/interceptors" 7 "dkforest/pkg/web/handlers/usersStreamsManager" 8 hutils "dkforest/pkg/web/handlers/utils" 9 "fmt" 10 wallet1 "github.com/monero-ecosystem/go-monero-rpc-client/wallet" 11 "gorm.io/gorm" 12 "io" 13 "math" 14 "net/http" 15 "regexp" 16 "strings" 17 18 "dkforest/pkg/config" 19 "dkforest/pkg/database" 20 "dkforest/pkg/utils" 21 "github.com/asaskevich/govalidator" 22 "github.com/google/uuid" 23 "github.com/labstack/echo" 24 "github.com/sirupsen/logrus" 25 "github.com/skratchdot/open-golang/open" 26 ) 27 28 func AdminSpamFiltersHandler(c echo.Context) error { 29 db := c.Get("database").(*database.DkfDB) 30 var data adminSpamFiltersData 31 data.ActiveTab = "spamfilters" 32 data.SpamFilters, _ = db.GetSpamFilters() 33 data.SpamFiltersCount = int64(len(data.SpamFilters)) 34 35 if c.Request().Method == http.MethodPost { 36 btnSubmit := c.Request().PostFormValue("btn_submit") 37 data.ID = utils.DoParseInt64(c.Request().PostFormValue("id")) 38 data.Filter = c.Request().PostFormValue("filter") 39 data.IsRegex = utils.DoParseBool(c.Request().PostFormValue("is_regex")) 40 data.Action = utils.Clamp(utils.DoParseInt64(c.Request().PostFormValue("action")), 0, 2) 41 data.NbMsg = utils.Clamp(utils.DoParseInt64(c.Request().PostFormValue("nb_msg")), 0, 100) 42 if !utils.ValidateRuneLength(data.Filter, 1, 255) { 43 data.Error = "filter must be within 1-255 characters" 44 return c.Render(http.StatusOK, "admin.spam-filter", data) 45 } 46 if data.ID == 0 || btnSubmit == "edit" { 47 if _, err := db.CreateOrEditSpamFilter(data.ID, data.Filter, data.IsRegex, data.Action, data.NbMsg); err != nil { 48 logrus.Error(err) 49 } 50 interceptors.LoadFilters(db) 51 } else if btnSubmit == "delete" { 52 if err := db.DeleteSpamFilterByID(data.ID); err != nil { 53 logrus.Error(err) 54 } 55 interceptors.LoadFilters(db) 56 } 57 return c.Redirect(http.StatusFound, "/admin/spam-filters") 58 } 59 60 return c.Render(http.StatusOK, "admin.spam-filters", data) 61 } 62 63 func AdminNewGistHandler(c echo.Context) error { 64 authUser := c.Get("authUser").(*database.User) 65 db := c.Get("database").(*database.DkfDB) 66 var data adminCreateGistData 67 data.ActiveTab = "gists" 68 if c.Request().Method == http.MethodPost { 69 data.Name = c.Request().PostFormValue("name") 70 data.Password = c.Request().PostFormValue("password") 71 data.Content = c.Request().PostFormValue("content") 72 if !govalidator.Matches(data.Name, "^[a-zA-Z0-9_.]{3,50}$") { 73 data.ErrorName = "invalid name" 74 return c.Render(http.StatusOK, "admin.gist-create", data) 75 } 76 passwordHash := "" 77 if data.Password != "" { 78 passwordHash = database.GetGistPasswordHash(data.Password) 79 } 80 gist := database.Gist{UUID: uuid.New().String(), Name: data.Name, Password: passwordHash, UserID: authUser.ID, Content: data.Content} 81 if err := db.DB().Create(&gist).Error; err != nil { 82 data.Error = err.Error() 83 return c.Render(http.StatusOK, "admin.gist-create", data) 84 } 85 return c.Redirect(http.StatusFound, "/gists/"+gist.UUID) 86 } 87 return c.Render(http.StatusOK, "admin.gist-create", data) 88 } 89 90 func AdminEditGistHandler(c echo.Context) error { 91 authUser := c.Get("authUser").(*database.User) 92 db := c.Get("database").(*database.DkfDB) 93 gistUUID := c.Param("gistUUID") 94 gist, err := db.GetGistByUUID(gistUUID) 95 if err != nil { 96 return c.Redirect(http.StatusFound, "/") 97 } 98 if gist.UserID != authUser.ID && !authUser.IsAdmin { 99 return c.Redirect(http.StatusFound, "/") 100 } 101 var data adminCreateGistData 102 data.ActiveTab = "gists" 103 data.IsEdit = true 104 data.Name = gist.Name 105 data.Content = gist.Content 106 if gist.Password != "" { 107 data.Password = "*****" 108 } 109 110 if c.Request().Method == http.MethodPost { 111 data.Name = c.Request().PostFormValue("name") 112 data.Password = c.Request().PostFormValue("password") 113 data.Content = c.Request().PostFormValue("content") 114 if !govalidator.Matches(data.Name, "^[a-zA-Z0-9_.]{3,50}$") { 115 data.ErrorName = "invalid name" 116 return c.Render(http.StatusOK, "admin.gist-create", data) 117 } 118 passwordHash := "" 119 if data.Password != "" && data.Password != "*****" { 120 passwordHash = database.GetGistPasswordHash(data.Password) 121 gist.Password = passwordHash 122 } 123 gist.Name = data.Name 124 gist.Content = data.Content 125 gist.DoSave(db) 126 return c.Redirect(http.StatusFound, "/gists/"+gist.UUID) 127 } 128 return c.Render(http.StatusOK, "admin.gist-create", data) 129 } 130 131 func AdminGistsHandler(c echo.Context) error { 132 db := c.Get("database").(*database.DkfDB) 133 var data adminGistsData 134 data.ActiveTab = "gists" 135 136 userQuery := c.QueryParam("u") 137 138 if err := db.DB().Table("gists"). 139 Scopes(func(query *gorm.DB) *gorm.DB { 140 if userQuery != "" { 141 query = query.Where("user_id = ?", userQuery) 142 } 143 data.CurrentPage, data.MaxPage, data.GistsCount, query = NewPaginator().Paginate(c, query) 144 return query 145 }). 146 Preload("User"). 147 Order("id DESC"). 148 Find(&data.Gists).Error; err != nil { 149 logrus.Error(err) 150 } 151 152 return c.Render(http.StatusOK, "admin.gists", data) 153 } 154 155 func AdminUploadsHandler(c echo.Context) error { 156 db := c.Get("database").(*database.DkfDB) 157 if c.Request().Method == http.MethodPost { 158 formName := c.FormValue("formName") 159 if formName == "deleteUpload" { 160 fileName := c.Request().PostFormValue("file_name") 161 file, err := db.GetUploadByFileName(fileName) 162 if err != nil { 163 return c.Redirect(http.StatusFound, "/") 164 } 165 if err := file.Delete(db); err != nil { 166 logrus.Error(err) 167 } 168 return c.Redirect(http.StatusFound, "/admin/uploads") 169 } 170 } 171 172 var data adminUploadsData 173 data.ActiveTab = "uploads" 174 data.Uploads, _ = db.GetUploads() 175 for _, f := range data.Uploads { 176 data.TotalSize += f.FileSize 177 } 178 return c.Render(http.StatusOK, "admin.uploads", data) 179 } 180 181 func AdminFiledropsHandler(c echo.Context) error { 182 db := c.Get("database").(*database.DkfDB) 183 if c.Request().Method == http.MethodPost { 184 formName := c.FormValue("formName") 185 if formName == "createFiledrop" { 186 if _, err := db.CreateFiledrop(); err != nil { 187 logrus.Error(err) 188 } 189 return c.Redirect(http.StatusFound, "/admin/filedrops") 190 191 } else if formName == "deleteFiledrop" { 192 fileName := c.Request().PostFormValue("file_name") 193 file, err := db.GetFiledropByFileName(fileName) 194 if err != nil { 195 return c.Redirect(http.StatusFound, "/admin/filedrops") 196 } 197 if err := file.Delete(db); err != nil { 198 logrus.Error(err) 199 } 200 return c.Redirect(http.StatusFound, "/admin/filedrops") 201 } 202 } 203 204 var data adminFiledropsData 205 data.ActiveTab = "filedrops" 206 data.Filedrops, _ = db.GetFiledrops() 207 for _, f := range data.Filedrops { 208 data.TotalSize += f.FileSize 209 } 210 return c.Render(http.StatusOK, "admin.filedrops", data) 211 } 212 213 func AdminDownloadsHandler(c echo.Context) error { 214 db := c.Get("database").(*database.DkfDB) 215 var data adminDownloadsData 216 data.ActiveTab = "downloads" 217 218 userQuery := c.QueryParam("u") 219 220 db.DB().Model(&database.Download{}). 221 Scopes(func(query *gorm.DB) *gorm.DB { 222 if userQuery != "" { 223 query = query.Where("user_id = ?", userQuery) 224 } 225 data.CurrentPage, data.MaxPage, data.DownloadsCount, query = NewPaginator().Paginate(c, query) 226 return query 227 }). 228 Preload("User"). 229 Order("id DESC"). 230 Find(&data.Downloads) 231 232 return c.Render(http.StatusOK, "admin.downloads", data) 233 } 234 235 func AdminDeleteDownloadHandler(c echo.Context) error { 236 db := c.Get("database").(*database.DkfDB) 237 downloadID, err := utils.ParseInt64(c.Param("downloadID")) 238 if err != nil { 239 return c.Render(http.StatusOK, "flash", 240 FlashResponse{"download id not found", "/admin/downloads", "alert-danger"}) 241 } 242 243 if err := db.DeleteDownloadByID(downloadID); err != nil { 244 logrus.Error(err) 245 } 246 return c.Redirect(http.StatusFound, "/admin/downloads") 247 } 248 249 // AdminSettingsHandler ... 250 func AdminSettingsHandler(c echo.Context) error { 251 db := c.Get("database").(*database.DkfDB) 252 var data adminSettingsData 253 data.ActiveTab = "settings" 254 settings := db.GetSettings() 255 data.ProtectHome = settings.ProtectHome 256 data.HomeUsersList = settings.HomeUsersList 257 data.ForceLoginCaptcha = settings.ForceLoginCaptcha 258 data.SignupEnabled = settings.SignupEnabled 259 data.SignupFakeEnabled = settings.SignupFakeEnabled 260 data.DownloadsEnabled = settings.DownloadsEnabled 261 data.ForumEnabled = settings.ForumEnabled 262 data.MaybeAuthEnabled = settings.MaybeAuthEnabled 263 data.CaptchaDifficulty = settings.CaptchaDifficulty 264 data.PowEnabled = settings.PowEnabled 265 data.PokerWithdrawEnabled = settings.PokerWithdrawEnabled 266 data.MoneroPrice = settings.MoneroPrice 267 268 if c.Request().Method == http.MethodPost { 269 formName := c.Request().PostFormValue("formName") 270 if formName == "openProjectFolder" { 271 if err := open.Run(config.Global.ProjectPath.Get()); err != nil { 272 logrus.Error(err) 273 } 274 return c.Redirect(http.StatusFound, "/admin/settings") 275 276 } else if formName == "saveSettings" { 277 settings := db.GetSettings() 278 settings.ProtectHome = utils.DoParseBool(c.Request().PostFormValue("protectHome")) 279 settings.HomeUsersList = utils.DoParseBool(c.Request().PostFormValue("homeUsersList")) 280 settings.ForceLoginCaptcha = utils.DoParseBool(c.Request().PostFormValue("forceLoginCaptcha")) 281 settings.SignupEnabled = utils.DoParseBool(c.Request().PostFormValue("signupEnabled")) 282 settings.SignupFakeEnabled = utils.DoParseBool(c.Request().PostFormValue("signupFakeEnabled")) 283 settings.DownloadsEnabled = utils.DoParseBool(c.Request().PostFormValue("downloadsEnabled")) 284 settings.ForumEnabled = utils.DoParseBool(c.Request().PostFormValue("forumEnabled")) 285 settings.MaybeAuthEnabled = utils.DoParseBool(c.Request().PostFormValue("maybeAuthEnabled")) 286 settings.CaptchaDifficulty = utils.DoParseInt64(c.Request().PostFormValue("captchaDifficulty")) 287 settings.PowEnabled = utils.DoParseBool(c.Request().PostFormValue("powEnabled")) 288 settings.PokerWithdrawEnabled = utils.DoParseBool(c.Request().PostFormValue("pokerWithdrawEnabled")) 289 settings.MoneroPrice = math.Max(utils.DoParseF64(c.Request().PostFormValue("moneroPrice")), 1) 290 settings.DoSave(db) 291 config.ProtectHome.Store(settings.ProtectHome) 292 config.HomeUsersList.Store(settings.HomeUsersList) 293 config.ForceLoginCaptcha.Store(settings.ForceLoginCaptcha) 294 config.SignupEnabled.Store(settings.SignupEnabled) 295 config.CaptchaDifficulty.Store(settings.CaptchaDifficulty) 296 config.PowEnabled.Store(settings.PowEnabled) 297 config.PokerWithdrawEnabled.Store(settings.PokerWithdrawEnabled) 298 config.SignupFakeEnabled.Store(settings.SignupFakeEnabled) 299 config.DownloadsEnabled.Store(settings.DownloadsEnabled) 300 config.ForumEnabled.Store(settings.ForumEnabled) 301 config.MaybeAuthEnabled.Store(settings.MaybeAuthEnabled) 302 config.MoneroPrice.Store(settings.MoneroPrice) 303 return c.Redirect(http.StatusFound, "/admin/settings") 304 } 305 306 } 307 308 return c.Render(http.StatusOK, "admin.settings", data) 309 } 310 311 func AdminHandler(c echo.Context) error { 312 db := c.Get("database").(*database.DkfDB) 313 var data adminData 314 data.ActiveTab = "users" 315 data.Query = strings.TrimSpace(c.QueryParam("q")) 316 likeQuery := "%" + data.Query + "%" 317 318 if err := db.DB(). 319 Table("users"). 320 Scopes(func(query *gorm.DB) *gorm.DB { 321 if data.Query != "" { 322 query = query.Where("username LIKE ?", likeQuery, likeQuery, data.Query) 323 } 324 data.CurrentPage, data.MaxPage, data.UsersCount, query = NewPaginator().Paginate(c, query) 325 return query 326 }). 327 Order("id DESC"). 328 Find(&data.Users).Error; err != nil { 329 logrus.Error(err) 330 } 331 332 return c.Render(http.StatusOK, "admin.users", data) 333 } 334 335 func SessionsHandler(c echo.Context) error { 336 db := c.Get("database").(*database.DkfDB) 337 var data adminSessionsData 338 data.ActiveTab = "sessions" 339 data.Query = c.QueryParam("q") 340 likeQuery := "%" + data.Query + "%" 341 342 if err := db.DB(). 343 Table("sessions"). 344 Where("deleted_at IS NULL"). 345 Scopes(func(query *gorm.DB) *gorm.DB { 346 if data.Query != "" { 347 query = query.Where("token LIKE ?", likeQuery, likeQuery, data.Query) 348 } 349 data.CurrentPage, data.MaxPage, data.SessionsCount, query = NewPaginator().Paginate(c, query) 350 return query 351 }).Preload("User"). 352 Order("created_at DESC"). 353 Find(&data.Sessions).Error; err != nil { 354 logrus.Error(err) 355 } 356 357 return c.Render(http.StatusOK, "admin.sessions", data) 358 } 359 360 func IgnoredHandler(c echo.Context) error { 361 db := c.Get("database").(*database.DkfDB) 362 var data adminIgnoredData 363 data.ActiveTab = "ignored" 364 data.Query = c.QueryParam("q") 365 likeQuery := "%" + data.Query + "%" 366 367 if err := db.DB(). 368 Table("ignored_users"). 369 Scopes(func(query *gorm.DB) *gorm.DB { 370 if data.Query != "" { 371 query = query.Where("token LIKE ?", likeQuery, likeQuery, data.Query) 372 } 373 data.CurrentPage, data.MaxPage, data.IgnoredCount, query = NewPaginator().Paginate(c, query) 374 return query 375 }). 376 Preload("User"). 377 Preload("IgnoredUser"). 378 Order("created_at DESC"). 379 Find(&data.Ignored).Error; err != nil { 380 logrus.Error(err) 381 } 382 383 return c.Render(http.StatusOK, "admin.ignored", data) 384 } 385 386 func DdosHandler(c echo.Context) error { 387 if c.Request().Method == http.MethodPost { 388 config.SignupPageLoad.Store(0) 389 config.SignupFailed.Store(0) 390 config.SignupSucceed.Store(0) 391 config.BHCCaptchaGenerated.Store(0) 392 config.BHCCaptchaSuccess.Store(0) 393 config.BHCCaptchaFailed.Store(0) 394 config.CaptchaRequiredGenerated.Store(0) 395 config.CaptchaRequiredSuccess.Store(0) 396 config.CaptchaRequiredFailed.Store(0) 397 return c.Redirect(http.StatusFound, "/admin/ddos") 398 } 399 var data adminDdosData 400 data.ActiveTab = "ddos" 401 data.RPS = config.RpsCounter.Rate() 402 data.RejectedReq = config.RejectedReqCounter.Rate() 403 data.SignupPageLoad = config.SignupPageLoad.Load() 404 data.SignupFailed = config.SignupFailed.Load() 405 data.SignupSucceed = config.SignupSucceed.Load() 406 data.BHCCaptchaGenerated = config.BHCCaptchaGenerated.Load() 407 data.BHCCaptchaSuccess = config.BHCCaptchaSuccess.Load() 408 data.BHCCaptchaFailed = config.BHCCaptchaFailed.Load() 409 data.CaptchaRequiredGenerated = config.CaptchaRequiredGenerated.Load() 410 data.CaptchaRequiredSuccess = config.CaptchaRequiredSuccess.Load() 411 data.CaptchaRequiredFailed = config.CaptchaRequiredFailed.Load() 412 return c.Render(http.StatusOK, "admin.ddos", data) 413 } 414 415 func BackupHandler(c echo.Context) error { 416 var data backupData 417 data.ActiveTab = "backup" 418 if c.Request().Method == http.MethodPost { 419 formName := c.Request().PostFormValue("formName") 420 if formName == "backup" { 421 if config.MaintenanceAtom.CAS(false, true) { 422 utils.SGo(func() { 423 defer config.MaintenanceAtom.SetFalse() 424 if err := database.Backup(); err != nil { 425 logrus.Error("Failed to backup database: ", err) 426 } 427 }) 428 } 429 return c.Redirect(http.StatusFound, "/admin/backup") 430 } else if formName == "toggleMaintenance" { 431 if config.MaintenanceAtom.CAS(false, true) { 432 logrus.Info("maintenance mode turned on") 433 } else if config.MaintenanceAtom.CAS(true, false) { 434 logrus.Info("maintenance mode turned off") 435 } 436 return c.Redirect(http.StatusFound, "/admin/backup") 437 } 438 } 439 440 return c.Render(http.StatusOK, "admin.backup", data) 441 } 442 443 func AdminAuditsHandler(c echo.Context) error { 444 db := c.Get("database").(*database.DkfDB) 445 var data adminAuditsData 446 data.ActiveTab = "audits" 447 448 if err := db.DB(). 449 Table("audit_logs"). 450 Scopes(func(query *gorm.DB) *gorm.DB { 451 data.CurrentPage, data.MaxPage, data.AuditLogsCount, query = NewPaginator().Paginate(c, query) 452 return query 453 }). 454 Preload("User"). 455 Order("id DESC"). 456 Find(&data.AuditLogs).Error; err != nil { 457 logrus.Error(err) 458 } 459 return c.Render(http.StatusOK, "admin.audits", data) 460 } 461 462 func AdminRoomsHandler(c echo.Context) error { 463 db := c.Get("database").(*database.DkfDB) 464 var data adminRoomsData 465 data.ActiveTab = "rooms" 466 data.Query = c.QueryParam("q") 467 likeQuery := "%" + data.Query + "%" 468 469 if err := db.DB(). 470 Table("chat_rooms"). 471 Scopes(func(query *gorm.DB) *gorm.DB { 472 if data.Query != "" { 473 query = query.Where("username LIKE ?", likeQuery, likeQuery, data.Query) 474 } 475 data.CurrentPage, data.MaxPage, data.RoomsCount, query = NewPaginator().Paginate(c, query) 476 return query 477 }). 478 Order("id DESC"). 479 Preload("OwnerUser"). 480 Find(&data.Rooms).Error; err != nil { 481 logrus.Error(err) 482 } 483 return c.Render(http.StatusOK, "admin.rooms", data) 484 } 485 486 func AdminPokerAddressesHandler(c echo.Context) error { 487 db := c.Get("database").(*database.DkfDB) 488 var data adminPokerAddressesData 489 data.ActiveTab = "pokerAddresses" 490 res, err := config.Xmr().GetAddress(&wallet1.RequestGetAddress{}) 491 if err != nil { 492 logrus.Error(err) 493 return hutils.RedirectReferer(c) 494 } 495 addrs := make([]string, 0) 496 for _, addr := range res.Addresses { 497 addrs = append(addrs, addr.Address) 498 } 499 var users []database.User 500 if err := db.DB().Where("poker_xmr_sub_address != '' AND poker_xmr_sub_address NOT IN (?)", addrs).Find(&users).Error; err != nil { 501 logrus.Error(err) 502 } 503 data.Addresses = addrs 504 data.Users = users 505 return c.Render(http.StatusOK, "admin.poker-addresses", data) 506 } 507 508 func AdminPokerTransactionsHandler(c echo.Context) error { 509 db := c.Get("database").(*database.DkfDB) 510 var data adminPokerTransactionsData 511 data.ActiveTab = "pokerTransactions" 512 data.PokerCasino = db.GetPokerCasino() 513 res, err := config.Xmr().GetBalance(&wallet1.RequestGetBalance{}) 514 if err != nil { 515 logrus.Error(err) 516 return hutils.RedirectReferer(c) 517 } 518 data.Balance = database.Piconero(res.Balance) 519 data.UnlockedBalance = database.Piconero(res.UnlockedBalance) 520 data.SumIn, _ = db.GetPokerXmrTransactionsSumIn() 521 data.SumOut, _ = db.GetPokerXmrTransactionsSumOut() 522 data.DiffInOut = data.SumIn - data.SumOut 523 sumXmrBalance, _ := db.GetUsersXmrBalance() 524 data.UsersRakeBack, _ = db.GetUsersRakeBack() 525 sumTableAccounts, sumTableBets, _ := db.GetPokerTableAccountSums() 526 data.Discrepancy = (int64(data.SumIn) - int64(data.SumOut)) - 527 int64(sumXmrBalance) - 528 int64(data.UsersRakeBack.ToPiconero()) - 529 int64(data.PokerCasino.Rake.ToPiconero()) - 530 int64(sumTableAccounts.ToPiconero()) - 531 int64(sumTableBets.ToPiconero()) 532 data.DiscrepancyPiconero = database.Piconero(uint64(math.Abs(float64(data.Discrepancy)))) 533 534 if err := db.DB(). 535 Table("poker_xmr_transactions"). 536 Scopes(func(query *gorm.DB) *gorm.DB { 537 data.CurrentPage, data.MaxPage, data.TransactionsCount, query = NewPaginator().Paginate(c, query) 538 return query 539 }). 540 Order("id DESC"). 541 Preload("User"). 542 Find(&data.Transactions).Error; err != nil { 543 logrus.Error(err) 544 } 545 546 return c.Render(http.StatusOK, "admin.poker-transactions", data) 547 } 548 549 func AdminCaptchaHandler(c echo.Context) error { 550 db := c.Get("database").(*database.DkfDB) 551 var data adminCaptchaData 552 data.ActiveTab = "captcha" 553 554 if err := db.DB().Table("captcha_requests"). 555 Scopes(func(query *gorm.DB) *gorm.DB { 556 data.CurrentPage, data.MaxPage, data.CaptchasCount, query = NewPaginator().Paginate(c, query) 557 return query 558 }). 559 Preload("User"). 560 Order("id DESC"). 561 Find(&data.Captchas).Error; err != nil { 562 logrus.Error(err) 563 } 564 return c.Render(http.StatusOK, "admin.captcha", data) 565 } 566 567 // AdminDeleteUserHandler ... 568 func AdminDeleteUserHandler(c echo.Context) error { 569 db := c.Get("database").(*database.DkfDB) 570 userID, err := dutils.ParseUserID(c.Param("userID")) 571 if err != nil { 572 return c.Render(http.StatusOK, "flash", 573 FlashResponse{"user id not found", "/admin/users", "alert-danger"}) 574 } 575 if userID == config.RootAdminID { 576 return c.Render(http.StatusOK, "flash", 577 FlashResponse{"Root admin cannot be deleted", "/admin/users", "alert-danger"}) 578 } 579 580 if err := db.DeleteUserByID(userID); err != nil { 581 logrus.Error(err) 582 } 583 return hutils.RedirectReferer(c) 584 } 585 586 func IgnoredDeleteHandler(c echo.Context) error { 587 db := c.Get("database").(*database.DkfDB) 588 userID := dutils.DoParseUserID(c.Request().PostFormValue("user_id")) 589 ignoredUserID := dutils.DoParseUserID(c.Request().PostFormValue("ignored_user_id")) 590 db.UnIgnoreUser(userID, ignoredUserID) 591 return c.Redirect(http.StatusFound, "/admin/ignored") 592 } 593 594 // AdminDeleteRoomHandler ... 595 func AdminDeleteRoomHandler(c echo.Context) error { 596 db := c.Get("database").(*database.DkfDB) 597 id := dutils.DoParseRoomID(c.Param("roomID")) 598 db.DeleteChatRoomByID(id) 599 return c.Redirect(http.StatusFound, "/admin/rooms") 600 } 601 602 func AdminUserSecurityLogsHandler(c echo.Context) error { 603 //authUser := c.Get("authUser").(*database.User) 604 db := c.Get("database").(*database.DkfDB) 605 userID, err := dutils.ParseUserID(c.Param("userID")) 606 if err != nil { 607 return c.Redirect(http.StatusFound, "/admin/users") 608 } 609 var data settingsSecurityData 610 data.ActiveTab = "security" 611 data.Logs, _ = db.GetSecurityLogs(userID) 612 return c.Render(http.StatusOK, "admin.user-security-logs", data) 613 } 614 615 // AdminEditUserHandler ... 616 func AdminEditUserHandler(c echo.Context) error { 617 authUser := c.Get("authUser").(*database.User) 618 db := c.Get("database").(*database.DkfDB) 619 userID, err := dutils.ParseUserID(c.Param("userID")) 620 if err != nil { 621 return c.Redirect(http.StatusFound, "/admin/users") 622 } 623 // Only root admin can edit the root admin 624 if userID == config.RootAdminID && authUser.ID != config.RootAdminID { 625 return c.Redirect(http.StatusFound, "/admin/users") 626 } 627 user, err := db.GetUserByID(userID) 628 if err != nil { 629 return c.Redirect(http.StatusFound, "/admin/users") 630 } 631 var data adminEditUsereData 632 data.ActiveTab = "users" 633 data.User = user 634 data.ChatTutorial = user.ChatTutorial 635 data.AllFonts = utils.GetFonts() 636 data.IsEdit = true 637 data.Username = user.Username 638 data.ApiKey = user.ApiKey 639 data.IsAdmin = user.IsAdmin 640 data.IsHellbanned = user.IsHellbanned 641 data.Verified = user.Verified 642 data.IsClubMember = user.IsClubMember 643 data.CanUploadFile = user.CanUploadFile 644 data.CanUseForum = user.CanUseForum 645 data.CanUseMultiline = user.CanUseMultiline 646 data.CanUseChessAnalyze = user.CanUseChessAnalyze 647 data.CanSeeHellbanned = user.CanSeeHellbanned 648 data.IsIncognito = user.IsIncognito 649 data.CanChangeUsername = user.CanChangeUsername 650 data.CanUseUppercase = user.CanUseUppercase 651 data.CanChangeColor = user.CanChangeColor 652 data.Vetted = user.Vetted 653 data.Role = user.Role 654 data.ChatColor = user.ChatColor 655 data.ChatFont = user.ChatFont 656 data.SignupMetadata = user.SignupMetadata 657 data.CollectMetadata = user.CollectMetadata 658 if c.Request().Method == http.MethodGet { 659 return c.Render(http.StatusOK, "admin.user-edit", data) 660 } 661 662 formName := c.Request().PostFormValue("formName") 663 if formName == "reset_login_attempts" { 664 user.ResetLoginAttempts(db) 665 return c.Redirect(http.StatusFound, "/admin/users/"+userID.String()+"/edit") 666 } else if formName == "disable_2fa" { 667 user.DisableTotp2FA(db) 668 user.DisableGpg2FA(db) 669 return c.Redirect(http.StatusFound, "/admin/users/"+userID.String()+"/edit") 670 } else if formName == "reset_tutorial" { 671 user.ResetTutorial(db) 672 return c.Redirect(http.StatusFound, "/admin/users/"+userID.String()+"/edit") 673 } 674 675 data.Username = database.Username(c.FormValue("username")) 676 data.Role = c.Request().PostFormValue("role") 677 data.IsAdmin = utils.DoParseBool(c.FormValue("isAdmin")) 678 data.IsHellbanned = utils.DoParseBool(c.FormValue("isHellbanned")) 679 data.Verified = utils.DoParseBool(c.FormValue("verified")) 680 data.IsClubMember = utils.DoParseBool(c.FormValue("is_club_member")) 681 data.CanUploadFile = utils.DoParseBool(c.FormValue("can_upload_file")) 682 data.CanUseForum = utils.DoParseBool(c.FormValue("can_use_forum")) 683 data.CanUseMultiline = utils.DoParseBool(c.FormValue("can_use_multiline")) 684 data.CanUseChessAnalyze = utils.DoParseBool(c.FormValue("can_use_chess_analyze")) 685 data.CanSeeHellbanned = utils.DoParseBool(c.FormValue("can_see_hellbanned")) 686 data.IsIncognito = utils.DoParseBool(c.FormValue("is_incognito")) 687 data.CanChangeUsername = utils.DoParseBool(c.FormValue("can_change_username")) 688 data.CanUseUppercase = utils.DoParseBool(c.FormValue("can_use_uppercase")) 689 data.CanChangeColor = utils.DoParseBool(c.FormValue("can_change_color")) 690 data.Vetted = utils.DoParseBool(c.FormValue("vetted")) 691 data.CollectMetadata = utils.DoParseBool(c.FormValue("collect_metadata")) 692 data.ChatColor = c.FormValue("chat_color") 693 colorRgx := regexp.MustCompile(`^#[0-9a-fA-F]{6}$`) 694 if !colorRgx.MatchString(data.ChatColor) { 695 data.Errors.Username = "Invalid color format" 696 } 697 data.ChatFont = utils.DoParseInt64(c.FormValue("chat_font")) 698 if data.Username != user.Username { 699 if err := db.CanRenameTo(user.Username, data.Username); err != nil { 700 data.Errors.Username = err.Error() 701 } 702 } 703 // Edit password 704 var hashedPassword string 705 data.Password = c.Request().PostFormValue("password") 706 data.RePassword = c.Request().PostFormValue("repassword") 707 data.ApiKey = c.Request().PostFormValue("api_key") 708 if data.Password != "" || data.RePassword != "" { 709 hashedPassword, err = database.NewPasswordValidator(db, data.Password).CompareWith(data.RePassword).Hash() 710 if err != nil { 711 data.Errors.Password = err.Error() 712 } 713 } 714 if data.Errors.HasError() { 715 return c.Render(http.StatusOK, "admin.user-edit", data) 716 } 717 718 if hashedPassword != "" { 719 user.LoginAttempts = 0 720 if err := user.ChangePassword(db, hashedPassword); err != nil { 721 data.Errors.Password = err.Error() 722 return c.Render(http.StatusOK, "admin.user-edit", data) 723 } 724 } 725 726 user.Username = data.Username 727 user.IsAdmin = data.IsAdmin 728 if data.IsHellbanned { 729 user.HellBan(db) 730 managers.ActiveUsers.UpdateUserHBInRooms(managers.NewUserInfo(&user)) 731 } 732 user.ApiKey = data.ApiKey 733 user.Verified = data.Verified 734 user.IsHellbanned = data.IsHellbanned 735 user.IsClubMember = data.IsClubMember 736 user.CanUploadFile = data.CanUploadFile 737 user.CanUseForum = data.CanUseForum 738 user.CanUseMultiline = data.CanUseMultiline 739 user.CanUseChessAnalyze = data.CanUseChessAnalyze 740 user.CanSeeHellbanned = data.CanSeeHellbanned 741 user.IsIncognito = data.IsIncognito 742 user.CanChangeUsername = data.CanChangeUsername 743 user.CanUseUppercase = data.CanUseUppercase 744 user.CanChangeColor = data.CanChangeColor 745 user.Vetted = data.Vetted 746 user.CollectMetadata = data.CollectMetadata 747 user.Role = data.Role 748 user.ChatColor = data.ChatColor 749 user.ChatFont = data.ChatFont 750 user.DoSave(db) 751 752 return c.Redirect(http.StatusFound, "/admin/users/"+userID.String()+"/edit") 753 } 754 755 // AdminEditRoomHandler ... 756 func AdminEditRoomHandler(c echo.Context) error { 757 db := c.Get("database").(*database.DkfDB) 758 roomID, err := dutils.ParseRoomID(c.Param("roomID")) 759 if err != nil { 760 return c.Redirect(http.StatusFound, "/admin/rooms") 761 } 762 room, err := db.GetChatRoomByID(roomID) 763 if err != nil { 764 return c.Redirect(http.StatusFound, "/admin/rooms") 765 } 766 var data adminEditRoomData 767 data.ActiveTab = "rooms" 768 data.IsEdit = true 769 data.IsEphemeral = room.IsEphemeral 770 data.IsListed = room.IsListed 771 if c.Request().Method == http.MethodGet { 772 return c.Render(http.StatusOK, "admin.room-edit", data) 773 } 774 775 data.IsEphemeral = utils.DoParseBool(c.Request().PostFormValue("is_ephemeral")) 776 data.IsListed = utils.DoParseBool(c.Request().PostFormValue("is_listed")) 777 778 room.IsEphemeral = data.IsEphemeral 779 room.IsListed = data.IsListed 780 room.DoSave(db) 781 782 return c.Redirect(http.StatusFound, "/admin/rooms") 783 } 784 785 func StreamUsersHandler(c echo.Context) error { 786 db := c.Get("database").(*database.DkfDB) 787 usersIDs := usersStreamsManager.Inst.GetUsers() 788 users, _ := db.GetUsersByID(usersIDs) 789 out := "" 790 for _, user := range users { 791 out += string(user.Username) + ", " 792 } 793 return c.String(http.StatusOK, out) 794 } 795 796 func FiledropDownloadHandler(c echo.Context) error { 797 filename := c.Param("filename") 798 db := c.Get("database").(*database.DkfDB) 799 filedrop, err := db.GetFiledropByFileName(filename) 800 if err != nil { 801 return c.Redirect(http.StatusFound, "/") 802 } 803 if !filedrop.Exists() { 804 logrus.Error(filename + " does not exists") 805 return c.Redirect(http.StatusFound, "/") 806 } 807 808 osFile, decrypter, err := filedrop.GetContent() 809 if err != nil { 810 return echo.NotFoundHandler(c) 811 } 812 defer osFile.Close() 813 814 c.Response().Header().Set(echo.HeaderContentDisposition, fmt.Sprintf("%s; filename=%q", "attachment", filedrop.OrigFileName)) 815 816 if _, err := io.Copy(c.Response().Writer, decrypter); err != nil { 817 logrus.Error(err) 818 } 819 c.Response().Flush() 820 return nil 821 }