mirror of
https://github.com/Mezeporta/Erupe.git
synced 2025-12-15 08:25:09 +01:00
Merge pull request #79 from ZeruLight/feature/psn-link
feature/psn-link
This commit is contained in:
11
patch-schema/psn-link.sql
Normal file
11
patch-schema/psn-link.sql
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
BEGIN;
|
||||||
|
|
||||||
|
ALTER TABLE public.sign_sessions ADD COLUMN id SERIAL;
|
||||||
|
|
||||||
|
ALTER TABLE public.sign_sessions ADD CONSTRAINT sign_sessions_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
ALTER TABLE public.sign_sessions ALTER COLUMN user_id DROP NOT NULL;
|
||||||
|
|
||||||
|
ALTER TABLE public.sign_sessions ADD COLUMN psn_id TEXT;
|
||||||
|
|
||||||
|
END;
|
||||||
@@ -89,9 +89,15 @@ func parseChatCommand(s *Session, command string) {
|
|||||||
if err != nil || n != 1 {
|
if err != nil || n != 1 {
|
||||||
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandPSNError"], commands["PSN"].Prefix))
|
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandPSNError"], commands["PSN"].Prefix))
|
||||||
} else {
|
} else {
|
||||||
_, err = s.server.db.Exec(`UPDATE users u SET psn_id=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, id, s.charID)
|
var exists int
|
||||||
if err == nil {
|
s.server.db.QueryRow(`SELECT count(*) FROM users WHERE psn_id = $1`, id).Scan(&exists)
|
||||||
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandPSNSuccess"], id))
|
if exists == 0 {
|
||||||
|
_, err = s.server.db.Exec(`UPDATE users u SET psn_id=$1 WHERE u.id=(SELECT c.user_id FROM characters c WHERE c.id=$2)`, id, s.charID)
|
||||||
|
if err == nil {
|
||||||
|
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandPSNSuccess"], id))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sendServerChatMessage(s, s.server.dict["commandPSNExists"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ func getLangStrings(s *Server) map[string]string {
|
|||||||
strings["commandTeleportSuccess"] = "%d %dにテレポート"
|
strings["commandTeleportSuccess"] = "%d %dにテレポート"
|
||||||
strings["commandPSNError"] = "PSN連携コマンドエラー 例:%s <psn id>"
|
strings["commandPSNError"] = "PSN連携コマンドエラー 例:%s <psn id>"
|
||||||
strings["commandPSNSuccess"] = "PSN「%s」が連携されています"
|
strings["commandPSNSuccess"] = "PSN「%s」が連携されています"
|
||||||
|
strings["commandPSNExists"] = "PSNは既存のユーザに接続されています"
|
||||||
|
|
||||||
strings["commandRaviNoCommand"] = "ラヴィコマンドが指定されていません"
|
strings["commandRaviNoCommand"] = "ラヴィコマンドが指定されていません"
|
||||||
strings["commandRaviStartSuccess"] = "大討伐を開始します"
|
strings["commandRaviStartSuccess"] = "大討伐を開始します"
|
||||||
@@ -72,6 +73,7 @@ func getLangStrings(s *Server) map[string]string {
|
|||||||
strings["commandTeleportSuccess"] = "Teleporting to %d %d"
|
strings["commandTeleportSuccess"] = "Teleporting to %d %d"
|
||||||
strings["commandPSNError"] = "Error in command. Format: %s <psn id>"
|
strings["commandPSNError"] = "Error in command. Format: %s <psn id>"
|
||||||
strings["commandPSNSuccess"] = "Connected PSN ID: %s"
|
strings["commandPSNSuccess"] = "Connected PSN ID: %s"
|
||||||
|
strings["commandPSNExists"] = "PSN ID is connected to another account!"
|
||||||
|
|
||||||
strings["commandRaviNoCommand"] = "No Raviente command specified!"
|
strings["commandRaviNoCommand"] = "No Raviente command specified!"
|
||||||
strings["commandRaviStartSuccess"] = "The Great Slaying will begin in a moment"
|
strings["commandRaviStartSuccess"] = "The Great Slaying will begin in a moment"
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
package signserver
|
package signserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
"erupe-ce/common/mhfcourse"
|
"erupe-ce/common/mhfcourse"
|
||||||
|
"erupe-ce/common/token"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) newUserChara(uid int) error {
|
func (s *Server) newUserChara(uid uint32) error {
|
||||||
var numNewChars int
|
var numNewChars int
|
||||||
err := s.db.QueryRow("SELECT COUNT(*) FROM characters WHERE user_id = $1 AND is_new_character = true", uid).Scan(&numNewChars)
|
err := s.db.QueryRow("SELECT COUNT(*) FROM characters WHERE user_id = $1 AND is_new_character = true", uid).Scan(&numNewChars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -35,20 +39,22 @@ func (s *Server) newUserChara(uid int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) registerDBAccount(username string, password string) (int, error) {
|
func (s *Server) registerDBAccount(username string, password string) (uint32, error) {
|
||||||
|
var uid uint32
|
||||||
|
s.logger.Info("Creating user", zap.String("User", username))
|
||||||
|
|
||||||
// Create salted hash of user password
|
// Create salted hash of user password
|
||||||
passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
passwordHash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var id int
|
err = s.db.QueryRow("INSERT INTO users (username, password, return_expires) VALUES ($1, $2, $3) RETURNING id", username, string(passwordHash), time.Now().Add(time.Hour*24*30)).Scan(&uid)
|
||||||
err = s.db.QueryRow("INSERT INTO users (username, password, return_expires) VALUES ($1, $2, $3) RETURNING id", username, string(passwordHash), time.Now().Add(time.Hour*24*30)).Scan(&id)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return id, nil
|
return uid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type character struct {
|
type character struct {
|
||||||
@@ -63,7 +69,7 @@ type character struct {
|
|||||||
LastLogin uint32 `db:"last_login"`
|
LastLogin uint32 `db:"last_login"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getCharactersForUser(uid int) ([]character, error) {
|
func (s *Server) getCharactersForUser(uid uint32) ([]character, error) {
|
||||||
characters := make([]character, 0)
|
characters := make([]character, 0)
|
||||||
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 ORDER BY id", uid)
|
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 ORDER BY id", uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -72,7 +78,7 @@ func (s *Server) getCharactersForUser(uid int) ([]character, error) {
|
|||||||
return characters, nil
|
return characters, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getReturnExpiry(uid int) time.Time {
|
func (s *Server) getReturnExpiry(uid uint32) time.Time {
|
||||||
var returnExpiry, lastLogin time.Time
|
var returnExpiry, lastLogin time.Time
|
||||||
s.db.Get(&lastLogin, "SELECT COALESCE(last_login, now()) FROM users WHERE id=$1", uid)
|
s.db.Get(&lastLogin, "SELECT COALESCE(last_login, now()) FROM users WHERE id=$1", uid)
|
||||||
if time.Now().Add((time.Hour * 24) * -90).After(lastLogin) {
|
if time.Now().Add((time.Hour * 24) * -90).After(lastLogin) {
|
||||||
@@ -89,16 +95,18 @@ func (s *Server) getReturnExpiry(uid int) time.Time {
|
|||||||
return returnExpiry
|
return returnExpiry
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getLastCID(uid int) uint32 {
|
func (s *Server) getLastCID(uid uint32) uint32 {
|
||||||
var lastPlayed uint32
|
var lastPlayed uint32
|
||||||
_ = s.db.QueryRow("SELECT last_character FROM users WHERE id=$1", uid).Scan(&lastPlayed)
|
_ = s.db.QueryRow("SELECT last_character FROM users WHERE id=$1", uid).Scan(&lastPlayed)
|
||||||
return lastPlayed
|
return lastPlayed
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getUserRights(uid int) uint32 {
|
func (s *Server) getUserRights(uid uint32) uint32 {
|
||||||
rights := uint32(2)
|
var rights uint32
|
||||||
_ = s.db.QueryRow("SELECT rights FROM users WHERE id=$1", uid).Scan(&rights)
|
if uid != 0 {
|
||||||
_, rights = mhfcourse.GetCourseStruct(rights)
|
_ = s.db.QueryRow("SELECT rights FROM users WHERE id=$1", uid).Scan(&rights)
|
||||||
|
_, rights = mhfcourse.GetCourseStruct(rights)
|
||||||
|
}
|
||||||
return rights
|
return rights
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,14 +167,12 @@ func (s *Server) getGuildmatesForCharacters(chars []character) []members {
|
|||||||
return guildmates
|
return guildmates
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) deleteCharacter(cid int, token string) error {
|
func (s *Server) deleteCharacter(cid int, token string, tokenID uint32) error {
|
||||||
var verify int
|
if !s.validateToken(token, tokenID) {
|
||||||
err := s.db.QueryRow("SELECT count(*) FROM sign_sessions WHERE token = $1", token).Scan(&verify)
|
return errors.New("invalid token")
|
||||||
if err != nil {
|
|
||||||
return err // Invalid token
|
|
||||||
}
|
}
|
||||||
var isNew bool
|
var isNew bool
|
||||||
err = s.db.QueryRow("SELECT is_new_character FROM characters WHERE id = $1", cid).Scan(&isNew)
|
err := s.db.QueryRow("SELECT is_new_character FROM characters WHERE id = $1", cid).Scan(&isNew)
|
||||||
if isNew {
|
if isNew {
|
||||||
_, err = s.db.Exec("DELETE FROM characters WHERE id = $1", cid)
|
_, err = s.db.Exec("DELETE FROM characters WHERE id = $1", cid)
|
||||||
} else {
|
} else {
|
||||||
@@ -179,7 +185,7 @@ func (s *Server) deleteCharacter(cid int, token string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unused
|
// Unused
|
||||||
func (s *Server) checkToken(uid int) (bool, error) {
|
func (s *Server) checkToken(uid uint32) (bool, error) {
|
||||||
var exists int
|
var exists int
|
||||||
err := s.db.QueryRow("SELECT count(*) FROM sign_sessions WHERE user_id = $1", uid).Scan(&exists)
|
err := s.db.QueryRow("SELECT count(*) FROM sign_sessions WHERE user_id = $1", uid).Scan(&exists)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -191,10 +197,55 @@ func (s *Server) checkToken(uid int) (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) registerToken(uid int, token string) error {
|
func (s *Server) registerUidToken(uid uint32) (uint32, string, error) {
|
||||||
_, err := s.db.Exec("INSERT INTO sign_sessions (user_id, token) VALUES ($1, $2)", uid, token)
|
token := token.Generate(16)
|
||||||
if err != nil {
|
var tid uint32
|
||||||
return err
|
err := s.db.QueryRow(`INSERT INTO sign_sessions (user_id, token) VALUES ($1, $2) RETURNING id`, uid, token).Scan(&tid)
|
||||||
}
|
return tid, token, err
|
||||||
return nil
|
}
|
||||||
|
|
||||||
|
func (s *Server) registerPsnToken(psn string) (uint32, string, error) {
|
||||||
|
token := token.Generate(16)
|
||||||
|
var tid uint32
|
||||||
|
err := s.db.QueryRow(`INSERT INTO sign_sessions (psn_id, token) VALUES ($1, $2) RETURNING id`, psn, token).Scan(&tid)
|
||||||
|
return tid, token, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) validateToken(token string, tokenID uint32) bool {
|
||||||
|
query := `SELECT count(*) FROM sign_sessions WHERE token = $1`
|
||||||
|
if tokenID > 0 {
|
||||||
|
query += ` AND id = $2`
|
||||||
|
}
|
||||||
|
var exists int
|
||||||
|
err := s.db.QueryRow(query, token, tokenID).Scan(&exists)
|
||||||
|
if err != nil || exists == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) validateLogin(user string, pass string) (uint32, RespID) {
|
||||||
|
var uid uint32
|
||||||
|
var passDB string
|
||||||
|
err := s.db.QueryRow(`SELECT id, password FROM users WHERE username = $1`, user).Scan(&uid, &passDB)
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
s.logger.Info("User not found", zap.String("User", user))
|
||||||
|
if s.erupeConfig.DevMode && s.erupeConfig.DevModeOptions.AutoCreateAccount {
|
||||||
|
uid, err = s.registerDBAccount(user, pass)
|
||||||
|
if err == nil {
|
||||||
|
return uid, SIGN_SUCCESS
|
||||||
|
} else {
|
||||||
|
return 0, SIGN_EABORT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, SIGN_EAUTH
|
||||||
|
}
|
||||||
|
return 0, SIGN_EABORT
|
||||||
|
} else {
|
||||||
|
if bcrypt.CompareHashAndPassword([]byte(passDB), []byte(pass)) == nil {
|
||||||
|
return uid, SIGN_SUCCESS
|
||||||
|
}
|
||||||
|
return 0, SIGN_EPASS
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
ps "erupe-ce/common/pascalstring"
|
ps "erupe-ce/common/pascalstring"
|
||||||
"erupe-ce/common/stringsupport"
|
"erupe-ce/common/stringsupport"
|
||||||
"erupe-ce/common/token"
|
|
||||||
_config "erupe-ce/config"
|
_config "erupe-ce/config"
|
||||||
"erupe-ce/server/channelserver"
|
"erupe-ce/server/channelserver"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -12,10 +11,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Session) makeSignResponse(uid int) []byte {
|
func (s *Session) makeSignResponse(uid uint32) []byte {
|
||||||
// Get the characters from the DB.
|
// Get the characters from the DB.
|
||||||
chars, err := s.server.getCharactersForUser(uid)
|
chars, err := s.server.getCharactersForUser(uid)
|
||||||
if len(chars) == 0 {
|
if len(chars) == 0 && uid != 0 {
|
||||||
err = s.server.newUserChara(uid)
|
err = s.server.newUserChara(uid)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
chars, err = s.server.getCharactersForUser(uid)
|
chars, err = s.server.getCharactersForUser(uid)
|
||||||
@@ -25,10 +24,18 @@ func (s *Session) makeSignResponse(uid int) []byte {
|
|||||||
s.logger.Warn("Error getting characters from DB", zap.Error(err))
|
s.logger.Warn("Error getting characters from DB", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
sessToken := token.Generate(16)
|
|
||||||
_ = s.server.registerToken(uid, sessToken)
|
|
||||||
|
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
|
var tokenID uint32
|
||||||
|
var sessToken string
|
||||||
|
if uid == 0 && s.psn != "" {
|
||||||
|
tokenID, sessToken, err = s.server.registerPsnToken(s.psn)
|
||||||
|
} else {
|
||||||
|
tokenID, sessToken, err = s.server.registerUidToken(uid)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
bf.WriteUint8(uint8(SIGN_EABORT))
|
||||||
|
return bf.Data()
|
||||||
|
}
|
||||||
|
|
||||||
bf.WriteUint8(uint8(SIGN_SUCCESS)) // resp_code
|
bf.WriteUint8(uint8(SIGN_SUCCESS)) // resp_code
|
||||||
if (s.server.erupeConfig.PatchServerManifest != "" && s.server.erupeConfig.PatchServerFile != "") || s.client == PS3 {
|
if (s.server.erupeConfig.PatchServerManifest != "" && s.server.erupeConfig.PatchServerFile != "") || s.client == PS3 {
|
||||||
@@ -38,7 +45,7 @@ func (s *Session) makeSignResponse(uid int) []byte {
|
|||||||
}
|
}
|
||||||
bf.WriteUint8(1) // entrance server count
|
bf.WriteUint8(1) // entrance server count
|
||||||
bf.WriteUint8(uint8(len(chars)))
|
bf.WriteUint8(uint8(len(chars)))
|
||||||
bf.WriteUint32(0xFFFFFFFF) // login_token_number
|
bf.WriteUint32(tokenID)
|
||||||
bf.WriteBytes([]byte(sessToken))
|
bf.WriteBytes([]byte(sessToken))
|
||||||
bf.WriteUint32(uint32(channelserver.TimeAdjusted().Unix()))
|
bf.WriteUint32(uint32(channelserver.TimeAdjusted().Unix()))
|
||||||
if s.client == PS3 {
|
if s.client == PS3 {
|
||||||
|
|||||||
@@ -3,20 +3,21 @@ package signserver
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"erupe-ce/common/stringsupport"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"erupe-ce/common/byteframe"
|
"erupe-ce/common/byteframe"
|
||||||
"erupe-ce/network"
|
"erupe-ce/network"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Client int
|
type client int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PC100 Client = iota
|
PC100 client = iota
|
||||||
VITA
|
VITA
|
||||||
PS3
|
PS3
|
||||||
WIIU
|
WIIU
|
||||||
@@ -29,7 +30,8 @@ type Session struct {
|
|||||||
server *Server
|
server *Server
|
||||||
rawConn net.Conn
|
rawConn net.Conn
|
||||||
cryptConn *network.CryptConn
|
cryptConn *network.CryptConn
|
||||||
client Client
|
client client
|
||||||
|
psn string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Session) work() {
|
func (s *Session) work() {
|
||||||
@@ -51,23 +53,25 @@ func (s *Session) work() {
|
|||||||
func (s *Session) handlePacket(pkt []byte) error {
|
func (s *Session) handlePacket(pkt []byte) error {
|
||||||
bf := byteframe.NewByteFrameFromBytes(pkt)
|
bf := byteframe.NewByteFrameFromBytes(pkt)
|
||||||
reqType := string(bf.ReadNullTerminatedBytes())
|
reqType := string(bf.ReadNullTerminatedBytes())
|
||||||
switch reqType {
|
switch reqType[:len(reqType)-3] {
|
||||||
case "DLTSKEYSIGN:100", "DSGN:100":
|
case "DLTSKEYSIGN:", "DSGN:":
|
||||||
s.handleDSGN(bf)
|
s.handleDSGN(bf)
|
||||||
case "PS3SGN:100":
|
case "PS3SGN:":
|
||||||
s.client = PS3
|
s.client = PS3
|
||||||
s.handlePSSGN(bf)
|
s.handlePSSGN(bf)
|
||||||
case "VITASGN:100", "VITASGN:000":
|
case "VITASGN:":
|
||||||
s.client = VITA
|
s.client = VITA
|
||||||
s.handlePSSGN(bf)
|
s.handlePSSGN(bf)
|
||||||
case "WIIUSGN:100", "WIIUSGN:000":
|
case "WIIUSGN:":
|
||||||
s.client = WIIU
|
s.client = WIIU
|
||||||
s.handleWIIUSGN(bf)
|
s.handleWIIUSGN(bf)
|
||||||
case "DELETE:100":
|
case "VITACOGLNK:", "COGLNK:":
|
||||||
loginTokenString := string(bf.ReadNullTerminatedBytes())
|
s.handlePSNLink(bf)
|
||||||
|
case "DELETE:":
|
||||||
|
token := string(bf.ReadNullTerminatedBytes())
|
||||||
characterID := int(bf.ReadUint32())
|
characterID := int(bf.ReadUint32())
|
||||||
_ = int(bf.ReadUint32()) // login_token_number
|
tokenID := bf.ReadUint32()
|
||||||
err := s.server.deleteCharacter(characterID, loginTokenString)
|
err := s.server.deleteCharacter(characterID, token, tokenID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
s.logger.Info("Deleted character", zap.Int("CharacterID", characterID))
|
s.logger.Info("Deleted character", zap.Int("CharacterID", characterID))
|
||||||
s.cryptConn.SendPacket([]byte{0x01}) // DEL_SUCCESS
|
s.cryptConn.SendPacket([]byte{0x01}) // DEL_SUCCESS
|
||||||
@@ -83,104 +87,117 @@ func (s *Session) handlePacket(pkt []byte) error {
|
|||||||
|
|
||||||
func (s *Session) authenticate(username string, password string) {
|
func (s *Session) authenticate(username string, password string) {
|
||||||
newCharaReq := false
|
newCharaReq := false
|
||||||
|
|
||||||
if username[len(username)-1] == 43 { // '+'
|
if username[len(username)-1] == 43 { // '+'
|
||||||
username = username[:len(username)-1]
|
username = username[:len(username)-1]
|
||||||
newCharaReq = true
|
newCharaReq = true
|
||||||
}
|
}
|
||||||
|
|
||||||
var id int
|
|
||||||
var hash string
|
|
||||||
bf := byteframe.NewByteFrame()
|
bf := byteframe.NewByteFrame()
|
||||||
|
uid, resp := s.server.validateLogin(username, password)
|
||||||
err := s.server.db.QueryRow("SELECT id, password FROM users WHERE username = $1", username).Scan(&id, &hash)
|
switch resp {
|
||||||
switch {
|
case SIGN_SUCCESS:
|
||||||
case err == sql.ErrNoRows:
|
if newCharaReq {
|
||||||
s.logger.Info("User not found", zap.String("Username", username))
|
_ = s.server.newUserChara(uid)
|
||||||
if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.AutoCreateAccount {
|
|
||||||
s.logger.Info("Creating user", zap.String("Username", username))
|
|
||||||
id, err = s.server.registerDBAccount(username, password)
|
|
||||||
if err == nil {
|
|
||||||
bf.WriteBytes(s.makeSignResponse(id))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bf.WriteUint8(uint8(SIGN_EAUTH))
|
|
||||||
}
|
}
|
||||||
case err != nil:
|
bf.WriteBytes(s.makeSignResponse(uid))
|
||||||
bf.WriteUint8(uint8(SIGN_EABORT))
|
|
||||||
s.logger.Error("Error getting user details", zap.Error(err))
|
|
||||||
default:
|
default:
|
||||||
if bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) == nil || s.client == VITA || s.client == PS3 || s.client == WIIU {
|
bf.WriteUint8(uint8(resp))
|
||||||
s.logger.Debug("Passwords match!")
|
|
||||||
if newCharaReq {
|
|
||||||
err = s.server.newUserChara(id)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Error adding new character to user", zap.Error(err))
|
|
||||||
bf.WriteUint8(uint8(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
|
|
||||||
// }
|
|
||||||
bf.WriteBytes(s.makeSignResponse(id))
|
|
||||||
} else {
|
|
||||||
s.logger.Warn("Incorrect password")
|
|
||||||
bf.WriteUint8(uint8(SIGN_EPASS))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.LogOutboundMessages {
|
if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.LogOutboundMessages {
|
||||||
fmt.Printf("\n[Server] -> [Client]\nData [%d bytes]:\n%s\n", len(bf.Data()), hex.Dump(bf.Data()))
|
fmt.Printf("\n[Server] -> [Client]\nData [%d bytes]:\n%s\n", len(bf.Data()), hex.Dump(bf.Data()))
|
||||||
}
|
}
|
||||||
|
_ = s.cryptConn.SendPacket(bf.Data())
|
||||||
err = s.cryptConn.SendPacket(bf.Data())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Session) handleWIIUSGN(bf *byteframe.ByteFrame) {
|
func (s *Session) handleWIIUSGN(bf *byteframe.ByteFrame) {
|
||||||
_ = bf.ReadBytes(1)
|
_ = bf.ReadBytes(1)
|
||||||
wiiuKey := string(bf.ReadBytes(64))
|
wiiuKey := string(bf.ReadBytes(64))
|
||||||
var reqUsername string
|
var uid uint32
|
||||||
err := s.server.db.QueryRow(`SELECT username FROM users WHERE wiiu_key = $1`, wiiuKey).Scan(&reqUsername)
|
err := s.server.db.QueryRow(`SELECT id FROM users WHERE wiiu_key = $1`, wiiuKey).Scan(&uid)
|
||||||
if err == sql.ErrNoRows {
|
if err != nil {
|
||||||
resp := byteframe.NewByteFrame()
|
if err == sql.ErrNoRows {
|
||||||
resp.WriteUint8(uint8(SIGN_ECOGLINK))
|
s.logger.Info("Unlinked Wii U attempted to authenticate", zap.String("Key", wiiuKey))
|
||||||
s.cryptConn.SendPacket(resp.Data())
|
s.sendCode(SIGN_ECOGLINK)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.sendCode(SIGN_EABORT)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.authenticate(reqUsername, "")
|
s.cryptConn.SendPacket(s.makeSignResponse(uid))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Session) handlePSSGN(bf *byteframe.ByteFrame) {
|
func (s *Session) handlePSSGN(bf *byteframe.ByteFrame) {
|
||||||
// Prevent reading malformed request
|
// Prevent reading malformed request
|
||||||
if len(bf.DataFromCurrent()) < 128 {
|
if len(bf.DataFromCurrent()) < 128 {
|
||||||
resp := byteframe.NewByteFrame()
|
s.sendCode(SIGN_EABORT)
|
||||||
resp.WriteUint8(uint8(SIGN_EABORT))
|
|
||||||
s.cryptConn.SendPacket(resp.Data())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = bf.ReadNullTerminatedBytes() // VITA = 0000000256, PS3 = 0000000255
|
_ = bf.ReadNullTerminatedBytes() // VITA = 0000000256, PS3 = 0000000255
|
||||||
_ = bf.ReadBytes(2) // VITA = 1, PS3 = !
|
_ = bf.ReadBytes(2) // VITA = 1, PS3 = !
|
||||||
_ = bf.ReadBytes(82)
|
_ = bf.ReadBytes(82)
|
||||||
psnUser := string(bf.ReadNullTerminatedBytes())
|
s.psn = string(bf.ReadNullTerminatedBytes())
|
||||||
var reqUsername string
|
var uid uint32
|
||||||
err := s.server.db.QueryRow(`SELECT username FROM users WHERE psn_id = $1`, psnUser).Scan(&reqUsername)
|
err := s.server.db.QueryRow(`SELECT id FROM users WHERE psn_id = $1`, s.psn).Scan(&uid)
|
||||||
if err == sql.ErrNoRows {
|
if err != nil {
|
||||||
resp := byteframe.NewByteFrame()
|
if err == sql.ErrNoRows {
|
||||||
resp.WriteUint8(uint8(SIGN_ECOGLINK))
|
s.cryptConn.SendPacket(s.makeSignResponse(0))
|
||||||
s.cryptConn.SendPacket(resp.Data())
|
return
|
||||||
|
}
|
||||||
|
s.sendCode(SIGN_EABORT)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.authenticate(reqUsername, "")
|
s.cryptConn.SendPacket(s.makeSignResponse(uid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Session) handlePSNLink(bf *byteframe.ByteFrame) {
|
||||||
|
_ = bf.ReadNullTerminatedBytes() // Client ID
|
||||||
|
credentials := strings.Split(stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes()), "\n")
|
||||||
|
token := string(bf.ReadNullTerminatedBytes())
|
||||||
|
uid, resp := s.server.validateLogin(credentials[0], credentials[1])
|
||||||
|
if resp == SIGN_SUCCESS && uid > 0 {
|
||||||
|
var psn string
|
||||||
|
err := s.server.db.QueryRow(`SELECT psn_id FROM sign_sessions WHERE token = $1`, token).Scan(&psn)
|
||||||
|
if err != nil {
|
||||||
|
s.sendCode(SIGN_ECOGLINK)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since we check for the psn_id, this will never run
|
||||||
|
var exists int
|
||||||
|
err = s.server.db.QueryRow(`SELECT count(*) FROM users WHERE psn_id = $1`, psn).Scan(&exists)
|
||||||
|
if err != nil {
|
||||||
|
s.sendCode(SIGN_ECOGLINK)
|
||||||
|
return
|
||||||
|
} else if exists > 0 {
|
||||||
|
s.sendCode(SIGN_EPSI)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentPSN string
|
||||||
|
err = s.server.db.QueryRow(`SELECT COALESCE(psn_id, '') FROM users WHERE username = $1`, credentials[0]).Scan(¤tPSN)
|
||||||
|
if err != nil {
|
||||||
|
s.sendCode(SIGN_ECOGLINK)
|
||||||
|
return
|
||||||
|
} else if currentPSN != "" {
|
||||||
|
s.sendCode(SIGN_EMBID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.server.db.Exec(`UPDATE users SET psn_id = $1 WHERE username = $2`, psn, credentials[0])
|
||||||
|
if err == nil {
|
||||||
|
s.sendCode(SIGN_SUCCESS)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.sendCode(SIGN_ECOGLINK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Session) handleDSGN(bf *byteframe.ByteFrame) {
|
func (s *Session) handleDSGN(bf *byteframe.ByteFrame) {
|
||||||
reqUsername := string(bf.ReadNullTerminatedBytes())
|
user := stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
|
||||||
reqPassword := string(bf.ReadNullTerminatedBytes())
|
pass := stringsupport.SJISToUTF8(bf.ReadNullTerminatedBytes())
|
||||||
_ = string(bf.ReadNullTerminatedBytes()) // Unk
|
_ = string(bf.ReadNullTerminatedBytes()) // Unk
|
||||||
s.authenticate(reqUsername, reqPassword)
|
s.authenticate(user, pass)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Session) sendCode(id RespID) {
|
||||||
|
s.cryptConn.SendPacket([]byte{byte(id)})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user