187 lines
5.3 KiB
Go
187 lines
5.3 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
"slices"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"git.maximotejeda.com/maximo/cedulados-bot/config"
|
|
"git.maximotejeda.com/maximo/cedulados-bot/internal/ports"
|
|
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
|
)
|
|
|
|
type Auth struct {
|
|
bot *tgbotapi.BotAPI
|
|
update *tgbotapi.Update
|
|
user *tgbotapi.User
|
|
uSVC ports.UserService
|
|
log *slog.Logger
|
|
ctx context.Context
|
|
}
|
|
|
|
func NewAuth(ctx context.Context, log *slog.Logger, bot *tgbotapi.BotAPI, update *tgbotapi.Update, user *tgbotapi.User, uSVC ports.UserService) *Auth {
|
|
a := &Auth{
|
|
ctx: ctx,
|
|
log: log,
|
|
user: user,
|
|
bot: bot,
|
|
uSVC: uSVC,
|
|
update: update,
|
|
}
|
|
return a
|
|
}
|
|
|
|
func (a *Auth) Authenticate() bool {
|
|
switch IsUserAdmin(a.user.ID) {
|
|
case true:
|
|
// theres an user env admin
|
|
// check if user exist on db
|
|
_, err := a.uSVC.Get(a.user.ID)
|
|
if err != nil {
|
|
a.log.Error("geting user", "error", err)
|
|
a.log.Debug("user seems to not exists")
|
|
if strings.Contains(err.Error(), "sql: no rows in result set") {
|
|
// if user does not exist create it
|
|
_, err := a.uSVC.Create(a.user)
|
|
a.log.Debug("creating user")
|
|
if err != nil {
|
|
a.log.Error("creating new user for admnin", "err", err)
|
|
}
|
|
// add bot to user list
|
|
_, err = a.uSVC.AddBot(a.user.ID, a.bot.Self.UserName)
|
|
if err != nil {
|
|
a.log.Error("Adding bot to admin user list", "err", err)
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
case false:
|
|
// user is not admin and need to be authorized
|
|
// check if user is on db
|
|
_, err := a.uSVC.Get(a.update.SentFrom().ID)
|
|
if err != nil {
|
|
// user need auth
|
|
a.log.Error("user not in db, authorization from an admin is required", "error", err)
|
|
// add user to manage it
|
|
|
|
if strings.Contains(err.Error(), "sql: no rows in result set") {
|
|
// check if theres an access request from the same user and bot
|
|
_, err := a.uSVC.Create(a.user)
|
|
if err != nil {
|
|
a.log.Error("creating new user", "user", a.user.ID, "error", err)
|
|
}
|
|
|
|
// create access request
|
|
_, err = a.uSVC.CreateAccessRequest(a.user.ID, a.bot.Self.UserName)
|
|
if err != nil {
|
|
a.log.Error("creating access request for ", "user", a.user.ID, "error", err)
|
|
}
|
|
}
|
|
} else {
|
|
bot, err := a.uSVC.GetBots(a.user.ID)
|
|
if err != nil {
|
|
a.log.Error("checking bots on user access")
|
|
}
|
|
switch HasUserAccess(bot, a.bot.Self.UserName) {
|
|
case true:
|
|
return true
|
|
case false:
|
|
// check for banned user
|
|
buser, err := a.uSVC.GetAllBannedUsers(a.bot.Self.UserName)
|
|
if err != nil {
|
|
a.log.Error("error querying banned user")
|
|
}
|
|
for _, u := range buser.GetBans(){
|
|
if u.TgbId == a.update.SentFrom().ID{
|
|
msg := tgbotapi.NewMessage(u.TgbId, "user access is restricted, please ask for permission")
|
|
a.bot.Send(msg)
|
|
return false
|
|
}
|
|
}
|
|
ac, err := a.uSVC.GetAccessRequest(a.user.ID)
|
|
acl := []string{}
|
|
for _, val := range ac.Access {
|
|
acl = append(acl, val.BotName)
|
|
}
|
|
if slices.Contains(acl, a.bot.Self.UserName) {
|
|
// create access request
|
|
a.log.Info("Access Request found returning early", "user", a.user.ID, "error", err)
|
|
return false
|
|
} else {
|
|
|
|
// create one
|
|
_, err = a.uSVC.CreateAccessRequest(a.user.ID, a.bot.Self.UserName)
|
|
if err != nil {
|
|
a.log.Error("creating access request", "err", err)
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// get all admins
|
|
userL, _ := GetAdminFromEnv()
|
|
// send a mesage to all admins
|
|
for _, adm := range userL {
|
|
msg := GenerateAccessRequestMessage(a.update.SentFrom(), adm, a.bot.Self.UserName)
|
|
a.bot.Send(msg)
|
|
}
|
|
return false
|
|
}
|
|
|
|
// GetAdminFromEnv
|
|
// will get an env variable that is a list of tgbID comma separated
|
|
// if the user trying to enter is admin auth the user
|
|
func GetAdminFromEnv() (adminList []int64, errList []error) {
|
|
adminsStrList := config.GetAdminsList()
|
|
list := strings.Split(adminsStrList, ",")
|
|
adminList = []int64{}
|
|
errList = []error{}
|
|
for _, item := range list {
|
|
adm, err := strconv.ParseInt(item, 10, 64)
|
|
if err != nil {
|
|
err = fmt.Errorf("parsing tgb admin id: %s\n err: %w", item, err)
|
|
fmt.Println(err)
|
|
errList = append(errList, err)
|
|
continue
|
|
}
|
|
adminList = append(adminList, adm)
|
|
}
|
|
return
|
|
}
|
|
|
|
// IsUserAdmin
|
|
// check if userID is admin on bot
|
|
func IsUserAdmin(userID int64) bool {
|
|
userL, errl := GetAdminFromEnv()
|
|
if len(errl) > 0 {
|
|
fmt.Printf("error no admin in var %v", errl)
|
|
}
|
|
return slices.Contains(userL, userID)
|
|
}
|
|
|
|
func HasUserAccess(bots []string, botName string) bool {
|
|
return slices.Contains(bots, botName)
|
|
}
|
|
|
|
func GenerateAccessRequestMessage(up *tgbotapi.User, adm int64, bn string) *tgbotapi.MessageConfig {
|
|
txt := fmt.Sprintf(`User %s is requesting access
|
|
ID: %d
|
|
FirstName: %s
|
|
LastName: %s
|
|
ChatID: %d
|
|
`, up.UserName, up.ID, up.FirstName, up.LastName, up.ID)
|
|
msg := tgbotapi.NewMessage(adm, txt)
|
|
keyboard := tgbotapi.InlineKeyboardMarkup{}
|
|
row := tgbotapi.NewInlineKeyboardRow()
|
|
row = append(row, tgbotapi.NewInlineKeyboardButtonData("Grant", fmt.Sprintf("operation=grant&userID=%d&bot=%s", up.ID, bn)))
|
|
row = append(row, tgbotapi.NewInlineKeyboardButtonData("Deny", fmt.Sprintf("operation=deny&userID=%d&bot=%s", up.ID, bn)))
|
|
row = append(row, tgbotapi.NewInlineKeyboardButtonData("Ignore", fmt.Sprintf("operation=ignore&userID=%d&bot=%s", up.ID, bn)))
|
|
keyboard.InlineKeyboard = append(keyboard.InlineKeyboard, row)
|
|
msg.ReplyMarkup = keyboard
|
|
return &msg
|
|
}
|