tgbot_level.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. package tgbot
  2. import (
  3. "github.com/mymmrac/telego"
  4. tu "github.com/mymmrac/telego/telegoutil"
  5. )
  6. // userLevel decides what the bot admits to existing at all: a Telegram account
  7. // that no admin has bound to a client must not be able to explore the bot.
  8. type userLevel int
  9. const (
  10. levelStranger userLevel = iota
  11. levelClient
  12. levelAdmin
  13. )
  14. // levelOf runs on every update, a stranger's included, so it reads the indexed
  15. // tg_id column of the clients table rather than expanding every inbound's JSON.
  16. func (t *Tgbot) levelOf(tgUserID int64) userLevel {
  17. if checkAdmin(tgUserID) {
  18. return levelAdmin
  19. }
  20. if tgUserID <= 0 {
  21. return levelStranger
  22. }
  23. records, err := t.clientService.GetRecordsByTgID(tgUserID)
  24. if err != nil || len(records) == 0 {
  25. return levelStranger
  26. }
  27. return levelClient
  28. }
  29. // Commands are allowlisted rather than denied one by one: a command added later
  30. // stays out of reach of non-admins until it is deliberately listed here.
  31. var commandsByLevel = map[userLevel]map[string]bool{
  32. // /id stays open because an admin binding by hand still asks for the ChatID.
  33. levelStranger: {"start": true, "id": true},
  34. levelClient: {"start": true, "help": true, "status": true, "id": true, "usage": true},
  35. }
  36. func commandAllowed(level userLevel, command string) bool {
  37. if level == levelAdmin {
  38. return true
  39. }
  40. return commandsByLevel[level][command]
  41. }
  42. // gateCommand reports whether a command reaches answerCommand, and as whom. A
  43. // stranger's refused command gets no reply, so the bot reveals nothing to probe.
  44. func (t *Tgbot) gateCommand(message *telego.Message) (isAdmin bool, ok bool) {
  45. level := t.levelOf(message.From.ID)
  46. command, _, _ := tu.ParseCommand(message.Text)
  47. if commandAllowed(level, command) {
  48. return level == levelAdmin, true
  49. }
  50. if level == levelClient {
  51. t.SendMsgToTgbot(message.Chat.ID, t.I18nBot("tgbot.commands.unknown"))
  52. }
  53. return false, false
  54. }
  55. // gateCallback answers a stranger's tap without acting on it: a stranger holds
  56. // no keyboard of ours, so any callback data from one is forged or stale.
  57. func (t *Tgbot) gateCallback(query *telego.CallbackQuery) (isAdmin bool, ok bool) {
  58. level := t.levelOf(query.From.ID)
  59. if level == levelStranger {
  60. t.sendCallbackAnswerTgBot(query.ID, "")
  61. return false, false
  62. }
  63. return level == levelAdmin, true
  64. }