Files
discord-retokenizer/storage/login.go
2022-12-27 22:21:54 -06:00

236 lines
5.3 KiB
Go

package storage
import (
"encoding/json"
"fmt"
"time"
"git.zomo.dev/zomo/discord-retokenizer/util"
"github.com/mileusna/useragent"
"golang.org/x/crypto/bcrypt"
)
type UserAgentSimple struct {
Name string `json:"name"`
Version string `json:"version"`
OS string `json:"os"`
OSVersion string `json:"os_version"`
Mobile bool `json:"mobile"`
Tablet bool `json:"tablet"`
Desktop bool `json:"desktop"`
}
func (ua UserAgentSimple) Compare(ua2 UserAgentSimple) bool {
return ua.Name == ua2.Name &&
ua.OS == ua2.OS &&
ua.Mobile == ua2.Mobile &&
ua.Tablet == ua2.Tablet &&
ua.Desktop == ua2.Desktop
}
func ParseUA(userAgentString string) UserAgentSimple {
ua := useragent.Parse(userAgentString)
return UserAgentSimple{
Name: ua.Name,
Version: ua.Version,
OS: ua.OS,
OSVersion: ua.OSVersion,
Mobile: ua.Mobile,
Tablet: ua.Tablet,
Desktop: ua.Desktop,
}
}
func UpdateUsername(username string) {
if username != "" {
client.Set(ctx, "username", username, 0)
}
}
func UpdatePassword(password string) {
if password != "" {
passHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
panic(err)
}
client.Set(ctx, "password", string(passHash), 0)
}
}
func CheckLoginPassword(username string, password string, ip string, userAgent UserAgentSimple) (bool, string) {
if username == "" || password == "" {
return false, ""
}
user, err := client.Get(ctx, "username").Result()
if err != nil {
panic(err)
}
pass, err := client.Get(ctx, "password").Result()
if err != nil {
panic(err)
}
if user != username {
return false, ""
}
err = bcrypt.CompareHashAndPassword([]byte(pass), []byte(password))
if err != nil {
return false, ""
}
//return existing token if it exists
tokens := getLoginTokens()
fmt.Printf("There are %d tokens", len(tokens))
for _, token := range tokens {
// fmt.Printf("Checking token %s\n", token.ID)
// fmt.Printf("IP:\n Given: %s\n Token: %s\n", ip, token.IP)
// fmt.Printf("UA:\n Given: %+v\n Token: %+v\n", userAgent, token.UserAgent)
// fmt.Printf("Compare UA: %t\n", token.UserAgent.Compare(userAgent))
if token.IP == ip && userAgent.Compare(token.UserAgent) {
return true, token.Token
}
}
return true, createLoginToken(ip, userAgent)
}
type LoginToken struct {
ID string `json:"id"`
Token string `json:"token"`
IP string `json:"ip"`
End string `json:"end"`
UserAgent UserAgentSimple `json:"user_agent"`
CreatedAt string `json:"created_at"`
LastLogin string `json:"last_login"`
}
type LoginTokenSimple struct {
ID string `json:"id"`
IP string `json:"ip"`
End string `json:"end"`
UserAgent UserAgentSimple `json:"user_agent"`
CreatedAt string `json:"created_at"`
LastLogin string `json:"last_login"`
}
func (t LoginToken) Simplify() LoginTokenSimple {
return LoginTokenSimple{
ID: t.ID,
IP: t.IP,
End: t.End,
UserAgent: t.UserAgent,
CreatedAt: t.CreatedAt,
LastLogin: t.LastLogin,
}
}
func (t LoginToken) MarshalBinary() ([]byte, error) {
return json.Marshal(t)
}
func (t *LoginToken) UnmarshalBinary(data []byte) error {
return json.Unmarshal(data, t)
}
func createLoginToken(ip string, ua UserAgentSimple) string {
token := util.GenerateToken()
tokenData := LoginToken{
ID: util.GenerateID(),
Token: token,
IP: ip,
End: util.GetEnd(token),
UserAgent: ua,
CreatedAt: time.Now().Format(time.RFC3339),
LastLogin: time.Now().Format(time.RFC3339),
}
err := client.RPush(ctx, "loginTokens", tokenData.ID).Err()
if err != nil {
panic(err)
}
err = client.Set(ctx, "loginToken:"+tokenData.ID, tokenData, 0).Err()
if err != nil {
panic(err)
}
return token
}
func getLoginTokens() []LoginToken {
var ids []string
err := client.LRange(ctx, "loginTokens", 0, -1).ScanSlice(&ids)
if err != nil {
panic(err)
}
var tokens []LoginToken
for _, id := range ids {
var token LoginToken
err = client.Get(ctx, "loginToken:"+id).Scan(&token)
if err != nil {
panic(err)
}
tokens = append(tokens, token)
}
return tokens
}
func updateLastLoginToken(token LoginToken) {
token.CreatedAt = time.Now().Format(time.RFC3339)
err := client.Set(ctx, "loginToken:"+token.ID, token, 0).Err()
if err != nil {
panic(err)
}
}
func GetLoginTokensSimple() []LoginTokenSimple {
simple := make([]LoginTokenSimple, 0)
for _, c := range getLoginTokens() {
simple = append(simple, c.Simplify())
}
return simple
}
func ClearLoginTokens() {
var ids []string
err := client.LRange(ctx, "loginTokens", 0, -1).ScanSlice(&ids)
if err != nil {
panic(err)
}
err = client.Del(ctx, "loginTokens").Err()
if err != nil {
panic(err)
}
for _, id := range ids {
err = client.Del(ctx, "loginToken:"+id).Err()
if err != nil {
panic(err)
}
}
}
func CheckLoginToken(token string, ip string, userAgent UserAgentSimple) bool {
current := getLoginTokens()
for _, c := range current {
if token == c.Token && ip == c.IP && userAgent.Compare(c.UserAgent) {
fmt.Printf("Checking token %s\n", c.ID)
fmt.Printf("IP:\n Given: %s\n Token: %s\n", ip, c.IP)
fmt.Printf("UA:\n Given: %+v\n Token: %+v\n", userAgent, c.UserAgent)
updateLastLoginToken(c)
return true
}
}
return false
}