mirror of
https://wiilab.wiimart.org/wiimart/WiiSOAP
synced 2025-09-05 21:11:02 +02:00
Properly check registration status
This commit is contained in:
parent
943f475bba
commit
3337ebb475
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
.idea
|
.idea
|
||||||
config.xml
|
config.xml
|
||||||
|
WiiSOAP
|
||||||
|
14
README.md
14
README.md
@ -1,16 +1,20 @@
|
|||||||
# WiiSOAP
|
# WiiSOAP
|
||||||
A SOAP Server, designed specifically to handle Wii Shop Channel SOAP. Slowly in development.
|
WiiSOAP is a server designed specifically to handle Wii Shop Channel SOAP - more specifically, that of the ECommerce library.
|
||||||
> WiiSOAP is being rewritten in the future, therefore Pull Requests may be ignored.
|
Ideally, one day this will become feature complete enough to handle other titles utilizing EC, such as DLCs or other purchases.
|
||||||
|
|
||||||
## What's the difference between this repo and that other SOAP repo?
|
It aims to implement everything necessary to provide title tickets, manage authentication, and everything between.
|
||||||
This is the SOAP Server Software. The other repository only has the communication templates between a Wii and WSC's server.
|
|
||||||
|
> Note that this software is still in development. The schema ma
|
||||||
|
|
||||||
|
## What's the difference between this repo and [that other SOAP repo](https://github.com/OpenShopChannel/Open-Shop-SOAP)?
|
||||||
|
This is the SOAP Server Software. The other repository, [Open-Shop-SOAP](https://github.com/OpenShopChannel/Open-Shop-SOAP), holds templates of communication between a Wii and WSC's server.
|
||||||
|
|
||||||
# Changelog
|
# Changelog
|
||||||
Versions on this software are based on goals. (e.g 0.2 works towards SQL support. 0.3 works towards NUS support, etc.)
|
Versions on this software are based on goals. (e.g 0.2 works towards SQL support. 0.3 works towards NUS support, etc.)
|
||||||
|
|
||||||
## 0.3.x Tanuki
|
## 0.3.x Tanuki
|
||||||
### 0.3.0
|
### 0.3.0
|
||||||
- Migrates to using PostgreSQL
|
- Migrate to using PostgreSQL
|
||||||
- Add routes and XML niceties
|
- Add routes and XML niceties
|
||||||
- Implement most routes
|
- Implement most routes
|
||||||
|
|
||||||
|
44
constants.go
Normal file
44
constants.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// LimitKinds represents various limits applied to the current ticket.
|
||||||
|
type LimitKinds int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// PR is presumably "purchased".
|
||||||
|
PR LimitKinds = 0
|
||||||
|
TR = 1
|
||||||
|
DR = 2
|
||||||
|
SR = 3
|
||||||
|
LR = 4
|
||||||
|
AT = 10000
|
||||||
|
)
|
||||||
|
|
||||||
|
// LimitStruct returns a Limits struct filled for the given kind.
|
||||||
|
func LimitStruct(kind LimitKinds) Limits {
|
||||||
|
names := map[LimitKinds]string{
|
||||||
|
PR: "PR",
|
||||||
|
TR: "TR",
|
||||||
|
DR: "DR",
|
||||||
|
SR: "SR",
|
||||||
|
LR: "LR",
|
||||||
|
AT: "AT",
|
||||||
|
}
|
||||||
|
|
||||||
|
return Limits{
|
||||||
|
Limits: kind,
|
||||||
|
LimitKind: names[kind],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeviceStatus represents the various statuses a device may have.
|
||||||
|
//
|
||||||
|
// These values do not appear to be directly checked by the client within the
|
||||||
|
// Wii Shop Channel, and are a generic string. We could utilize any value we wish.
|
||||||
|
// However, titles utilizing DLCs appear to check the raw values.
|
||||||
|
// For this reason, we mirror values from Nintendo.
|
||||||
|
type DeviceStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
DeviceStatusRegistered = "R"
|
||||||
|
DeviceStatusUnregistered = "U"
|
||||||
|
)
|
22
database.sql
22
database.sql
@ -2,8 +2,8 @@
|
|||||||
-- PostgreSQL database dump
|
-- PostgreSQL database dump
|
||||||
--
|
--
|
||||||
|
|
||||||
-- Dumped from database version 13.2
|
-- Dumped from database version 14.1
|
||||||
-- Dumped by pg_dump version 13.2
|
-- Dumped by pg_dump version 14.1
|
||||||
|
|
||||||
SET statement_timeout = 0;
|
SET statement_timeout = 0;
|
||||||
SET lock_timeout = 0;
|
SET lock_timeout = 0;
|
||||||
@ -64,22 +64,12 @@ CREATE TABLE public.userbase (
|
|||||||
device_token_hashed character varying(32) NOT NULL,
|
device_token_hashed character varying(32) NOT NULL,
|
||||||
account_id integer NOT NULL,
|
account_id integer NOT NULL,
|
||||||
region character varying(3),
|
region character varying(3),
|
||||||
country character varying(2),
|
serial_number character varying(11)
|
||||||
language character varying(2),
|
|
||||||
serial_number character varying(11),
|
|
||||||
device_code bigint
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
ALTER TABLE public.userbase OWNER TO wiisoap;
|
ALTER TABLE public.userbase OWNER TO wiisoap;
|
||||||
|
|
||||||
--
|
|
||||||
-- Name: COLUMN userbase.device_code; Type: COMMENT; Schema: public; Owner: wiisoap
|
|
||||||
--
|
|
||||||
|
|
||||||
COMMENT ON COLUMN public.userbase.device_code IS 'Also known as the console''s friend code.';
|
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: owned_titles owned_titles_pk; Type: CONSTRAINT; Schema: public; Owner: wiisoap
|
-- Name: owned_titles owned_titles_pk; Type: CONSTRAINT; Schema: public; Owner: wiisoap
|
||||||
--
|
--
|
||||||
@ -126,10 +116,10 @@ CREATE UNIQUE INDEX userbase_account_id_uindex ON public.userbase USING btree (a
|
|||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: userbase_device_code_uindex; Type: INDEX; Schema: public; Owner: wiisoap
|
-- Name: userbase_device_id_uindex; Type: INDEX; Schema: public; Owner: wiisoap
|
||||||
--
|
--
|
||||||
|
|
||||||
CREATE UNIQUE INDEX userbase_device_code_uindex ON public.userbase USING btree (device_code);
|
CREATE UNIQUE INDEX userbase_device_id_uindex ON public.userbase USING btree (device_id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -157,4 +147,4 @@ ALTER TABLE ONLY public.owned_titles
|
|||||||
|
|
||||||
--
|
--
|
||||||
-- PostgreSQL database dump complete
|
-- PostgreSQL database dump complete
|
||||||
--
|
--
|
||||||
|
64
ias.go
64
ias.go
@ -23,25 +23,55 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
wiino "github.com/RiiConnect24/wiino/golang"
|
wiino "github.com/RiiConnect24/wiino/golang"
|
||||||
"github.com/jackc/pgconn"
|
"github.com/jackc/pgconn"
|
||||||
|
"github.com/jackc/pgx/v4"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PrepareUserStatement = `INSERT INTO userbase (device_id, device_token, device_token_hashed, account_id, region, country, language, serial_number, device_code) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`
|
PrepareUserStatement = `INSERT INTO userbase
|
||||||
SyncUserStatement = `SELECT account_id, device_code, device_token FROM userbase WHERE language = $1 AND country = $2 AND region = $3 AND device_id = $4`
|
(device_id, device_token, device_token_hashed, account_id, region, serial_number)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6)`
|
||||||
|
SyncUserStatement = `SELECT
|
||||||
|
account_id, device_token
|
||||||
|
FROM userbase WHERE
|
||||||
|
region = $1 AND
|
||||||
|
device_id = $2`
|
||||||
|
CheckUserStatement = `SELECT
|
||||||
|
1
|
||||||
|
FROM userbase WHERE
|
||||||
|
device_id = $1 AND
|
||||||
|
serial_number = $2 AND
|
||||||
|
region = $3`
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkRegistration(e *Envelope) {
|
func checkRegistration(e *Envelope) {
|
||||||
serialNo, err := getKey(e.doc, "SerialNumber")
|
serialNo, err := getKey(e.doc, "SerialNumber")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Error(5, "not good enough for me. ;3", err)
|
e.Error(5, "missing serial number", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We'll utilize our sync user statement.
|
||||||
|
query := pool.QueryRow(ctx, CheckUserStatement, e.DeviceId(), serialNo, e.Region())
|
||||||
|
err = query.Scan(nil)
|
||||||
|
|
||||||
|
// Formulate our response
|
||||||
e.AddKVNode("OriginalSerialNumber", serialNo)
|
e.AddKVNode("OriginalSerialNumber", serialNo)
|
||||||
e.AddKVNode("DeviceStatus", "R")
|
|
||||||
|
if err != nil {
|
||||||
|
// We're either unregistered, or a database error occurred.
|
||||||
|
if err == pgx.ErrNoRows {
|
||||||
|
e.AddKVNode("DeviceStatus", DeviceStatusUnregistered)
|
||||||
|
} else {
|
||||||
|
log.Printf("error executing statement: %v\n", err)
|
||||||
|
e.Error(5, "server-side error", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No errors! We're safe.
|
||||||
|
e.AddKVNode("DeviceStatus", DeviceStatusRegistered)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getChallenge(e *Envelope) {
|
func getChallenge(e *Envelope) {
|
||||||
@ -64,11 +94,10 @@ func getRegistrationInfo(e *Envelope) {
|
|||||||
|
|
||||||
func syncRegistration(e *Envelope) {
|
func syncRegistration(e *Envelope) {
|
||||||
var accountId int64
|
var accountId int64
|
||||||
var deviceCode int
|
|
||||||
var deviceToken string
|
var deviceToken string
|
||||||
|
|
||||||
user := pool.QueryRow(ctx, SyncUserStatement, e.Language(), e.Country(), e.Region(), e.DeviceId())
|
user := pool.QueryRow(ctx, SyncUserStatement, e.Region(), e.DeviceId())
|
||||||
err := user.Scan(&accountId, &deviceCode, &deviceToken)
|
err := user.Scan(&accountId, &deviceToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Error(7, "An error occurred querying the database.", err)
|
e.Error(7, "An error occurred querying the database.", err)
|
||||||
}
|
}
|
||||||
@ -82,37 +111,36 @@ func syncRegistration(e *Envelope) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func register(e *Envelope) {
|
func register(e *Envelope) {
|
||||||
reason := "disgustingly invalid. ;3"
|
|
||||||
deviceCode, err := getKey(e.doc, "DeviceCode")
|
deviceCode, err := getKey(e.doc, "DeviceCode")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Error(7, reason, err)
|
e.Error(7, "missing device code", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
registerRegion, err := getKey(e.doc, "RegisterRegion")
|
registerRegion, err := getKey(e.doc, "RegisterRegion")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Error(7, reason, err)
|
e.Error(7, "missing registration region", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if registerRegion != e.Region() {
|
if registerRegion != e.Region() {
|
||||||
e.Error(7, reason, errors.New("region does not match registration region"))
|
e.Error(7, "mismatched region", errors.New("region does not match registration region"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
serialNo, err := getKey(e.doc, "SerialNumber")
|
serialNo, err := getKey(e.doc, "SerialNumber")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Error(7, reason, err)
|
e.Error(7, "missing serial number", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate given friend code.
|
// Validate given friend code.
|
||||||
userId, err := strconv.ParseUint(deviceCode, 10, 64)
|
userId, err := strconv.ParseUint(deviceCode, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Error(7, reason, err)
|
e.Error(7, "invalid friend code", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if wiino.NWC24CheckUserID(userId) != 0 {
|
if wiino.NWC24CheckUserID(userId) != 0 {
|
||||||
e.Error(7, reason, err)
|
e.Error(7, "invalid friend code", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,18 +152,18 @@ func register(e *Envelope) {
|
|||||||
// ...and then its md5, because the Wii sends this for most requests.
|
// ...and then its md5, because the Wii sends this for most requests.
|
||||||
md5DeviceToken := fmt.Sprintf("%x", md5.Sum([]byte(deviceToken)))
|
md5DeviceToken := fmt.Sprintf("%x", md5.Sum([]byte(deviceToken)))
|
||||||
|
|
||||||
// Insert all of our obtained values to the database..
|
// Insert all of our obtained values to the database...
|
||||||
_, err = pool.Exec(ctx, PrepareUserStatement, e.DeviceId(), deviceToken, md5DeviceToken, accountId, e.Region(), e.Country(), e.Language(), serialNo, deviceCode)
|
_, err = pool.Exec(ctx, PrepareUserStatement, e.DeviceId(), deviceToken, md5DeviceToken, accountId, e.Region(), serialNo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// It's okay if this isn't a PostgreSQL error, as perhaps other issues have come in.
|
// It's okay if this isn't a PostgreSQL error, as perhaps other issues have come in.
|
||||||
if driverErr, ok := err.(*pgconn.PgError); ok {
|
if driverErr, ok := err.(*pgconn.PgError); ok {
|
||||||
if driverErr.Code == "23505" {
|
if driverErr.Code == "23505" {
|
||||||
e.Error(7, reason, errors.New("user already exists"))
|
e.Error(7, "database error", errors.New("user already exists"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Printf("error executing statement: %v\n", err)
|
log.Printf("error executing statement: %v\n", err)
|
||||||
e.Error(7, reason, errors.New("failed to execute db operation"))
|
e.Error(7, "database error", errors.New("failed to execute db operation"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
29
structure.go
29
structure.go
@ -101,35 +101,6 @@ type Balance struct {
|
|||||||
Currency string `xml:"Currency"`
|
Currency string `xml:"Currency"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LimitKinds int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// PR is presumably "purchased".
|
|
||||||
PR LimitKinds = 0
|
|
||||||
TR = 1
|
|
||||||
DR = 2
|
|
||||||
SR = 3
|
|
||||||
LR = 4
|
|
||||||
AT = 10000
|
|
||||||
)
|
|
||||||
|
|
||||||
// LimitStruct returns a Limits struct filled for the given kind.
|
|
||||||
func LimitStruct(kind LimitKinds) Limits {
|
|
||||||
names := map[LimitKinds]string{
|
|
||||||
PR: "PR",
|
|
||||||
TR: "TR",
|
|
||||||
DR: "DR",
|
|
||||||
SR: "SR",
|
|
||||||
LR: "LR",
|
|
||||||
AT: "AT",
|
|
||||||
}
|
|
||||||
|
|
||||||
return Limits{
|
|
||||||
Limits: kind,
|
|
||||||
LimitKind: names[kind],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Limits represents a common XML structure for transaction information.
|
// Limits represents a common XML structure for transaction information.
|
||||||
type Limits struct {
|
type Limits struct {
|
||||||
XMLName xml.Name `xml:"Limits"`
|
XMLName xml.Name `xml:"Limits"`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user