mirror of
https://wiilab.wiimart.org/wiimart/WiiSOAP
synced 2025-09-04 04:21:15 +02:00
209 lines
6.0 KiB
Go
209 lines
6.0 KiB
Go
// Copyright (C) 2018-2020 CornierKhan1
|
|
//
|
|
// WiiSOAP is SOAP Server Software, designed specifically to handle Wii Shop Channel SOAP.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as published
|
|
// by the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see http://www.gnu.org/licenses/.
|
|
|
|
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"github.com/wii-tools/wadlib"
|
|
"log"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
QueryOwnedTitles = `SELECT owned_titles.title_id, tickets.version
|
|
FROM owned_titles, tickets
|
|
WHERE owned_titles.title_id = tickets.title_id
|
|
AND owned_titles.account_id = $1`
|
|
|
|
QueryTicketStatement = `SELECT ticket, version FROM tickets WHERE title_id = $1`
|
|
|
|
AssociateTicketStatement = `INSERT INTO owned_titles (account_id, title_id, version)
|
|
VALUES ($1, $2, $3)`
|
|
|
|
// SharedBalanceAmount describes the maximum signed 32-bit integer value.
|
|
// It is not an actual tracked points value, but exists to permit reuse.
|
|
SharedBalanceAmount = 2147483647
|
|
)
|
|
|
|
func getBalance() Balance {
|
|
return Balance{
|
|
Amount: SharedBalanceAmount,
|
|
Currency: "POINTS",
|
|
}
|
|
}
|
|
|
|
func checkDeviceStatus(e *Envelope) {
|
|
e.AddCustomType(getBalance())
|
|
e.AddKVNode("ForceSyncTime", "0")
|
|
e.AddKVNode("ExtTicketTime", e.Timestamp())
|
|
e.AddKVNode("SyncTime", e.Timestamp())
|
|
}
|
|
|
|
func notifyETicketsSynced(e *Envelope) {
|
|
// TODO: Implement handling of synchronization timing
|
|
}
|
|
|
|
func listETickets(e *Envelope) {
|
|
accountId, err := e.AccountId()
|
|
if err != nil {
|
|
e.Error(2, "missing account ID", err)
|
|
return
|
|
}
|
|
|
|
rows, err := pool.Query(ctx, QueryOwnedTitles, accountId)
|
|
if err != nil {
|
|
log.Printf("error executing statement: %v\n", err)
|
|
e.Error(2, "database error", errors.New("failed to execute db operation"))
|
|
return
|
|
}
|
|
|
|
// Add all available titles for this account.
|
|
defer rows.Close()
|
|
for rows.Next() {
|
|
var titleId string
|
|
var version int
|
|
err = rows.Scan(&titleId, &version)
|
|
if err != nil {
|
|
log.Printf("error executing statement: %v\n", err)
|
|
e.Error(2, "database error", errors.New("failed to execute db operation"))
|
|
return
|
|
}
|
|
|
|
e.AddCustomType(Tickets{
|
|
TitleId: titleId,
|
|
Version: version,
|
|
|
|
// We do not support migration, ticket IDs, or revocation.
|
|
TicketId: "0",
|
|
RevokeDate: 0,
|
|
MigrateCount: 0,
|
|
MigrateLimit: 0,
|
|
})
|
|
}
|
|
|
|
e.AddKVNode("ForceSyncTime", "0")
|
|
e.AddKVNode("ExtTicketTime", e.Timestamp())
|
|
e.AddKVNode("SyncTime", e.Timestamp())
|
|
}
|
|
|
|
func getETickets(e *Envelope) {
|
|
e.AddKVNode("ForceSyncTime", "0")
|
|
e.AddKVNode("ExtTicketTime", e.Timestamp())
|
|
e.AddKVNode("SyncTime", e.Timestamp())
|
|
}
|
|
|
|
func purchaseTitle(e *Envelope) {
|
|
//accountId, err := e.AccountId()
|
|
//if err != nil {
|
|
// e.Error(2, "missing account ID", err)
|
|
// return
|
|
//}
|
|
|
|
// Determine the title ID we're going to purchase.
|
|
titleId, err := e.getKey("TitleId")
|
|
if err != nil {
|
|
e.Error(2, "missing account ID", err)
|
|
return
|
|
}
|
|
|
|
// We store title IDs in lowercase.
|
|
titleId = strings.ToLower(titleId)
|
|
|
|
// Query the ticket and current version for this title.
|
|
var ticket []byte
|
|
var version int
|
|
row := pool.QueryRow(ctx, QueryTicketStatement, titleId)
|
|
|
|
err = row.Scan(&ticket, &version)
|
|
if err != nil {
|
|
log.Printf("unexpected error purchasing: %v", err)
|
|
// TODO(spotlightishere): Can we more elegantly return an error when a title may not exist here?
|
|
e.Error(2, "error purchasing", nil)
|
|
return
|
|
}
|
|
|
|
// Associate the given title ID with the user.
|
|
//_, err = pool.Exec(ctx, AssociateTicketStatement, accountId, titleId, version)
|
|
//if err != nil {
|
|
// log.Printf("unexpected error purchasing: %v", err)
|
|
// e.Error(2, "error purchasing", nil)
|
|
//}
|
|
|
|
// The returned ticket is expected to have two other certificates associated.
|
|
ticketString := b64(append(ticket, wadlib.CertChainTemplate...))
|
|
|
|
e.AddCustomType(getBalance())
|
|
e.AddCustomType(Transactions{
|
|
TransactionId: "00000000",
|
|
Date: e.Timestamp(),
|
|
Type: "PURCHGAME",
|
|
TotalPaid: 0,
|
|
Currency: "POINTS",
|
|
ItemId: 0,
|
|
})
|
|
e.AddKVNode("SyncTime", e.Timestamp())
|
|
|
|
e.AddKVNode("ETickets", ticketString)
|
|
// Two cert types must be present.
|
|
e.AddKVNode("Certs", b64(wadlib.CertChainTemplate))
|
|
e.AddKVNode("Certs", b64(wadlib.CertChainTemplate))
|
|
e.AddKVNode("TitleId", titleId)
|
|
}
|
|
|
|
func listPurchaseHistory(e *Envelope) {
|
|
e.AddCustomType([]Transactions{
|
|
{
|
|
TransactionId: "12345678",
|
|
Date: e.Timestamp(),
|
|
Type: "SERVICE",
|
|
TotalPaid: 7,
|
|
Currency: "POINTS",
|
|
ItemId: 0,
|
|
TitleId: "000100014843494A",
|
|
ItemPricing: []Limits{
|
|
LimitStruct(DR),
|
|
},
|
|
ReferenceId: 1,
|
|
ReferenceValue: 19224,
|
|
},
|
|
})
|
|
|
|
e.AddKVNode("ListResultTotalSize", "1")
|
|
}
|
|
|
|
// genServiceUrl returns a URL with the given service against a configured URL.
|
|
// Given a baseUrl of example.com and genServiceUrl("ias", "IdentityAuthenticationSOAP"),
|
|
// it would return http://ias.example.com/ias/services/ias/IdentityAuthenticationSOAP.
|
|
func genServiceUrl(service string, path string) string {
|
|
return fmt.Sprintf("http://%s.%s/%s/services/%s", service, baseUrl, service, path)
|
|
}
|
|
|
|
func getECConfig(e *Envelope) {
|
|
contentUrl := fmt.Sprintf("http://ccs.%s/ccs/download", baseUrl)
|
|
e.AddKVNode("ContentPrefixURL", contentUrl)
|
|
e.AddKVNode("UncachedContentPrefixURL", contentUrl)
|
|
e.AddKVNode("SystemContentPrefixURL", contentUrl)
|
|
e.AddKVNode("SystemUncachedContentPrefixURL", contentUrl)
|
|
|
|
e.AddKVNode("EcsURL", genServiceUrl("ecs", "ECommerceSOAP"))
|
|
e.AddKVNode("IasURL", genServiceUrl("ias", "IdentityAuthenticationSOAP"))
|
|
e.AddKVNode("CasURL", genServiceUrl("cas", "CatalogingSOAP"))
|
|
e.AddKVNode("NusURL", genServiceUrl("nus", "NetUpdateSOAP"))
|
|
}
|