Files
Erupe/server/signserver/session.go
2020-01-19 12:52:57 -05:00

140 lines
3.4 KiB
Go

package signserver
import (
"database/sql"
"encoding/hex"
"net"
"sync"
"github.com/Andoryuuta/Erupe/network"
"github.com/Andoryuuta/byteframe"
"go.uber.org/zap"
)
// 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())
_ = loginTokenString
characterID := bf.ReadUint32()
sugar.Infof("Got delete request for character ID: %v\n", characterID)
sugar.Infof("remaining unknown data:\n%s\n", hex.Dump(bf.DataFromCurrent()))
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),
)
// TODO(Andoryuuta): remove plaintext password storage if this ever becomes more than a toy project.
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 reqPassword == password {
s.logger.Info("Passwords match!")
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
}