public function getObject() { // setup of full message $content = $this->getHeaders(true) . "\n\n"; $content .= file_get_contents($this->getPath()); $input = Adapter::getTempFilename(); file_put_contents($input, $content); // setup of mailmime decoder $params = array('include_bodies' => false, 'decode_headers' => true, 'decode_bodies' => false, 'input' => false); $decoder = new Mail_mimeDecode(file_get_contents($input)); $structure = $decoder->decode($params); $mimetype = $structure->ctype_primary . '/' . $structure->ctype_secondary; // handle crypted content $crypted = false; if (strtolower($mimetype) == 'application/pkcs7-mime') { try { // rewrite message into base64 encoding $content = file_get_contents($input); $mime_part = Horde_MIME_Structure::parseTextMIMEMessage($content); $input = Adapter::getTempFilename(); file_put_contents($input, $mime_part->toString(true)); $this->eventDispatcher->dispatch('log', new Log(Log::TYPE_INFO, 'AS2 message is encrypted.')); $input = $this->adapter->decrypt($input); $this->eventDispatcher->dispatch('log', new Log(Log::TYPE_INFO, 'The data has been decrypted using the key "' . $this->getPartnerTo() . '".')); $crypted = true; // reload extracted content to get mimetype $decoder = new Mail_mimeDecode(file_get_contents($input)); $structure = $decoder->decode($params); $mimetype = $structure->ctype_primary . '/' . $structure->ctype_secondary; } catch (Exception $e) { throw new AS2Exception($e->getMessage(), 3); } } // handle signed content $signed = false; $mic = false; if (strtolower($mimetype) == 'multipart/signed') { try { $this->eventDispatcher->dispatch('log', new Log(Log::TYPE_INFO, 'AS2 message is signed.')); // get MicChecksum from signature $mic = $this->adapter->getMicChecksum($input); $input = $this->adapter->verify($input); $signed = true; $this->eventDispatcher->dispatch('log', new Log(Log::TYPE_INFO, 'The sender used the algorithm "' . $structure->ctype_parameters['micalg'] . '" to sign the message.')); // reload extracted content to get mimetype $decoder = new Mail_mimeDecode(file_get_contents($input)); $structure = $decoder->decode($params); $mimetype = $structure->ctype_primary . '/' . $structure->ctype_secondary; $this->eventDispatcher->dispatch('log', new Log(Log::TYPE_INFO, 'Using certificate "' . $this->getPartnerFrom() . '" to verify signature.')); } catch (Exception $e) { throw new AS2Exception($e->getMessage(), 5); } } else { // check requested algo $mic = Adapter::calculateMicChecksum($input, 'sha1'); } // security check if (strtolower($mimetype) == 'multipart/report') { // check about sign /*if ($this->getPartnerFrom()->sec_signature_algorithm == Partner::SIGN_NONE && !$this->getPartnerFrom()->mdn_signed && $signed){ throw new AS2Exception('AS2 message is signed and shouldn\'t be.', 4); } else*/ if ($this->getPartnerFrom()->sec_signature_algorithm != Partner::SIGN_NONE && $this->getPartnerFrom()->mdn_signed && !$signed) { throw new AS2Exception('AS2 message is not signed and should be.', 4); } } else { // check about crypt /*if ($this->getPartnerFrom()->sec_encrypt_algorithm == Partner::CRYPT_NONE && $crypted){ throw new AS2Exception('AS2 message is crypted and shouldn\'t be.', 4); } else*/ if ($this->getPartnerFrom()->sec_encrypt_algorithm != Partner::CRYPT_NONE && !$crypted) { throw new AS2Exception('AS2 message is not crypted and should be.', 4); } // check about sign /*if ($this->getPartnerFrom()->sec_signature_algorithm == Partner::SIGN_NONE && $signed){ throw new AS2Exception('AS2 message is signed and shouldn\'t be.', 4); } else*/ if ($this->getPartnerFrom()->sec_signature_algorithm != Partner::SIGN_NONE && !$signed) { throw new AS2Exception('AS2 message is not signed and should be.', 4); } } try { // build object with extracted content $message = file_get_contents($input); $mime_part = Horde_MIME_Structure::parseTextMIMEMessage($message); switch (strtolower($mimetype)) { case 'multipart/report': $params = array('partner_from' => $this->getPartnerTo(), 'partner_to' => $this->getPartnerFrom(), 'is_file' => false, 'mic' => $mic); $object = $this->mdnFactory->build($mime_part, $params); return $object; default: $params = array('partner_from' => $this->getPartnerFrom(), 'partner_to' => $this->getPartnerTo(), 'is_file' => false, 'mic' => $mic); $object = $this->messageFactory->build($mime_part, $params); $object->setHeaders($this->getHeaders()); return $object; } } catch (Exception $e) { throw new AS2Exception($e->getMessage(), 6); } throw new AS2Exception('Unexpected error while handling message.', 6); }
protected final function initializeBase($data, $params = array()) { if (is_null($this->headers)) { $this->headers = new Header(); } if (is_array($data)) { $this->path = $data; } elseif ($data) { // do nothing // content : default is file if (isset($params['is_file']) && $params['is_file'] === false) { $file = Adapter::getTempFilename(); file_put_contents($file, $data); $this->path = $file; // filename if (isset($params['filename'])) { $this->filename = $params['filename']; } } else { $this->path = $data; // filename $this->filename = isset($params['filename']) ? $params['filename'] : basename($this->path); } // mimetype handle $this->mimetype = isset($params['mimetype']) ? $params['mimetype'] : Adapter::detectMimeType($this->path); } // partners if (isset($params['partner_from']) && $params['partner_from']) { $this->setPartnerFrom($params['partner_from']); } else { throw new AS2Exception('No AS2 From Partner specified.'); } if (isset($params['partner_to']) && $params['partner_to']) { $this->setPartnerTo($params['partner_to']); } else { throw new AS2Exception('NO AS2 To Partner specified.'); } $this->adapter = $this->getAdapterFactory()->build($this->getPartnerFrom(), $this->getPartnerTo()); }
/** * @param $partner_from * @param $partner_to * @return AdapterModel * @throws \TechData\AS2SecureBundle\Models\AS2Exception */ public function build($partner_from, $partner_to) { $adapter = new AdapterModel($this->partnerFactory, $this->AS2_DIR_BIN); $adapter->initialize($partner_from, $partner_to); return $adapter; }
/** * Build message and encode it (signing and/or crypting) * */ public function encode() { if (!$this->getPartnerFrom() instanceof Partner || !$this->getPartnerTo() instanceof Partner) { throw new AS2Exception('Object not properly initialized'); } // initialisation $this->mic_checksum = false; $this->setMessageId(self::generateMessageID($this->getPartnerFrom())); // chargement et construction du message $files = $this->getFiles(); // initial message creation : mime_part // TODO : use adapter to build multipart file try { // managing all files (parts) $parts = array(); foreach ($files as $file) { $mime_part = new Horde_MIME_Part($file['mimetype']); $mime_part->setContents(file_get_contents($file['path'])); $mime_part->setName($file['filename']); if ($file['encoding']) { $mime_part->setTransferEncoding($file['encoding']); } $parts[] = $mime_part; } if (count($parts) > 1) { // handling multipart file $mime_part = new Horde_MIME_Part('multipart/mixed'); foreach ($parts as $part) { $mime_part->addPart($part); } } else { // handling mono part (body) $mime_part = $parts[0]; } $file = Adapter::getTempFilename(); file_put_contents($file, $mime_part->toString()); } catch (Exception $e) { throw $e; return false; } // signing file if wanted by Partner_To if ($this->getPartnerTo()->sec_signature_algorithm != Partner::SIGN_NONE) { try { $file = $this->adapter->sign($file, $this->getPartnerTo()->send_compress, $this->getPartnerTo()->send_encoding); $this->is_signed = true; //echo file_get_contents($file); $this->mic_checksum = $this->getMicChecksum($file); } catch (Exception $e) { throw $e; return false; } } // crypting file if wanted by Partner_To if ($this->getPartnerTo()->sec_encrypt_algorithm != Partner::CRYPT_NONE) { try { $file = $this->adapter->encrypt($file); $this->is_crypted = true; } catch (Exception $e) { throw $e; return false; } } $this->path = $file; /*if ($mime_part->getTransferEncoding() == 'base64'){ file_put_contents($this->path, base64_decode($mime_part->toString(false))); } else{ file_put_contents($this->path, $mime_part->toString()); }*/ // headers setup $headers = array('AS2-From' => '"' . $this->getPartnerFrom()->id . '"', 'AS2-To' => '"' . $this->getPartnerTo()->id . '"', 'AS2-Version' => '1.0', 'From' => $this->getPartnerFrom()->email, 'Subject' => $this->getPartnerFrom()->send_subject, 'Message-ID' => $this->getMessageId(), 'Mime-Version' => '1.0', 'Disposition-Notification-To' => $this->getPartnerFrom()->send_url, 'Recipient-Address' => $this->getPartnerTo()->send_url, 'User-Agent' => 'AS2Secure - PHP Lib for AS2 message encoding / decoding'); if ($this->getPartnerTo()->mdn_signed) { $headers['Disposition-Notification-Options'] = 'signed-receipt-protocol=optional, pkcs7-signature; signed-receipt-micalg=optional, sha1'; } if ($this->getPartnerTo()->mdn_request == Partner::ACK_ASYNC) { $headers['Receipt-Delivery-Option'] = $this->getPartnerFrom()->send_url; } $this->headers = new Header($headers); // look for additionnal headers from message // eg : content-type $content = file_get_contents($this->path); $this->headers->addHeadersFromMessage($content); if (strpos($content, "\n\n") !== false) { $content = substr($content, strpos($content, "\n\n") + 2); } file_put_contents($this->path, $content); return true; }
/** * Extract files from mime multipart file * * @param string $input The file to extract * * @return array The list of extracted files (path / mimetype / filename) */ public function extract($input) { try { $output = self::getTempFilename(); // execute main operation $command = self::$javapath . ' -jar ' . escapeshellarg($this->AS2_DIR_BIN . self::$ssl_adapter) . ' extract' . ' -in ' . escapeshellarg($input) . ' -out ' . escapeshellarg($output); $results = self::exec($command, true); // array returned $files = array(); foreach ($results as $tmp) { $tmp = explode(';', $tmp); if (count($tmp) <= 1) { continue; } if (count($tmp) != 3) { throw new AS2Exception('Unexpected data structure while extracting message.'); } $file = array(); $file['path'] = trim($tmp[0], '"'); $file['mimetype'] = trim($tmp[1], '"'); $file['filename'] = trim($tmp[2], '"'); $files[] = $file; // schedule file deletion Adapter::addTempFileForDelete($file['path']); } return $files; } catch (Exception $e) { throw $e; } }