2022-06-24 02:22:17 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
// todo: make a consistent "player" type and have these functions return it
|
2022-06-25 03:25:49 +00:00
|
|
|
// todo: dont manually patch column name into various internal funcs (would make the extra funcs unnecessary)
|
2022-06-24 02:22:17 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
|
|
|
"errors"
|
|
|
|
"io/fs"
|
|
|
|
"os"
|
|
|
|
)
|
|
|
|
|
2022-06-25 03:25:49 +00:00
|
|
|
func _playerExistsBy(query string, value any) (bool, error) {
|
2022-06-24 02:22:17 +00:00
|
|
|
sqlStatement := `
|
2022-06-25 03:25:49 +00:00
|
|
|
SELECT username FROM users WHERE ` + query + ` = ?;
|
2022-06-24 02:22:17 +00:00
|
|
|
`
|
|
|
|
var x string
|
2022-06-25 03:25:49 +00:00
|
|
|
err := DB.QueryRow(sqlStatement, value).Scan(&x)
|
2022-06-24 02:22:17 +00:00
|
|
|
if err != nil {
|
|
|
|
if err == sql.ErrNoRows {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
func playerExistsByUUID(uuid string) (bool, error) {
|
2022-06-25 03:25:49 +00:00
|
|
|
return _playerExistsBy("uuid", uuid)
|
|
|
|
}
|
|
|
|
func playerExistsByUsername(username string) (bool, error) {
|
|
|
|
return _playerExistsBy("username", username)
|
|
|
|
}
|
|
|
|
|
|
|
|
func _getPlayerBy(query string, value any) (PlayerData, error) {
|
|
|
|
// todo: make this function less repetitive if possible
|
|
|
|
|
2022-06-24 02:22:17 +00:00
|
|
|
sqlStatement := `
|
2022-06-25 03:25:49 +00:00
|
|
|
SELECT id, username, password, uuid, client_token, auth_token, web_token, created_at FROM users WHERE ` + query + ` = ?;
|
2022-06-24 02:22:17 +00:00
|
|
|
`
|
2022-06-25 03:25:49 +00:00
|
|
|
var player PlayerData
|
|
|
|
err := DB.QueryRow(sqlStatement, value).Scan(
|
|
|
|
&player.Id,
|
|
|
|
&player.Username,
|
|
|
|
&player.Password,
|
|
|
|
&player.UUID,
|
|
|
|
&player.ClientToken,
|
|
|
|
&player.AuthToken,
|
|
|
|
&player.WebToken,
|
|
|
|
&player.CreatedAt,
|
|
|
|
)
|
2022-06-24 02:22:17 +00:00
|
|
|
if err != nil {
|
|
|
|
if err == sql.ErrNoRows {
|
2022-06-25 03:25:49 +00:00
|
|
|
return player, nil
|
2022-06-24 02:22:17 +00:00
|
|
|
}
|
2022-06-25 03:25:49 +00:00
|
|
|
return player, err
|
2022-06-24 02:22:17 +00:00
|
|
|
}
|
2022-06-25 03:25:49 +00:00
|
|
|
return player, nil
|
2022-06-24 02:22:17 +00:00
|
|
|
}
|
2022-06-25 03:25:49 +00:00
|
|
|
func getPlayerByUUID(uuid string) (PlayerData, error) {
|
|
|
|
return _getPlayerBy("uuid", uuid)
|
2022-06-24 02:22:17 +00:00
|
|
|
}
|
2022-06-25 03:25:49 +00:00
|
|
|
func getPlayerByUsername(username string) (PlayerData, error) {
|
|
|
|
return _getPlayerBy("username", username)
|
|
|
|
}
|
|
|
|
func getPlayerByAuthToken(auth string) (PlayerData, error) {
|
|
|
|
return _getPlayerBy("auth_token", auth)
|
2022-06-24 02:22:17 +00:00
|
|
|
}
|
|
|
|
|
2022-06-25 03:25:49 +00:00
|
|
|
// todo: dedupe skin and cape functions if possible
|
|
|
|
func getPlayerTexture(textureId string, uuid string) ([]byte, error) {
|
|
|
|
if !(textureId == "skin" || textureId == "cape") {
|
|
|
|
return []byte{}, &InvalidDataError{}
|
|
|
|
}
|
|
|
|
tex, err := os.ReadFile(textureId + "s/" + uuid + ".png")
|
2022-06-24 02:22:17 +00:00
|
|
|
if err != nil {
|
|
|
|
if errors.Is(err, fs.ErrNotExist) {
|
|
|
|
return []byte{}, &NotFoundError{}
|
|
|
|
}
|
|
|
|
return []byte{}, err
|
|
|
|
}
|
|
|
|
|
2022-06-25 03:25:49 +00:00
|
|
|
return tex, nil
|
2022-06-24 02:22:17 +00:00
|
|
|
}
|
|
|
|
|
2022-06-25 03:25:49 +00:00
|
|
|
func setPlayerTexture(textureId string, uuid string, tex []byte) error {
|
|
|
|
if !(textureId == "skin" || textureId == "cape") {
|
|
|
|
return &InvalidDataError{}
|
|
|
|
}
|
|
|
|
if len(tex) > config.MaxTextureSize {
|
2022-06-24 02:22:17 +00:00
|
|
|
return &TooLargeError{}
|
|
|
|
}
|
2022-06-25 03:25:49 +00:00
|
|
|
|
2022-06-24 02:22:17 +00:00
|
|
|
exists, err := playerExistsByUUID(uuid)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !exists {
|
|
|
|
return &NotFoundError{}
|
|
|
|
}
|
|
|
|
|
2022-06-25 03:25:49 +00:00
|
|
|
err = os.WriteFile(textureId+"s/"+uuid+".png", tex, 0644)
|
2022-06-24 02:22:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-06-25 03:25:49 +00:00
|
|
|
func playerHasTexture(textureId string, uuid string) (bool, error) {
|
|
|
|
if !(textureId == "skin" || textureId == "cape") {
|
|
|
|
return false, &InvalidDataError{}
|
|
|
|
}
|
2022-06-24 02:22:17 +00:00
|
|
|
|
2022-06-25 03:25:49 +00:00
|
|
|
_, err := os.Stat(textureId + "s/" + uuid + ".png")
|
2022-06-24 02:22:17 +00:00
|
|
|
if err != nil {
|
2022-06-25 03:25:49 +00:00
|
|
|
if errors.Is(err, fs.ErrNotExist) {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
return false, err
|
2022-06-24 02:22:17 +00:00
|
|
|
}
|
2022-06-25 03:25:49 +00:00
|
|
|
return true, nil
|
2022-06-24 02:22:17 +00:00
|
|
|
}
|
|
|
|
|
2022-06-25 03:25:49 +00:00
|
|
|
func _checkPlayerPassBy(query string, value any, password string) (bool, error) {
|
2022-06-24 02:22:17 +00:00
|
|
|
sqlStatement := `
|
2022-06-25 03:25:49 +00:00
|
|
|
SELECT password FROM users WHERE ` + query + ` = ?;
|
2022-06-24 02:22:17 +00:00
|
|
|
`
|
2022-06-25 03:25:49 +00:00
|
|
|
row := DB.QueryRow(sqlStatement, value)
|
2022-06-24 02:22:17 +00:00
|
|
|
|
|
|
|
var pass string
|
|
|
|
err := row.Scan(&pass)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
if pass != password {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
return true, nil
|
|
|
|
}
|
2022-06-25 03:25:49 +00:00
|
|
|
func checkPlayerPassByUUID(uuid string, password string) (bool, error) {
|
|
|
|
return _checkPlayerPassBy("uuid", uuid, password)
|
|
|
|
}
|
|
|
|
func checkPlayerPassByUsername(username string, password string) (bool, error) {
|
|
|
|
return _checkPlayerPassBy("username", username, password)
|
|
|
|
}
|