mirror of
https://github.com/Mezeporta/Erupe.git
synced 2025-12-14 07:55:33 +01:00
repository cleanup
This commit is contained in:
211
server/signserver/dbutils.go
Normal file
211
server/signserver/dbutils.go
Normal file
@@ -0,0 +1,211 @@
|
||||
package signserver
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func (s *Server) newUserChara(username string) error {
|
||||
var id int
|
||||
err := s.db.QueryRow("SELECT id FROM users WHERE username = $1", username).Scan(&id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var numNewChars int
|
||||
err = s.db.QueryRow("SELECT COUNT(*) FROM characters WHERE user_id = $1 AND is_new_character = true", id).Scan(&numNewChars)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// prevent users with an uninitialised character from creating more
|
||||
if numNewChars >= 1 {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.db.Exec(`
|
||||
INSERT INTO characters (
|
||||
user_id, is_female, is_new_character, name, unk_desc_string,
|
||||
hrp, gr, weapon_type, last_login)
|
||||
VALUES($1, False, True, '', '', 1, 0, 0, $2)`,
|
||||
id,
|
||||
uint32(time.Now().Unix()),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) registerDBAccount(username string, password string) error {
|
||||
// Create salted hash of user password
|
||||
passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.db.Exec("INSERT INTO users (username, password) VALUES ($1, $2)", username, string(passwordHash))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var id int
|
||||
err = s.db.QueryRow("SELECT id FROM users WHERE username = $1", username).Scan(&id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a base new character.
|
||||
_, err = s.db.Exec(`
|
||||
INSERT INTO characters (
|
||||
user_id, is_female, is_new_character, name, unk_desc_string,
|
||||
hrp, gr, weapon_type, last_login)
|
||||
VALUES($1, False, True, '', '', 1, 0, 0, $2)`,
|
||||
id,
|
||||
uint32(time.Now().Unix()),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type character struct {
|
||||
ID uint32 `db:"id"`
|
||||
IsFemale bool `db:"is_female"`
|
||||
IsNewCharacter bool `db:"is_new_character"`
|
||||
Name string `db:"name"`
|
||||
UnkDescString string `db:"unk_desc_string"`
|
||||
HRP uint16 `db:"hrp"`
|
||||
GR uint16 `db:"gr"`
|
||||
WeaponType uint16 `db:"weapon_type"`
|
||||
LastLogin uint32 `db:"last_login"`
|
||||
}
|
||||
|
||||
func (s *Server) getCharactersForUser(uid int) ([]character, error) {
|
||||
characters := []character{}
|
||||
err := s.db.Select(&characters, "SELECT id, is_female, is_new_character, name, unk_desc_string, hrp, gr, weapon_type, last_login FROM characters WHERE user_id = $1 AND deleted = false", uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return characters, nil
|
||||
}
|
||||
|
||||
func (s *Server) getLastCID(uid int) uint32 {
|
||||
var lastPlayed uint32
|
||||
_ = s.db.QueryRow("SELECT last_character FROM users WHERE id=$1", uid).Scan(&lastPlayed)
|
||||
return lastPlayed
|
||||
}
|
||||
|
||||
func (s *Server) getUserRights(uid int) uint32 {
|
||||
var rights uint32
|
||||
_ = s.db.QueryRow("SELECT rights FROM users WHERE id=$1", uid).Scan(&rights)
|
||||
return rights
|
||||
}
|
||||
|
||||
type members struct {
|
||||
CID uint32 // Local character ID
|
||||
ID uint32 `db:"id"`
|
||||
Name string `db:"name"`
|
||||
}
|
||||
|
||||
func (s *Server) getFriendsForCharacters(chars []character) []members {
|
||||
friends := make([]members, 0)
|
||||
for _, char := range chars {
|
||||
friendsCSV := ""
|
||||
err := s.db.QueryRow("SELECT friends FROM characters WHERE id=$1", char.ID).Scan(&friendsCSV)
|
||||
friendsSlice := strings.Split(friendsCSV, ",")
|
||||
friendQuery := "SELECT id, name FROM characters WHERE id="
|
||||
for i := 0; i < len(friendsSlice); i++ {
|
||||
friendQuery += friendsSlice[i]
|
||||
if i+1 != len(friendsSlice) {
|
||||
friendQuery += " OR id="
|
||||
}
|
||||
}
|
||||
charFriends := []members{}
|
||||
err = s.db.Select(&charFriends, friendQuery)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for i, _ := range charFriends {
|
||||
charFriends[i].CID = char.ID
|
||||
}
|
||||
friends = append(friends, charFriends...)
|
||||
}
|
||||
if len(friends) > 255 { // Uint8
|
||||
friends = friends[:255]
|
||||
}
|
||||
return friends
|
||||
}
|
||||
|
||||
func (s *Server) getGuildmatesForCharacters(chars []character) []members {
|
||||
guildmates := make([]members, 0)
|
||||
for _, char := range chars {
|
||||
var inGuild int
|
||||
_ = s.db.QueryRow("SELECT count(*) FROM guild_characters WHERE character_id=$1", char.ID).Scan(&inGuild)
|
||||
if inGuild > 0 {
|
||||
var guildID int
|
||||
err := s.db.QueryRow("SELECT guild_id FROM guild_characters WHERE character_id=$1", char.ID).Scan(&guildID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
charGuildmates := []members{}
|
||||
err = s.db.Select(&charGuildmates, "SELECT character_id AS id, c.name FROM guild_characters gc JOIN characters c ON c.id = gc.character_id WHERE guild_id=$1 AND character_id!=$2", guildID, char.ID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for i, _ := range charGuildmates {
|
||||
charGuildmates[i].CID = char.ID
|
||||
}
|
||||
guildmates = append(guildmates, charGuildmates...)
|
||||
}
|
||||
}
|
||||
if len(guildmates) > 255 { // Uint8
|
||||
guildmates = guildmates[:255]
|
||||
}
|
||||
return guildmates
|
||||
}
|
||||
|
||||
func (s *Server) deleteCharacter(cid int, token string) error {
|
||||
var verify int
|
||||
err := s.db.QueryRow("SELECT count(*) FROM sign_sessions WHERE token = $1", token).Scan(&verify)
|
||||
if err != nil {
|
||||
return err // Invalid token
|
||||
}
|
||||
var isNew bool
|
||||
err = s.db.QueryRow("SELECT is_new_character FROM characters WHERE id = $1", cid).Scan(&isNew)
|
||||
if isNew {
|
||||
_, err = s.db.Exec("DELETE FROM characters WHERE id = $1", cid)
|
||||
} else {
|
||||
_, err = s.db.Exec("UPDATE characters SET deleted = true WHERE id = $1", cid)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unused
|
||||
func (s *Server) checkToken(uid int) (bool, error) {
|
||||
var exists int
|
||||
err := s.db.QueryRow("SELECT count(*) FROM sign_sessions WHERE user_id = $1", uid).Scan(&exists)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if exists > 0 {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (s *Server) registerToken(uid int, token string) error {
|
||||
_, err := s.db.Exec("INSERT INTO sign_sessions (user_id, token) VALUES ($1, $2)", uid, token)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
154
server/signserver/dsgn_resp.go
Normal file
154
server/signserver/dsgn_resp.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package signserver
|
||||
|
||||
import (
|
||||
"erupe-ce/common/byteframe"
|
||||
ps "erupe-ce/common/pascalstring"
|
||||
"erupe-ce/common/stringsupport"
|
||||
"erupe-ce/server/channelserver"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func makeSignInFailureResp(respID RespID) []byte {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.WriteUint8(uint8(respID))
|
||||
return bf.Data()
|
||||
}
|
||||
|
||||
func randSeq(n int) string {
|
||||
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
b := make([]rune, n)
|
||||
for i := range b {
|
||||
b[i] = letters[rand.Intn(len(letters))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (s *Session) makeSignInResp(uid int) []byte {
|
||||
// Get the characters from the DB.
|
||||
chars, err := s.server.getCharactersForUser(uid)
|
||||
if err != nil {
|
||||
s.logger.Warn("Error getting characters from DB", zap.Error(err))
|
||||
}
|
||||
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
token := randSeq(16)
|
||||
s.server.registerToken(uid, token)
|
||||
|
||||
bf := byteframe.NewByteFrame()
|
||||
|
||||
bf.WriteUint8(1) // resp_code
|
||||
bf.WriteUint8(0) // file/patch server count
|
||||
bf.WriteUint8(1) // entrance server count
|
||||
bf.WriteUint8(uint8(len(chars))) // character count
|
||||
bf.WriteUint32(0xFFFFFFFF) // login_token_number
|
||||
bf.WriteBytes([]byte(token)) // login_token
|
||||
bf.WriteUint32(uint32(time.Now().Unix())) // current time
|
||||
ps.Uint8(bf, fmt.Sprintf("%s:%d", s.server.erupeConfig.HostIP, s.server.erupeConfig.Entrance.Port), false)
|
||||
|
||||
lastPlayed := uint32(0)
|
||||
for _, char := range chars {
|
||||
if lastPlayed == 0 {
|
||||
lastPlayed = char.ID
|
||||
}
|
||||
bf.WriteUint32(char.ID)
|
||||
|
||||
// Exp, HR[x] is split by 0, 1, 30, 50, 99, 299, 998, 999
|
||||
if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.MaxLauncherHR {
|
||||
bf.WriteUint16(999)
|
||||
} else {
|
||||
bf.WriteUint16(char.HRP)
|
||||
}
|
||||
|
||||
bf.WriteUint16(char.WeaponType) // Weapon, 0-13.
|
||||
bf.WriteUint32(char.LastLogin) // Last login date, unix timestamp in seconds.
|
||||
bf.WriteBool(char.IsFemale) // Sex, 0=male, 1=female.
|
||||
bf.WriteBool(char.IsNewCharacter) // Is new character, 1 replaces character name with ?????.
|
||||
bf.WriteUint8(0) // Old GR
|
||||
bf.WriteBool(true) // Use uint16 GR, no reason not to
|
||||
bf.WriteBytes(stringsupport.PaddedString(char.Name, 16, true)) // Character name
|
||||
bf.WriteBytes(stringsupport.PaddedString(char.UnkDescString, 32, false)) // unk str
|
||||
bf.WriteUint16(char.GR)
|
||||
bf.WriteUint16(0) // Unk
|
||||
}
|
||||
|
||||
friends := s.server.getFriendsForCharacters(chars)
|
||||
if len(friends) == 0 {
|
||||
bf.WriteUint8(0)
|
||||
} else {
|
||||
bf.WriteUint8(uint8(len(friends)))
|
||||
for _, friend := range friends {
|
||||
bf.WriteUint32(friend.CID)
|
||||
bf.WriteUint32(friend.ID)
|
||||
ps.Uint8(bf, friend.Name, true)
|
||||
}
|
||||
}
|
||||
|
||||
guildmates := s.server.getGuildmatesForCharacters(chars)
|
||||
if len(guildmates) == 0 {
|
||||
bf.WriteUint8(0)
|
||||
} else {
|
||||
bf.WriteUint8(uint8(len(guildmates)))
|
||||
for _, guildmate := range guildmates {
|
||||
bf.WriteUint32(guildmate.CID)
|
||||
bf.WriteUint32(guildmate.ID)
|
||||
ps.Uint8(bf, guildmate.Name, true)
|
||||
}
|
||||
}
|
||||
|
||||
bf.WriteUint8(1) // Notice count
|
||||
noticeText := "<BODY><CENTER><SIZE_3><C_4>Welcome to Erupe SU9 Beta 2!<BR><BODY><LEFT><SIZE_2><C_5>Erupe is experimental software<C_7>, we are not liable for any<BR><BODY>issues caused by installing the software!<BR><BODY><BR><BODY><C_4>■Report bugs on Discord!<C_7><BR><BODY><BR><BODY><C_4>■Test everything!<C_7><BR><BODY><BR><BODY><C_4>■Don't talk to softlocking NPCs!<C_7><BR><BODY><BR><BODY><C_4>■Fork the code on GitHub!<C_7><BR><BODY><BR><BODY>Thank you to all of the contributors,<BR><BODY><BR><BODY>this wouldn't exist without you."
|
||||
ps.Uint32(bf, noticeText, true)
|
||||
|
||||
bf.WriteUint32(s.server.getLastCID(uid))
|
||||
bf.WriteUint32(s.server.getUserRights(uid))
|
||||
ps.Uint16(bf, "", false) // filters
|
||||
bf.WriteUint32(0xCA104E20)
|
||||
ps.Uint16(bf, "", false) // encryption
|
||||
bf.WriteUint8(0x00)
|
||||
bf.WriteUint32(0xCA110001)
|
||||
bf.WriteUint32(0x4E200000)
|
||||
|
||||
returning := false
|
||||
// return course end time
|
||||
if returning {
|
||||
bf.WriteUint32(uint32(channelserver.Time_Current_Adjusted().Add(30 * 24 * time.Hour).Unix()))
|
||||
} else {
|
||||
bf.WriteUint32(0)
|
||||
}
|
||||
|
||||
bf.WriteUint32(0x00000000)
|
||||
bf.WriteUint32(0x0A5197DF)
|
||||
|
||||
mezfes := s.server.erupeConfig.DevModeOptions.MezFesEvent
|
||||
alt := false
|
||||
if mezfes {
|
||||
// Start time
|
||||
bf.WriteUint32(uint32(channelserver.Time_Current_Adjusted().Add(-5 * time.Minute).Unix()))
|
||||
// End time
|
||||
bf.WriteUint32(uint32(channelserver.Time_Current_Adjusted().Add(24 * time.Hour * 7).Unix()))
|
||||
bf.WriteUint8(2) // Unk
|
||||
bf.WriteUint32(20) // Single tickets
|
||||
bf.WriteUint32(0) // Group tickets
|
||||
bf.WriteUint8(8) // Stalls open
|
||||
bf.WriteUint8(0xA) // Unk
|
||||
bf.WriteUint8(0x3) // Pachinko
|
||||
bf.WriteUint8(0x6) // Nyanrendo
|
||||
bf.WriteUint8(0x9) // Point stall
|
||||
if alt {
|
||||
bf.WriteUint8(0x2) // Tokotoko
|
||||
} else {
|
||||
bf.WriteUint8(0x4) // Volpakkun
|
||||
}
|
||||
bf.WriteUint8(0x8) // Battle cats
|
||||
bf.WriteUint8(0x5) // Gook
|
||||
bf.WriteUint8(0x7) // Honey
|
||||
} else {
|
||||
bf.WriteUint32(0)
|
||||
bf.WriteUint32(0)
|
||||
}
|
||||
return bf.Data()
|
||||
}
|
||||
51
server/signserver/respid.go
Normal file
51
server/signserver/respid.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package signserver
|
||||
|
||||
//revive:disable
|
||||
|
||||
type RespID uint16
|
||||
|
||||
//go:generate stringer -type=RespID
|
||||
const (
|
||||
SIGN_UNKNOWN RespID = iota
|
||||
SIGN_SUCCESS
|
||||
SIGN_EFAILED // Authentication server communication failed
|
||||
SIGN_EILLEGAL // Incorrect input, authentication has been suspended
|
||||
SIGN_EALERT // Authentication server process error
|
||||
SIGN_EABORT // The internal procedure of the authentication server ended abnormally
|
||||
SIGN_ERESPONSE // Procedure terminated due to abnormal certification report
|
||||
SIGN_EDATABASE // Database connection failed
|
||||
SIGN_EABSENCE
|
||||
SIGN_ERESIGN
|
||||
SIGN_ESUSPEND_D
|
||||
SIGN_ELOCK
|
||||
SIGN_EPASS
|
||||
SIGN_ERIGHT
|
||||
SIGN_EAUTH
|
||||
SIGN_ESUSPEND // This account is temporarily suspended. Please contact customer service for details
|
||||
SIGN_EELIMINATE // This account is permanently suspended. Please contact customer service for details
|
||||
SIGN_ECLOSE
|
||||
SIGN_ECLOSE_EX // Login process is congested. <br> Please try to sign in again later
|
||||
SIGN_EINTERVAL
|
||||
SIGN_EMOVED
|
||||
SIGN_ENOTREADY
|
||||
SIGN_EALREADY
|
||||
SIGN_EIPADDR // Region block because of IP address.
|
||||
SIGN_EHANGAME
|
||||
SIGN_UPD_ONLY
|
||||
SIGN_EMBID
|
||||
SIGN_ECOGCODE
|
||||
SIGN_ETOKEN
|
||||
SIGN_ECOGLINK
|
||||
SIGN_EMAINTE
|
||||
SIGN_EMAINTE_NOUPDATE
|
||||
|
||||
// Couldn't find names for the following:
|
||||
UNK_32
|
||||
UNK_33
|
||||
UNK_34
|
||||
UNK_35
|
||||
|
||||
SIGN_XBRESPONSE
|
||||
SIGN_EPSI
|
||||
SIGN_EMBID_PSI
|
||||
)
|
||||
163
server/signserver/session.go
Normal file
163
server/signserver/session.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package signserver
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// Session holds state for the sign server connection.
|
||||
type Session struct {
|
||||
sync.Mutex
|
||||
logger *zap.Logger
|
||||
sid int
|
||||
server *Server
|
||||
rawConn *net.Conn
|
||||
cryptConn *network.CryptConn
|
||||
}
|
||||
|
||||
func (s *Session) fail() {
|
||||
s.server.Lock()
|
||||
delete(s.server.sessions, s.sid)
|
||||
s.server.Unlock()
|
||||
|
||||
}
|
||||
|
||||
func (s *Session) work() {
|
||||
for {
|
||||
pkt, err := s.cryptConn.ReadPacket()
|
||||
if err != nil {
|
||||
s.fail()
|
||||
return
|
||||
}
|
||||
|
||||
err = s.handlePacket(pkt)
|
||||
if err != nil {
|
||||
s.fail()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Session) handlePacket(pkt []byte) error {
|
||||
sugar := s.logger.Sugar()
|
||||
|
||||
bf := byteframe.NewByteFrameFromBytes(pkt)
|
||||
reqType := string(bf.ReadNullTerminatedBytes())
|
||||
switch reqType {
|
||||
case "DLTSKEYSIGN:100":
|
||||
fallthrough
|
||||
case "DSGN:100":
|
||||
err := s.handleDSGNRequest(bf)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
case "DELETE:100":
|
||||
loginTokenString := string(bf.ReadNullTerminatedBytes())
|
||||
characterID := int(bf.ReadUint32())
|
||||
s.server.deleteCharacter(characterID, loginTokenString)
|
||||
sugar.Infof("Deleted character ID: %v\n", characterID)
|
||||
err := s.cryptConn.SendPacket([]byte{0x01}) // DEL_SUCCESS
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
sugar.Infof("Got unknown request type %s, data:\n%s\n", reqType, hex.Dump(bf.DataFromCurrent()))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) handleDSGNRequest(bf *byteframe.ByteFrame) error {
|
||||
|
||||
reqUsername := string(bf.ReadNullTerminatedBytes())
|
||||
reqPassword := string(bf.ReadNullTerminatedBytes())
|
||||
reqUnk := string(bf.ReadNullTerminatedBytes())
|
||||
|
||||
s.server.logger.Info(
|
||||
"Got sign in request",
|
||||
zap.String("reqUsername", reqUsername),
|
||||
zap.String("reqPassword", reqPassword),
|
||||
zap.String("reqUnk", reqUnk),
|
||||
)
|
||||
|
||||
newCharaReq := false
|
||||
|
||||
if reqUsername[len(reqUsername)-1] == 43 { // '+'
|
||||
reqUsername = reqUsername[:len(reqUsername)-1]
|
||||
newCharaReq = true
|
||||
}
|
||||
|
||||
var (
|
||||
id int
|
||||
password string
|
||||
)
|
||||
err := s.server.db.QueryRow("SELECT id, password FROM users WHERE username = $1", reqUsername).Scan(&id, &password)
|
||||
var serverRespBytes []byte
|
||||
switch {
|
||||
case err == sql.ErrNoRows:
|
||||
s.logger.Info("Account not found", zap.String("reqUsername", reqUsername))
|
||||
serverRespBytes = makeSignInFailureResp(SIGN_EAUTH)
|
||||
|
||||
// HACK(Andoryuuta): Create a new account if it doesn't exit.
|
||||
s.logger.Info("Creating account", zap.String("reqUsername", reqUsername), zap.String("reqPassword", reqPassword))
|
||||
err = s.server.registerDBAccount(reqUsername, reqPassword)
|
||||
if err != nil {
|
||||
s.logger.Info("Error on creating new account", zap.Error(err))
|
||||
serverRespBytes = makeSignInFailureResp(SIGN_EABORT)
|
||||
break
|
||||
}
|
||||
|
||||
var id int
|
||||
err = s.server.db.QueryRow("SELECT id FROM users WHERE username = $1", reqUsername).Scan(&id)
|
||||
if err != nil {
|
||||
s.logger.Info("Error on querying account id", zap.Error(err))
|
||||
serverRespBytes = makeSignInFailureResp(SIGN_EABORT)
|
||||
break
|
||||
}
|
||||
|
||||
serverRespBytes = s.makeSignInResp(id)
|
||||
break
|
||||
case err != nil:
|
||||
serverRespBytes = makeSignInFailureResp(SIGN_EABORT)
|
||||
s.logger.Warn("Got error on SQL query", zap.Error(err))
|
||||
break
|
||||
default:
|
||||
if bcrypt.CompareHashAndPassword([]byte(password), []byte(reqPassword)) == nil {
|
||||
s.logger.Info("Passwords match!")
|
||||
if newCharaReq {
|
||||
err = s.server.newUserChara(reqUsername)
|
||||
if err != nil {
|
||||
s.logger.Info("Error on adding new character to account", zap.Error(err))
|
||||
serverRespBytes = makeSignInFailureResp(SIGN_EABORT)
|
||||
break
|
||||
}
|
||||
}
|
||||
// TODO: Need to auto delete user tokens after inactivity
|
||||
// exists, err := s.server.checkToken(id)
|
||||
// if err != nil {
|
||||
// s.logger.Info("Error checking for live tokens", zap.Error(err))
|
||||
// serverRespBytes = makeSignInFailureResp(SIGN_EABORT)
|
||||
// break
|
||||
// }
|
||||
serverRespBytes = s.makeSignInResp(id)
|
||||
} else {
|
||||
s.logger.Info("Passwords don't match!")
|
||||
serverRespBytes = makeSignInFailureResp(SIGN_EPASS)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
err = s.cryptConn.SendPacket(serverRespBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
119
server/signserver/sign_server.go
Normal file
119
server/signserver/sign_server.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package signserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"erupe-ce/config"
|
||||
"erupe-ce/network"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// Config struct allows configuring the server.
|
||||
type Config struct {
|
||||
Logger *zap.Logger
|
||||
DB *sqlx.DB
|
||||
ErupeConfig *config.Config
|
||||
}
|
||||
|
||||
// Server is a MHF sign server.
|
||||
type Server struct {
|
||||
sync.Mutex
|
||||
logger *zap.Logger
|
||||
erupeConfig *config.Config
|
||||
sid int
|
||||
sessions map[int]*Session
|
||||
db *sqlx.DB
|
||||
listener net.Listener
|
||||
isShuttingDown bool
|
||||
}
|
||||
|
||||
// NewServer creates a new Server type.
|
||||
func NewServer(config *Config) *Server {
|
||||
s := &Server{
|
||||
logger: config.Logger,
|
||||
erupeConfig: config.ErupeConfig,
|
||||
sid: 0,
|
||||
sessions: make(map[int]*Session),
|
||||
db: config.DB,
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Start starts the server in a new goroutine.
|
||||
func (s *Server) Start() error {
|
||||
l, err := net.Listen("tcp", fmt.Sprintf(":%d", s.erupeConfig.Sign.Port))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.listener = l
|
||||
|
||||
go s.acceptClients()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shutdown exits the server gracefully.
|
||||
func (s *Server) Shutdown() {
|
||||
s.logger.Debug("Shutting down")
|
||||
|
||||
s.Lock()
|
||||
s.isShuttingDown = true
|
||||
s.Unlock()
|
||||
|
||||
// This will cause the acceptor goroutine to error and exit gracefully.
|
||||
s.listener.Close()
|
||||
}
|
||||
|
||||
func (s *Server) acceptClients() {
|
||||
for {
|
||||
conn, err := s.listener.Accept()
|
||||
if err != nil {
|
||||
// Check if we are shutting down and exit gracefully if so.
|
||||
s.Lock()
|
||||
shutdown := s.isShuttingDown
|
||||
s.Unlock()
|
||||
|
||||
if shutdown {
|
||||
break
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
go s.handleConnection(s.sid, conn)
|
||||
s.sid++
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) handleConnection(sid int, conn net.Conn) {
|
||||
s.logger.Info("Got connection to sign server", zap.String("remoteaddr", conn.RemoteAddr().String()))
|
||||
|
||||
// Client initalizes the connection with a one-time buffer of 8 NULL bytes.
|
||||
nullInit := make([]byte, 8)
|
||||
_, err := io.ReadFull(conn, nullInit)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
// Create a new session.
|
||||
session := &Session{
|
||||
logger: s.logger,
|
||||
server: s,
|
||||
rawConn: &conn,
|
||||
cryptConn: network.NewCryptConn(conn),
|
||||
}
|
||||
|
||||
// Add the session to the server's sessions map.
|
||||
s.Lock()
|
||||
s.sessions[sid] = session
|
||||
s.Unlock()
|
||||
|
||||
// Do the session's work.
|
||||
session.work()
|
||||
}
|
||||
Reference in New Issue
Block a user