/** * @param Session $session * @param RequestEnvelope $env * @param Request[] $reqs * @throws Exception */ public static function sign(Session $session, RequestEnvelope $env, $reqs) { if (!$session->hasAuthTicket()) { return; } $location = $session->getLocation(); $rawTicket = $session->getAuthTicket()->toBinary(); $microTime = MicroTime::get(); $protoSignature = new ProtoSignature(); $protoSignature->setTimestampSinceStart($microTime - $session->getStartMicroTime()); // TODO: LocationFix // TODO: AndroidGpsInfo // TODO: SensorInfo // TODO: DeviceInfo // TODO: ActivityStatus $protoSignature->setLocationHash1(self::generateLocation1($rawTicket, $location)); $protoSignature->setLocationHash2(self::generateLocation2($location)); $protoSignature->setSessionHash($session->getSessionHash()); $protoSignature->setTimestamp($microTime); foreach ($reqs as $req) { $protoSignature->addRequestHash(self::generateRequestHash($rawTicket, $req->toProto()->toStream()->getContents())); } $protoSignature->setUnknown25(9.909701338899655E+18); $uk6 = new Unknown6(); $uk6->setRequestType(6); $uk2 = new Unknown2(); $enc = Encrypt::encrypt($protoSignature->toStream()->getContents(), random_bytes(32)); $uk2->setEncryptedSignature($enc); $uk6->setUnknown2($uk2); $env->setUnknown6($uk6); $session->getLogger()->debug("Signed request: " . strlen($enc) . " bytes"); }
/** * @param Request[] $reqs * @param bool|false $createEndpoint * @param bool|false $redo * @throws Exception */ public function execute($reqs, $createEndpoint = false, $redo = true) { $reqTypes = []; foreach ($reqs as $req) { $reqTypes[] = get_class($req); } $this->logger->info("Execute " . implode(", ", $reqTypes)); $env = new RequestEnvelope(); $env->setStatusCode(2); $env->setRequestId($this->getRPCId()); $location = $this->session->getLocation(); $env->setLatitude($location->getLatitude()); $env->setLongitude($location->getLongitude()); $env->setAltitude($location->getAltitude()); if ($this->session->hasAuthTicket() && $this->session->getAuthTicket()->isValid()) { $this->logger->debug("Existing auth ticket"); $env->setAuthTicket($this->session->getAuthTicket()->toProto()); } else { if (!$this->session->hasToken()) { $this->session->authenticate(); } $this->session->setEndpoint(null); $this->logger->debug("Auth with token"); $info = new AuthInfo(); $info->setProvider($this->session->getType()->getProvider()); $token = new JWT(); $token->setContents($this->session->getToken()); $token->setUnknown2(59); $info->setToken($token); $env->setAuthInfo($info); } $env->setUnknown12(989); foreach ($reqs as $req) { $env->addRequests($req->toProto()); } $URL = $this->session->hasEndpoint() ? $this->session->getEndpoint() : self::APIURL; Signature::sign($this->session, $env, $reqs); $resp = $this->client->post($URL, ["body" => $env->toStream()->getContents()]); $respEnv = new ResponseEnvelope($resp->getBody()->getContents()); if ($respEnv->hasAuthTicket()) { $ticket = new AuthTicket($respEnv->getAuthTicket()); $this->logger->info("Received auth ticket, expires in " . $ticket->getTimeToExpire() . "s"); $this->session->setAuthTicket($ticket); } if ($respEnv->hasApiUrl()) { $endpoint = $respEnv->getApiUrl(); $this->logger->info("Received API endpoint " . $endpoint); $this->session->setEndpoint("https://" . $endpoint . "/rpc"); } $statusCode = $respEnv->getStatusCode(); $this->logger->debug("Status code " . $statusCode); if ($statusCode == 102) { // Some auth problem throw new Exception("Received status code 102: invalid auth"); } elseif ($statusCode == 53) { // Wrong endpoint if ($redo) { sleep(3); $this->execute($reqs, $createEndpoint, false); return; } else { throw new Exception("Received status code 53: wrong endpoint"); } } elseif ($statusCode == 3) { // Possible ban throw new Exception("Received status code 3: account possibly banned"); } if (!$respEnv->hasReturnsList()) { throw new Exception("No responses given"); } $returns = $respEnv->getReturnsList(); $countResponses = $returns->count(); if ($countResponses != count($reqs)) { throw new Exception("Invalid responses found"); } $responses = []; foreach ($returns as $return) { $responses[] = $return; } array_map(function (Request $req, $response) { $req->setRawResponse($response); }, $reqs, $responses); }
/** * Is a setup for the request * * @param RequestEnvelope $requestEnvelope */ private function resetBuilder(RequestEnvelope &$requestEnvelope) { $requestEnvelope->setStatusCode(2); $requestEnvelope->setRequestId($this->getRequestId()); if ($this->lastAuthTicket != null && $this->lastAuthTicket->getExpireTimestampMs() > 0 && $this->lastAuthTicket->getExpireTimestampMs() > round(microtime(true) * 1000)) { $requestEnvelope->setAuthTicket($this->lastAuthTicket); } else { $authInfo = new RequestEnvelope_AuthInfo(); $authInfo->setProvider($this->PokemonGoAPI->getUserProvider()); $authToken = new RequestEnvelope_AuthInfo_JWT(); $authToken->setContents($this->userAuthToken); $authToken->setUnknown2(59); $authInfo->setToken($authToken); $requestEnvelope->setAuthInfo($authInfo); } $requestEnvelope->setUnknown12(989); $requestEnvelope->setLatitude($this->PokemonGoAPI->getLatitude()); $requestEnvelope->setLongitude($this->PokemonGoAPI->getLongitude()); $requestEnvelope->setAltitude($this->PokemonGoAPI->getAltitude()); }