/** * @param ProtocolNode $node */ public function process($node) { // Example of process function, you have to guess a number (psss it's 5) // If you guess it right you get a gift $text = $node->getChild('body'); $text = $text->getData(); if ($text && ($text == "5" || trim($text) == "5")) { $this->wp->sendMessageImage($this->target, "https://s3.amazonaws.com/f.cl.ly/items/2F3U0A1K2o051q1q1e1G/baby-nailed-it.jpg"); $this->wp->sendMessage($this->target, "Congratulations you guessed the right number!"); } elseif (ctype_digit($text)) { if ((int) $text != "5") { $this->wp->sendMessage($this->target, "I'm sorry, try again!"); } } $text = $node->getChild('body'); $text = $text->getData(); $notify = $node->getAttribute("notify"); echo "\n- " . $notify . ": " . $text . " " . date('H:i') . "\n"; }
/** * Processes received picture node * * @param ProtocolNode $node * ProtocolNode containing the picture */ protected function processProfilePicture($node) { $pictureNode = $node->getChild("picture"); if ($pictureNode != null) { $type = $pictureNode->getAttribute("type"); $data = $pictureNode->getData(); if ($type == "preview") { $filename = static::PICTURES_FOLDER . "/preview_" . $node->getAttribute("from") . ".jpg"; } else { $filename = static::PICTURES_FOLDER . "/" . $node->getAttribute("from") . ".jpg"; } $fp = @fopen($filename, "w"); if ($fp) { fwrite($fp, $data); fclose($fp); } } }
/** * @param ProtocolNode $groupNode * @param mixed $fromGetGroups */ protected function handleGroupV2InfoResponse(ProtocolNode $groupNode, $fromGetGroups = false) { $creator = $groupNode->getAttribute('creator'); $creation = $groupNode->getAttribute('creation'); $subject = $groupNode->getAttribute('subject'); $groupID = $groupNode->getAttribute('id'); $participants = array(); $admins = array(); if ($groupNode->getChild(0) != null) { foreach ($groupNode->getChildren() as $child) { $participants[] = $child->getAttribute('jid'); if ($child->getAttribute('type') == "admin") { $admins[] = $child->getAttribute('jid'); } } } $this->eventManager()->fire("onGetGroupV2Info", array($this->phoneNumber, $groupID, $creator, $creation, $subject, $participants, $admins, $fromGetGroups)); }
/** * Process media upload response * * @param ProtocolNode $node Message node * @return bool */ protected function processUploadResponse($node) { $id = $node->getAttribute("id"); $messageNode = @$this->mediaQueue[$id]; if ($messageNode == null) { //message not found, can't send! $this->eventManager()->fire("onMediaUploadFailed", array($this->phoneNumber, $id, $node, $messageNode, "Message node not found in queue")); return false; } $duplicate = $node->getChild("duplicate"); if ($duplicate != null) { //file already on whatsapp servers $url = $duplicate->getAttribute("url"); $filesize = $duplicate->getAttribute("size"); // $mimetype = $duplicate->getAttribute("mimetype"); $filehash = $duplicate->getAttribute("filehash"); $filetype = $duplicate->getAttribute("type"); // $width = $duplicate->getAttribute("width"); // $height = $duplicate->getAttribute("height"); $exploded = explode("/", $url); $filename = array_pop($exploded); } else { //upload new file $json = WhatsMediaUploader::pushFile($node, $messageNode, $this->mediaFileInfo, $this->phoneNumber); if (!$json) { //failed upload $this->eventManager()->fire("onMediaUploadFailed", array($this->phoneNumber, $id, $node, $messageNode, "Failed to push file to server")); return false; } $url = $json->url; $filesize = $json->size; // $mimetype = $json->mimetype; $filehash = $json->filehash; $filetype = $json->type; // $width = $json->width; // $height = $json->height; $filename = $json->name; } $mediaAttribs = array(); $mediaAttribs["type"] = $filetype; $mediaAttribs["url"] = $url; $mediaAttribs["encoding"] = "raw"; $mediaAttribs["file"] = $filename; $mediaAttribs["size"] = $filesize; if ($this->mediaQueue[$id]['caption'] != '') { $mediaAttribs["caption"] = $this->mediaQueue[$id]['caption']; } $filepath = $this->mediaQueue[$id]['filePath']; $to = $this->mediaQueue[$id]['to']; $icon = ""; switch ($filetype) { case "image": $caption = $this->mediaQueue[$id]['caption']; $icon = createIcon($filepath); break; case "video": $caption = $this->mediaQueue[$id]['caption']; $icon = createVideoIcon($filepath); break; default: $caption = ''; $icon = ''; break; } $mediaNode = new ProtocolNode("media", $mediaAttribs, null, $icon); if (is_array($to)) { $this->sendBroadcast($to, $mediaNode, "media"); } else { $this->sendMessageNode($to, $mediaNode); } $this->eventManager()->fire("onMediaMessageSent", array($this->phoneNumber, $to, $id, $filetype, $url, $filename, $filesize, $filehash, $caption, $icon)); return true; }
public function process(\ProtocolNode $node) { $text = $node->getChild('body'); $text = $text->getData(); $notify = $node->getAttribute('notify'); echo "\n- " . $notify . ': ' . $text . ' ' . date('H:i') . "\n"; }
/** * @param ProtocolNode $node */ public function process($node) { // Example of process function, you have to guess a number (psss it's 5) // If you guess it right you get a gift $text = $node->getChild('body'); $text = $text->getData(); if ($text && ($text == "5" || trim($text) == "5")) { $iconfile = "../../tests/Gift.jpgb64"; $fp = fopen($iconfile, "r"); $icon = fread($fp, filesize($iconfile)); fclose($fp); $this->wp->sendMessageImage($this->target, "https://mms604.whatsapp.net/d11/26/09/8/5/85a13e7812a5e7ad1f8071319d9d1b43.jpg", "hero.jpg", 84712, $icon); $this->wp->sendMessage($this->target, "Congratulations you guessed the right number!"); } else { $this->wp->sendMessage($this->target, "I'm sorry, try again!"); } }
/** * Process media upload response. * * @param ProtocolNode $node Message node * * @return bool */ public function processUploadResponse($node) { $id = $node->getAttribute('id'); $messageNode = @$this->mediaQueue[$id]; if ($messageNode == null) { //message not found, can't send! $this->eventManager()->fire('onMediaUploadFailed', [$this->phoneNumber, $id, $node, $messageNode, 'Message node not found in queue']); return false; } $duplicate = $node->getChild('duplicate'); if ($duplicate != null) { //file already on whatsapp servers $url = $duplicate->getAttribute('url'); $filesize = $duplicate->getAttribute('size'); // $mimetype = $duplicate->getAttribute("mimetype"); $filehash = $duplicate->getAttribute('filehash'); $filetype = $duplicate->getAttribute('type'); // $width = $duplicate->getAttribute("width"); // $height = $duplicate->getAttribute("height"); $exploded = explode('/', $url); $filename = array_pop($exploded); } else { //upload new file $json = WhatsMediaUploader::pushFile($node, $messageNode, $this->mediaFileInfo, $this->phoneNumber); if (!$json) { //failed upload $this->eventManager()->fire('onMediaUploadFailed', [$this->phoneNumber, $id, $node, $messageNode, 'Failed to push file to server']); return false; } $url = $json->url; $filesize = $json->size; // $mimetype = $json->mimetype; $filehash = $json->filehash; $filetype = $json->type; // $width = $json->width; // $height = $json->height; $filename = $json->name; } $mediaAttribs = []; $mediaAttribs['type'] = $filetype; $mediaAttribs['url'] = $url; $mediaAttribs['encoding'] = 'raw'; $mediaAttribs['file'] = $filename; $mediaAttribs['size'] = $filesize; if ($this->mediaQueue[$id]['caption'] != '') { $mediaAttribs['caption'] = $this->mediaQueue[$id]['caption']; } if ($this->voice == true) { $mediaAttribs['origin'] = 'live'; $this->voice = false; } $filepath = $this->mediaQueue[$id]['filePath']; $to = $this->mediaQueue[$id]['to']; switch ($filetype) { case 'image': $caption = $this->mediaQueue[$id]['caption']; $icon = createIcon($filepath); break; case 'video': $caption = $this->mediaQueue[$id]['caption']; $icon = createVideoIcon($filepath); break; default: $caption = ''; $icon = ''; break; } //Retrieve Message ID $message_id = $messageNode['message_id']; $mediaNode = new ProtocolNode('media', $mediaAttribs, null, $icon); if (is_array($to)) { $this->sendBroadcast($to, $mediaNode, 'media'); } else { $this->sendMessageNode($to, $mediaNode, $message_id); } $this->eventManager()->fire('onMediaMessageSent', [$this->phoneNumber, $to, $message_id, $filetype, $url, $filename, $filesize, $filehash, $caption, $icon]); return true; }
/** * Tell the server we received the message. * * @param ProtocolNode $msg * The ProtocolTreeNode that contains the message. */ protected function sendMessageReceived($msg) { $requestNode = $msg->getChild("request"); $receivedNode = $msg->getChild("received"); if ($requestNode != null || $receivedNode != null) { $receivedHash = array(); $receivedHash["xmlns"] = "urn:xmpp:receipts"; $response = "received"; if ($receivedNode != null) { $response = "ack"; } $receivedNode = new ProtocolNode($response, $receivedHash, null, ""); $messageHash = array(); $messageHash["to"] = $msg->getAttribute("from"); $messageHash["type"] = "chat"; $messageHash["id"] = $msg->getAttribute("id"); $messageHash["t"] = time(); $messageNode = new ProtocolNode("message", $messageHash, array($receivedNode), ""); $this->sendNode($messageNode); $this->eventManager()->fire('onSendMessageReceived', array($this->phoneNumber, $messageHash["t"], $msg->getAttribute("from"))); } }
protected function processEncryptedNode(ProtocolNode $node) { if ($this->parent->getAxolotlStore() == null) { return; } //is a chat encrypted message $from = $node->getAttribute('from'); if (strpos($from, Constants::WHATSAPP_SERVER) !== false) { $author = ExtractNumber($node->getAttribute('from')); $version = $node->getChild(0)->getAttribute('v'); $encType = $node->getChild(0)->getAttribute('type'); $encMsg = $node->getChild('enc')->getData(); if (!$this->parent->getAxolotlStore()->containsSession($author, 1)) { //we don't have the session to decrypt, save it in pending and process it later $this->parent->addPendingNode($node); $this->parent->logFile('info', 'Requesting cipher keys from {from}', ['from' => $author]); $this->parent->sendGetCipherKeysFromUser($author); } else { //decrypt the message with the session if ($node->getChild('enc')->getAttribute('count') == '') { $this->parent->setRetryCounter($node->getAttribute('id'), 1); } if ($version == '2') { if (!in_array($author, $this->parent->getv2Jids())) { $this->parent->setv2Jids($author); } } $plaintext = $this->decryptMessage($from, $encMsg, $encType, $node->getAttribute('id'), $node->getAttribute('t')); //$plaintext ="A"; if ($plaintext === false) { $this->parent->sendRetry($this->node, $from, $node->getAttribute('id'), $node->getAttribute('t')); $this->parent->logFile('info', 'Couldn\'t decrypt message with {id} id from {from}. Retrying...', ['id' => $node->getAttribute('id'), 'from' => ExtractNumber($from)]); return $node; // could not decrypt } if (isset($this->parent->retryNodes[$node->getAttribute('id')])) { unset($this->parent->retryNodes[$node->getAttribute('id')]); } if (isset($this->parent->retryCounters[$node->getAttribute('id')])) { unset($this->parent->retryCounters[$node->getAttribute('id')]); } switch ($node->getAttribute('type')) { case 'text': $node->addChild(new ProtocolNode('body', null, null, $plaintext)); break; case 'media': switch ($node->getChild('enc')->getAttribute('mediatype')) { case 'image': $image = new ImageMessage(); $image->parseFromString($plaintext); $keys = (new HKDFv3())->deriveSecrets($image->getRefKey(), hex2bin('576861747341707020496d616765204b657973'), 112); $iv = substr($keys, 0, 16); $keys = substr($keys, 16); $parts = str_split($keys, 32); $key = $parts[0]; $macKey = $parts[1]; $refKey = $parts[2]; //should be changed to nice curl, no extra headers :D $file_enc = file_get_contents($image->getUrl()); //requires mac check , last 10 chars $mac = substr($file_enc, -10); $cipherImage = substr($file_enc, 0, strlen($file_enc) - 10); $decrypted_image = pkcs5_unpad(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $cipherImage, MCRYPT_MODE_CBC, $iv)); //$save_file = tempnam(sys_get_temp_dir(),"WAIMG_"); //file_put_contents($save_file,$decrypted_image); $child = new ProtocolNode('media', ['size' => $image->getLength(), 'caption' => $image->getCaption(), 'url' => $image->getUrl(), 'mimetype' => $image->getMimeType(), 'filehash' => bin2hex($image->getSha256()), 'width' => 0, 'height' => 0, 'file' => $decrypted_image, 'type' => 'image'], null, $image->getThumbnail()); $node->addChild($child); break; } break; } $this->parent->logFile('info', 'Decrypted message with {id} from {from}', ['id' => $node->getAttribute('id'), 'from' => ExtractNumber($from)]); return $node; } } else { $author = ExtractNumber($node->getAttribute('participant')); $group_number = ExtractNumber($node->getAttribute('from')); $childs = $node->getChildren(); foreach ($childs as $child) { if ($child->getAttribute('type') == 'pkmsg' || $child->getAttribute('type') == 'msg') { if (!$this->parent->getAxolotlStore()->containsSession($author, 1)) { $this->parent->addPendingNode($node); $this->parent->sendGetCipherKeysFromUser($author); break; } else { //decrypt senderKey and save it $encType = $child->getAttribute('type'); $encMsg = $child->getData(); $from = $node->getAttribute('participant'); $version = $child->getAttribute('v'); if ($node->getChild('enc')->getAttribute('count') == '') { $this->parent->setRetryCounter($node->getAttribute('id'), 1); } if ($version == '2') { if (!in_array($author, $this->parent->getv2Jids())) { $this->parent->setv2Jids($author); } } $skip_unpad = $node->getChild('enc', ['type' => 'skmsg']) == null; $senderKeyBytes = $this->decryptMessage($from, $encMsg, $encType, $node->getAttribute('id'), $node->getAttribute('t'), $node->getAttribute('from'), $skip_unpad); if ($senderKeyBytes) { if (!$skip_unpad) { $senderKeyGroupMessage = new SenderKeyGroupMessage(); $senderKeyGroupMessage->parseFromString($senderKeyBytes); } else { $senderKeyGroupMessage = new SenderKeyGroupData(); try { $senderKeyGroupMessage->parseFromString($senderKeyBytes); } catch (Exception $ex) { try { $senderKeyGroupMessage->parseFromString(substr($senderKeyBytes, 0, -1)); } catch (Exception $ex) { return $node; } } $message = $senderKeyGroupMessage->getMessage(); $senderKeyGroupMessage = $senderKeyGroupMessage->getSenderKey(); } $senderKey = new SenderKeyDistributionMessage(null, null, null, null, $senderKeyGroupMessage->getSenderKey()); $groupSessionBuilder = new GroupSessionBuilder($this->parent->axolotlStore); $groupSessionBuilder->processSender($group_number . ':' . $author, $senderKey); if (isset($message)) { $this->parent->sendReceipt($node, 'receipt', $this->parent->getJID($this->phoneNumber)); $node->addChild(new ProtocolNode('body', null, null, $message)); } } } } elseif ($child->getAttribute('type') == 'skmsg') { $version = $child->getAttribute('v'); if ($version == '2') { if (!in_array($author, $this->parent->v2Jids)) { $this->parent->setv2Jids($author); } } $plaintext = $this->decryptMessage([$group_number, $author], $child->getData(), $child->getAttribute('type'), $node->getAttribute('id'), $node->getAttribute('t')); if (!$plaintext) { $this->parent->sendRetry($this->node, $from, $node->getAttribute('id'), $node->getAttribute('t'), $node->getAttribute('participant')); $this->parent->logFile('info', 'Couldn\'t decrypt group message with {id} id from {from}. Retrying...', ['id' => $node->getAttribute('id'), 'from' => $from]); return $node; // could not decrypt } else { if (isset($this->parent->retryNodes[$node->getAttribute('id')])) { unset($this->parent->retryNodes[$node->getAttribute('id')]); } if (isset($this->parent->retryCounters[$node->getAttribute('id')])) { unset($this->parent->retryCounters[$node->getAttribute('id')]); } $this->parent->logFile('info', 'Decrypted group message with {id} from {from}', ['id' => $node->getAttribute('id'), 'from' => $from]); $this->parent->sendReceipt($node, 'receipt', $this->parent->getJID($this->phoneNumber)); $node->addChild(new ProtocolNode('body', null, null, $plaintext)); } } } } }
protected function processEncryptedNode(ProtocolNode $node) { if ($this->parent->getAxolotlStore() == null) { return null; } //is a chat encrypted message $from = $node->getAttribute('from'); if (strpos($from, Constants::WHATSAPP_SERVER) !== false) { $author = ExtractNumber($node->getAttribute("from")); $version = $node->getChild(0)->getAttribute("v"); $encType = $node->getChild(0)->getAttribute("type"); $encMsg = $node->getChild("enc")->getData(); if (!$this->parent->getAxolotlStore()->containsSession($author, 1)) { //we don't have the session to decrypt, save it in pending and process it later $this->parent->addPendingNode($node); $this->parent->logFile('info', 'Requesting cipher keys from {from}', array('from' => $author)); $this->parent->sendGetCipherKeysFromUser($author); } else { //decrypt the message with the session if ($node->getChild("enc")->getAttribute('count') == "") { $this->parent->setRetryCounter = 1; } if ($version == "2") { if (!in_array($author, $this->parent->getv2Jids())) { $this->parent->setv2Jids($author); } } $plaintext = $this->decryptMessage($from, $encMsg, $encType, $node->getAttribute('id'), $node->getAttribute('t')); if (!$plaintext) { $this->parent->sendRetry($from, $node->getAttribute('id'), $node->getAttribute('t')); $this->parent->logFile('info', 'Couldn\'t decrypt message with {id} id from {from}. Retrying...', array('id' => $node->getAttribute('id'), 'from' => ExtractNumber($from))); return $node; // could not decrypt } switch ($node->getAttribute("type")) { case "text": $node->addChild(new ProtocolNode("body", null, null, $plaintext)); break; case "media": switch ($node->getChild("enc")->getAttribute("mediatype")) { case "image": $image = new ImageMessage(); $image->parseFromString($plaintext); break; } break; } $this->parent->logFile('info', 'Decrypted message with {id} from {from}', array('id' => $node->getAttribute('id'), 'from' => ExtractNumber($from))); return $node; } } else { $author = ExtractNumber($node->getAttribute("participant")); $group_number = ExtractNumber($node->getAttribute("from")); $childs = $node->getChildren(); foreach ($childs as $child) { if ($child->getAttribute("type") == "pkmsg" || $child->getAttribute("type") == "msg") { if (!$this->parent->getAxolotlStore()->containsSession($author, 1)) { $this->parent->addPendingNode($node); $this->parent->sendGetCipherKeysFromUser($author); break; } else { //decrypt senderKey and save it $encType = $child->getAttribute("type"); $encMsg = $child->getData(); $from = $node->getAttribute("participant"); $version = $child->getAttribute("v"); if ($node->getChild("enc")->getAttribute('count') == "") { $this->parent->retryCounter = 1; } if ($version == "2") { if (!in_array($author, $this->parent->getv2Jids())) { $this->parent->setv2Jids($author); } } $skip_unpad = $node->getChild("enc", ["type" => "skmsg"]) == null; $senderKeyBytes = $this->decryptMessage($from, $encMsg, $encType, $node->getAttribute('id'), $node->getAttribute('t'), $node->getAttribute("from"), $skip_unpad); if ($senderKeyBytes) { if (!$skip_unpad) { $senderKeyGroupMessage = new SenderKeyGroupMessage(); $senderKeyGroupMessage->parseFromString($senderKeyBytes); } else { $senderKeyGroupMessage = new SenderKeyGroupData(); try { $senderKeyGroupMessage->parseFromString($senderKeyBytes); } catch (Exception $ex) { try { $senderKeyGroupMessage->parseFromString(substr($senderKeyBytes, 0, -1)); } catch (Exception $ex) { return $node; } } $message = $senderKeyGroupMessage->getMessage(); $senderKeyGroupMessage = $senderKeyGroupMessage->getSenderKey(); } $senderKey = new SenderKeyDistributionMessage(null, null, null, null, $senderKeyGroupMessage->getSenderKey()); $groupSessionBuilder = new GroupSessionBuilder($this->axolotlStore); $groupSessionBuilder->processSender($group_number . ":" . $author, $senderKey); if (isset($message)) { $this->parent->sendReceipt($node, 'receipt', $this->parent->getJID($this->phoneNumber)); $node->addChild(new ProtocolNode("body", null, null, $message)); } } } } else { if ($child->getAttribute("type") == "skmsg") { $version = $child->getAttribute("v"); if ($version == "2") { if (!in_array($author, $this->v2Jids)) { $this->v2Jids[] = $author; } } $plaintext = $this->decryptMessage([$group_number, $author], $child->getData(), $child->getAttribute("type"), $node->getAttribute('id'), $node->getAttribute('t')); if (!$plaintext) { $this->parent->sendRetry($from, $node->getAttribute('id'), $node->getAttribute('t')); $this->parent->logFile('info', 'Couldn\'t decrypt group message with {id} id from {from}. Retrying...', array('id' => $node->getAttribute('id'), 'from' => $from)); return $node; // could not decrypt } else { $this->parent->logFile('info', 'Decrypted group message with {id} from {from}', array('id' => $node->getAttribute('id'), 'from' => $from)); $this->parent->sendReceipt($node, 'receipt', $this->parent->getJID($this->phoneNumber)); $node->addChild(new ProtocolNode("body", null, null, $plaintext)); } } } } } }
public function process(\ProtocolNode $node) { if ($node->getAttribute('type') == 'text') { $text = $node->getChild('body'); $text = $text->getData(); $number = ExtractNumber($node->getAttribute('from')); $nickname = findNicknameByPhone($number); echo "\n- " . $nickname . ': ' . $text . ' ' . date('H:i') . "\n"; } }