mirror of
https://wiilab.wiimart.org/wiimart/WiiSOAP
synced 2025-09-05 21:11:02 +02:00
Add proper registration response
This commit is contained in:
parent
de5c682dd5
commit
5cbf9f81a8
21
database.sql
21
database.sql
@ -36,16 +36,19 @@ SET time_zone = "+00:00";
|
||||
--
|
||||
|
||||
CREATE TABLE `userbase` (
|
||||
`DeviceId` int(10) UNSIGNED ZEROFILL NOT NULL,
|
||||
`DeviceToken` varchar(21) NOT NULL,
|
||||
`AccountId` int(9) UNSIGNED ZEROFILL NOT NULL,
|
||||
`Region` varchar(2) DEFAULT NULL,
|
||||
`Country` varchar(2) DEFAULT NULL,
|
||||
`Language` varchar(2) DEFAULT NULL,
|
||||
`SerialNo` varchar(11) DEFAULT NULL,
|
||||
`DeviceCode` int(16) UNSIGNED ZEROFILL NOT NULL
|
||||
`DeviceId` varchar(10) NOT NULL,
|
||||
`DeviceToken` varchar(64) NOT NULL COMMENT 'This token should be considered a secret, so after generation only the sha256sum of the md5 the Wii sends is inserted.',
|
||||
`AccountId` varchar(9) NOT NULL,
|
||||
`Region` varchar(2) NOT NULL,
|
||||
`Country` varchar(2) NOT NULL,
|
||||
`Language` varchar(2) NOT NULL,
|
||||
`SerialNo` varchar(11) NOT NULL,
|
||||
`DeviceCode` varchar(16) NOT NULL,
|
||||
PRIMARY KEY (`AccountId`),
|
||||
UNIQUE KEY `AccountId` (`AccountId`),
|
||||
UNIQUE KEY `userbase_DeviceId_uindex` (`DeviceId`),
|
||||
UNIQUE KEY `userbase_DeviceToken_uindex` (`DeviceToken`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
COMMIT;
|
||||
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
|
1
go.mod
1
go.mod
@ -3,6 +3,7 @@ module github.com/morenatsu-net/WiiSOAP
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/RiiConnect24/wiino v0.0.0-20200719211820-910fed2fa406
|
||||
github.com/antchfx/xmlquery v1.2.4
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
)
|
||||
|
2
go.sum
2
go.sum
@ -1,3 +1,5 @@
|
||||
github.com/RiiConnect24/wiino v0.0.0-20200719211820-910fed2fa406 h1:io4hcjlXc3gsbSLtIR7Xd7nK+Tngl3hHrPVlI7aZfR0=
|
||||
github.com/RiiConnect24/wiino v0.0.0-20200719211820-910fed2fa406/go.mod h1:BmIQ5QOpoum6rxYqqAjdpwwdfoQeKVi1xnxeEU+56ro=
|
||||
github.com/antchfx/xmlquery v1.2.4 h1:T/SH1bYdzdjTMoz2RgsfVKbM5uWh3gjDYYepFqQmFv4=
|
||||
github.com/antchfx/xmlquery v1.2.4/go.mod h1:KQQuESaxSlqugE2ZBcM/qn+ebIpt+d+4Xx7YcSGAIrM=
|
||||
github.com/antchfx/xpath v1.1.6 h1:6sVh6hB5T6phw1pFpHRQ+C4bd8sNI+O58flqtg7h0R0=
|
||||
|
95
ias.go
95
ias.go
@ -18,11 +18,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
sha2562 "crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/RiiConnect24/wiino/golang"
|
||||
"github.com/antchfx/xmlquery"
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"log"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func iasHandler(e Envelope, doc *xmlquery.Node) (bool, string) {
|
||||
// All IAS-related functions should contain these keys.
|
||||
region, err := getKey(doc, "Region")
|
||||
if err != nil {
|
||||
return e.ReturnError(5, "not good enough for me. ;3", err)
|
||||
}
|
||||
country, err := getKey(doc, "Country")
|
||||
if err != nil {
|
||||
return e.ReturnError(5, "not good enough for me. ;3", err)
|
||||
}
|
||||
language, err := getKey(doc, "Language")
|
||||
if err != nil {
|
||||
return e.ReturnError(5, "not good enough for me. ;3", err)
|
||||
}
|
||||
|
||||
// All actions below are for IAS-related functions.
|
||||
switch e.Action() {
|
||||
@ -50,14 +71,15 @@ func iasHandler(e Envelope, doc *xmlquery.Node) (bool, string) {
|
||||
break
|
||||
|
||||
case "GetRegistrationInfo":
|
||||
reason := "how dirty. ;3"
|
||||
accountId, err := getKey(doc, "AccountId")
|
||||
if err != nil {
|
||||
return e.ReturnError(7, "how dirty. ;3", err)
|
||||
return e.ReturnError(7, reason, err)
|
||||
}
|
||||
|
||||
country, err := getKey(doc, "Country")
|
||||
deviceCode, err := getKey(doc, "DeviceCode")
|
||||
if err != nil {
|
||||
return e.ReturnError(7, "how dirty. ;3", err)
|
||||
return e.ReturnError(7, reason, err)
|
||||
}
|
||||
|
||||
fmt.Println("The request is valid! Responding...")
|
||||
@ -66,29 +88,82 @@ func iasHandler(e Envelope, doc *xmlquery.Node) (bool, string) {
|
||||
e.AddKVNode("DeviceTokenExpired", "false")
|
||||
e.AddKVNode("Country", country)
|
||||
e.AddKVNode("ExtAccountId", "")
|
||||
e.AddKVNode("DeviceCode", "0000000000000000")
|
||||
e.AddKVNode("DeviceCode", deviceCode)
|
||||
e.AddKVNode("DeviceStatus", "R")
|
||||
// This _must_ be POINTS.
|
||||
e.AddKVNode("Currency", "POINTS")
|
||||
break
|
||||
|
||||
case "Register":
|
||||
accountId, err := getKey(doc, "AccountId")
|
||||
reason := "disgustingly invalid. ;3"
|
||||
deviceCode, err := getKey(doc, "DeviceCode")
|
||||
if err != nil {
|
||||
return e.ReturnError(8, "disgustingly invalid. ;3", err)
|
||||
return e.ReturnError(7, reason, err)
|
||||
}
|
||||
|
||||
country, err := getKey(doc, "Country")
|
||||
registerRegion, err := getKey(doc, "RegisterRegion")
|
||||
if err != nil {
|
||||
return e.ReturnError(8, "disgustingly invalid. ;3", err)
|
||||
return e.ReturnError(7, reason, err)
|
||||
}
|
||||
if registerRegion != region {
|
||||
return e.ReturnError(7, reason, errors.New("region does not match registration region"))
|
||||
}
|
||||
|
||||
serialNo, err := getKey(doc, "SerialNumber")
|
||||
if err != nil {
|
||||
return e.ReturnError(7, reason, err)
|
||||
}
|
||||
|
||||
// Validate given friend code.
|
||||
userId, err := strconv.ParseUint(deviceCode, 10, 64)
|
||||
if err != nil {
|
||||
return e.ReturnError(7, reason, err)
|
||||
}
|
||||
if wiino.NWC24CheckUserID(userId) != 0 {
|
||||
return e.ReturnError(7, reason, err)
|
||||
}
|
||||
|
||||
// Generate a random 9-digit number, padding zeros as necessary.
|
||||
accountId := fmt.Sprintf("%9d", rand.Intn(999999999))
|
||||
|
||||
// This is where it gets hairy.
|
||||
// Generate a device token, 21 characters...
|
||||
deviceToken := RandString(21)
|
||||
// ...and then its md5, because the Wii sends this...
|
||||
md5DeviceToken := fmt.Sprintf("%x", md5.Sum([]byte(deviceToken)))
|
||||
// ...and then the sha256 of that md5.
|
||||
// We'll store this in our database, as storing the md5 itself is effectively the token.
|
||||
// It would not be good for security to directly store the token either.
|
||||
// This is the hash of the md5 represented as a string, not individual byte values.
|
||||
doublyHashedDeviceToken := fmt.Sprintf("%x", sha2562.Sum256([]byte(md5DeviceToken)))
|
||||
|
||||
// Insert all of our obtained values to the database..
|
||||
stmt, err := db.Prepare(`INSERT INTO wiisoap.userbase (DeviceId, DeviceToken, AccountId, Region, Country, Language, SerialNo, DeviceCode) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
|
||||
if err != nil {
|
||||
log.Printf("error preparing statement: %v\n", err)
|
||||
return e.ReturnError(7, reason, errors.New("failed to prepare statement"))
|
||||
}
|
||||
_, err = stmt.Exec(e.DeviceId(), doublyHashedDeviceToken, accountId, region, country, language, serialNo, deviceCode)
|
||||
if err != nil {
|
||||
// It's okay if this isn't a MySQL error, as perhaps other issues have come in.
|
||||
if driverErr, ok := err.(*mysql.MySQLError); ok {
|
||||
if driverErr.Number == 1062 {
|
||||
return e.ReturnError(7, reason, errors.New("user already exists"))
|
||||
}
|
||||
}
|
||||
log.Printf("error executing statement: %v\n", err)
|
||||
return e.ReturnError(7, reason, errors.New("failed to execute db operation"))
|
||||
}
|
||||
|
||||
fmt.Println("The request is valid! Responding...")
|
||||
e.AddKVNode("AccountId", accountId)
|
||||
e.AddKVNode("DeviceToken", "00000000")
|
||||
e.AddKVNode("DeviceToken", deviceToken)
|
||||
e.AddKVNode("DeviceTokenExpired", "false")
|
||||
e.AddKVNode("Country", country)
|
||||
// Optionally, one can send back DeviceCode and ExtAccountId to update on device.
|
||||
// We send these back as-is regardless.
|
||||
e.AddKVNode("ExtAccountId", "")
|
||||
e.AddKVNode("DeviceCode", "0000000000000000")
|
||||
e.AddKVNode("DeviceCode", deviceCode)
|
||||
break
|
||||
|
||||
case "Unregister":
|
||||
|
7
main.go
7
main.go
@ -29,10 +29,13 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// Any given challenge must be 10 characters or less (challenge.length > 0xb)
|
||||
// SharedChallenge represents a static value to this nonsensical challenge response system.
|
||||
// The given challenge must be 11 characters or less. Contents do not matter.
|
||||
SharedChallenge = "NintyWhyPls"
|
||||
)
|
||||
|
||||
var db *sql.DB
|
||||
|
||||
// checkError makes error handling not as ugly and inefficient.
|
||||
func checkError(err error) {
|
||||
if err != nil {
|
||||
@ -54,7 +57,7 @@ func main() {
|
||||
fmt.Println("[i] Initializing core...")
|
||||
|
||||
// Start SQL.
|
||||
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s", CON.SQLUser, CON.SQLPass, CON.SQLAddress, CON.SQLDB))
|
||||
db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s", CON.SQLUser, CON.SQLPass, CON.SQLAddress, CON.SQLDB))
|
||||
checkError(err)
|
||||
|
||||
// Close SQL after everything else is done.
|
||||
|
21
utils.go
21
utils.go
@ -23,6 +23,7 @@ import (
|
||||
"fmt"
|
||||
"github.com/antchfx/xmlquery"
|
||||
"io"
|
||||
"math/rand"
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
@ -75,7 +76,12 @@ func (e *Envelope) Timestamp() string {
|
||||
return e.Body.Response.TimeStamp
|
||||
}
|
||||
|
||||
// obtainCommon interprets a given node, and updates the envelope with common key values.
|
||||
// DeviceId returns the Device ID for this request.
|
||||
func (e *Envelope) DeviceId() string {
|
||||
return e.Body.Response.DeviceId
|
||||
}
|
||||
|
||||
// ObtainCommon interprets a given node, and updates the envelope with common key values.
|
||||
func (e *Envelope) ObtainCommon(doc *xmlquery.Node) error {
|
||||
var err error
|
||||
|
||||
@ -130,7 +136,7 @@ func (e *Envelope) ReturnSuccess() (bool, string) {
|
||||
return e.becomeXML(true)
|
||||
}
|
||||
|
||||
// formatError returns a standard SOAP response with an error code.
|
||||
// ReturnError returns a standard SOAP response with an error code.
|
||||
func (e *Envelope) ReturnError(errorCode int, reason string, err error) (bool, string) {
|
||||
e.Body.Response.ErrorCode = errorCode
|
||||
|
||||
@ -180,3 +186,14 @@ func getKey(doc *xmlquery.Node, key string) (string, error) {
|
||||
return node.InnerText(), nil
|
||||
}
|
||||
}
|
||||
|
||||
// Derived from https://stackoverflow.com/a/31832326, adding numbers
|
||||
const letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
func RandString(n int) string {
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
b[i] = letterBytes[rand.Intn(len(letterBytes))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user