Skip to content
Merged

Hw #57

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions db/login_hardware_ids.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package db

import "time"

type LoginHardwareId struct {
Id int `db:"id"`
UserId int `db:"user_id"`
CpuId string `db:"cpu_id"`
DiskId string `db:"disk_id"`
CpuDiskId string `db:"cpu_disk_id"`
QuaverDll string `db:"quaver_dll"`
QuaverAPIDll string `db:"quaver_api_dll"`
QuaverServerClientDll string `db:"quaver_server_client_dll"`
QuaverServerCommonDll string `db:"quaver_server_common_dll"`
QuaverSharedDll string `db:"quaver_shared_dll"`
Occurrences int `db:"occurrences"`
Timestamp int64 `db:"timestamp"`
}

// InsertLoginHardwareId Logs the hardware ids and client build signatures used by a user during login.
func InsertLoginHardwareId(userId int, cpuId string, diskId string, cpuDiskId string, build GameBuild) error {
timestamp := time.Now().UnixMilli()

updateQuery := "UPDATE login_hardware_ids SET " +
"quaver_dll = ?, quaver_api_dll = ?, quaver_server_client_dll = ?, quaver_server_common_dll = ?, quaver_shared_dll = ?, occurrences = occurrences + 1, timestamp = ? " +
"WHERE user_id = ? AND cpu_id = ? AND disk_id = ? AND cpu_disk_id = ?"

result, err := SQL.Exec(updateQuery, build.QuaverDll, build.QuaverAPIDll, build.QuaverServerClientDll,
build.QuaverServerCommonDll, build.QuaverSharedDll, timestamp, userId, cpuId, diskId, cpuDiskId)

if err != nil {
return err
}

rowsAffected, err := result.RowsAffected()

if err != nil {
return err
}

if rowsAffected > 0 {
return nil
}

query := "INSERT INTO login_hardware_ids " +
"(user_id, cpu_id, disk_id, cpu_disk_id, quaver_dll, quaver_api_dll, quaver_server_client_dll, quaver_server_common_dll, quaver_shared_dll, occurrences, timestamp) " +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"

_, err = SQL.Exec(query, userId, cpuId, diskId, cpuDiskId, build.QuaverDll, build.QuaverAPIDll,
build.QuaverServerClientDll, build.QuaverServerCommonDll, build.QuaverSharedDll, 1, timestamp)

if err != nil {
return err
}

return nil
}
82 changes: 68 additions & 14 deletions handlers/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ import (
"database/sql"
"encoding/base64"
"encoding/json"
"fmt"
"log"
"net"
"net/http"
"strconv"
"strings"

"example.com/Quaver/Z/chat"
"example.com/Quaver/Z/common"
"example.com/Quaver/Z/config"
Expand All @@ -12,13 +19,7 @@ import (
"example.com/Quaver/Z/sessions"
"example.com/Quaver/Z/utils"
"example.com/Quaver/Z/webhooks"
"fmt"
"github.com/go-resty/resty/v2"
"log"
"net"
"net/http"
"strconv"
"strings"
)

// LoginData The data that the user sends to log in
Expand All @@ -34,6 +35,15 @@ type LoginData struct {

// Game Client file signatures
Client string `json:"client"`

// Hardware string
Hardware string `json:"hw,omitempty"`
}

type HardwareIds struct {
CpuId string
DiskId string
CpuDiskId string
}

var (
Expand Down Expand Up @@ -75,7 +85,13 @@ func HandleLogin(conn net.Conn, r *http.Request) error {
return nil
}

err = verifyGameBuild(data)
build, err := parseGameBuild(data.Client)

if err != nil {
return err
}

err = verifyGameBuild(build)

if err != nil {
if err == sql.ErrNoRows {
Expand All @@ -87,6 +103,14 @@ func HandleLogin(conn net.Conn, r *http.Request) error {
}
}

hardware := parseHardwareIds(data.Hardware)

err = db.InsertLoginHardwareId(user.Id, hardware.CpuId, hardware.DiskId, hardware.CpuDiskId, build)

if err != nil {
return err
}

ip := conn.RemoteAddr().String()
ipHeader := r.Header.Get("X-Forwarded-For")

Expand Down Expand Up @@ -280,20 +304,49 @@ func checkSteamAppOwnership(steamId string) error {
return nil
}

// Checks the client signatures to see if the build they are using is valid
func verifyGameBuild(data *LoginData) error {
split := strings.Split(data.Client, "|")
func parseGameBuild(client string) (db.GameBuild, error) {
split := strings.Split(client, "|")

if len(split) != 5 {
return fmt.Errorf("user provided an incorrect amount of client signatures - %v", data.Client)
return db.GameBuild{}, fmt.Errorf("user provided an incorrect amount of client signatures - %v", client)
}

err := db.VerifyGameBuild(db.GameBuild{
return db.GameBuild{
QuaverDll: split[0],
QuaverAPIDll: split[1],
QuaverServerClientDll: split[2],
QuaverServerCommonDll: split[3],
QuaverSharedDll: split[4],
})
}, nil
}

func parseHardwareIds(hardware string) HardwareIds {
split := strings.Split(hardware, "|")

ids := HardwareIds{
CpuId: "none",
DiskId: "none",
CpuDiskId: "none",
}

if len(split) > 0 && split[0] != "" {
ids.CpuId = split[0]
}

if len(split) > 1 && split[1] != "" {
ids.DiskId = split[1]
}

if len(split) > 2 && split[2] != "" {
ids.CpuDiskId = split[2]
}

return ids
}

// Checks the client signatures to see if the build they are using is valid
func verifyGameBuild(build db.GameBuild) error {
err := db.VerifyGameBuild(build)

if err != nil {
return err
Expand Down Expand Up @@ -344,9 +397,10 @@ func handleCustomGameBuildUsage(conn net.Conn, user *db.User, client string) boo
}

clientStr := fmt.Sprintf("```json\n%v```", formatCustomGameBuild(client))
webhooks.SendAntiCheat(user.Username, user.Id, user.GetProfileUrl(), user.AvatarUrl.String, "Invalid Game Build", clientStr)

if !canUserUseCustomGameBuild(user) {
webhooks.SendAntiCheat(user.Username, user.Id, user.GetProfileUrl(), user.AvatarUrl.String, "Invalid Game Build", clientStr)

sessions.SendPacketToConnection(packets.NewServerNotificationError("Please update your client before attempting to login."), conn)
utils.CloseConnectionDelayed(conn)
return false
Expand Down
67 changes: 67 additions & 0 deletions handlers/login_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package handlers

import "testing"

func TestParseHardwareIds(t *testing.T) {
tests := []struct {
name string
hardware string
expectedCpu string
expectedDisk string
expectedCombo string
}{
{
name: "all values",
hardware: "cpu|disk|combo",
expectedCpu: "cpu",
expectedDisk: "disk",
expectedCombo: "combo",
},
{
name: "missing cpu",
hardware: "|disk|combo",
expectedCpu: "none",
expectedDisk: "disk",
expectedCombo: "combo",
},
{
name: "missing disk",
hardware: "cpu||combo",
expectedCpu: "cpu",
expectedDisk: "none",
expectedCombo: "combo",
},
{
name: "missing combo",
hardware: "cpu|disk",
expectedCpu: "cpu",
expectedDisk: "disk",
expectedCombo: "none",
},
{
name: "empty",
hardware: "",
expectedCpu: "none",
expectedDisk: "none",
expectedCombo: "none",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
hardware := parseHardwareIds(test.hardware)

if hardware.CpuId != test.expectedCpu {
t.Fatalf("expected cpu id %q, got %q", test.expectedCpu, hardware.CpuId)
}

if hardware.DiskId != test.expectedDisk {
t.Fatalf("expected disk id %q, got %q", test.expectedDisk, hardware.DiskId)
}

if hardware.CpuDiskId != test.expectedCombo {
t.Fatalf("expected cpu disk id %q, got %q", test.expectedCombo, hardware.CpuDiskId)
}
})
}
}
Loading