Files
discord-retokenizer/storage/login.go
2022-12-09 23:26:38 -06:00

163 lines
3.0 KiB
Go

package storage
import (
"encoding/json"
"fmt"
"time"
"git.zomo.dev/zomo/discord-retokenizer/util"
"github.com/go-redis/redis/v9"
"golang.org/x/crypto/bcrypt"
)
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 CheckLogin(username string, password string, ip string) (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 true, createLoginToken(ip)
}
type LoginToken struct {
ID string `json:"id"`
TokenHash string `json:"token"`
IP string `json:"ip"`
End string `json:"end"`
}
type LoginTokenSimple struct {
ID string `json:"id"`
IP string `json:"ip"`
End string `json:"end"`
}
func (t LoginToken) Simplify() LoginTokenSimple {
return LoginTokenSimple{
ID: t.ID,
IP: t.IP,
End: t.End,
}
}
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) string {
token := util.GenerateToken()
tokenHash, err := bcrypt.GenerateFromPassword([]byte(token), bcrypt.DefaultCost)
if err != nil {
panic(err)
}
tokenData := LoginToken{
ID: util.GenerateID(),
TokenHash: string(tokenHash),
IP: ip,
End: util.GetEnd(token),
}
member := redis.Z{
Score: float64(time.Now().Unix() + 4 * 60 * 60),
Member: tokenData,
}
err = client.ZAdd(ctx, "loginTokens", member).Err()
if err != nil {
panic(err)
}
return token
}
func getLoginTokens() []LoginToken {
expired, err := client.ZRangeByScore(ctx, "loginTokens", &redis.ZRangeBy{
Min: "-inf",
Max: fmt.Sprintf("%d", time.Now().Unix()),
}).Result()
if err != nil {
panic(err)
}
for _, e := range expired {
client.ZRem(ctx, "loginTokens", e)
}
var current []LoginToken
err = client.ZRange(ctx, "loginTokens", 0, -1).ScanSlice(&current)
if err != nil {
panic(err)
}
return current
}
func GetLoginTokensSimple() []LoginTokenSimple {
simple := make([]LoginTokenSimple, 0)
for _, c := range getLoginTokens() {
simple = append(simple, c.Simplify())
}
return simple
}
func ClearLoginTokens() {
client.Del(ctx, "loginTokens")
}
func CheckLoginToken(token string, ip string) bool {
current := getLoginTokens()
for _, c := range current {
err := bcrypt.CompareHashAndPassword([]byte(c.TokenHash), []byte(token))
if err == nil && ip == c.IP {
return true
}
}
return false
}