From c2f231bf256216c4fa1118bcc29743924365347b Mon Sep 17 00:00:00 2001 From: Ocarinaoftime <89474990+Ocarinaoftime@users.noreply.github.com> Date: Fri, 25 Apr 2025 11:35:49 -0400 Subject: [PATCH] Update ecs.go Upload current SOAP files --- ecs.go | 435 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 375 insertions(+), 60 deletions(-) diff --git a/ecs.go b/ecs.go index 0bd5e1b..6fb714b 100644 --- a/ecs.go +++ b/ecs.go @@ -19,16 +19,22 @@ package main import ( "bytes" + "crypto/md5" "encoding/binary" "encoding/hex" - "errors" "fmt" - v1Ticket "github.com/OpenShopChannel/V1TicketGenerator" - "github.com/wii-tools/wadlib" + "html" "log" "math" + "math/rand" + "os" "strconv" + "strings" "time" + + v1Ticket "github.com/OpenShopChannel/V1TicketGenerator" + "github.com/antchfx/xmlquery" + "github.com/wii-tools/wadlib" ) const ( @@ -43,11 +49,25 @@ const ( AND owned_titles.account_id = $2` AssociateTicketStatement = `INSERT INTO owned_titles (account_id, title_id, version, item_id, date_purchased) - VALUES ($1, $2, $3, $4, $5)` + VALUES ($1, $2, $3, $4, $5) + ON CONFLICT (accound_id) DO NOTHING` + AssociatePointsStatement = `INSERT INTO public.userbase (device_id, device_token, device_token_hashed, account_id, region, serial_number, points) + VALUES ($1, $2, $3, $4, $5, $6, $7) + ON CONFLICT (device_id) DO UPDATE SET points = $7` + + QueryPointsStatement = `SELECT points from public.userbase WHERE device_id = $1` + + AssociateGiftedTitleStatement = `INSERT INTO public.gifted_titles (title_id, trans_id, friend_code) + VALUES ($1, $2, $3)` + + QueryGiftedTitleStatement = `SELECT trans_id FROM public.gifted_titles` + + RemoveGiftedTitleStatement = `DELETE FROM public.gifted_titles + WHERE title_id = $1 AND trans_id = $2` // SharedBalanceAmount describes the maximum signed 32-bit integer value. // It is not an actual tracked points value, but exists to permit reuse. - SharedBalanceAmount = math.MaxInt32 + SharedBalanceAmount = 1000 // WiinoMaApplicationID is the title ID for the Japanese channel Wii no Ma. WiinoMaApplicationID = "000100014843494A" @@ -58,79 +78,111 @@ const ( // contentAesKey is the AES key that is used to encrypt title contents. var contentAesKey = [16]byte{0x72, 0x95, 0xDB, 0xC0, 0x47, 0x3C, 0x90, 0x0B, 0xB5, 0x94, 0x19, 0x9C, 0xB5, 0xBC, 0xD3, 0xDC} -func getBalance() Balance { +func getBalance(e *Envelope) Balance { + var points string + err := pool.QueryRow(ctx, QueryPointsStatement, e.DeviceId()).Scan(&points) + if err != nil { + e.Error(104, "Could not retrieve points balance.", err) + } + log.Printf("Points balance for device %s: %s", e.DeviceId(), points) + if points == "" { + points = "0" + } + pointsInt, err := strconv.Atoi(points) + if err != nil { + e.Error(114, "Could not convert points balance to integer.", err) + } + log.Printf("Points balance for device %s: %d", e.DeviceId(), pointsInt) return Balance{ - Amount: SharedBalanceAmount, + Amount: pointsInt, Currency: "POINTS", } } func checkDeviceStatus(e *Envelope) { - e.AddCustomType(getBalance()) + e.AddCustomType(getBalance(e)) e.AddKVNode("ForceSyncTime", "0") - e.AddKVNode("ExtTicketTime", e.Timestamp()) + e.AddKVNode("ExtTicketTime", "0") 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 - } + /* var titleIds [5]string + var ticketIds [5]string + titleIds[0] = "0001000144574641" + ticketIds[0] = "0001000000000000" + titleIds[1] = "000100014F484243" + ticketIds[1] = "0023DB4424D033EC" + titleIds[2] = "0001000452464E45" + ticketIds[2] = "00019E9781E7E89F" + titleIds[3] = "0001000452465045" + ticketIds[3] = "0001F72A2763BFA2" + titleIds[4] = "00010004524D4345" + ticketIds[4] = "00019B1950DF85DF" + for i := 0; i < len(titleIds); i++ { + e.AddCustomType(Tickets{ + TitleId: titleIds[i], + Version: 1, - // Add all available titles for this account. - defer rows.Close() - for rows.Next() { - var titleId string - err = rows.Scan(&titleId) - if err != nil { - log.Printf("error executing statement: %v\n", err) - e.Error(2, "database error", errors.New("failed to execute db operation")) - return + // We do not support migration, ticket IDs, or revocation. + TicketId: ticketIds[i], + RevokeDate: 0, + MigrateCount: 0, + MigrateLimit: 0, + }) } - - app, err := GetOSCApp(titleId) - if err != nil { - e.Error(2, "an error has occurred retrieving app metadata", err) - return - } - - if app == nil { - // Quite possibly an app was de-listed? - e.Error(2, "title does not exist", nil) - return - } - - e.AddCustomType(Tickets{ - TitleId: titleId, - Version: app.Shop.Version, + /*e.AddCustomType(Tickets{ + TitleId: titleIds[2], + Version: 1, // 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("ExtTicketTime", "0") e.AddKVNode("SyncTime", e.Timestamp()) } func getETickets(e *Envelope) { + /* var etickets [8]string + etickets[0] = "AAEAAVtvJd7vSdT1RY1l6q5kaCHrdVis2lLa0/25pbbHaqr560eOnp/VpWjhGfD1ElTDJN3vRgb+ijzM9NrnBQvW/oFXAfsAyhw/UuO3Av7rB6cdd4e2wmpraxIavl9XL8nVrsKVbtI8vH35HUzTDO46ES1M7+cYtCIAWToSJE+UtWK0PNPAlhJZ2poKT96kiq+9bGT1u+Tls7pVrgv8ZnT4dDKUIZkBUWntfCU84WVpvl953lC/8Xff/B29umu9jjKpfvmx436Oi9TpZE94zRdR2DLs0kxtyreV/uIjBYLv2eZcjzskXNoOTEe+3++V5yvNW201bgUwAhiTlIVx+AQwgScAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSb290LUNBMDAwMDAwMDEtWFMwMDAwMDAwMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALTS+bbifI4ioLdMFp2KjnlkPV+Gq0jq3IjvdPz6AEIHZUFmW9vJW+S/PyWqqdndg67xqOOy5EOHteuwAAAAXl16v6DlPOAaZ7b6wUSvqwAAAY7miaw1FQJ7CPUAAQAASEFaQf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + etickets[1] = "AAEAATuy8VhF9O0027viWCvKomWmnnJVjhiuYsJ6ycMJzwRLn/o5IEY5v7MZiNY2Sn5+ixDfiean3Wny1Kq9DIMVwoERgCUkY4D051d4YPuPnraERmNU5oMU9DvZosCEdOWlihKYdUGyyCbk2r4uy9Sai+cv+ozru+FAB2LLsgG/t8U5ekKpbYHBB/Z1IfSJiqt7gg5Fn1o+NIeaMNZBYZHQU7tGjzYnkCGJQj00LusAnz76gtOlfYms9mpHr0iWWlDWDYeYosJ1XTf8Swuu0zUf5po1l0li767/sZ/N8oYRSMok2CkXSwyQHlrRJqlmK4IOUIhRrUfsIlwkvp6WSxeBnl8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSb290LUNBMDAwMDAwMDEtWFMwMDAwMDAwMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALTS+bbifI4ioLdMFp2KjnlkPV+Gq0jq3IjvdPz6AEIHZUFmW9vJW+S/PyWqqdndg67xqOOy5EOHteuwAAAACtSjNHpZMSx0mtlhmYd1LgAAAdSMLJjFDAJ7CPUAAQABSENSRf//AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + //----- + //WiiSOAP eticket + //etickets[2] = "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" + //vWii eticket + etickets[2] = "AAEAASNTxfAL/ZyPDwPVv2IUZsPS/NbZxdcoiHUt5pR33+IWAJEmkgp3SudX/BhuCKTdzGC9gdBIXWNVdzlx5sn0RtmOSsZkazePp2tU+BRi3EpJ8Oiz2Sh03BrZmOayRJybVsc/OfhtbAJo0XOXVoHWXjx/UfBpcPIf4X7Sm4pQUdD0/xQAo0OoCnWVBf1bNYy1VRBN5srdnLu0qSaVX7zj6MqrjXs1JRxYokQ2l1u0/2/Tj1u89Kw2dzgm8vb77kdLJ58co+IJYTii3hsCySItp0t2yzWnWVfRsJFNjsXTDxPwo6Uw+5YfoBrR5+EiuT0MgD5CJIqlJraeI8maqiL7ySMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSb290LUNBMDAwMDAwMDEtWFMwMDAwMDAwMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALTS+bbifI4ioLdMFp2KjnlkPV+Gq0jq3IjvdPz6AEIHZUFmW9vJW+S/PyWqqdndg67xqOOy5EOHteuwAAAAAXc90P6nEAXs/JOIzaCuVwAAAepYrULdZQJ7CPUAAQABSEFURf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + //----- + etickets[3] = "AAEAAafzenrwRhEO0HsLSaejzYM+Lm8QW8ahw1PR+pZFEY4YFNygeyDkDtEWf9/aq3y1YG+cEPy1Y5Mrn1fhomhDPKQpoDr8ou3ZiZkiYLBzAp1EfxUIpeLSVwY5AsQ55U1+cihFLBRxC3l3eYxCWqIsiAZm1kj/79cRYHoDGIhRvbGfHjgEFPLF73IeIqZn5kkkukuRjX4PXVe6lungGZuTnvgsb/TzrCVRZ8hjFmCINUiOHxtG4CvybJqxnXekl8hVRmIG3eDmiWuHfskN+jHIe4YjVQotZLIB7FcZr1Tk35XJN08re99cxJfEGC/SRHd/VMwn0/WFJDQh6KWjy4fX1K8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSb290LUNBMDAwMDAwMDEtWFMwMDAwMDAwMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALTS+bbifI4ioLdMFp2KjnlkPV+Gq0jq3IjvdPz6AEIHZUFmW9vJW+S/PyWqqdndg67xqOOy5EOHteuwAAAAhz/e0Ych6ONikIIpXPQq1gAAAapyxP88DQJ7CPUAAQABSEFKRf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + etickets[4] = "AAEAAUth7dnIIm2kr6Bw3hZkkBCycZV+73NNOs95tTHFnYyO+GJ/zVOWF1s0Rne2PugqcPHWe9Skn6Z1gGmGdXMgNK5q0+QqWfoG/LkD4F8WvYO06ihcsXfDn9GTDDAcDfFTMWssApcpQeER18S/zG45tug+0ZnsayhmyBbyK6zJnZFm6Mxp9PsuuN79TRpK8pKpRPLXVjzKFUaY2Y3g+Tc+RHJ/ptDb+ONgP6iZ2kd9k81J1kugRn6DqisbC8ZKuEaHqeCQ3hLc9xKc2EfpVWW62grEbkWSZOM7ellar5BM0Hd3Ne3Xcsp8b1v4JFMVdRahrL94qVlFX7GugQubHK9tI4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSb290LUNBMDAwMDAwMDEtWFMwMDAwMDAwMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALTS+bbifI4ioLdMFp2KjnlkPV+Gq0jq3IjvdPz6AEIHZUFmW9vJW+S/PyWqqdndg67xqOOy5EOHteuwAAAAk+b/rdrXVvwTB4zE+vuiXgAAAUaiyG6pjQJ7CPUAAQABSEFQRf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + etickets[5] = "AAEAAZzaP2lz+bZIy6fSW/ncG+8BnyYhX6+lyEwGDBMlyTInPeNxvEohK4jjhZzYK6uvV4PM5MPLu0e3rfcEqzYTVKVJI9sn06O+JuTFzEIzyV5OTRRNqAlwzG+6KFSwMxwH5qOfwRCoSYsy6vw+F0QAbwFcdvuN0BpRVhDZKu390GBCM6sKTFE881oX+q2RfhKnA+ZFsSYlklpOAHwdlzRrlgVgnfkHTGh0JgtgcNtvWsPgfEZqkj5lrrvINWwr+yWZKrIhcD1xRIWX2w8zKBCExyqdmIfMKPDR0+RLzi4EAMWcNEA3pDUoneKcxE/tlZ3m5A0heRSCfTlbeMcyra0fR0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSb290LUNBMDAwMDAwMDEtWFMwMDAwMDAwMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALTS+bbifI4ioLdMFp2KjnlkPV+Gq0jq3IjvdPz6AEIHZUFmW9vJW+S/PyWqqdndg67xqOOy5EOHteuwAAAARfNQD9UtTUOVSCUyDkupPAAAASdjIxILugJ7CPUAAQABSENTRf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + etickets[6] = "AAEAAX8fEr0hDFGPJalcFmdQztiwR3Fb8tvPEAfeA5kO2Nbynyw2bhL4MAV54sGsxHfBlcm5kTNnH+V+aBum2I+U/Y9sxXQhqvlNJ9qjBNCAJBR8DIz8//biXPwbh0hQOp4FaH9yYfGVNw4m7qrKvFiSVvrCLS4SZJx5Ka8QjiS2smDtj++b7F78C2k6UK7guCRgnVoUTg4po/4+FOSdfkKEdOIKNXKfnocJcUsdmOBO4NLK73/lDdz3XPjWTPtg2/IQ2UGxp5oH1Z+W57jcWFfYgIDcXk4E1xtBd4s33om4RMnL4jvVUtxA2xx/ixQ7H2j3Inqk71lTqEZDHFckwoUY9OUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSb290LUNBMDAwMDAwMDEtWFMwMDAwMDAwMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALTS+bbifI4ioLdMFp2KjnlkPV+Gq0jq3IjvdPz6AEIHZUFmW9vJW+S/PyWqqdndg67xqOOy5EOHteuwAAAAWnOfqtsyBhg0ReE0M9dVxwAAAV8mkF0mKAJ7CPUAAQABSEFXRQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + etickets[7] = "AAEAAR1dFX4o1WcYlRaHWYwiNPqKuGB6xHbZ46f8w9LBZXRkX/5P9ORxHKwjeWI0sAM3m0bCn4gR1et4821FrDw1gidnMcRqolZqvvtDhtRj3whdYbDgIii1lmpZPOOoWQnTKaKJp6/FUm+eytBB/wr9azJ69tyP3fp0Brg1m8dgRajg5gs2rTKOEpOeuCGMaQBB/a05TRf9zyfvOhL8kHQher8lB2AdkkL88AD2PqIDV4HeE82dk7hi/NI1HZVJejf5aOcswc3FhDNHFSBMKKBPGpVD7RHCjJVEoPXa7LhdZZ9nkpmgQaa1F8s06N5q/yD1rwtWnTyHca7U1z9BoTghn5EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSb290LUNBMDAwMDAwMDEtWFMwMDAwMDAwMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALTS+bbifI4ioLdMFp2KjnlkPV+Gq0jq3IjvdPz6AEIHZUFmW9vJW+S/PyWqqdndg67xqOOy5EOHteuwAAAAT2D7XouKddLkZlKJXqcuegAAtzdsE3eQLQJ7CPUAAQABSEFERf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + //etickets[8] = "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" + var certs [2]string + // vWii certs + certs[0] = "AAEAALOtsyJrPD3/G0tAdxb/T3rXZIbIlaxWLSHxBgHU9mQoGRwHdo/fGuLOeyfJD7wK0DEleOwHebZX1DckE6f4bwwUwO9uCUHtKwXsOVc2B4kASoeNLp34x6Wp+MqzEbEYeVe7+JjiolQCz1Q5zyu/oOH4XAZug5rglMpH4BVY9W5vNOkqotw4k343zYxcTf0vEU/oaMmo2f7YbgwhdaK9fom5x7UT9Bp5YUQ5EO/51/5XIhjVbft/SXqky5DU8a6xduRoXaeUQGCYLwRIQB/Pxrrr2hYwtHO0FSM1CAcKn0+JeOYs7F6SRqWovaCFeGh1DDoRL6+V6DjImQ6HsWLNENqzMZZl74ibVBuzNrtnU5+vwq4tCi51wCN06k6sjZlQf1m5U3cwXyY1xgipkJOsj8beI7l66nC0xM9msw5YMg7FtnIESM47sRxTH8twKHy1wnxnT7v9jH/JQiCkcyMdWH5aGhqC43V5obuCbs4Bccl1Y0dLHUbmebKCN2IRzccAL0aHwjxtwNW1eG7h8nP/AZJQD/THUGrucrb0PfYI/qWDofmGD4evUkRUu0fDBgyU6Zv31jKnyKtLT/U1IR/BgEe7evpaK9e4hK2OVk9bif83lzfx9QE7H57EGG+SKtXEs8DVhwucBK8atfO8bQrxfUcI5EPpc/e3cHdUuvPs0qxJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUm9vdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFDQTAwMDAwMDAxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW/p9XLJ5yeLu4SHG6vRP9jn4jweLS3ftn5VgsDWCgbUOVatyERWhd3A8ejD+OunvHGC8HZdGdrI6aMwEsZhSW8lo8R3i21Dk2efwceVi2uIJIjPp02P2HdfBn/OkqR6PZVPUcd17hLnxuM5zNfD1VAVjoeq4OWPgm+kBAR+ZVGNhKHAg6cwNq0h/FA1mJqGDbScRHyBo3kdyFJFRz2nGG6YO+dlJoPcfVJny05rSjHAFNIKTxDH/vTP2vKYNxxleorzFbSALr20G0JxB243pxyAVTKSDK2nAjGnNOwc6AGNgL0YtM4BhpepskVzVYjV5w+tkzkTvWG0UuqqINAGbPuvu03kAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + certs[1] = "AAEAAX2dXrpSgdynBl0vCGjbisc6zn6pkfGWn+HQ8sEfrsDD8BrctEat5coDtiUhlGLG4UENueY/3pjRryY7TLKHhCeCcu8nE0uHwljWe2Lytb+ctrqMiRkuxQaJrHQkoCIJQAPumKS9LwE7WT/lZmzV61rXpJMQ8077tD1Gy/G1I8+C9o61bbkEp8KoK+EdeNObog2Q0wdC2156we/yIVEJYs+pFKiA3PQXupmTCu4IsLDlGj6fr83C1+PLoS86wAeQ3kR6w8U4qGeSOAeL1MSyRawpFohtKg5ZTu1cyDVpi01iON8Fck3M9oGAinB0Blkwv/hRQTfoFfq6oXK44GlsYeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSb290LUNBMDAwMDAwMDEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVhTMDAwMDAwMDMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADxuJ/RrQepN4p7EAx9xzm+nt23MgCJqyWx+HGvWqn0WJ7RgwIyjoEaH+/QCcgGNkP4VLnhO7thOnrPhxSFa6Rbque7xk6y912H6/Jn7Q+kQakzZl5XfVreq/tGLnYAypzpTcTLmDmSq3ovs6Oeor+cU+zQ3Ppri16yy6QP+kB1+PKy3pc4EYct9eKmw4sv3I5X3b1fRusn1hlS9q74YrfumsaCorGaqbVY++uziS+9UMn13EpunJv+RYA0qUIYLd63X+DRs98Ol+OZgIdwGMKyg/E1dXxaMPw/MISkmqrAHucGaU+OFEjaEjrMT/omqjj3778njzaXeXddt8Wtx4mR3PhDjQABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + //WiiSOAP certs + //certs[0] = "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" + //certs[1] = "AAEAALOtsyJrPD3/G0tAdxb/T3rXZIbIlaxWLSHxBgHU9mQoGRwHdo/fGuLOeyfJD7wK0DEleOwHebZX1DckE6f4bwwUwO9uCUHtKwXsOVc2B4kASoeNLp34x6Wp+MqzEbEYeVe7+JjiolQCz1Q5zyu/oOH4XAZug5rglMpH4BVY9W5vNOkqotw4k343zYxcTf0vEU/oaMmo2f7YbgwhdaK9fom5x7UT9Bp5YUQ5EO/51/5XIhjVbft/SXqky5DU8a6xduRoXaeUQGCYLwRIQB/Pxrrr2hYwtHO0FSM1CAcKn0+JeOYs7F6SRqWovaCFeGh1DDoRL6+V6DjImQ6HsWLNENqzMZZl74ibVBuzNrtnU5+vwq4tCi51wCN06k6sjZlQf1m5U3cwXyY1xgipkJOsj8beI7l66nC0xM9msw5YMg7FtnIESM47sRxTH8twKHy1wnxnT7v9jH/JQiCkcyMdWH5aGhqC43V5obuCbs4Bccl1Y0dLHUbmebKCN2IRzccAL0aHwjxtwNW1eG7h8nP/AZJQD/THUGrucrb0PfYI/qWDofmGD4evUkRUu0fDBgyU6Zv31jKnyKtLT/U1IR/BgEe7evpaK9e4hK2OVk9bif83lzfx9QE7H57EGG+SKtXEs8DVhwucBK8atfO8bQrxfUcI5EPpc/e3cHdUuvPs0qxJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUm9vdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFDQTAwMDAwMDAxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW/p9XLJ5yeLu4SHG6vRP9jn4jweLS3ftn5VgsDWCgbUOVatyERWhd3A8ejD+OunvHGC8HZdGdrI6aMwEsZhSW8lo8R3i21Dk2efwceVi2uIJIjPp02P2HdfBn/OkqR6PZVPUcd17hLnxuM5zNfD1VAVjoeq4OWPgm+kBAR+ZVGNhKHAg6cwNq0h/FA1mJqGDbScRHyBo3kdyFJFRz2nGG6YO+dlJoPcfVJny05rSjHAFNIKTxDH/vTP2vKYNxxleorzFbSALr20G0JxB243pxyAVTKSDK2nAjGnNOwc6AGNgL0YtM4BhpepskVzVYjV5w+tkzkTvWG0UuqqINAGbPuvu03kAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAFOAF/xP4Z1jbacRWMP1Jv0zF1Uz8wiNHJXq6S6U9KzPebsnqFXVFOuX5M9lr/3zHp5Vm6Eextgd8KpOHEwGozTyT1Nsybph5Jm6dO6n3m8Rjj6LSCgOnBnpBGnoLfZEq0RajrEbjJCR8IIurSUnMUu0C8Z9lHg3y42U6qvl6aSu6kd2G4kLrMId1URzpj2ovQmyScE0PyN1ICe12G9EbeFlIzW0HrbpAjQ8Ib2Wq4ZFLKImqiuSqKqx2GpDUEssVAJqz6T/Kkk3s5PfAar3C5gnWi+AHP6gFdqFF7txIt0MocHk8j8ptg+CW7F8qnEIedIs3NAW+L6iuFYeOnVI4h1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUm9vdC1DQTAwMDAwMDAxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFDUDAwMDAwMDA0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8bigZMFt84MpVcMpW3LwMy6X7xSEimgEnKaOrN4UUDO4bBCNSDNcXQyrdwRiVEdVRSqQAHCxVpJcF4bizSBtzNwsLjduJ/y0IGbMCozp/uhXBObKYxoufpF+lHw5kXc2KdFVYYW717dzyjdHnl+qo7YF4AHhrOWN2PhHgtZF/OOhzQOrNvDzhrGi0TdAoZSKU7obDYxIY81rLC4gZJSATGL6qTp+M6nqeGtZyuOrNkX0y4/XkGuCaM2s8Xs67EaDG5H23hhhg7xLMmeTxy5Q2R42oNziuX2gIT5GlgIfMxy+ro38kocyqkTceOcZmj3dVyJ+nnfeMmOGk2wRrKcPgRnTOpkAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAF9nV66UoHcpwZdLwho24rHOs5+qZHxlp/h0PLBH67Aw/Aa3LRGreXKA7YlIZRixuFBDbnmP96Y0a8mO0yyh4QngnLvJxNLh8JY1nti8rW/nLa6jIkZLsUGiax0JKAiCUAD7pikvS8BO1k/5WZs1eta16STEPNO+7Q9RsvxtSPPgvaOtW25BKfCqCvhHXjTm6INkNMHQtteesHv8iFRCWLPqRSogNz0F7qZkwruCLCw5Ro+n6/Nwtfjy6EvOsAHkN5EesPFOKhnkjgHi9TEskWsKRaIbSoOWU7tXMg1aYtNYjjfBXJNzPaBgIpwdAZZML/4UUE36BX6uqFyuOBpbGHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUm9vdC1DQTAwMDAwMDAxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFYUzAwMDAwMDAzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8bif0a0HqTeKexAMfcc5vp7dtzIAiaslsfhxr1qp9Fie0YMCMo6BGh/v0AnIBjZD+FS54Tu7YTp6z4cUhWukW6rnu8ZOsvddh+vyZ+0PpEGpM2ZeV31a3qv7Ri52AMqc6U3Ey5g5kqt6L7OjnqK/nFPs0Nz6a4tessukD/pAdfjyst6XOBGHLfXipsOLL9yOV929X0brJ9YZUvau+GK37prGgqKxmqm1WPvrs4kvvVDJ9dxKbpyb/kWANKlCGC3et1/g0bPfDpfjmYCHcBjCsoPxNXV8WjD8PzCEpJqqwB7nBmlPjhRI2hI6zE/6Jqo49++/J482l3l3XbfFrceJkdz4Q40AAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + for i := 0; i < len(etickets); i++ { + e.AddKVNode("ETickets", etickets[i]) + } + for i := 0; i < len(certs); i++ { + e.AddKVNode("Certs", certs[i]) + }*/ e.AddKVNode("ForceSyncTime", "0") e.AddKVNode("ExtTicketTime", e.Timestamp()) e.AddKVNode("SyncTime", e.Timestamp()) @@ -179,8 +231,62 @@ func purchaseTitle(e *Envelope) { // Title key is encrypted with the common key and current title ID ticketStruct.UpdateTitleKey(contentAesKey) + tikFile, err := os.ReadFile("./tickets/" + strings.ToLower(strings.Replace(titleId, "00010001", "", 1)) + ".tik") + fmt.Println("ticket name: " + strings.ToLower(strings.Replace(titleId, "00010001", "", 1)) + ".tik") + if err != nil { + tikFile, err = os.ReadFile("/media/sdc1/hydrobleach/Local/ccs.cdn.shop.wii.com/ccs/download/" + titleId + "/cetk") + fmt.Println("ticket name: " + titleId + ".tik") + } + /*wad, err := wadlib.LoadWADFromFile("../WiiLikeToParty/wad/ticket/" + strings.ToLower(titleId) + "_bogus.wad") + if err != nil { + e.Error(2, "couldn't read wad", err) + return + } + wadTicket, err := wad.GetTicket() + if err != nil { + e.Error(2, "couldn't read ticket", err) + return + }*/ + /*wad, err := wadlib.LoadWADFromFile("./smash bros.wad") + if err != nil { + e.Error(2, "couldn't read wad", err) + return + } + wad.ChangeTitleKey(contentAesKey) + tik, err := wad.GetTicket() + if err != nil { + e.Error(2, "couldn't read ticket", err) + return + } + os.WriteFile("content/cetk", tik, 0777) - version := 0 + wadBytes, err := wad.GetWAD(wadlib.WADTypeCommon) + if err != nil { + e.Error(2, "couldn't get wad", err) + return + } + + wadContent1, err := wad.GetContent(0) + os.WriteFile("content/00000000", wadContent1, 0777) + wadContent2, err := wad.GetContent(1) + os.WriteFile("content/00000001", wadContent2, 0777) + wadContent3, err := wad.GetContent(2) + os.WriteFile("content/00000002", wadContent3, 0777) + wadContent4, err := wad.GetContent(3) + os.WriteFile("content/00000003", wadContent4, 0777) + wadContent5, err := wad.GetContent(4) + os.WriteFile("content/00000004", wadContent5, 0777) + wadContent6, err := wad.GetContent(5) + os.WriteFile("content/00000005", wadContent6, 0777) + wadContent7, err := wad.GetContent(6) + os.WriteFile("content/00000006", wadContent7, 0777) + wadContent8, err := wad.GetContent(7) + os.WriteFile("content/00000007", wadContent8, 0777) + wadTmd, err := wad.GetTMD() + os.WriteFile("content/tmd", wadTmd, 0777) + os.WriteFile("smashnew.wad", wadBytes[:], 0777)*/ + + //version := 0 if titleId == WiinoMaServiceTitleID { // Wii no Ma needs the ticket to be in the v1 ticket format. // Update the ticket to reflect that. @@ -202,6 +308,7 @@ func purchaseTitle(e *Envelope) { // Convert reference ID to bytes refIdBytes, err := hex.DecodeString(refId) + log.Printf("refIdBytes err: %b", refIdBytes) if err != nil { log.Printf("unexpected error converting reference id to bytes: %v", err) e.Error(2, "error purchasing", nil) @@ -273,8 +380,6 @@ func purchaseTitle(e *Envelope) { return } - version = app.Shop.Version - err = binary.Write(ticket, binary.BigEndian, ticketStruct) if err != nil { e.Error(2, "failed to create ticket", err) @@ -283,33 +388,63 @@ func purchaseTitle(e *Envelope) { } // Associate the given title ID with the user. - _, err = pool.Exec(ctx, AssociateTicketStatement, accountId, titleId, version, itemId, time.Now().UTC()) + //_, err = pool.Exec(ctx, AssociateTicketStatement, accountId, titleId, version, itemId, time.Now().UTC()) + //if err != nil { + // log.Printf("unexpected error purchasing: %v", err) + // e.Error(2, "error purchasing", nil) + //} + amount, err := e.getKey("Amount") if err != nil { - log.Printf("unexpected error purchasing: %v", err) - e.Error(2, "error purchasing", nil) + e.Error(2, "couldn't get amount", err) } + amount = strings.ReplaceAll(amount, ".", "") + amountInt, err := strconv.Atoi(amount) + if err != nil { + e.Error(2, "couldn't convert amount to integer", err) + } // The returned ticket is expected to have two other certificates associated. - ticketString := b64(append(ticket.Bytes(), wadlib.CertChainTemplate...)) - - e.AddCustomType(getBalance()) + //ticketString := b64(append(ticket.Bytes(), wadlib.CertChainTemplate...)) + ticketString := b64(tikFile) + //var pointsToRemove int + e.AddCustomType(getBalance(e)) e.AddCustomType(Transactions{ TransactionId: "00000000", Date: e.Timestamp(), Type: "PURCHGAME", - TotalPaid: 0, + TotalPaid: amountInt, Currency: "POINTS", ItemId: itemId, ItemPricing: Prices{ ItemId: itemId, - Price: Price{Amount: 0, Currency: "POINTS"}, + Price: Price{Amount: amountInt, Currency: "POINTS"}, Limits: LimitStruct(PR), LicenseKind: PERMANENT, }, }) - e.AddKVNode("SyncTime", e.Timestamp()) + var points string + deviceToken, err := e.getKey("DeviceToken") + if err != nil { + e.Error(2, "missing device token", err) + return + } + deviceToken = strings.Split(deviceToken, "-")[1] + md5DeviceToken := fmt.Sprintf("%x", md5.Sum([]byte(deviceToken))) + serialNo, err := e.getKey("SerialNo") + if err != nil { + e.Error(2, "missing serial", err) + return + } + points = strconv.Itoa(getBalance(e).Amount - amountInt) + _, err = pool.Exec(ctx, AssociatePointsStatement, e.DeviceId(), deviceToken, md5DeviceToken, accountId, e.region, serialNo, points) + if err != nil { + e.Error(103, "error calculating points", err) + } + e.AddKVNode("SyncTime", e.Timestamp()) + //log.Println(ticketString) e.AddKVNode("ETickets", ticketString) + //e.AddKVNode("ETickets", "AAEAAR1dFX4o1WcYlRaHWYwiNPqKuGB6xHbZ46f8w9LBZXRkX/5P9ORxHKwjeWI0sAM3m0bCn4gR1et4821FrDw1gidnMcRqolZqvvtDhtRj3whdYbDgIii1lmpZPOOoWQnTKaKJp6/FUm+eytBB/wr9azJ69tyP3fp0Brg1m8dgRajg5gs2rTKOEpOeuCGMaQBB/a05TRf9zyfvOhL8kHQher8lB2AdkkL88AD2PqIDV4HeE82dk7hi/NI1HZVJejf5aOcswc3FhDNHFSBMKKBPGpVD7RHCjJVEoPXa7LhdZZ9nkpmgQaa1F8s06N5q/yD1rwtWnTyHca7U1z9BoTghn5EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSb290LUNBMDAwMDAwMDEtWFMwMDAwMDAwMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALTS+bbifI4ioLdMFp2KjnlkPV+Gq0jq3IjvdPz6AEIHZUFmW9vJW+S/PyWqqdndg67xqOOy5EOHteuwAAAAT2D7XouKddLkZlKJXqcuegAAtzdsE3eQLQJ7CPUAAQABSEFERf//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//////////////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==") // Two cert types must be present. e.AddKVNode("Certs", b64(wadlib.CertChainTemplate)) e.AddKVNode("Certs", b64(wadlib.CertChainTemplate)) @@ -421,3 +556,183 @@ func getECConfig(e *Envelope) { e.AddKVNode("CasURL", genServiceUrl("cas", "CatalogingSOAP")) e.AddKVNode("NusURL", genServiceUrl("nus", "NetUpdateSOAP")) } + +func purchasePoints(e *Envelope) { + deviceToken, err := e.getKey("DeviceToken") + if err != nil { + e.Error(2, "missing device token", err) + return + } + deviceToken = strings.Split(deviceToken, "-")[1] + md5DeviceToken := fmt.Sprintf("%x", md5.Sum([]byte(deviceToken))) + accountId, err := e.getKey("AccountId") + if err != nil { + e.Error(2, "missing account ID", err) + return + } + serialNo, err := e.getKey("SerialNo") + if err != nil { + e.Error(2, "missing serial", err) + return + } + itemId, err := e.getKey("ItemId") + if err != nil { + e.Error(2, "missing item ID", err) + return + } + amount, err := e.getKey("Amount") + if err != nil { + e.Error(2, "couldn't get amount", err) + } + currency, err := e.getKey("Currency") + if err != nil { + e.Error(2, "couldn't get currency", err) + } + var pointsToAdd int + var points string + if itemId == "100008" { + pointsToAdd = 1000 + } else if itemId == "100030" { + pointsToAdd = 2000 + } else if itemId == "100031" { + pointsToAdd = 3000 + } else if itemId == "100032" { + pointsToAdd = 5000 + } + points = strconv.Itoa(getBalance(e).Amount + pointsToAdd) + + _, err = pool.Exec(ctx, AssociatePointsStatement, e.DeviceId(), deviceToken, md5DeviceToken, accountId, e.region, serialNo, points) + if err != nil { + e.Error(113, "error purchasing points", err) + } + itemIdStr, err := strconv.Atoi(itemId) + if err != nil { + e.Error(201, "couldn't convert item id to string", err) + } + rand.NewSource(time.Now().UnixNano()) + // Generate a random 8-digit integer + transactionId := 10000000 + rand.Intn(90000000) + e.AddCustomType(PointsPurchaseInfo{ + Transactions: PointsTransactions{ + TransactionId: strconv.Itoa(transactionId), + Date: e.Timestamp(), + Type: "PURCHPOINTS", + TotalPaid: amount, + Currency: currency, + ItemId: itemId, + ItemPricing: GiftPrices{ + ItemId: itemIdStr, + Price: GiftPrice{ + Amount: amount, + Currency: currency, + }, + }, + }, + }) +} +func checkAccountBalance(e *Envelope) { + e.AddCustomType(getBalance(e)) +} +func giftTitle(e *Envelope) { + accountId, err := e.getKey("AccountId") + if err != nil { + e.Error(1, "missing mandatory key named AccountId", err) + } + titleId, err := e.getKey("TitleId") + if err != nil { + e.Error(1, "missing mandatory key named TitleId", err) + } + notes, err := e.getKey("Notes") + if err != nil { + e.Error(1, "missing mandatory key named Notes", err) + } + unescapedNotes := html.UnescapeString(notes) + doc, err := xmlquery.Parse(strings.NewReader(unescapedNotes)) + if err != nil { + fmt.Println("Error:", err) + return + } + senderFCNode := xmlquery.FindOne(doc, "//DeviceCode") + var senderFC string + if senderFCNode != nil { + senderFC = senderFCNode.InnerText() + } else { + e.Error(124, "Cannot find sender friend code", nil) + } + amount, err := e.getKey("Amount") + if err != nil { + e.Error(2, "couldn't get amount", err) + } + amount = strings.ReplaceAll(amount, ".", "") + log.Println("New amount: " + amount) + amountInt, err := strconv.Atoi(amount) + if err != nil { + e.Error(2, "couldn't convert amount to integer", err) + } + + rand.NewSource(time.Now().UnixNano()) + // Generate a random 8-digit integer + transactionId := 10000000 + rand.Intn(90000000) + log.Println(transactionId) + _, err = pool.Exec(ctx, AssociateGiftedTitleStatement, titleId, strconv.Itoa(transactionId+1), senderFC) + if err != nil { + e.Error(123, "error putting title in gifted titles table", err) + } + + var points string + deviceToken, err := e.getKey("DeviceToken") + if err != nil { + e.Error(2, "missing device token", err) + return + } + deviceToken = strings.Split(deviceToken, "-")[1] + md5DeviceToken := fmt.Sprintf("%x", md5.Sum([]byte(deviceToken))) + serialNo, err := e.getKey("SerialNo") + if err != nil { + e.Error(2, "missing serial", err) + return + } + points = strconv.Itoa(getBalance(e).Amount - amountInt) + + _, err = pool.Exec(ctx, AssociatePointsStatement, e.DeviceId(), deviceToken, md5DeviceToken, accountId, e.region, serialNo, points) + if err != nil { + e.Error(133, "error calculating points", err) + } + + e.AddCustomType(getBalance(e)) + e.AddCustomType(GiftTransactions{ + TransactionId: strconv.Itoa(transactionId), + Date: e.Timestamp(), + Type: "PGIFTGAME", + }) + e.AddCustomType(GiftTransactions{ + TransactionId: strconv.Itoa(transactionId + 1), + Date: e.Timestamp(), + Type: "RGIFTGAME", + }) +} + +func acceptGiftTitle(e *Envelope) { + titleId, err := e.getKey("TitleId") + if err != nil { + e.Error(2, "missing mandatory key named TitleId", err) + } + accept, err := e.getKey("Accept") + if err != nil { + e.Error(2, "missing mandatory key named Accept", err) + } + transId, err := e.getKey("TransactionId") + if err != nil { + e.Error(2, "missing mandatory key named TransactionId", err) + } + if accept != "1" { + e.Error(10, "not accepting", nil) + } + + _, err = pool.Exec(ctx, RemoveGiftedTitleStatement, titleId, transId) + if err != nil { + e.Error(143, "error removing title from database", err) + } + //Probably need to add ETicket, but will do later. + +}