package main import ( "fmt" "math/rand" "net/http" "strings" "time" "github.com/gorilla/mux" ) func reqPass(w http.ResponseWriter, r *http.Request) { username := r.FormValue("UserName") ipaddr := r.Header.Get("X-Real-IP") log.LogInfo(fmt.Sprintf("reqPass called:```username: %s\nip : %s```", username, ipaddr)) sendPassword(username, ipaddr) http.Redirect(w, r, "/login", 302) } func tryLogin(w http.ResponseWriter, r *http.Request) { 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)) } } } fmt.Fprintf(w, "

Login Success: %+v


Session: %+v", access, session.Values) } func usePassword(user string, pass string, ip string) bool { tok := toks[user] delete(toks, user) if time.Since(tok.timestamp) > (time.Minute * 5) { log.LogWarn(fmt.Sprintf("%s attempted to use expired token.", user)) return false } 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 } return true } func genPassword(length int) string { 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) { str := genPassword(8) m, _ := dg.GuildMember(config.GuildID, user) toks[m.User.Username] = tokens{ username: user, ip: ipaddr, password: str, timestamp: time.Now(), } pmChann, _ := dg.UserChannelCreate(user) 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 { 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) { 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, "" }