Golang bot for managing discord verifications
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

196 lines
5.2 KiB

package main
import (
"fmt"
"math/rand"
"net/http"
"strings"
"time"
"github.com/bwmarrin/discordgo"
"github.com/gorilla/mux"
)
func reqPass(w http.ResponseWriter, r *http.Request) {
defer log.PanicSafe()
log.LogInfo("reqPass called.")
username := r.URL.Query()["UserName"][0]
log.LogInfo("reqPass username is %+v.", username)
var userID string
if dg == nil {
log.LogError("Discord session was nill.")
}
g, err := dg.GuildMembers(config.GuildID, "", 1000)
log.LogInfo("reqPass guild is %+v.", config.GuildID)
if err == nil {
for _, m := range g {
if strings.EqualFold(m.Nick, username) {
for _, r := range m.Roles {
if r == config.AdminRole {
userID = m.User.ID
log.LogInfo("User ID found for %+v as %+v", username, userID)
}
}
}
}
} else {
log.LogError("Unable to find user ID for %+v", username)
}
ipaddr := r.Header.Get("X-Real-IP")
log.LogInfo("reqPass IP is %+v.", ipaddr)
log.LogInfo(fmt.Sprintf("reqPass called:```username: %s\nip : %s```", username, ipaddr))
go sendPassword(userID, ipaddr)
http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
}
func tryLogin(w http.ResponseWriter, r *http.Request) {
defer log.PanicSafe()
session, err := store.Get(r, "2fa")
if err != nil {
log.LogWarn("Error opening session for 2fa store")
}
vars := mux.Vars(r)
username := vars["username"]
password := vars["password"]
ip := r.Header.Get("X-Real-IP")
if len(username) == 0 {
username = r.FormValue("UserName")
password = r.FormValue("TempPass")
}
access, _ := detectUser(r, "tryLogin")
if !access {
log.LogDebug(fmt.Sprintf("%s is attempting login", getSessionIdentifier(r)))
access = usePassword(username, password, ip)
if access {
log.LogInfo(fmt.Sprintf("%s has successfully logged in from %s", username, ip))
log.LogDebug(fmt.Sprintf("```%+v```", session.Values))
session.Values["username"] = username
session.Values["ip"] = ip
session.Values["timestamp"] = fmt.Sprintf("%+v", time.Now())
err = session.Save(r, w)
if err != nil {
log.LogWarn(fmt.Sprintf("Error saving cookie. ```%+v```", err))
}
}
}
greetUser(w, r)
}
func usePassword(user string, pass string, ip string) bool {
defer log.PanicSafe()
log.LogInfo("%+v", toks)
tok := toks[strings.ToUpper(user)]
delete(toks, strings.ToUpper(user))
if tok.IP != ip {
log.LogWarn(fmt.Sprintf("%s attempted to use an improper IP.", user))
return false
}
if tok.Password != pass {
log.LogWarn(fmt.Sprintf("%s attempted to use an improper password. %s vs %s", user, tok.Password, pass))
return false
}
if time.Since(tok.Timestamp) > (time.Minute * 5) {
log.LogWarn("%s attempted to use expired token. \n%+v\n%+v\n%+v", user, time.Since(tok.Timestamp), tok.Timestamp, time.Now())
return false
}
return true
}
func genPassword(length int) string {
defer log.PanicSafe()
rand.Seed(time.Now().UnixNano())
chars := []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz" +
"0123456789")
var b strings.Builder
for i := 0; i < length; i++ {
b.WriteRune(chars[rand.Intn(len(chars))])
}
return b.String() // E.g. "ExcbsVQs"
}
func sendPassword(user string, ipaddr string) {
defer log.PanicSafe()
str := genPassword(15)
log.LogInfo("sending password to %+v for %+v: %+v", ipaddr, user, str)
m, err := dg.GuildMember(config.GuildID, user)
if err != nil {
log.LogErrorType(err)
}
now := time.Now()
toks[strings.ToUpper(m.Nick)] = Tokens{
Username: user,
IP: ipaddr,
Password: str,
Timestamp: now,
}
pmChann, err := dg.UserChannelCreate(user)
if err != nil {
log.LogErrorType(err)
}
dg.ChannelMessageSend(pmChann.ID, fmt.Sprintf("A temporary password was requested from %s:", ipaddr))
dg.ChannelMessageSend(pmChann.ID, fmt.Sprintf("```%s```", str))
}
func getSessionIdentifier(r *http.Request) string {
defer log.PanicSafe()
ipaddr := r.Header.Get("X-Real-IP")
if ipaddr == "" {
ipaddr = r.RemoteAddr
}
uri := r.URL.Path
return fmt.Sprintf("%s:%s", ipaddr, uri)
}
func detectUser(r *http.Request, callFunc string) (bool, string) {
defer log.PanicSafe()
log.LogInfo(fmt.Sprintf("%s called detectUser", getSessionIdentifier(r)))
session, err := store.Get(r, "2fa")
if err != nil {
log.LogDebug(fmt.Sprintf("Unable to open 2fa session in %s", callFunc))
}
if session.Values["username"] != nil {
return true, fmt.Sprintf("%s", session.Values["username"])
}
return false, ""
}
func userFromID(i string) discordgo.User {
u, err := dg.GuildMember(config.GuildID, i)
if err != nil {
log.LogErrorType(err)
return discordgo.User{}
}
return *u.User
}
func idFromUsername(username string) string {
userID := ""
g, err := dg.GuildMembers(config.GuildID, "", 1000)
log.LogInfo("reqPass guild is %+v.", config.GuildID)
if err == nil {
for _, m := range g {
if strings.EqualFold(m.User.Username, username) {
userID = m.User.ID
log.LogInfo("User ID found for %+v as %+v", username, userID)
}
}
} else {
log.LogError("Unable to find user ID for %+v", username)
}
return userID
}
func isAdmin(m *discordgo.Member) bool {
log.LogDebug("Checking %+v for %+v", m.Roles, config.AdminRole)
for _, role := range m.Roles {
if role == config.AdminRole {
return true
} else {
log.LogDebug("%+v != %+v", role, config.AdminRole)
}
}
return false
}