diff --git a/api/crypto.go b/api/crypto.go deleted file mode 100644 index 5c96c92..0000000 --- a/api/crypto.go +++ /dev/null @@ -1,31 +0,0 @@ -package api - -import ( - "errors" -) - -// Crypto is a common interface for allowing pluggable signature -type Crypto interface { - CreateIV() []byte - Encrypt(in []byte, iv []byte) ([]byte, error) - Enabled() bool -} - -// DefaultCrypto is a minimally implemented version of the Crypto interface -type DefaultCrypto struct{} - -// Encrypt does nothing in the mock -func (c *DefaultCrypto) Encrypt(in []byte, iv []byte) ([]byte, error) { - return nil, errors.New("Cannot encrypt using the mock") -} - -// CreateIV creates a random initialization vector to be used with the Encrypt function -func (c *DefaultCrypto) CreateIV() []byte { - iv := make([]byte, 32) - return iv -} - -// Enabled returns wether or not crypto is enabled -func (c *DefaultCrypto) Enabled() bool { - return false -} diff --git a/api/location_test.go b/api/location_test.go index f05d34c..c23cff1 100644 --- a/api/location_test.go +++ b/api/location_test.go @@ -3,7 +3,7 @@ package api import "testing" func BenchmarkGetBytes(b *testing.B) { - l := Location{0.0, 0.0, 0.0} + l := Location{0.0, 0.0, 0.0, 0.0} for n := 0; n < b.N; n++ { l.GetBytes() } diff --git a/api/session.go b/api/session.go index 609b919..8a22567 100644 --- a/api/session.go +++ b/api/session.go @@ -3,15 +3,16 @@ package api import ( "context" "crypto/rand" + "errors" "fmt" "log" "time" "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/proto" - protos "github.com/pogodevorg/POGOProtos-go" "github.com/pogodevorg/pgoapi-go/auth" + "gopkg.in/pokelibs/go-pokelib.v43" ) const defaultURL = "https://pgorelease.nianticlabs.com/plfe/rpc" @@ -20,7 +21,6 @@ const downloadSettingsHash = "05daf51635c82611d1aac95c0b051d3ec088a930" // Session is used to communicate with the Pokémon Go API type Session struct { feed Feed - crypto Crypto location *Location rpc *RPC url string @@ -32,6 +32,8 @@ type Session struct { started time.Time provider auth.Provider hash []byte + + deviceInfo *protos.Signature_DeviceInfo } func generateRequests() []*protos.Request { @@ -43,7 +45,20 @@ func getTimestamp(t time.Time) uint64 { } // NewSession constructs a Pokémon Go RPC API client -func NewSession(provider auth.Provider, location *Location, feed Feed, crypto Crypto, debug bool) *Session { +func NewSession(provider auth.Provider, location *Location, feed Feed, deviceInfo *protos.Signature_DeviceInfo, debug bool) *Session { + if deviceInfo == nil{ + // Default deviceInfo + deviceInfo = &protos.Signature_DeviceInfo{ + DeviceId: "", + DeviceBrand: "Apple", + DeviceModel: "iPhone", + DeviceModelBoot: "Iphone7,2", + HardwareManufacturer: "Apple", + HardwareModel: "N66AP", + FirmwareBrand: "iPhone OS", + FirmwareType: "9.3.3", + } + } return &Session{ location: location, rpc: NewRPC(), @@ -51,10 +66,10 @@ func NewSession(provider auth.Provider, location *Location, feed Feed, crypto Cr debug: debug, debugger: &jsonpb.Marshaler{Indent: "\t"}, feed: feed, - crypto: crypto, started: time.Now(), hasTicket: false, hash: make([]byte, 32), + deviceInfo:deviceInfo, } } @@ -118,36 +133,34 @@ func (s *Session) Call(ctx context.Context, requests []*protos.Request) (*protos } } - if s.crypto.Enabled() && s.hasTicket { + if s.hasTicket { t := getTimestamp(time.Now()) - + ticket, _ := proto.Marshal(s.ticket) requestHash := make([]uint64, len(requests)) for idx, request := range requests { - hash, err := generateRequestHash(s.ticket, request) + req, err := proto.Marshal(request) if err != nil { return nil, err } - requestHash[idx] = hash + requestHash[idx] = pokelib.HashRequest(ticket, req) } - locationHash1, err := generateLocation1(s.ticket, s.location) - if err != nil { - return nil, err - } - - locationHash2, err := generateLocation2(s.location) - if err != nil { - return nil, err - } + locationHash1 := pokelib.HashLocation1(ticket, s.location.Lat, s.location.Lon, s.location.Alt) + locationHash2 := pokelib.HashLocation2(s.location.Lat, s.location.Lon, s.location.Alt) signature := &protos.Signature{ - RequestHash: requestHash, - LocationHash1: locationHash1, - LocationHash2: locationHash2, + RequestHash: requestHash, + LocationHash1: int32(locationHash1), + LocationHash2: int32(locationHash2), + ActivityStatus: &protos.Signature_ActivityStatus{ + Stationary: true, + }, + DeviceInfo: s.deviceInfo, SessionHash: s.hash, Timestamp: t, TimestampSinceStart: (t - getTimestamp(s.started)), + Unknown25: pokelib.Hash25(), } signatureProto, err := proto.Marshal(signature) @@ -155,14 +168,8 @@ func (s *Session) Call(ctx context.Context, requests []*protos.Request) (*protos return nil, ErrFormatting } - iv := s.crypto.CreateIV() - encryptedSignature, err := s.crypto.Encrypt(signatureProto, iv) - if err != nil { - return nil, ErrFormatting - } - requestMessage, err := proto.Marshal(&protos.SendEncryptedSignatureRequest{ - EncryptedSignature: encryptedSignature, + EncryptedSignature: pokelib.Encrypt(signatureProto, uint32(signature.TimestampSinceStart)), }) if err != nil { return nil, ErrFormatting @@ -265,6 +272,7 @@ func (s *Session) Announce(ctx context.Context) (mapObjects *protos.GetMapObject {RequestType: protos.RequestType_CHECK_AWARDED_BADGES}, {protos.RequestType_DOWNLOAD_SETTINGS, settingsMessage}, {protos.RequestType_GET_MAP_OBJECTS, getMapObjectsMessage}, + {RequestType: protos.RequestType_CHECK_CHALLENGE}, } response, err := s.Call(ctx, requests) @@ -273,6 +281,9 @@ func (s *Session) Announce(ctx context.Context) (mapObjects *protos.GetMapObject } mapObjects = &protos.GetMapObjectsResponse{} + if len(response.Returns) < 5 { + return nil, errors.New("Empty response") + } err = proto.Unmarshal(response.Returns[5], mapObjects) if err != nil { return nil, &ErrResponse{err} diff --git a/api/util.go b/api/util.go deleted file mode 100644 index 694a3b5..0000000 --- a/api/util.go +++ /dev/null @@ -1,78 +0,0 @@ -package api - -import ( - "github.com/OneOfOne/xxhash/native" - "github.com/golang/protobuf/proto" - protos "github.com/pogodevorg/POGOProtos-go" -) - -const hashSeed = uint64(0x1B845238) // Static xxhash seed - -func protoToXXHash64(seed uint64, pb proto.Message) (uint64, error) { - h := xxhash.NewS64(seed) - b, err := proto.Marshal(pb) - if err != nil { - return uint64(0), ErrFormatting - } - _, err = h.Write(b) - if err != nil { - return uint64(0), ErrFormatting - } - return h.Sum64(), nil -} - -func protoToXXHash32(seed uint32, pb proto.Message) (uint32, error) { - h := xxhash.NewS32(seed) - b, err := proto.Marshal(pb) - if err != nil { - return uint32(0), ErrFormatting - } - _, err = h.Write(b) - if err != nil { - return uint32(0), ErrFormatting - } - return h.Sum32(), nil -} - -func locationToXXHash32(seed uint32, location *Location) (uint32, error) { - h := xxhash.NewS32(seed) - b := location.GetBytes() - _, err := h.Write(b) - if err != nil { - return uint32(0), ErrFormatting - } - return h.Sum32(), nil -} - -func generateRequestHash(authTicket *protos.AuthTicket, request *protos.Request) (uint64, error) { - h, err := protoToXXHash64(hashSeed, authTicket) - if err != nil { - return h, ErrFormatting - } - h, err = protoToXXHash64(h, request) - if err != nil { - return h, ErrFormatting - } - - return h, nil -} - -func generateLocation1(authTicket *protos.AuthTicket, location *Location) (uint32, error) { - h, err := protoToXXHash32(uint32(hashSeed), authTicket) - if err != nil { - return h, ErrFormatting - } - h, err = locationToXXHash32(h, location) - if err != nil { - return h, ErrFormatting - } - return h, nil -} - -func generateLocation2(location *Location) (uint32, error) { - h, err := locationToXXHash32(uint32(hashSeed), location) - if err != nil { - return h, ErrFormatting - } - return h, nil -} diff --git a/cli/cli.go b/cli/cli.go index bf81af9..44b369b 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -1,16 +1,11 @@ package cli -import ( - "github.com/pogodevorg/pgoapi-go/api" - "github.com/urfave/cli" -) +import "github.com/urfave/cli" // Run interprets arguments and performs actions -func Run(crypto api.Crypto, args []string) { +func Run(args []string) { - w := wrapper{ - crypto: crypto, - } + w := wrapper{} app := cli.NewApp() app.Name = "pgoapi-go" diff --git a/cli/wrapper.go b/cli/wrapper.go index 6fb3ef5..a2954f8 100644 --- a/cli/wrapper.go +++ b/cli/wrapper.go @@ -19,8 +19,7 @@ type wrapper struct { alt float64 accuracy float64 - debug bool - crypto api.Crypto + debug bool } func (w *wrapper) wrap(action func(context.Context, *api.Session, auth.Provider) error) func(*cli.Context) error { @@ -40,7 +39,7 @@ func (w *wrapper) wrap(action func(context.Context, *api.Session, auth.Provider) Accuracy: w.accuracy, } - client := api.NewSession(provider, location, &api.VoidFeed{}, w.crypto, w.debug) + client := api.NewSession(provider, location, &api.VoidFeed{}, nil, w.debug) return action(ctx, client, provider) } diff --git a/main.go b/main.go index 1548533..36dc440 100644 --- a/main.go +++ b/main.go @@ -3,11 +3,9 @@ package main import ( "os" - "github.com/pogodevorg/pgoapi-go/api" "github.com/pogodevorg/pgoapi-go/cli" ) func main() { - crypto := &api.DefaultCrypto{} - cli.Run(crypto, os.Args) + cli.Run(os.Args) }