protected function parseEnvelope(Request $request)
 {
     $requestValues = $request->getValues();
     $secureLog = Logger::getTaggedLogger('RawData');
     $secureLog->info("Incoming message (raw)", $requestValues);
     $messages = array();
     // Can't even check signature without these four
     $required = array('result', 'x_amount', 'x_invoice', 'x_control');
     $missing = array_diff($required, array_keys($requestValues));
     if (count($missing)) {
         $list = implode(',', $missing);
         throw new ListenerDataException("AstroPay message missing required key(s) {$list}.");
     }
     $result = $requestValues['result'];
     if (array_key_exists($result, $this->byResult)) {
         $klass = $this->byResult[$result];
         $message = new $klass();
         $message->constructFromValues($requestValues);
         $secureLog->debug("Found message ", $message);
         $messages[] = $message;
     } else {
         Logger::info("Message ignored: result = {$result}");
     }
     return $messages;
 }
 protected function parseEnvelope(Request $request)
 {
     $message = new PaymentMessage();
     $message->constructFromValues($request->getValues());
     $this->success = true;
     return array($message);
 }
 protected function parseEnvelope(Request $request)
 {
     // Symfony's framework gives us each header's value as an array
     // (to account for potential repeated headers?
     // IpnHandler's constructor expects scalar values, so we flatten them
     $headers = array();
     foreach ($request->headers->all() as $header => $annoyingArray) {
         if (count($annoyingArray) !== 1) {
             throw new ListenerDataException("header '{$header}' should have a single value");
         }
         $headers[$header] = $annoyingArray[0];
     }
     $json = $request->getRawRequest();
     $secureLog = Logger::getTaggedLogger('RawData');
     $secureLog->info('Incoming message (raw)', array('headers' => $headers, 'body' => $json));
     $messages = array();
     try {
         $amazonHandlerMessage = AmazonApi::createIpnHandler($headers, $json);
     } catch (\Exception $ex) {
         // FIXYOU: IpnHandler should use exception subclasses or error codes
         // Assuming here that IpnHandler's problem was with the signature
         // We can get away with throwing ListenerSecurityException here
         // because of how RestListener is implemented and because we only
         // process one message per request
         // Bad form, but it would be odd to hold this till doMessageSecurity
         throw new ListenerSecurityException($ex->getMessage());
     }
     $messageValues = $amazonHandlerMessage->toArray();
     $type = $messageValues['NotificationType'];
     if (array_key_exists($type, $this->messageClasses)) {
         $byStatus = $this->messageClasses[$type];
         $status = $this->getMessageStatus($messageValues, $type);
         if (array_key_exists($status, $byStatus)) {
             $klass = $byStatus[$status];
             $message = new $klass($messageValues);
             $secureLog->debug('Created message', $message);
             $messages[] = $message;
         } else {
             Logger::info("Message ignored: status = {$status}");
         }
     } else {
         Logger::info("Message ignored: notificationType = {$type}");
     }
     return $messages;
 }
 /**
  * Determine remote IP address and check validity against an IP whitelist. Will throw exception
  * on error or invalid IP.
  *
  * TODO: This function only handles IPv4 -- it should also handle v6
  *
  * @throws ListenerConfigException
  * @throws ListenerSecurityException
  */
 protected function validateRemoteIp()
 {
     // Obtain whitelist
     $whitelist = $this->c->val('security/ip-whitelist', true);
     // Obtain remote party IP
     $remote_ip = $this->request->getClientIp();
     // Do we continue?
     if (empty($whitelist)) {
         Logger::info("No IP whitelist specified. Continuing and not validating remote IP '{$remote_ip}'.");
         return;
     }
     // Validate remote party IP (right now we can only handle IPv4)
     if (!filter_var($remote_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
         throw new ListenerSecurityException("Bizarre remote IP address: {$remote_ip}");
     }
     // Check remote address against the IP whitelist -- the whitelist can be either individual
     // or CIDR blocks.
     foreach ((array) $whitelist as $ip) {
         if ($remote_ip === $ip) {
             return;
         } elseif (count(explode('/', $ip)) === 2) {
             // Obtain address, CIDR block, and verify correctness of form
             list($network_ip, $block) = explode('/', $ip);
             if (!filter_var($network_ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) || !filter_var($block, FILTER_VALIDATE_INT, array('min_range' => 0, 'max_range' => 32))) {
                 throw new ListenerConfigException("Malformed IP address in whitelist: {$ip}");
             }
             // Obtain raw IP addresses
             $network_long = ip2long($network_ip);
             $mask_long = ~(pow(2, 32 - $block) - 1);
             $remote_long = ip2long($remote_ip);
             // Validate in CIDR
             if (($remote_long & $mask_long) === ($network_long & $mask_long)) {
                 return;
                 // the remote IP address is in this range
             }
         } else {
             throw new ListenerConfigException("Malformed IP address in whitelist: {$ip}");
         }
     }
     // we have fallen through everything in the whitelist, throw
     $agent = $this->request->server->get('User-Agent', '');
     throw new ListenerSecurityException("Received a connection from a bogus IP: {$remote_ip}, agent: {$agent}");
 }
 public function execute(Request $request, Response $response)
 {
     $this->config = Configuration::getDefaultConfig();
     $requestValues = $request->getValues();
     // Don't store blank messages.
     if (empty($requestValues)) {
         return;
     }
     // Don't store invalid messages.
     $valid = $this->config->object('api')->validate($requestValues);
     if (!$valid) {
         // This will tell them to resend later.
         $response->setStatusCode(403, 'Failed verification');
         return false;
     }
     // Dump the request right into the queue with no validation.
     $job = new Job();
     $job->payload = $requestValues;
     $this->config->object('data-store/jobs-paypal')->push($job);
     Logger::info('Pushed new message to jobs-paypal: ' . print_r($requestValues, true));
 }
 /**
  * @return Response
  */
 public static function process()
 {
     // Can go away once we require PHP 5.6
     ini_set('default_charset', 'UTF-8');
     // --- Get the request and response objects
     $request = Request::createFromGlobals();
     $response = new Response();
     $response->setPrivate();
     // --- Break the request into parts ---
     $uri = $request->query->get('p', '');
     $parts = explode('/', $uri);
     $request->query->remove('p');
     if (count($parts) < 2) {
         $response->setStatusCode(403, 'Cannot process this request: bad URI format. A configuration node and an action is required');
         return $response;
     }
     $view = array_shift($parts);
     $action = array_shift($parts);
     // --- Initialize core services ---
     $config = Configuration::createForView($view);
     Context::init($config);
     Logger::init($config->val('logging/root-context'), $config->val('logging/log-level'), $config, Context::get()->getContextId());
     if ($config->nodeExists('disabled') && $config->val('disabled')) {
         Logger::debug('403 will be given for disabled view.', $uri);
         $response->setStatusCode(403, "View '{$view}' disabled. Cannot continue.");
         return $response;
     }
     if ($config->nodeExists('charset')) {
         // recreate the request with a different input encoding
         // FIXME: This is only converting the POST values.  Also,
         // is there really no better way to do this?
         $decoded = rawurldecode($request->getContent());
         $content = mb_convert_encoding($decoded, 'UTF-8', $config->val('charset'));
         parse_str($content, $data);
         $request->request = new ParameterBag($data);
     }
     set_error_handler('\\SmashPig\\Core\\Http\\RequestHandler::lastChanceErrorHandler');
     set_exception_handler('\\SmashPig\\Core\\Http\\RequestHandler::lastChanceExceptionHandler');
     register_shutdown_function('\\SmashPig\\Core\\Http\\RequestHandler::shutdownHandler');
     // Check to make sure there's even a point to continuing
     Logger::info("Starting processing for request, configuration view: '{$view}', action: '{$action}'");
     if (!$config->nodeExists("endpoints/{$action}")) {
         Logger::debug('403 will be given for unknown action on inbound URL.', $uri);
         $response->setStatusCode(403, "Action '{$action}' not configured. Cannot continue.");
         return $response;
     }
     // Inform the request object of our security environment
     $trustedHeader = $config->val('security/ip-header-name');
     if ($trustedHeader) {
         $request->setTrustedHeaderName(Request::HEADER_CLIENT_IP, $trustedHeader);
     }
     $trustedProxies = $config->val('security/ip-trusted-proxies');
     if ($trustedProxies) {
         $request->setTrustedProxies($trustedProxies);
     }
     // --- Actually get the endpoint object and start the request ---
     $endpointObj = $config->object("endpoints/{$action}");
     if ($endpointObj instanceof IHttpActionHandler) {
         $endpointObj->execute($request, $response);
     } else {
         $str = "Requested action '{$action}' does not implement a known handler. Cannot continue.";
         Logger::debug($str);
         $response->setStatusCode(500, $str);
     }
     $code = $response->getStatusCode();
     if ($code !== 200 && $code !== 302) {
         $response->setContent('');
     }
     return $response;
 }