minecraft-server-invites/invite/invite.go
2022-07-15 17:38:53 +01:00

80 lines
1.6 KiB
Go

package invite
import (
"crypto/rand"
"database/sql"
"errors"
"math/big"
"whitelistmanager/store"
)
const NotOwnerofServer = "user is not owner of server"
type Manager struct {
store store.Storer
}
type InviteManager interface {
Create(in store.Invite, user store.User) (string, error)
RemainingUses(in store.Invite) (int, error)
}
func NewManager(db store.Storer) *Manager {
return &Manager{store: db}
}
func (i *Manager) Create(in store.Invite, user store.User) (string, error) {
server, err := i.store.GetServer(in.Server.Id)
if server.Owner.Id != user.Id {
return "", errors.New(NotOwnerofServer)
}
token, err := i.createToken()
if err != nil {
return "", err
}
// If we have an unlikely collision, generate a new token.
_, err = i.store.GetInvite(token)
if err != nil {
if !errors.Is(err, sql.ErrNoRows) {
return "", err
}
} else {
token, err = i.createToken()
if err != nil {
return "", err
}
}
in.Token = token
in.Creator = user
return token, i.store.SaveInvite(in)
}
func (i *Manager) createToken() (string, error) {
const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
ret := make([]byte, 8)
for i := 0; i < 8; i++ {
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
if err != nil {
return "", err
}
ret[i] = letters[num.Int64()]
}
return string(ret), nil
}
func (i *Manager) RemainingUses(in store.Invite) (int, error) {
if in.Unlimited {
return 1, nil
}
logs, err := i.store.InviteLog(in)
if err != nil {
return 0, nil
}
return in.Uses - len(logs), nil
}