This commit is contained in:
2022-12-09 23:26:38 -06:00
parent 8df6231b71
commit d8a6c8acd1
15 changed files with 643 additions and 56 deletions

View File

@@ -6,8 +6,8 @@ import (
"net/http" "net/http"
) )
func getDiscordUser(token string) User { func GetDiscordUser(token string) User {
req, err := http.NewRequest("GET", "https://discord.com/api/v19/users/@me", nil) req, err := http.NewRequest("GET", "https://discord.com/api/v10/users/@me", nil)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -24,7 +24,7 @@ func getDiscordUser(token string) User {
panic(err) panic(err)
} }
var respObj = User{} var respObj User
err = json.Unmarshal(respBody, &respObj) err = json.Unmarshal(respBody, &respObj)
if err != nil { if err != nil {
panic(err) panic(err)

View File

@@ -1,5 +1,7 @@
package discord package discord
import "encoding/json"
type User struct { type User struct {
ID string `json:"id"` ID string `json:"id"`
Username string `json:"username"` Username string `json:"username"`
@@ -17,3 +19,43 @@ type User struct {
Premium_type int `json:"premium_type"` Premium_type int `json:"premium_type"`
Public_flags int `json:"public_flags"` Public_flags int `json:"public_flags"`
} }
type SimpleUser struct {
ID string `json:"id"`
Username string `json:"username"`
Discriminator string `json:"discriminator"`
Avatar string `json:"avatar"`
Bot bool `json:"bot"`
Banner string `json:"banner"`
AccentColor int `json:"accent_color"`
Verified bool `json:"verified"`
}
func (u User) Simplify() SimpleUser {
return SimpleUser{
ID: u.ID,
Username: u.Username,
Discriminator: u.Discriminator,
Avatar: u.Avatar,
Bot: u.Bot,
Banner: u.Banner,
AccentColor: u.Accent_color,
Verified: u.Verified,
}
}
func (u User) MarshalBinary() ([]byte, error) {
return json.Marshal(u)
}
func (u *User) UnmarshalBinary(data []byte) error {
return json.Unmarshal(data, u)
}
func (u SimpleUser) MarshalBinary() ([]byte, error) {
return json.Marshal(u)
}
func (u *SimpleUser) UnmarshalBinary(data []byte) error {
return json.Unmarshal(data, u)
}

16
endpoints/access.go Normal file
View File

@@ -0,0 +1,16 @@
package endpoints
import (
"git.zomo.dev/zomo/discord-retokenizer/storage"
"github.com/gin-gonic/gin"
)
func access(c *gin.Context) {
authType, token := getAuthorization(c)
if authType != AuthorizationScopeBot {
c.AbortWithStatus(401)
}
_, botToken := storage.BotTokenFromToken(token)
c.String(200, botToken)
}

View File

@@ -23,15 +23,16 @@ func getAuthorization(c *gin.Context) (AuthorizationScope, string) {
if len(headerSpl) != 2 { if len(headerSpl) != 2 {
return AuthorizationScopeNone, "" return AuthorizationScopeNone, ""
} }
if headerSpl[0] == "Bearer" { prefix := headerSpl[0]
if storage.CheckLoginToken(headerSpl[1], c.ClientIP()) { token := strings.ToLower(headerSpl[1])
return AuthorizationScopeUser, headerSpl[1] if prefix == "Bearer" {
if storage.CheckLoginToken(token, c.ClientIP()) {
return AuthorizationScopeUser, token
} }
} }
if headerSpl[0] == "Bot" { if prefix == "Bot" {
// TODO check bot token if found, _ := storage.BotTokenFromToken(token); found {
if true { return AuthorizationScopeBot, token
return AuthorizationScopeBot, headerSpl[1]
} }
} }
return AuthorizationScopeNone, "" return AuthorizationScopeNone, ""

69
endpoints/bots.go Normal file
View File

@@ -0,0 +1,69 @@
package endpoints
import (
"fmt"
"git.zomo.dev/zomo/discord-retokenizer/storage"
"github.com/gin-gonic/gin"
)
type SimpleDiscordUser struct {
Username string `json:"username"`
Discriminator string `json:"discriminator"`
Avatar string `json:"avatar"`
Banner string `json:"banner"`
Accent_color int `json:"accent_color"`
Verified bool `json:"verified"`
}
type BotData struct {
Token string
ID string
Loaded SimpleDiscordUser
}
// one array of just bot ids
// `bot:(id):token`
// `bot:(id):data`
// SimpleDiscordUser
func bots(c *gin.Context) {
bots := storage.GetBots()
c.JSON(200, bots)
}
func bot(c *gin.Context) {
id := c.Param("id")
bot := storage.GetBot(id)
c.JSON(200, bot)
}
type addBotBody struct {
Token string `json:"token" binding:"required"`
}
func addBot(c *gin.Context) {
var tokenBody addBotBody
if err := c.BindJSON(&tokenBody); err != nil {
fmt.Println(err)
return
}
didSet := storage.AddBot(tokenBody.Token)
if didSet {
c.JSON(200, gin.H{
"success": true,
})
} else {
c.JSON(400, gin.H{
"success": false,
})
}
}
func removeBot(c *gin.Context) {
id := c.Param("id")
storage.RemoveBot(id)
c.JSON(200, gin.H{
"success": true,
})
}

View File

@@ -10,23 +10,25 @@ func Run() {
public := r.Group("/") public := r.Group("/")
public.POST("/login", login) //web login public.POST("/login", login) //web login
public.POST("/access", func(c *gin.Context) {}) //access token public.GET("/access", access) //access token
private := r.Group("/") private := r.Group("/")
private.Use(userIsAuthorized) private.Use(userIsAuthorized)
private.PATCH("/login", updateLogin) //change username/password (required before adding bots) private.PATCH("/login", updateLogin) //change username/password (required before adding bots)
private.GET("/login/tokens", getLoginTokens) //list of login tokens
private.DELETE("/login/tokens", clearLoginTokens) //clears all login tokens
private.GET("/bots", func(c *gin.Context) {}) //generalized list of bots private.GET("/bots", bots) //generalized list of bots
private.GET("/bot/:bot", func(c *gin.Context) {}) //specific bot private.GET("/bot/:id", bot) //specific bot
private.POST("/bot/", func(c *gin.Context) {}) //add bot given token private.POST("/bot", addBot) //add bot given token
private.DELETE("/bot/:bot", func(c *gin.Context) {}) //remove bot private.DELETE("/bot/:id", removeBot) //remove bot
private.GET("/tokens", func(c *gin.Context) {}) //generalized list of tokens private.GET("/tokens", getTokens) //generalized list of tokens
private.GET("/token/:token", func(c *gin.Context) {}) //specific token private.GET("/token/:id", getToken) //specific token
private.POST("/token/", func(c *gin.Context) {}) //new token given bot (so you cant add a token if theres no bots) private.POST("/token", addToken) //new token given bot (so you cant add a token if theres no bots)
private.DELETE("/token/:token", func(c *gin.Context) {}) //remove token private.DELETE("/token/:id", deleteToken) //remove token
private.PATCH("/token/:token", func(c *gin.Context) {}) //update token given bot private.PATCH("/token/:id", updateToken) //update token given bot
r.Run() r.Run()
} }

View File

@@ -13,7 +13,6 @@ type LoginBody struct {
} }
func login(c *gin.Context) { func login(c *gin.Context) {
var loginBody LoginBody var loginBody LoginBody
if err := c.BindJSON(&loginBody); err != nil { if err := c.BindJSON(&loginBody); err != nil {
fmt.Println(err) fmt.Println(err)
@@ -31,7 +30,6 @@ func login(c *gin.Context) {
"error": "invalid username or password", "error": "invalid username or password",
}) })
} }
} }
func updateLogin(c *gin.Context) { func updateLogin(c *gin.Context) {
@@ -43,3 +41,12 @@ func updateLogin(c *gin.Context) {
storage.UpdateUsername(updateLogin.Username) storage.UpdateUsername(updateLogin.Username)
storage.UpdatePassword(updateLogin.Password) storage.UpdatePassword(updateLogin.Password)
} }
func getLoginTokens(c *gin.Context) {
tokens := storage.GetLoginTokensSimple()
c.JSON(200, tokens)
}
func clearLoginTokens(c *gin.Context) {
storage.ClearLoginTokens()
}

68
endpoints/tokens.go Normal file
View File

@@ -0,0 +1,68 @@
package endpoints
import (
"fmt"
"git.zomo.dev/zomo/discord-retokenizer/storage"
"github.com/gin-gonic/gin"
)
func getTokens(c *gin.Context) {
tokens := storage.GetTokens()
c.JSON(200, tokens)
}
func getToken(c *gin.Context) {
id := c.Param("id")
token := storage.GetToken(id)
c.JSON(200, token)
}
type TokenBody struct {
BotID string `json:"bot_id" binding:"required"`
}
func addToken(c *gin.Context) {
var tokenBody TokenBody
if err := c.BindJSON(&tokenBody); err != nil {
fmt.Println(err)
return
}
token := storage.GenerateToken(tokenBody.BotID)
if token == "" {
c.JSON(400, gin.H{
"message": "bot id not found",
})
return
}
c.JSON(200, gin.H{
"token": token,
})
}
func deleteToken(c *gin.Context) {
id := c.Param("id")
storage.DeleteToken(id)
c.JSON(200, gin.H{
"message": "success",
})
}
func updateToken(c *gin.Context) {
id := c.Param("id")
var tokenBody TokenBody
if err := c.BindJSON(&tokenBody); err != nil {
fmt.Println(err)
return
}
didSet := storage.UpdateToken(id, tokenBody.BotID)
if !didSet {
c.JSON(400, gin.H{
"message": "token or bot id not found",
})
return
}
c.JSON(200, gin.H{
"message": "success",
})
}

4
go.mod
View File

@@ -2,7 +2,10 @@ module git.zomo.dev/zomo/discord-retokenizer
go 1.19 go 1.19
require github.com/joho/godotenv v1.4.0
require ( require (
github.com/bwmarrin/snowflake v0.3.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
@@ -12,7 +15,6 @@ require (
github.com/go-playground/validator/v10 v10.11.1 // indirect github.com/go-playground/validator/v10 v10.11.1 // indirect
github.com/go-redis/redis/v9 v9.0.0-rc.2 // indirect github.com/go-redis/redis/v9 v9.0.0-rc.2 // indirect
github.com/goccy/go-json v0.10.0 // indirect github.com/goccy/go-json v0.10.0 // indirect
github.com/joho/godotenv v1.4.0
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/leodido/go-urn v1.2.1 // indirect github.com/leodido/go-urn v1.2.1 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect github.com/mattn/go-isatty v0.0.16 // indirect

2
go.sum
View File

@@ -1,3 +1,5 @@
github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0=
github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=

View File

@@ -1,27 +1,125 @@
package storage package storage
type SimpleDiscordUser struct { import (
Username string `json:"username"` "fmt"
Discriminator string `json:"discriminator"`
Avatar string `json:"avatar"` "git.zomo.dev/zomo/discord-retokenizer/discord"
Banner string `json:"banner"` "github.com/go-redis/redis/v9"
Accent_color int `json:"accent_color"` )
Verified bool `json:"verified"`
func BotExists(id string) bool {
exist, err := client.SMIsMember(ctx, "bots", id).Result()
if err != nil {
if err == redis.Nil {
return false
}
panic(err)
}
for _, b := range exist {
if !b {
return false
}
}
return true
} }
type BotData struct { func GetBots() []discord.SimpleUser {
Token string botIDs, err := client.SMembers(ctx, "bots").Result()
ID string if err != nil && err != redis.Nil {
Loaded SimpleDiscordUser panic(err)
}
bots := make([]discord.SimpleUser, 0)
for _, id := range botIDs {
bots = append(bots, GetBot(id).Simplify())
}
return bots
} }
// one array of just bot ids func GetBot(id string) discord.User {
// `bot:(id):token` var bot discord.User
// `bot:(id):data` key := fmt.Sprintf("bot:%s:data", id)
// SimpleDiscordUser err := client.Get(ctx, key).Scan(&bot)
if err != nil && err != redis.Nil {
func GetBots() { panic(err)
}
return bot
}
func ExistsBot(id string) bool {
exist, err := client.SIsMember(ctx, "bots", id).Result()
if err != nil {
if err == redis.Nil {
return false
}
panic(err)
}
return exist
}
func RemoveBot(id string) {
err := client.SRem(ctx, "bots", id).Err()
if err != nil {
panic(err)
}
keyPrefix := fmt.Sprintf("bot:%s:", id)
err = client.Del(ctx, keyPrefix + "token").Err()
if err != nil {
panic(err)
}
err = client.Del(ctx, keyPrefix + "data").Err()
if err != nil {
panic(err)
}
}
func getBotToken(id string) string {
if !BotExists(id) {
return ""
}
key := fmt.Sprintf("bot:%s:token", id)
token, err := client.Get(ctx, key).Result()
if err != nil {
panic(err)
}
return token
}
func RefreshBot(id string) discord.User {
token := getBotToken(id)
bot := discord.GetDiscordUser(token)
key := fmt.Sprintf("bot:%s:data", id)
err := client.Set(ctx, key, bot, 0).Err()
if err != nil {
panic(err)
}
return bot
}
func AddBot(token string) bool {
user := discord.GetDiscordUser(token)
if user.ID == "" {
return false
}
err := client.SAdd(ctx, "bots", user.ID).Err()
if err != nil {
panic(err)
}
userID := user.ID
keyPrefix := fmt.Sprintf("bot:%s:", userID)
err = client.Set(ctx, keyPrefix + "token", token, 0).Err()
if err != nil {
panic(err)
}
err = client.Set(ctx, keyPrefix + "data", user, 0).Err()
if err != nil {
panic(err)
}
return true
} }

View File

@@ -41,8 +41,6 @@ func CheckLogin(username string, password string, ip string) (bool, string) {
panic(err) panic(err)
} }
fmt.Println(user, username)
if user != username { if user != username {
return false, "" return false, ""
} }
@@ -56,11 +54,27 @@ func CheckLogin(username string, password string, ip string) (bool, string) {
} }
type LoginToken struct { type LoginToken struct {
Token string `json:"token"` 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"` IP string `json:"ip"`
End string `json:"end"` 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) { func (t LoginToken) MarshalBinary() ([]byte, error) {
return json.Marshal(t) return json.Marshal(t)
} }
@@ -70,7 +84,7 @@ func (t *LoginToken) UnmarshalBinary(data []byte) error {
} }
func createLoginToken(ip string) string { func createLoginToken(ip string) string {
token := util.GeneratePassword(32) token := util.GenerateToken()
tokenHash, err := bcrypt.GenerateFromPassword([]byte(token), bcrypt.DefaultCost) tokenHash, err := bcrypt.GenerateFromPassword([]byte(token), bcrypt.DefaultCost)
if err != nil { if err != nil {
@@ -78,13 +92,14 @@ func createLoginToken(ip string) string {
} }
tokenData := LoginToken{ tokenData := LoginToken{
Token: string(tokenHash), ID: util.GenerateID(),
IP: ip, TokenHash: string(tokenHash),
End: token[len(token) - 4:], IP: ip,
End: util.GetEnd(token),
} }
member := redis.Z{ member := redis.Z{
Score: float64(time.Now().Unix() + 4 * 60 * 60), Score: float64(time.Now().Unix() + 4 * 60 * 60),
Member: tokenData, Member: tokenData,
} }
@@ -96,8 +111,7 @@ func createLoginToken(ip string) string {
return token return token
} }
func CheckLoginToken(token string, ip string) bool { func getLoginTokens() []LoginToken {
expired, err := client.ZRangeByScore(ctx, "loginTokens", &redis.ZRangeBy{ expired, err := client.ZRangeByScore(ctx, "loginTokens", &redis.ZRangeBy{
Min: "-inf", Min: "-inf",
Max: fmt.Sprintf("%d", time.Now().Unix()), Max: fmt.Sprintf("%d", time.Now().Unix()),
@@ -118,10 +132,28 @@ func CheckLoginToken(token string, ip string) bool {
panic(err) panic(err)
} }
fmt.Printf("%v\n", current) 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 { for _, c := range current {
err = bcrypt.CompareHashAndPassword([]byte(c.Token), []byte(token)) err := bcrypt.CompareHashAndPassword([]byte(c.TokenHash), []byte(token))
if err == nil && ip == c.IP { if err == nil && ip == c.IP {
return true return true
} }

View File

@@ -15,9 +15,9 @@ var client *redis.Client = nil
func initializeRedis() { func initializeRedis() {
username := "default" username := "default"
UpdateUsername( username) UpdateUsername(username)
password := util.GeneratePassword(16) password := util.GeneratePassword(16)
UpdatePassword( password) UpdatePassword(password)
fmt.Printf("FIRST TIME SETUP\nusername: %s\npassword: %s\n\n\n", username, password) fmt.Printf("FIRST TIME SETUP\nusername: %s\npassword: %s\n\n\n", username, password)
} }

229
storage/tokens.go Normal file
View File

@@ -0,0 +1,229 @@
package storage
import (
"encoding/json"
"git.zomo.dev/zomo/discord-retokenizer/discord"
"git.zomo.dev/zomo/discord-retokenizer/util"
"golang.org/x/crypto/bcrypt"
)
type TokenTiny struct {
ID string `json:"id"`
TokenHash string `json:"token"`
}
type TokenBot struct {
ID string `json:"id"`
BotID string `json:"bot_id"`
End string `json:"end"`
TokenHash string `json:"token"`
}
type SimpleTokenBot struct {
ID string `json:"id"`
BotID string `json:"bot_id"`
End string `json:"end"`
}
func (t TokenBot) Simplify() SimpleTokenBot {
return SimpleTokenBot{
ID: t.ID,
BotID: t.BotID,
End: t.End,
}
}
func (t TokenTiny) MarshalBinary() ([]byte, error) {
return json.Marshal(t)
}
func (t *TokenTiny) UnmarshalBinary(data []byte) error {
return json.Unmarshal(data, t)
}
func (t TokenBot) MarshalBinary() ([]byte, error) {
return json.Marshal(t)
}
func (t *TokenBot) UnmarshalBinary(data []byte) error {
return json.Unmarshal(data, t)
}
func (t SimpleTokenBot) MarshalBinary() ([]byte, error) {
return json.Marshal(t)
}
func (t *SimpleTokenBot) UnmarshalBinary(data []byte) error {
return json.Unmarshal(data, t)
}
func GenerateToken(botID string) string {
if !ExistsBot(botID) {
return ""
}
// Generate a token
token := util.GenerateToken()
tokenID := util.GenerateID()
tokenHash, err := bcrypt.GenerateFromPassword([]byte(token), bcrypt.DefaultCost)
if err != nil {
panic(err)
}
tinyToken := TokenTiny{
ID: tokenID,
TokenHash: string(tokenHash),
}
err = client.SAdd(ctx, "tokens", tinyToken).Err()
if err != nil {
panic(err)
}
botToken := TokenBot{
ID: tokenID,
BotID: botID,
End: util.GetEnd(token),
TokenHash: string(tokenHash),
}
err = client.Set(ctx, "token:" + tokenID, botToken, 0).Err()
if err != nil {
panic(err)
}
return token
}
func getTokenBot(token string) (bool, TokenBot) {
var tokens []TokenTiny
err := client.SMembers(ctx, "tokens").ScanSlice(&tokens)
if err != nil {
panic(err)
}
for _, t := range tokens {
err = bcrypt.CompareHashAndPassword([]byte(t.TokenHash), []byte(token))
if err == nil {
var botToken TokenBot
err := client.Get(ctx, "token:" + t.ID).Scan(&botToken)
if err != nil {
panic(err)
}
return true, botToken
}
}
return false, TokenBot{}
}
func DeleteToken(token string) {
foundToken, botToken := getTokenBot(token)
if !foundToken {
return
}
err := client.SRem(ctx, "tokens", botToken.TokenHash).Err()
if err != nil {
panic(err)
}
err = client.Del(ctx, "token:" + botToken.ID).Err()
if err != nil {
panic(err)
}
}
func UpdateToken(token string, botID string) bool {
if !ExistsBot(botID) {
return false
}
foundToken, botToken := getTokenBot(token)
if !foundToken {
return false
}
err := client.Set(ctx, "token:" + botToken.ID, botToken, 0).Err()
if err != nil {
panic(err)
}
return true
}
type TokenUserBot struct {
ID string `json:"id"`
End string `json:"token_end"`
User discord.User `json:"user"`
}
type SimpleTokenUserBot struct {
ID string `json:"id"`
End string `json:"token_end"`
User discord.SimpleUser `json:"user"`
}
func (t TokenBot) WithUser() TokenUserBot {
return TokenUserBot{
ID: t.ID,
End: t.End,
User: GetBot(t.BotID),
}
}
func (t TokenUserBot) Simplify() SimpleTokenUserBot {
return SimpleTokenUserBot{
ID: t.ID,
End: t.End,
User: t.User.Simplify(),
}
}
func (t TokenUserBot) MarshalBinary() ([]byte, error) {
return json.Marshal(t)
}
func (t *TokenUserBot) UnmarshalBinary(data []byte) error {
return json.Unmarshal(data, t)
}
func (t SimpleTokenUserBot) MarshalBinary() ([]byte, error) {
return json.Marshal(t)
}
func (t *SimpleTokenUserBot) UnmarshalBinary(data []byte) error {
return json.Unmarshal(data, t)
}
func GetTokens() []SimpleTokenUserBot {
var tokens []TokenTiny
err := client.SMembers(ctx, "tokens").ScanSlice(&tokens)
if err != nil {
panic(err)
}
simpleTokens := make([]SimpleTokenUserBot, 0)
for _, t := range tokens {
var tokenBot TokenBot
err := client.Get(ctx, "token:" + t.ID).Scan(&tokenBot)
if err != nil {
panic(err)
}
simpleTokens = append(simpleTokens, tokenBot.WithUser().Simplify())
}
return simpleTokens
}
func GetToken(id string) TokenUserBot {
var tokenBot TokenBot
err := client.Get(ctx, "token:" + id).Scan(&tokenBot)
if err != nil {
panic(err)
}
return tokenBot.WithUser()
}
func BotTokenFromToken(token string) (bool, string) {
foundBot, tokenBot := getTokenBot(token)
if !foundBot {
return false, ""
}
return true, getBotToken(tokenBot.BotID)
}

View File

@@ -4,9 +4,12 @@ import (
"encoding/hex" "encoding/hex"
"math/rand" "math/rand"
"time" "time"
"github.com/bwmarrin/snowflake"
) )
var passwordChars = []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-=_+!@#$%^&*()[]{}|;:,.<>/?") // var passwordChars = []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-=_+!@#$%^&*()[]{}|;:,.<>/?")
var passwordChars = []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-=_+!@#$%^&*?")
func GeneratePassword(length int) string { func GeneratePassword(length int) string {
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
@@ -27,3 +30,19 @@ func GenerateToken() string {
} }
return hex.EncodeToString(b) return hex.EncodeToString(b)
} }
var snowflakeNodeIndex int64 = 0
func GenerateID() string {
node, err := snowflake.NewNode(snowflakeNodeIndex)
if err != nil {
panic(err)
}
return node.Generate().String()
}
func GetEnd(token string) string {
if len(token) < 8 {
return ""
}
return token[len(token)-8:]
}