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.
127 lines
3.4 KiB
127 lines
3.4 KiB
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") |
|
var userID string |
|
g, err := dg.State.Guild(config.GuildID) |
|
if err == nil { |
|
for _, m := range g.Members { |
|
if m.User.Username == "johndoe" { |
|
userID = m.User.ID |
|
} |
|
} |
|
} |
|
ipaddr := r.Header.Get("X-Real-IP") |
|
log.LogInfo(fmt.Sprintf("reqPass called:```username: %s\nip : %s```", username, ipaddr)) |
|
go sendPassword(userID, 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, "<br><p>Login Success: %+v</p><br>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, "" |
|
}
|
|
|