From c1d21ad719b6799ecd5c2181be1569d8344777c1 Mon Sep 17 00:00:00 2001 From: Carlo Field Date: Sat, 18 Apr 2020 19:58:47 +0200 Subject: [PATCH] improve item serialization --- internal/item/bits.go | 21 +++--- internal/item/item.go | 4 +- internal/item/item_test.go | 128 ++++++++++++++++++++++++++++++----- internal/server/character.go | 1 + 4 files changed, 124 insertions(+), 30 deletions(-) diff --git a/internal/item/bits.go b/internal/item/bits.go index 7c947bf..2404e3d 100644 --- a/internal/item/bits.go +++ b/internal/item/bits.go @@ -11,9 +11,11 @@ type Reader struct { stream string } +var ErrOutOfRange = errors.New("error: out of range") + func (r *Reader) ReadInt(n int) (uint64, error) { - if len(r.stream)-n < 0 { - n = len(r.stream) + if len(r.stream) < n { + return 0, ErrOutOfRange } val, err := strconv.ParseUint(r.stream[len(r.stream)-n:], 2, 64) r.stream = r.stream[:len(r.stream)-n] @@ -49,17 +51,12 @@ func (w *Writer) WriteInt(v, n int) error { func (w *Writer) GetBytes() []byte { bs := make([]byte, 0) - for i := len(*w); i > 8; i -= 8 { - p := (*w)[i-8 : i] - i, err := strconv.ParseUint(string(p), 2, 8) - if err != nil { - panic(err) - } - bs = append(bs, byte(i)) + padding := (8 - len(*w)) % 8 + for i := 0; i < padding; i++ { + *w = "0" + *w } - if len(*w)%8 > 0 { - p := (*w)[:len(*w)%8] - i, err := strconv.ParseInt(string(p), 2, 8) + for i := len(*w)/8 - 1; i > -1; i-- { + i, err := strconv.ParseUint(string((*w)[i*8:i*8+8]), 2, 8) if err != nil { panic(err) } diff --git a/internal/item/item.go b/internal/item/item.go index dc683bf..95efa9e 100644 --- a/internal/item/item.go +++ b/internal/item/item.go @@ -178,10 +178,10 @@ func Deserialize(data []byte) (item Item, err error) { for i := 0; i < partCount; i++ { item.Parts[i] = getPart(k, readNBits(r, bits)-1) } - genericCount := int(readNBits(r, 4)) + genericCount := readNBits(r, 4) item.Generics = make([]string, genericCount) bits = getBits("InventoryGenericPartData", item.Version) - for i := 0; i < genericCount; i++ { + for i := 0; i < int(genericCount); i++ { // looks like the bits are the same // for all the parts and generics item.Generics[i] = getPart("InventoryGenericPartData", readNBits(r, bits)-1) diff --git a/internal/item/item_test.go b/internal/item/item_test.go index ae182d4..f59aa2f 100644 --- a/internal/item/item_test.go +++ b/internal/item/item_test.go @@ -2,12 +2,86 @@ package item import ( "encoding/base64" + "encoding/hex" "log" "testing" ) var checks = []string{ "A6cRHH+sfCuWGEZz2Lc5FWDbSfcQLmbaOV6SzgYP", + "AwAAAADFtIC3/mrBkEsaj5NM0xGVIBFDCAAAAAAAMAYA", + "AwAAAABLZ4A3RhkBkWMalJ8AEtSYWC1gJWYIAQAAAAAAyhgA", + "AwAAAADuCYA3RhkBkWMalJ8AEtSYWC1gJmYIAQAAAAAAyhgA", + "AwAAAACiM4A3rVMBk2tkjwhEwkRYO5cMpwkIAQAAAAAAyIAA", + "AwAAAAA+uIC3syBDllvs4u4gGyP7LLHEEkssMQAA", + "AwAAAADtqIC31oBBkWMEBcKAJnqQTAdOLWIIAQAAAAAAyIAA", + "AwAAAACGEoC36JCAkTsKGoSgBASiIgsA", + "AwAAAAAL94C3t9hAkysShLxMKmMLAA==", + "AwAAAAByhIC3A/pBkWMGBYLB+IDMbhnFMWYIAQAAAAAAzoAA", + "AwAAAACr6IC37xABkWsIqFPqeE0YjJJYUxUxhAAAAAAAAGQMAA==", + "AwAAAAB1WoC3t9hAkysShLxMKkMLAA==", + "AwAAAACaOoA3VJMAkSsQUhYFGGMLAA==", + "AwAAAADkl4A3VJMAkSsQUhYFGEMLAA==", + "AwAAAAAZzYA3VJMAkSsQUhYFGAMLAA==", + "AwAAAACd1YA3VJMAkSsQUhYFGKMLAA==", + "AwAAAAC754A3ElwAmCtYUlWPjAAAAA==", + "AwAAAADBk4A3ElwAmCtYUlWxjgAAAA==", + "AwAAAABM+oC33IBBkWMEA0LBZlmkGKfELb4IAQAAAAAAzoAA", + "AwAAAABDBIC3syBDllvs4u4gDG3MtcQVE0tsRQAA", + "AwAAAADT2YC3syBDllvs4u6gz2zcdcUVS0ysRAAA", + "AwAAAAB0xYA3pNNBkXMIKNMJSiplJhFOghEFhAAAAAAAAGUMAA==", + "AwAAAADh6oA3p+vCkHsiOIpkJRQgNB8QyRCcxAwhAAAAAABAGQMA", + "AwAAAACr94A3wNBBkWMIJxRMBMrEIJyELGIIAQAAAAAAyoAA", + "AwAAAAA2EYC3pGNBk2MaDghSkel4SJFSMnQIAQAAAAAAyhgA", + "AwAAAABvRoA38QgBk0sap9jjQvFwZDFDCAAAAAAAQAYA", + "AwAAAABRaYC3DUGBkGMGuXk40BtJSotjghAAAAAAAGAMAA==", + "AwAAAAAHiIC3NmvBkEsaD4dOwwlNchFDCAAAAAAAUAYA", + "AwAAAAC2soA31ECBkFOGteE+ViSvNkwIAQAAAAAA0oAA", + "AwAAAAB0hoA3a1IBk3MeMkhEkisIJhZQhqOLGUIAAAAAAIAzIAA=", + "AwAAAACxi4C3ZINBkXMEA0KBl9EoUowTAtQDhAAAAAAAAGNAAA==", + "AwAAAABMd4C3y+qAEmCaB3LONQrZ6stiihAAAAAAAGAJAA==", + "AwAAAABnloC3z5lBk1saN8zHFMEJCKlMzBACAAAAAACQAQA=", + "AwAAAACIAIC3t9hAkysShLxMKgMLAA==", + "AwAAAADjeIA3VJMAkSsQUhYFGIMLAA==", + "AwAAAADEyIA37wgBk1sap5fBcYmAShxYzBACAAAAAACkAQA=", + // potentially corrupt items + "AwAAAAAZDYC3/mrBkEsaj5NM0xGVIBFDCAAAAAAAMA==", + "AwAAAAA0qYA3RhkBkWMalJ8AEtSYWC1gJWYIAQAAAAAAyg==", + "AwAAAABknYA3RhkBkWMalJ8AEtSYWC1gJmYIAQAAAAAAyg==", + "AwAAAACrOoA3RhkBkWMalJ8AEtSYWC0gJmYIAQAAAAAAyg==", + "AwAAAADHT4A3rVMBk2tkjwhEwkRYO5cMpwkIAQAAAAAAyA==", + "AwAAAAAicYC3syBDllvs4u4gGyP7LLHEEkssMQ==", + "AwAAAAAXDIC31oBBkWMEBcKAJnqQTAdOLWIIAQAAAAAAyA==", + "AwAAAAD+8YC36JCAkTsKGoSgBASiIg==", + "AwAAAADDxoC3t9hAkysShLxMKmM=", + "AwAAAAAxn4C3A/pBkWMGBYLB+IDMbhnFMWYIAQAAAAAAzg==", + "AwAAAACAxIC37xABkWsIqFPqeE0YjJJYUxUxhAAAAAAAAGQ=", + "AwAAAADYYIC3t9hAkysShLxMKkM=", + "AwAAAAA/dIA34pIAkSsQUgAFBGM=", + "AwAAAAAk0oA34pIAkSsQUgAFBEM=", + "AwAAAAATnoA34pIAkSsQUgAFBAM=", + "AwAAAABmoIA34pIAkSsQUgAFBKM=", + "AwAAAACSJoA3ElwAmCtYUlWPjAA=", + "AwAAAAAk/YA3ElwAmCtYUlWxjgA=", + "AwAAAAB00IC33IBBkWMEA0LBZlmkGKfELb4IAQAAAAAAzg==", + "AwAAAACIjYC3syBDllvs4u4gDG3MtcQVE0tsRQ==", + "AwAAAACIjYC3syBDllvs4u4gDG3MtcQVE0tsRQ==", + "AwAAAACIBYC3syBDllvs4u6gz2zcdcUVS0ysRA==", + "AwAAAADCYoA3pNNBkXMIKNMJSiplJhFOghEFhAAAAAAAAGU=", + "AwAAAACsaIA3p+vCkHsiOIpkJRQgNB8QyRCcxAwhAAAAAABAGQ==", + "AwAAAACEUoA3wNBBkWMIJxRMBMrEIJyELGIIAQAAAAAAyg==", + "AwAAAABLQIC3pGNBk2MaDghSkel4SJFSMnQIAQAAAAAAyg==", + "AwAAAABzIoA38QgBk0sap9jjQvFwZDFDCAAAAAAAQA==", + "AwAAAABf1YC3DUGBkGMGuXk40BtJSotjghAAAAAAAGA=", + "AwAAAAAljoC3NmvBkEsaD4dOwwlNchFDCAAAAAAAUA==", + "AwAAAABQjoA31ECBkFOGteE+ViSvNkwIAQAAAAAA0g==", + "AwAAAAAqpYA3a1IBk3MeMkhEkisIJhZQhqOLGUIAAAAAAIAz", + "AwAAAABDxoC3ZINBkXMEA0KBl9EoUowTAtQDhAAAAAAAAGM=", + "AwAAAADQCIC3y+qAEmCaB3LONQrZ6stiihAAAAAAAGA=", + "AwAAAAB4aIC3z5lBk1saN8zHFMEJCKlMzBACAAAAAACQ", + "AwAAAADvLIC3t9hAkysShLxMKgM=", + "AwAAAAB9BoA34pIAkSsQUgAFBIM=", + "AwAAAAAfmYA37wgBk1sap5fBcYmAShxYzBACAAAAAACk", } func TestDecryptSerial(t *testing.T) { @@ -40,24 +114,46 @@ func TestDeserialize(t *testing.T) { func TestSerialize(t *testing.T) { for _, check := range checks { - bs, err := base64.StdEncoding.DecodeString(check) - if err != nil { - panic(err) - } - seed, err := GetSeedFromSerial(bs) - if err != nil { - panic(err) - } - item, err := Deserialize(bs) - if err != nil { - panic(err) - } - bs, err = Serialize(item, seed) - if err != nil { - panic(err) + var result = check + var history = make([]string, 10) + var item Item + var err error + for i := 0; i < 10; i++ { + bs, err := base64.StdEncoding.DecodeString(result) + if err != nil { + panic(err) + } + seed, err := GetSeedFromSerial(bs) + if err != nil { + panic(err) + } + item, err = Deserialize(bs) + if err != nil { + panic(err) + } + bs, err = Serialize(item, seed) + if err != nil { + panic(err) + } + result = base64.StdEncoding.EncodeToString(bs) + history[i] = result } - result := base64.StdEncoding.EncodeToString(bs) if result != check { + log.Println(err) + bs1, _ := base64.StdEncoding.DecodeString(check) + bs2, _ := base64.StdEncoding.DecodeString(result) + log.Println(hex.EncodeToString(bs1)) + log.Println(hex.EncodeToString(bs2)) + dec1, _ := DecryptSerial(bs1) + dec2, _ := DecryptSerial(bs2) + bs1, _ = base64.StdEncoding.DecodeString(check) + bs2, _ = base64.StdEncoding.DecodeString(result) + log.Println(hex.EncodeToString(dec1)) + log.Println(hex.EncodeToString(dec2)) + i1, _ := Deserialize(bs1) + i2, _ := Deserialize(bs2) + log.Println(i1.Version) + log.Println(i2.Version) panic("invalid serial") } } diff --git a/internal/server/character.go b/internal/server/character.go index b28ff92..5f68e57 100644 --- a/internal/server/character.go +++ b/internal/server/character.go @@ -133,6 +133,7 @@ func getItemsRequest(c *gin.Context) { for _, data := range char.InventoryItems { d := make([]byte, len(data.ItemSerialNumber)) copy(d, data.ItemSerialNumber) + log.Println(base64.StdEncoding.EncodeToString(data.ItemSerialNumber)) i, err := item.Deserialize(d) if err != nil { log.Println(err)