Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add logging and update phpstan #5

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
language: php
php:
- '7.1'
- '7.2'
- '7.3'
- '7.4'
sudo: false
script:
- make test
10 changes: 5 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
"php": "^7.1",
"react/event-loop": "^1.0",
"react/socket": "^1.1",
"symfony/console": "^4.1",
"symfony/http-foundation": "^4.1"
"symfony/console": "^5.0",
"symfony/http-foundation": "^5.0"
},
"autoload": {
"psr-4": {
Expand All @@ -22,9 +22,9 @@
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.13",
"phpstan/phpstan": "^0.11.2",
"phpstan/phpstan-strict-rules": "^0.11.0",
"phpunit/phpunit": "^7.3|^8.0"
"phpstan/phpstan": "^0.12.23",
"phpstan/phpstan-strict-rules": "^0.12.2",
"phpunit/phpunit": "^7.0|^8.0|^9.0"
},
"autoload-dev": {
"psr-4": {
Expand Down
11 changes: 11 additions & 0 deletions phproxy-wrapper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/sh

set -axupe

PROXY_PORT=4269
PACPORT=4270
LOCAL_IP=$(ip -o route get to 8.8.8.8 | sed -n 's/.*src \([0-9.]\+\).*/\1/p')

echo "Listening on ${LOCAL_IP}:${PROXY_PORT}"
echo "Autoconfiguration url : http://${LOCAL_IP}:${PACPORT}/"
$(dirname ${0})/bin/phproxy run 0.0.0.0:${PROXY_PORT} --pac 0.0.0.0:${PACPORT}:${LOCAL_IP}:${PROXY_PORT} "$@"
19 changes: 17 additions & 2 deletions src/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,37 @@
namespace Paxal\Phproxy;

use Paxal\Phproxy\Command\ProxyCommand;
use Paxal\Phproxy\Logger\LoggerWrapper;
use React\EventLoop\Factory;
use Symfony\Component\Console\Application as BaseApplication;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Logger\ConsoleLogger;
use Symfony\Component\Console\Output\OutputInterface;

final class Application extends BaseApplication
{
/** @var \React\EventLoop\LoopInterface */
private $loop;
/** @var LoggerWrapper */
private $logger;

public function __construct()
{
parent::__construct('PHPROXY', '@package_version@');

$this->loop = Factory::create();
$this->logger = new LoggerWrapper();

$command = new ProxyCommand($this->loop);
$command = new ProxyCommand($this->loop, $this->logger);
$this->add($command);
$this->setDefaultCommand($command->getName());
$this->setDefaultCommand((string) $command->getName());
}

protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output): int
{
$this->logger->setLogger(new ConsoleLogger($output));

return parent::doRunCommand($command, $input, $output);
}
}
6 changes: 6 additions & 0 deletions src/Command/OptionsHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

class OptionsHelper
{
/**
* @return array<string, string|array<string>>
*/
public static function read(string $filename): array
{
$contents = @file_get_contents($filename);
Expand All @@ -25,6 +28,9 @@ public static function read(string $filename): array
return $json;
}

/**
* @param array<string, string|array<string>> $options
*/
public static function save(string $filename, array $options): void
{
@file_put_contents(
Expand Down
35 changes: 27 additions & 8 deletions src/Command/ProxyCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Paxal\Phproxy\Proxy\ConnectionHandler;
use Paxal\Phproxy\Proxy\DataHandlerFactory;
use Paxal\Phproxy\Translator\TranslatorBuilder;
use Psr\Log\LoggerInterface;
use React\EventLoop\LoopInterface;
use React\Socket\SecureServer;
use React\Socket\TcpServer;
Expand All @@ -25,10 +26,16 @@ class ProxyCommand extends Command
*/
private $loop;

public function __construct(LoopInterface $loop)
/**
* @var LoggerInterface
*/
private $logger;

public function __construct(LoopInterface $loop, LoggerInterface $logger)
{
parent::__construct();
$this->loop = $loop;
$this->logger = $logger;
}

protected function configure(): void
Expand All @@ -47,14 +54,14 @@ protected function configure(): void
->addArgument('binding', InputArgument::OPTIONAL, 'Bind address', '127.0.0.1:8001');
}

protected function execute(InputInterface $input, OutputInterface $output)
protected function execute(InputInterface $input, OutputInterface $output): int
{
$configurationFile = $input->getOption('config');
if (is_string($configurationFile)) {
if (file_exists($configurationFile)) {
$savedOptions = $this->cleanOptionForSave(OptionsHelper::read($configurationFile));
foreach ($savedOptions as $name => $option) {
$input->setOption($name, $input->getOption($name) ?: $option);
$input->setOption($name, $input->getOption($name) ?? $option);
}
}

Expand All @@ -64,14 +71,16 @@ protected function execute(InputInterface $input, OutputInterface $output)
}

$translatorBuilder = $this->buildTranslatorBuilder($input);
/** @phpstan-ignore-next-line */
$authenticator = AuthenticatorFactory::create((array) $input->getOption('auth'));
$dataHandlerFactory = new DataHandlerFactory($this->loop, $translatorBuilder, $authenticator);
$dataHandlerFactory = new DataHandlerFactory($this->loop, $translatorBuilder, $authenticator, $this->logger);

$binding = $input->getArgument('binding');
if (!is_string($binding)) {
throw new \RuntimeException('Invalid argument binding.');
}
$server = new TcpServer($binding, $this->loop);
$this->logger->info('PROXY Server listening on {binding}', ['binding' => $binding]);

if ((bool) $input->getOption('ssl')) {
$context = [];
Expand All @@ -95,6 +104,9 @@ protected function execute(InputInterface $input, OutputInterface $output)
}

$this->loop->run();

// Never reached
return 1;
}

private function buildTranslatorBuilder(InputInterface $input): TranslatorBuilder
Expand All @@ -109,6 +121,11 @@ private function buildTranslatorBuilder(InputInterface $input): TranslatorBuilde
return $translatorBuilder;
}

/**
* @param array<string, array<string>|string|null> $options
*
* @return array<string, string>
*/
private function cleanOptionForSave(array $options): array
{
$cleaned = [];
Expand All @@ -118,22 +135,24 @@ private function cleanOptionForSave(array $options): array
}
}

/* @phpstan-ignore-next-line */
return $cleaned;
}

private function configurePACServer(string $pacConfiguration, TranslatorBuilder $translatorBuilder): void
{
$serverFactory = new ServerFactory($this->loop);
$serverFactory = new ServerFactory($this->loop, $this->logger);
[$binding, $proxyHost] = $this->parsePACConfiguration($pacConfiguration);
$serverFactory->create($binding, $proxyHost, $translatorBuilder);
}

/**
* @return array{0: string, 1: string}
*/
private function parsePACConfiguration(string $pacConfiguration): array
{
if (!(bool) preg_match('|^(.+?:\d+?):(.+?:\d+?)$|', $pacConfiguration, $matches)) {
throw new \InvalidArgumentException(
'Bad PAC configuration value : should be BINDING_HOST:BINDING_PORT:EXTERNAL_PROXY_HOST:EXTERNAL_PROXY_PORT'
);
throw new \InvalidArgumentException('Bad PAC configuration value : should be BINDING_HOST:BINDING_PORT:EXTERNAL_PROXY_HOST:EXTERNAL_PROXY_PORT');
}

return [$matches[1], $matches[2]];
Expand Down
24 changes: 24 additions & 0 deletions src/Logger/LoggerWrapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Paxal\Phproxy\Logger;

use Psr\Log\AbstractLogger;
use Psr\Log\LoggerAwareTrait;
use Psr\Log\NullLogger;

final class LoggerWrapper extends AbstractLogger
{
use LoggerAwareTrait;

public function __construct()
{
$this->logger = new NullLogger();
}

public function log($level, $message, array $context = [])
{
$this->logger->log($level, $message, $context);
}
}
3 changes: 0 additions & 3 deletions src/PAC/ResponseFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,7 @@ function FindProxyForURL(url, host) {
/**
* Build matches given hostnames.
*
* @param string $proxyHost
* @param string[] $domains
*
* @return string
*/
private static function buildMatches(string $proxyHost, array $domains): string
{
Expand Down
18 changes: 13 additions & 5 deletions src/PAC/ServerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Paxal\Phproxy\PAC;

use Paxal\Phproxy\Translator\TranslatorBuilder;
use Psr\Log\LoggerInterface;
use React\EventLoop\LoopInterface;
use React\Socket\ConnectionInterface;
use React\Socket\ServerInterface;
Expand All @@ -20,9 +21,13 @@ class ServerFactory
/** @var LoopInterface */
private $loop;

public function __construct(LoopInterface $loop)
/** @var LoggerInterface */
private $logger;

public function __construct(LoopInterface $loop, LoggerInterface $logger)
{
$this->loop = $loop;
$this->logger = $logger;
}

/**
Expand All @@ -31,8 +36,6 @@ public function __construct(LoopInterface $loop)
* @param string $binding Binding host, eg ip:port
* @param string $proxyHost The proxy host, as of remote-side view (eg external_ip:port)
* @param TranslatorBuilder $translatorBuilder The translator builder
*
* @return ServerInterface
*/
public function create(string $binding, string $proxyHost, TranslatorBuilder $translatorBuilder): ServerInterface
{
Expand All @@ -42,14 +45,19 @@ public function create(string $binding, string $proxyHost, TranslatorBuilder $tr
$this->handle($connection, $contents);
});

$this->loop->futureTick(function () use ($binding, $contents): void {
$this->logger->info('PAC Server listening on {binding}', ['binding' => $binding]);
$this->logger->debug('PAC Contents :'.PHP_EOL.$contents);
});

return $server;
}

private function handle(ConnectionInterface $connection, string $contents): void
{
// Hodor !
$connection->on('data', function () use ($contents, $connection) {
error_log('Connection from '.$connection->getRemoteAddress());
$connection->on('data', function () use ($contents, $connection): void {
$this->logger->info('New PAC Connection from {remote}', ['remote' => $connection->getRemoteAddress()]);
$connection->end($contents);
});
}
Expand Down
7 changes: 6 additions & 1 deletion src/Proxy/Authenticator/AuthenticatorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@

final class AuthenticatorFactory
{
public static function create(array $credentials, string $type = 'Basic'): Authenticator
/**
* Creates authenticator. If any credential is given, it will be considered as basic.
*
* @param string[] $credentials
*/
public static function create(array $credentials, string $type = 'basic'): Authenticator
{
if (0 !== count($credentials)) {
switch ($type) {
Expand Down
12 changes: 10 additions & 2 deletions src/Proxy/Authenticator/BasicAuthenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,23 @@
final class BasicAuthenticator implements Authenticator
{
/**
* @var array
* @var array<string, array-key>
*/
private $credentials;

/**
* @param array<string> $credentials
*/
public function __construct(array $credentials)
{
$this->credentials = array_flip($this->encode($credentials));
}

/**
* @param array<string> $credentials
*
* @return array<string, array-key>
*/
private function encode(array $credentials): array
{
return array_map(
Expand All @@ -30,7 +38,7 @@ function (string $credentials): string {

public function isAuthorized(ProxyRequest $request): bool
{
$headerValue = $request->getHeaders()->get('proxy-authorization', null, true);
$headerValue = $request->getHeaders()->get('proxy-authorization', null);
if (!\is_string($headerValue)) {
return false;
}
Expand Down
Loading