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; }