Merge branch 'master' of github.com:beyondcode/phunnel

This commit is contained in:
Marcel Pociot
2020-06-17 12:38:11 +02:00
56 changed files with 189 additions and 316 deletions

View File

@@ -6,12 +6,11 @@ use App\Client\Connections\ControlConnection;
use App\Logger\CliRequestLogger;
use Carbon\Carbon;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use function Ratchet\Client\connect;
use Ratchet\Client\WebSocket;
use React\EventLoop\LoopInterface;
use React\Promise\Deferred;
use React\Promise\PromiseInterface;
use function Ratchet\Client\connect;
class Client
{
@@ -26,7 +25,7 @@ class Client
/** @var CliRequestLogger */
protected $logger;
/** @var int */
/** @var int */
protected $connectionRetries = 0;
/** @var int */
@@ -73,7 +72,7 @@ class Client
$deferred = new Deferred();
$promise = $deferred->promise();
$wsProtocol = $this->configuration->port() === 443 ? "wss" : "ws";
$wsProtocol = $this->configuration->port() === 443 ? 'wss' : 'ws';
connect($wsProtocol."://{$this->configuration->host()}:{$this->configuration->port()}/expose/control?authToken={$authToken}", [], [
'X-Expose-Control' => 'enabled',
@@ -85,7 +84,7 @@ class Client
$connection->authenticate($sharedUrl, $subdomain);
$clientConnection->on('close', function() use ($deferred, $sharedUrl, $subdomain, $authToken) {
$clientConnection->on('close', function () use ($deferred, $sharedUrl, $subdomain, $authToken) {
$this->logger->error('Connection to server closed.');
$this->retryConnectionOrExit($sharedUrl, $subdomain, $authToken);
@@ -106,7 +105,7 @@ class Client
$connection->on('setMaximumConnectionLength', function ($data) {
$timeoutSection = $this->logger->getOutput()->section();
$this->loop->addPeriodicTimer(1, function() use ($data, $timeoutSection) {
$this->loop->addPeriodicTimer(1, function () use ($data, $timeoutSection) {
$this->timeConnected++;
$carbon = Carbon::createFromFormat('s', str_pad($data->length * 60 - $this->timeConnected, 2, 0, STR_PAD_LEFT));
@@ -117,7 +116,7 @@ class Client
});
$connection->on('authenticated', function ($data) use ($deferred, $sharedUrl) {
$httpProtocol = $this->configuration->port() === 443 ? "https" : "http";
$httpProtocol = $this->configuration->port() === 443 ? 'https' : 'http';
$host = $this->configuration->host();
if ($httpProtocol !== 'https') {
@@ -134,13 +133,13 @@ class Client
$deferred->resolve($data);
});
}, function (\Exception $e) use ($deferred, $sharedUrl, $subdomain, $authToken) {
if ($this->connectionRetries > 0) {
$this->retryConnectionOrExit($sharedUrl, $subdomain, $authToken);
return;
}
$this->logger->error("Could not connect to the server.");
$this->logger->error('Could not connect to the server.');
$this->logger->error($e->getMessage());
$this->exit($deferred);
@@ -153,7 +152,7 @@ class Client
{
$deferred->reject();
$this->loop->futureTick(function(){
$this->loop->futureTick(function () {
exit(1);
});
}
@@ -163,8 +162,8 @@ class Client
$this->connectionRetries++;
if ($this->connectionRetries <= static::MAX_CONNECTION_RETRIES) {
$this->loop->addTimer($this->connectionRetries, function() use ($sharedUrl, $subdomain, $authToken) {
$this->logger->info("Retrying connection ({$this->connectionRetries}/".static::MAX_CONNECTION_RETRIES.")");
$this->loop->addTimer($this->connectionRetries, function () use ($sharedUrl, $subdomain, $authToken) {
$this->logger->info("Retrying connection ({$this->connectionRetries}/".static::MAX_CONNECTION_RETRIES.')');
$this->connectToServer($sharedUrl, $subdomain, $authToken);
});

View File

@@ -3,9 +3,9 @@
namespace App\Client\Connections;
use App\Client\ProxyManager;
use Evenement\EventEmitterTrait;
use Ratchet\Client\WebSocket;
use Ratchet\ConnectionInterface;
use Evenement\EventEmitterTrait;
use Ratchet\RFC6455\Messaging\Message;
class ControlConnection

View File

@@ -2,19 +2,19 @@
namespace App\Client;
use App\Client\Http\Controllers\AttachDataToLogController;
use App\Client\Http\Controllers\ClearLogsController;
use App\Client\Http\Controllers\CreateTunnelController;
use App\Client\Http\Controllers\PushLogsToDashboardController;
use App\Http\App;
use App\Client\Http\Controllers\AttachDataToLogController;
use App\Client\Http\Controllers\DashboardController;
use App\Client\Http\Controllers\LogController;
use App\Client\Http\Controllers\PushLogsToDashboardController;
use App\Client\Http\Controllers\ReplayLogController;
use App\Http\App;
use App\Http\RouteGenerator;
use App\WebSockets\Socket;
use Ratchet\WebSocket\WsServer;
use React\EventLoop\LoopInterface;
use React\EventLoop\Factory as LoopFactory;
use React\EventLoop\LoopInterface;
class Factory
{
@@ -158,5 +158,4 @@ class Factory
{
$this->loop->run();
}
}

View File

@@ -3,11 +3,11 @@
namespace App\Client\Http\Controllers;
use App\Http\Controllers\Controller;
use GuzzleHttp\Psr7\Response;
use Illuminate\Http\Request;
use App\Logger\RequestLogger;
use Ratchet\ConnectionInterface;
use GuzzleHttp\Psr7\Response;
use function GuzzleHttp\Psr7\str;
use Illuminate\Http\Request;
use Ratchet\ConnectionInterface;
class AttachDataToLogController extends Controller
{
@@ -24,11 +24,12 @@ class AttachDataToLogController extends Controller
$loggedRequest = $this->requestLogger->findLoggedRequest($request->get('request_id', ''));
if (! is_null($loggedRequest)) {
$loggedRequest->setAdditionalData((array)$request->get('data', []));
$loggedRequest->setAdditionalData((array) $request->get('data', []));
$this->requestLogger->pushLoggedRequest($loggedRequest);
$httpConnection->send(str(new Response(200)));
return;
}

View File

@@ -3,18 +3,13 @@
namespace App\Client\Http\Controllers;
use App\Http\Controllers\Controller;
use Exception;
use App\WebSockets\Socket;
use GuzzleHttp\Psr7\Response;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Ratchet\ConnectionInterface;
use function GuzzleHttp\Psr7\str;
use Psr\Http\Message\RequestInterface;
use Illuminate\Http\Request;
use Ratchet\ConnectionInterface;
class CreateTunnelController extends Controller
{
protected $keepConnectionOpen = true;
public function handle(Request $request, ConnectionInterface $httpConnection)
@@ -24,10 +19,9 @@ class CreateTunnelController extends Controller
->then(function ($data) use ($httpConnection) {
$httpConnection->send(respond_json($data));
$httpConnection->close();
}, function() use ($httpConnection) {
}, function () use ($httpConnection) {
$httpConnection->send(str(new Response(500)));
$httpConnection->close();
});
}
}

View File

@@ -4,15 +4,11 @@ namespace App\Client\Http\Controllers;
use App\Client\Client;
use App\Http\Controllers\Controller;
use GuzzleHttp\Psr7\Response;
use Illuminate\Http\Request;
use function GuzzleHttp\Psr7\str;
use Psr\Http\Message\RequestInterface;
use Ratchet\ConnectionInterface;
class DashboardController extends Controller
{
public function handle(Request $request, ConnectionInterface $httpConnection)
{
$httpConnection->send(respond_html($this->getView($httpConnection, 'client.dashboard', [

View File

@@ -4,11 +4,8 @@ namespace App\Client\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Logger\RequestLogger;
use GuzzleHttp\Psr7\Response;
use Illuminate\Http\Request;
use Ratchet\ConnectionInterface;
use function GuzzleHttp\Psr7\str;
use Psr\Http\Message\RequestInterface;
class LogController extends Controller
{

View File

@@ -3,18 +3,15 @@
namespace App\Client\Http\Controllers;
use App\Http\Controllers\Controller;
use Exception;
use App\WebSockets\Socket;
use Exception;
use GuzzleHttp\Psr7\Response;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Ratchet\ConnectionInterface;
use function GuzzleHttp\Psr7\str;
use Psr\Http\Message\RequestInterface;
use Illuminate\Http\Request;
use Ratchet\ConnectionInterface;
class PushLogsToDashboardController extends Controller
{
public function handle(Request $request, ConnectionInterface $httpConnection)
{
try {

View File

@@ -4,13 +4,11 @@ namespace App\Client\Http\Controllers;
use App\Client\Http\HttpClient;
use App\Http\Controllers\Controller;
use App\Http\QueryParameters;
use App\Logger\RequestLogger;
use GuzzleHttp\Psr7\Response;
use function GuzzleHttp\Psr7\str;
use Illuminate\Http\Request;
use Ratchet\ConnectionInterface;
use function GuzzleHttp\Psr7\str;
use Psr\Http\Message\RequestInterface;
class ReplayLogController extends Controller
{
@@ -32,6 +30,7 @@ class ReplayLogController extends Controller
if (is_null($loggedRequest)) {
$httpConnection->send(str(new Response(404)));
return;
}

View File

@@ -5,8 +5,8 @@ namespace App\Client\Http;
use App\Client\Http\Modifiers\CheckBasicAuthentication;
use App\Logger\RequestLogger;
use Clue\React\Buzz\Browser;
use Illuminate\Pipeline\Pipeline;
use Illuminate\Support\Arr;
use function GuzzleHttp\Psr7\parse_request;
use function GuzzleHttp\Psr7\str;
use Laminas\Http\Request;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
@@ -14,8 +14,6 @@ use Ratchet\Client\WebSocket;
use Ratchet\RFC6455\Messaging\Frame;
use React\EventLoop\LoopInterface;
use React\Socket\Connector;
use function GuzzleHttp\Psr7\parse_request;
use function GuzzleHttp\Psr7\str;
class HttpClient
{
@@ -67,13 +65,13 @@ class HttpClient
protected function createConnector(): Connector
{
return new Connector($this->loop, array(
return new Connector($this->loop, [
'dns' => '127.0.0.1',
'tls' => array(
'tls' => [
'verify_peer' => false,
'verify_peer_name' => false
)
));
'verify_peer_name' => false,
],
]);
}
protected function sendRequestToApplication(RequestInterface $request, $proxyConnection = null)

View File

@@ -4,10 +4,10 @@ namespace App\Client\Http\Modifiers;
use App\Client\Configuration;
use GuzzleHttp\Psr7\Response;
use function GuzzleHttp\Psr7\str;
use Illuminate\Support\Arr;
use Psr\Http\Message\RequestInterface;
use Ratchet\Client\WebSocket;
use function GuzzleHttp\Psr7\str;
class CheckBasicAuthentication
{
@@ -30,10 +30,11 @@ class CheckBasicAuthentication
if (is_null($username)) {
$proxyConnection->send(
str(new Response(401, [
'WWW-Authenticate' => 'Basic realm=Expose'
'WWW-Authenticate' => 'Basic realm=Expose',
], 'Unauthorized'))
);
$proxyConnection->close();
return null;
}
@@ -49,7 +50,7 @@ class CheckBasicAuthentication
return null;
}
if (!array_key_exists($authorization['username'], $credentials)) {
if (! array_key_exists($authorization['username'], $credentials)) {
return null;
}
@@ -63,13 +64,13 @@ class CheckBasicAuthentication
protected function parseAuthorizationHeader(string $header)
{
if (strpos($header, 'Basic') !== 0) {
return null;
return;
}
$header = base64_decode(substr($header, 6));
if ($header === false) {
return null;
return;
}
$header = explode(':', $header, 2);
@@ -82,13 +83,14 @@ class CheckBasicAuthentication
protected function requiresAuthentication(): bool
{
return !empty($this->getCredentials());
return ! empty($this->getCredentials());
}
protected function getCredentials()
{
try {
$credentials = explode(':', $this->configuration->auth());
return [
$credentials[0] => $credentials[1],
];

View File

@@ -3,10 +3,9 @@
namespace App\Client;
use App\Client\Http\HttpClient;
use Ratchet\Client\WebSocket;
use Ratchet\ConnectionInterface;
use React\EventLoop\LoopInterface;
use function Ratchet\Client\connect;
use Ratchet\Client\WebSocket;
use React\EventLoop\LoopInterface;
class ProxyManager
{
@@ -24,14 +23,14 @@ class ProxyManager
public function createProxy(string $clientId, $connectionData)
{
$protocol = $this->configuration->port() === 443 ? "wss" : "ws";
$protocol = $this->configuration->port() === 443 ? 'wss' : 'ws';
connect($protocol."://{$this->configuration->host()}:{$this->configuration->port()}/expose/control", [], [
'X-Expose-Control' => 'enabled',
], $this->loop)
->then(function (WebSocket $proxyConnection) use ($clientId, $connectionData) {
$proxyConnection->on('message', function ($message) use ($proxyConnection, $connectionData) {
$this->performRequest($proxyConnection, $connectionData->request_id, (string)$message);
$this->performRequest($proxyConnection, $connectionData->request_id, (string) $message);
});
$proxyConnection->send(json_encode([
@@ -46,6 +45,6 @@ class ProxyManager
protected function performRequest(WebSocket $proxyConnection, $requestId, string $requestData)
{
app(HttpClient::class)->performRequest((string)$requestData, $proxyConnection, $requestId);
app(HttpClient::class)->performRequest((string) $requestData, $proxyConnection, $requestId);
}
}

View File

@@ -22,6 +22,5 @@ class TokenNodeVisitor extends NodeVisitorAbstract
return $node;
}
return null;
}
}

View File

@@ -15,17 +15,18 @@ class PublishCommand extends Command
$configFile = implode(DIRECTORY_SEPARATOR, [
$_SERVER['HOME'],
'.expose',
'config.php'
'config.php',
]);
if (! $this->option('force') && file_exists($configFile)) {
$this->error('Expose configuration file already exists at '.$configFile);
return;
}
@mkdir(dirname($configFile), 0755, true);
file_put_contents($configFile, file_get_contents(base_path('config/expose.php')));
$this->info('Published expose configuration file to: ' . $configFile);
$this->info('Published expose configuration file to: '.$configFile);
}
}

View File

@@ -18,7 +18,7 @@ class ServeCommand extends Command
$loop = app(LoopInterface::class);
$loop->futureTick(function () {
$this->info("Expose server running on port ".$this->option('port').".");
$this->info('Expose server running on port '.$this->option('port').'.');
});
$validateAuthTokens = config('expose.admin.validate_auth_tokens');

View File

@@ -4,7 +4,6 @@ namespace App\Commands;
use App\Client\Factory;
use App\Logger\CliRequestLogger;
use Illuminate\Console\Scheduling\Schedule;
use LaravelZero\Framework\Commands\Command;
use React\EventLoop\LoopInterface;
use Symfony\Component\Console\Output\ConsoleOutput;

View File

@@ -2,8 +2,6 @@
namespace App\Commands;
use Illuminate\Console\Command;
class ShareCurrentWorkingDirectoryCommand extends ShareCommand
{
protected $signature = 'share-cwd {host?} {--subdomain=} {--auth=}';
@@ -21,10 +19,11 @@ class ShareCurrentWorkingDirectoryCommand extends ShareCommand
protected function detectTld(): string
{
$valetConfigFile = $_SERVER['HOME'] . DIRECTORY_SEPARATOR . '.config' . DIRECTORY_SEPARATOR . 'valet' . DIRECTORY_SEPARATOR . 'config.json';
$valetConfigFile = $_SERVER['HOME'].DIRECTORY_SEPARATOR.'.config'.DIRECTORY_SEPARATOR.'valet'.DIRECTORY_SEPARATOR.'config.json';
if (file_exists($valetConfigFile)) {
$valetConfig = json_decode(file_get_contents($valetConfigFile));
return $valetConfig->tld;
}

View File

@@ -8,7 +8,6 @@ use PhpParser\Lexer\Emulative;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\CloningVisitor;
use PhpParser\Parser\Php7;
use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter\Standard;
class StoreAuthenticationTokenCommand extends Command
@@ -21,13 +20,13 @@ class StoreAuthenticationTokenCommand extends Command
{
$config = config('expose', []);
if (!is_null($this->argument('token'))) {
$this->info('Setting the expose authentication token to "' . $this->argument('token') . '"');
if (! is_null($this->argument('token'))) {
$this->info('Setting the expose authentication token to "'.$this->argument('token').'"');
$configFile = implode(DIRECTORY_SEPARATOR, [
$_SERVER['HOME'],
'.expose',
'config.php'
'config.php',
]);
if (! file_exists($configFile)) {
@@ -38,13 +37,14 @@ class StoreAuthenticationTokenCommand extends Command
}
file_put_contents($configFile, $updatedConfigFile);
return;
}
if (is_null($token = config('expose.auth_token'))) {
$this->info('There is no authentication token specified.');
} else {
$this->info('Current authentication token: ' . $token);
$this->info('Current authentication token: '.$token);
}
}

View File

@@ -2,10 +2,10 @@
namespace App\Http\Controllers\Concerns;
use function GuzzleHttp\Psr7\stream_for;
use Ratchet\ConnectionInterface;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use function GuzzleHttp\Psr7\stream_for;
trait LoadsViews
{

View File

@@ -14,8 +14,8 @@ trait ParsesIncomingRequest
protected function findContentLength(array $headers): int
{
return Collection::make($headers)->first(function ($values, $header) {
return strtolower($header) === 'content-length';
})[0] ?? 0;
return strtolower($header) === 'content-length';
})[0] ?? 0;
}
protected function shouldHandleRequest(Request $request, ConnectionInterface $httpConnection): bool
@@ -32,7 +32,7 @@ trait ParsesIncomingRequest
$this->handle($connection->laravelRequest, $connection);
}
if (!$this->keepConnectionOpen) {
if (! $this->keepConnectionOpen) {
$connection->close();
}
@@ -57,7 +57,7 @@ trait ParsesIncomingRequest
$connection->requestBuffer,
$connection->request->getProtocolVersion(),
[
'REMOTE_ADDR' => $connection->remoteAddress
'REMOTE_ADDR' => $connection->remoteAddress,
]
))
->withQueryParams(QueryParameters::create($connection->request)->all())

View File

@@ -4,12 +4,11 @@ namespace App\Http\Controllers;
use App\Http\Controllers\Concerns\LoadsViews;
use App\Http\Controllers\Concerns\ParsesIncomingRequest;
use function GuzzleHttp\Psr7\parse_request;
use Illuminate\Http\Request;
use Psr\Http\Message\RequestInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Http\HttpServerInterface;
use React\Promise\PromiseInterface;
use function GuzzleHttp\Psr7\parse_request;
abstract class Controller implements HttpServerInterface
{
@@ -51,7 +50,7 @@ abstract class Controller implements HttpServerInterface
$this->checkContentLength($from);
}
function onError(ConnectionInterface $conn, \Exception $e)
public function onError(ConnectionInterface $conn, \Exception $e)
{
//
}

View File

@@ -2,9 +2,6 @@
namespace App\Http;
use Ratchet\WebSocket\MessageComponentInterface;
use Ratchet\WebSocket\WsServer;
use React\EventLoop\LoopInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;

View File

@@ -2,7 +2,6 @@
namespace App\Logger;
use Illuminate\Console\OutputStyle;
use Illuminate\Support\Collection;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
@@ -53,8 +52,8 @@ class CliRequestLogger extends Logger
return [
$loggedRequest->getRequest()->getMethod(),
$loggedRequest->getRequest()->getUri(),
optional($loggedRequest->getResponse())->getStatusCode() . ' ' . optional($loggedRequest->getResponse())->getReasonPhrase(),
$loggedRequest->getDuration().'ms'
optional($loggedRequest->getResponse())->getStatusCode().' '.optional($loggedRequest->getResponse())->getReasonPhrase(),
$loggedRequest->getDuration().'ms',
];
})->toArray());

View File

@@ -3,13 +3,13 @@
namespace App\Logger;
use Carbon\Carbon;
use function GuzzleHttp\Psr7\parse_request;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Laminas\Http\Request;
use Laminas\Http\Response;
use Namshi\Cuzzle\Formatter\CurlFormatter;
use Riverline\MultiPartParser\StreamedPart;
use function GuzzleHttp\Psr7\parse_request;
class LoggedRequest implements \JsonSerializable
{
@@ -49,7 +49,7 @@ class LoggedRequest implements \JsonSerializable
}
/**
* @inheritDoc
* {@inheritdoc}
*/
public function jsonSerialize()
{
@@ -133,7 +133,6 @@ class LoggedRequest implements \JsonSerializable
'*javascript*',
];
return Str::is($patterns, $contentType);
}
@@ -157,7 +156,7 @@ class LoggedRequest implements \JsonSerializable
return Str::is(config()->get('expose.skip_body_log.content_type'), $contentType);
}
protected function skipByExtension(): bool
{
if (empty(config()->get('expose.skip_body_log.extension'))) {
@@ -185,7 +184,7 @@ class LoggedRequest implements \JsonSerializable
{
$units = ['B', 'KB', 'MB', 'GB'];
$number = substr($size, 0, -2);
$suffix = strtoupper(substr($size,-2));
$suffix = strtoupper(substr($size, -2));
// B or no suffix
if (is_numeric(substr($suffix, 0, 1))) {
@@ -294,7 +293,7 @@ class LoggedRequest implements \JsonSerializable
return collect($this->parsedRequest->getHeaders()->toArray())
->mapWithKeys(function ($value, $key) {
return [strtolower($key) => $value];
})->get('x-expose-request-id', (string)Str::uuid());
})->get('x-expose-request-id', (string) Str::uuid());
}
public function getDuration()

View File

@@ -3,10 +3,7 @@
namespace App\Logger;
use Illuminate\Console\Concerns\InteractsWithIO;
use Illuminate\Console\OutputStyle;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class Logger
{

View File

@@ -2,12 +2,9 @@
namespace App\Logger;
use App\WebSockets\Socket;
use Clue\React\Buzz\Browser;
use GuzzleHttp\RequestOptions;
use Laminas\Http\Request;
use Laminas\Http\Response;
use function GuzzleHttp\Psr7\stream_for;
class RequestLogger
{
@@ -80,5 +77,4 @@ class RequestLogger
json_encode($request, JSON_INVALID_UTF8_IGNORE)
);
}
}

View File

@@ -35,19 +35,19 @@ class AppServiceProvider extends ServiceProvider
{
$builtInConfig = config('expose');
$localConfigFile = getcwd() . DIRECTORY_SEPARATOR . '.expose.php';
$localConfigFile = getcwd().DIRECTORY_SEPARATOR.'.expose.php';
if (file_exists($localConfigFile)) {
$localConfig = require $localConfigFile;
config()->set('expose', array_merge($builtInConfig, $localConfig));
return;
}
$configFile = implode(DIRECTORY_SEPARATOR, [
$_SERVER['HOME'] ?? __DIR__,
'.expose',
'config.php'
'config.php',
]);
if (file_exists($configFile)) {

View File

@@ -38,7 +38,7 @@ class Configuration implements \JsonSerializable
}
/**
* @inheritDoc
* {@inheritdoc}
*/
public function jsonSerialize()
{

View File

@@ -35,14 +35,14 @@ class ConnectionManager implements ConnectionManagerContract
$connection->setMaximumConnectionLength($maximumConnectionLength);
$this->loop->addTimer($maximumConnectionLength * 60, function() use ($connection) {
$this->loop->addTimer($maximumConnectionLength * 60, function () use ($connection) {
$connection->socket->close();
});
}
public function storeConnection(string $host, ?string $subdomain, ConnectionInterface $connection): ControlConnection
{
$clientId = (string)uniqid();
$clientId = (string) uniqid();
$connection->client_id = $clientId;

View File

@@ -3,16 +3,7 @@
namespace App\Server\Connections;
use Evenement\EventEmitterTrait;
use GuzzleHttp\Psr7\Request;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Str;
use Nyholm\Psr7\Factory\Psr17Factory;
use Ratchet\Client\WebSocket;
use Ratchet\ConnectionInterface;
use Ratchet\RFC6455\Messaging\Frame;
use Ratchet\WebSocket\WsConnection;
use React\Stream\Util;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
class ControlConnection
{

View File

@@ -5,6 +5,7 @@ namespace App\Server;
use App\Contracts\ConnectionManager as ConnectionManagerContract;
use App\Contracts\SubdomainGenerator;
use App\Contracts\UserRepository;
use App\Http\RouteGenerator;
use App\Http\Server as HttpServer;
use App\Server\Connections\ConnectionManager;
use App\Server\Http\Controllers\Admin\DeleteUsersController;
@@ -15,28 +16,24 @@ use App\Server\Http\Controllers\Admin\GetUsersController;
use App\Server\Http\Controllers\Admin\ListSitesController;
use App\Server\Http\Controllers\Admin\ListUsersController;
use App\Server\Http\Controllers\Admin\RedirectToUsersController;
use App\Server\Http\Controllers\Admin\StoreSettingsController;
use App\Server\Http\Controllers\Admin\ShowSettingsController;
use App\Server\Http\Controllers\Admin\StoreSettingsController;
use App\Server\Http\Controllers\Admin\StoreUsersController;
use App\Server\Http\Controllers\ControlMessageController;
use App\Server\Http\Controllers\TunnelMessageController;
use App\Http\RouteGenerator;
use App\Server\Http\Router;
use App\Server\SubdomainGenerator\RandomSubdomainGenerator;
use Clue\React\SQLite\DatabaseInterface;
use Phar;
use Ratchet\Server\IoServer;
use Ratchet\WebSocket\WsServer;
use React\Socket\Server;
use React\EventLoop\LoopInterface;
use React\EventLoop\Factory as LoopFactory;
use React\EventLoop\LoopInterface;
use React\Socket\Server;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
class Factory
{
@@ -98,7 +95,7 @@ class Factory
new Route('/{__catchall__}', [
'_controller' => app(TunnelMessageController::class),
], [
'__catchall__' => '.*'
'__catchall__' => '.*',
]));
}
@@ -195,7 +192,7 @@ class Factory
protected function bindUserRepository()
{
app()->singleton(UserRepository::class, function() {
app()->singleton(UserRepository::class, function () {
return app(config('expose.admin.user_repository'));
});
@@ -204,10 +201,10 @@ class Factory
protected function bindDatabase()
{
app()->singleton(DatabaseInterface::class, function() {
app()->singleton(DatabaseInterface::class, function () {
$factory = new \Clue\React\SQLite\Factory($this->loop);
$options = ['worker_command' => Phar::running(false) ? Phar::running(false) . ' --sqlite-worker' : null];
$options = ['worker_command' => Phar::running(false) ? Phar::running(false).' --sqlite-worker' : null];
return $factory->openLazy(
config('expose.admin.database', ':memory:'),
@@ -244,5 +241,4 @@ class Factory
return $this;
}
}

View File

@@ -4,10 +4,10 @@ namespace App\Server\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use GuzzleHttp\Psr7\Response;
use function GuzzleHttp\Psr7\str;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Ratchet\ConnectionInterface;
use function GuzzleHttp\Psr7\str;
abstract class AdminController extends Controller
{
@@ -16,17 +16,19 @@ abstract class AdminController extends Controller
try {
$authorization = Str::after($request->header('Authorization'), 'Basic ');
$authParts = explode(':', base64_decode($authorization), 2);
list($user, $password) = $authParts;
[$user, $password] = $authParts;
if (! $this->credentialsAreAllowed($user, $password)) {
throw new \InvalidArgumentException('Invalid Login');
}
return true;
} catch (\Throwable $e) {
$httpConnection->send(str(new Response(401, [
'WWW-Authenticate' => 'Basic realm="Expose"'
'WWW-Authenticate' => 'Basic realm="Expose"',
])));
}
return false;
}

View File

@@ -3,16 +3,8 @@
namespace App\Server\Http\Controllers\Admin;
use App\Contracts\UserRepository;
use App\Http\Controllers\Controller;
use GuzzleHttp\Psr7\Response;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Ratchet\ConnectionInterface;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use function GuzzleHttp\Psr7\str;
use function GuzzleHttp\Psr7\stream_for;
class DeleteUsersController extends AdminController
{
@@ -29,7 +21,7 @@ class DeleteUsersController extends AdminController
public function handle(Request $request, ConnectionInterface $httpConnection)
{
$this->userRepository->deleteUser($request->get('id'))
->then(function() use ($httpConnection) {
->then(function () use ($httpConnection) {
$httpConnection->send(respond_json(['deleted' => true], 200));
$httpConnection->close();
});

View File

@@ -3,15 +3,9 @@
namespace App\Server\Http\Controllers\Admin;
use App\Contracts\ConnectionManager;
use App\Http\Controllers\Controller;
use App\Server\Configuration;
use GuzzleHttp\Psr7\Response;
use Illuminate\Http\Request;
use Ratchet\ConnectionInterface;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use function GuzzleHttp\Psr7\str;
use function GuzzleHttp\Psr7\stream_for;
class DisconnectSiteController extends AdminController
{
@@ -37,7 +31,7 @@ class DisconnectSiteController extends AdminController
}
$httpConnection->send(respond_json([
'sites' => $this->connectionManager->getConnections()
'sites' => $this->connectionManager->getConnections(),
]));
}
}

View File

@@ -6,10 +6,6 @@ use App\Contracts\ConnectionManager;
use App\Server\Configuration;
use Illuminate\Http\Request;
use Ratchet\ConnectionInterface;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use function GuzzleHttp\Psr7\str;
use function GuzzleHttp\Psr7\stream_for;
class GetSettingsController extends AdminController
{

View File

@@ -3,14 +3,9 @@
namespace App\Server\Http\Controllers\Admin;
use App\Contracts\ConnectionManager;
use App\Http\Controllers\Controller;
use App\Server\Configuration;
use Illuminate\Http\Request;
use Ratchet\ConnectionInterface;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use function GuzzleHttp\Psr7\str;
use function GuzzleHttp\Psr7\stream_for;
class GetSitesController extends AdminController
{
@@ -33,7 +28,7 @@ class GetSitesController extends AdminController
$site['id'] = $siteId;
return $site;
})->values()
})->values(),
])
);
}

View File

@@ -3,15 +3,8 @@
namespace App\Server\Http\Controllers\Admin;
use App\Contracts\UserRepository;
use App\Http\Controllers\Controller;
use Clue\React\SQLite\Result;
use GuzzleHttp\Psr7\Response;
use Illuminate\Http\Request;
use Ratchet\ConnectionInterface;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use function GuzzleHttp\Psr7\str;
use function GuzzleHttp\Psr7\stream_for;
class GetUsersController extends AdminController
{

View File

@@ -3,14 +3,9 @@
namespace App\Server\Http\Controllers\Admin;
use App\Contracts\ConnectionManager;
use App\Http\Controllers\Controller;
use App\Server\Configuration;
use Illuminate\Http\Request;
use Ratchet\ConnectionInterface;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use function GuzzleHttp\Psr7\str;
use function GuzzleHttp\Psr7\stream_for;
class ListSitesController extends AdminController
{
@@ -30,7 +25,7 @@ class ListSitesController extends AdminController
$sites = $this->getView($httpConnection, 'server.sites.index', [
'scheme' => $this->configuration->port() === 443 ? 'https' : 'http',
'configuration' => $this->configuration,
'sites' => $this->connectionManager->getConnections()
'sites' => $this->connectionManager->getConnections(),
]);
$httpConnection->send(

View File

@@ -3,15 +3,8 @@
namespace App\Server\Http\Controllers\Admin;
use App\Contracts\UserRepository;
use App\Http\Controllers\Controller;
use Clue\React\SQLite\Result;
use GuzzleHttp\Psr7\Response;
use Illuminate\Http\Request;
use Ratchet\ConnectionInterface;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use function GuzzleHttp\Psr7\str;
use function GuzzleHttp\Psr7\stream_for;
class ListUsersController extends AdminController
{

View File

@@ -2,19 +2,18 @@
namespace App\Server\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use GuzzleHttp\Psr7\Response;
use function GuzzleHttp\Psr7\str;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Ratchet\ConnectionInterface;
use function GuzzleHttp\Psr7\str;
class RedirectToUsersController extends AdminController
{
public function handle(Request $request, ConnectionInterface $httpConnection)
{
$httpConnection->send(str(new Response(301, [
'Location' => '/sites'
'Location' => '/sites',
])));
}
}

View File

@@ -6,10 +6,6 @@ use App\Contracts\ConnectionManager;
use App\Server\Configuration;
use Illuminate\Http\Request;
use Ratchet\ConnectionInterface;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use function GuzzleHttp\Psr7\str;
use function GuzzleHttp\Psr7\stream_for;
class ShowSettingsController extends AdminController
{

View File

@@ -2,18 +2,10 @@
namespace App\Server\Http\Controllers\Admin;
use App\Contracts\ConnectionManager;
use App\Http\Controllers\Controller;
use App\Server\Configuration;
use Clue\React\SQLite\Result;
use GuzzleHttp\Psr7\Response;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Ratchet\ConnectionInterface;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use function GuzzleHttp\Psr7\str;
use function GuzzleHttp\Psr7\stream_for;
class StoreSettingsController extends AdminController
{
@@ -27,7 +19,7 @@ class StoreSettingsController extends AdminController
public function handle(Request $request, ConnectionInterface $httpConnection)
{
config()->set('expose.admin.validate_auth_tokens', (bool)$request->get('validate_auth_tokens'));
config()->set('expose.admin.validate_auth_tokens', (bool) $request->get('validate_auth_tokens'));
$messages = $request->get('messages');

View File

@@ -3,17 +3,11 @@
namespace App\Server\Http\Controllers\Admin;
use App\Contracts\UserRepository;
use App\Http\Controllers\Controller;
use Clue\React\SQLite\Result;
use GuzzleHttp\Psr7\Response;
use function GuzzleHttp\Psr7\str;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Ratchet\ConnectionInterface;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use function GuzzleHttp\Psr7\str;
use function GuzzleHttp\Psr7\stream_for;
class StoreUsersController extends AdminController
{
@@ -44,7 +38,7 @@ class StoreUsersController extends AdminController
$insertData = [
'name' => $request->get('name'),
'auth_token' => (string)Str::uuid()
'auth_token' => (string) Str::uuid(),
];
$this->userRepository

View File

@@ -5,16 +5,15 @@ namespace App\Server\Http\Controllers;
use App\Contracts\ConnectionManager;
use App\Contracts\UserRepository;
use App\Http\QueryParameters;
use Ratchet\ConnectionInterface;
use Ratchet\WebSocket\MessageComponentInterface;
use React\Promise\Deferred;
use React\Promise\FulfilledPromise;
use React\Promise\PromiseInterface;
use stdClass;
use Ratchet\ConnectionInterface;
class ControlMessageController implements MessageComponentInterface
{
/** @var ConnectionManager */
protected $connectionManager;
@@ -28,16 +27,16 @@ class ControlMessageController implements MessageComponentInterface
}
/**
* @inheritDoc
* {@inheritdoc}
*/
function onOpen(ConnectionInterface $connection)
public function onOpen(ConnectionInterface $connection)
{
}
/**
* @inheritDoc
* {@inheritdoc}
*/
function onClose(ConnectionInterface $connection)
public function onClose(ConnectionInterface $connection)
{
if (isset($connection->request_id)) {
$httpConnection = $this->connectionManager->getHttpConnectionForRequestId($connection->request_id);
@@ -48,9 +47,9 @@ class ControlMessageController implements MessageComponentInterface
}
/**
* @inheritDoc
* {@inheritdoc}
*/
function onMessage(ConnectionInterface $connection, $msg)
public function onMessage(ConnectionInterface $connection, $msg)
{
if (isset($connection->request_id)) {
return $this->sendResponseToHttpConnection($connection->request_id, $msg);
@@ -92,15 +91,15 @@ class ControlMessageController implements MessageComponentInterface
'data' => [
'message' => config('expose.admin.messages.message_of_the_day'),
'subdomain' => $connectionInfo->subdomain,
'client_id' => $connectionInfo->client_id
'client_id' => $connectionInfo->client_id,
],
]));
}, function () use ($connection) {
$connection->send(json_encode([
'event' => 'authenticationFailed',
'data' => [
'message' => config('expose.admin.messages.invalid_auth_token')
]
'message' => config('expose.admin.messages.invalid_auth_token'),
],
]));
$connection->close();
});
@@ -112,15 +111,15 @@ class ControlMessageController implements MessageComponentInterface
$connectionInfo = $this->connectionManager->findControlConnectionForClientId($data->client_id);
$connectionInfo->emit('proxy_ready_' . $data->request_id, [
$connectionInfo->emit('proxy_ready_'.$data->request_id, [
$connection,
]);
}
/**
* @inheritDoc
* {@inheritdoc}
*/
function onError(ConnectionInterface $conn, \Exception $e)
public function onError(ConnectionInterface $conn, \Exception $e)
{
//
}
@@ -150,9 +149,9 @@ class ControlMessageController implements MessageComponentInterface
protected function hasValidSubdomain(ConnectionInterface $connection, ?string $subdomain): bool
{
if (!is_null($subdomain)) {
if (! is_null($subdomain)) {
$controlConnection = $this->connectionManager->findControlConnectionForSubdomain($subdomain);
if (!is_null($controlConnection) || $subdomain === config('expose.admin.subdomain')) {
if (! is_null($controlConnection) || $subdomain === config('expose.admin.subdomain')) {
$message = config('expose.admin.messages.subdomain_taken');
$message = str_replace(':subdomain', $subdomain, $message);
@@ -160,7 +159,7 @@ class ControlMessageController implements MessageComponentInterface
'event' => 'subdomainTaken',
'data' => [
'message' => $message,
]
],
]));
$connection->close();

View File

@@ -7,16 +7,13 @@ use App\Http\Controllers\Controller;
use App\Server\Configuration;
use App\Server\Connections\ControlConnection;
use App\Server\Connections\HttpConnection;
use GuzzleHttp\Psr7\Response;
use function GuzzleHttp\Psr7\str;
use Illuminate\Http\Request;
use Illuminate\Pipeline\Pipeline;
use Illuminate\Support\Str;
use Nyholm\Psr7\Factory\Psr17Factory;
use Ratchet\ConnectionInterface;
use Ratchet\RFC6455\Messaging\Frame;
use React\Promise\Deferred;
use Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory;
use function GuzzleHttp\Psr7\str;
class TunnelMessageController extends Controller
{
@@ -45,6 +42,7 @@ class TunnelMessageController extends Controller
respond_html($this->getView($httpConnection, 'server.homepage'), 200)
);
$httpConnection->close();
return;
}
@@ -55,6 +53,7 @@ class TunnelMessageController extends Controller
respond_html($this->getView($httpConnection, 'server.errors.404', ['subdomain' => $subdomain]), 404)
);
$httpConnection->close();
return;
}
@@ -77,7 +76,7 @@ class TunnelMessageController extends Controller
$httpConnection = $this->connectionManager->storeHttpConnection($httpConnection, $requestId);
transform($this->passRequestThroughModifiers($request, $httpConnection), function (Request $request) use ($controlConnection, $httpConnection, $requestId) {
$controlConnection->once('proxy_ready_' . $requestId, function (ConnectionInterface $proxy) use ($request) {
$controlConnection->once('proxy_ready_'.$requestId, function (ConnectionInterface $proxy) use ($request) {
// Convert the Laravel request into a PSR7 request
$psr17Factory = new Psr17Factory();
$psrHttpFactory = new PsrHttpFactory($psr17Factory, $psr17Factory, $psr17Factory, $psr17Factory);
@@ -110,7 +109,7 @@ class TunnelMessageController extends Controller
$host = $this->configuration->hostname();
if (!$request->isSecure()) {
if (! $request->isSecure()) {
$host .= ":{$this->configuration->port()}";
}
@@ -118,7 +117,7 @@ class TunnelMessageController extends Controller
$request->headers->set('X-Forwarded-Proto', $request->isSecure() ? 'https' : 'http');
$request->headers->set('X-Expose-Request-ID', uniqid());
$request->headers->set('Upgrade-Insecure-Requests', 1);
$request->headers->set('X-Exposed-By', config('app.name') . ' ' . config('app.version'));
$request->headers->set('X-Exposed-By', config('app.name').' '.config('app.version'));
$request->headers->set('X-Original-Host', "{$controlConnection->subdomain}.{$host}");
return $request;

View File

@@ -3,6 +3,8 @@
namespace App\Server\Http;
use App\Http\QueryParameters;
use function GuzzleHttp\Psr7\build_query;
use function GuzzleHttp\Psr7\parse_query;
use GuzzleHttp\Psr7\ServerRequest;
use Psr\Http\Message\RequestInterface;
use Ratchet\ConnectionInterface;
@@ -13,8 +15,6 @@ use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
use Symfony\Component\Routing\Exception\MethodNotAllowedException;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use function GuzzleHttp\Psr7\build_query;
use function GuzzleHttp\Psr7\parse_query;
class Router implements HttpServerInterface
{
@@ -56,7 +56,7 @@ class Router implements HttpServerInterface
try {
$route = $this->_matcher->matchRequest($symfonyRequest);
} catch (MethodNotAllowedException $nae) {
return $this->close($conn, 405, array('Allow' => $nae->getAllowedMethods()));
return $this->close($conn, 405, ['Allow' => $nae->getAllowedMethods()]);
} catch (ResourceNotFoundException $nfe) {
return $this->close($conn, 404);
}
@@ -65,7 +65,7 @@ class Router implements HttpServerInterface
$route['_controller'] = new $route['_controller'];
}
if (!($route['_controller'] instanceof HttpServerInterface)) {
if (! ($route['_controller'] instanceof HttpServerInterface)) {
throw new \UnexpectedValueException('All routes must implement Ratchet\Http\HttpServerInterface');
}

View File

@@ -2,8 +2,8 @@
namespace App\Server\SubdomainGenerator;
use Illuminate\Support\Str;
use App\Contracts\SubdomainGenerator;
use Illuminate\Support\Str;
class RandomSubdomainGenerator implements SubdomainGenerator
{

View File

@@ -23,7 +23,7 @@ class DatabaseUserRepository implements UserRepository
$deferred = new Deferred();
$this->database
->query("SELECT * FROM users ORDER by created_at DESC")
->query('SELECT * FROM users ORDER by created_at DESC')
->then(function (Result $result) use ($deferred) {
$deferred->resolve($result->rows);
});
@@ -36,7 +36,7 @@ class DatabaseUserRepository implements UserRepository
$deferred = new Deferred();
$this->database
->query("SELECT * FROM users WHERE id = :id", ['id' => $id])
->query('SELECT * FROM users WHERE id = :id', ['id' => $id])
->then(function (Result $result) use ($deferred) {
$deferred->resolve($result->rows[0] ?? null);
});
@@ -49,7 +49,7 @@ class DatabaseUserRepository implements UserRepository
$deferred = new Deferred();
$this->database
->query("SELECT * FROM users WHERE auth_token = :token", ['token' => $authToken])
->query('SELECT * FROM users WHERE auth_token = :token', ['token' => $authToken])
->then(function (Result $result) use ($deferred) {
$deferred->resolve($result->rows[0] ?? null);
});
@@ -66,7 +66,7 @@ class DatabaseUserRepository implements UserRepository
VALUES (:name, :auth_token, DATETIME('now'))
", $data)
->then(function (Result $result) use ($deferred) {
$this->database->query("SELECT * FROM users WHERE id = :id", ['id' => $result->insertId])
$this->database->query('SELECT * FROM users WHERE id = :id', ['id' => $result->insertId])
->then(function (Result $result) use ($deferred) {
$deferred->resolve($result->rows[0]);
});
@@ -79,7 +79,7 @@ class DatabaseUserRepository implements UserRepository
{
$deferred = new Deferred();
$this->database->query("DELETE FROM users WHERE id = :id", ['id' => $id])
$this->database->query('DELETE FROM users WHERE id = :id', ['id' => $id])
->then(function (Result $result) use ($deferred) {
$deferred->resolve($result);
});

View File

@@ -93,28 +93,28 @@ return [
*/
'skip_body_log' => [
/**
| Skip response logging by HTTP response code. Format: 4*, 5*
* | Skip response logging by HTTP response code. Format: 4*, 5*.
*/
'status' => [
// "4*"
],
/**
| Skip response logging by HTTP response content type. Ex: "text/css"
* | Skip response logging by HTTP response content type. Ex: "text/css"
*/
'content_type' => [
//
],
/**
| Skip response logging by file extension. Ex: ".js.map", ".min.js", ".min.css"
* | Skip response logging by file extension. Ex: ".js.map", ".min.js", ".min.css"
*/
'extension' => [
'.js.map',
'.css.map',
],
/**
| Skip response logging if response size is greater than configured value.
| Valid suffixes are: B, KB, MB, GB.
| Ex: 500B, 1KB, 2MB, 3GB
* | Skip response logging if response size is greater than configured value.
* | Valid suffixes are: B, KB, MB, GB.
* | Ex: 500B, 1KB, 2MB, 3GB
*/
'size' => '1MB',
],
@@ -134,7 +134,7 @@ return [
'database' => implode(DIRECTORY_SEPARATOR, [
$_SERVER['HOME'] ?? __DIR__,
'.expose',
'expose.db'
'expose.db',
]),
/*
@@ -199,7 +199,7 @@ return [
|
*/
'users' => [
'username' => 'password'
'username' => 'password',
],
/*
@@ -230,6 +230,6 @@ return [
'invalid_auth_token' => 'Authentication failed. Please check your authentication token and try again.',
'subdomain_taken' => 'The chosen subdomain :subdomain is already taken. Please choose a different subdomain.',
]
]
],
],
];

View File

@@ -9,14 +9,11 @@ use App\Logger\RequestLogger;
use Clue\React\Buzz\Browser;
use Clue\React\Buzz\Message\ResponseException;
use GuzzleHttp\Psr7\Request;
use function GuzzleHttp\Psr7\str;
use Mockery as m;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use React\EventLoop\LoopInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Tests\Feature\TestCase;
use function GuzzleHttp\Psr7\str;
class DashboardTest extends TestCase
{
@@ -59,7 +56,7 @@ class DashboardTest extends TestCase
public function it_can_replay_requests()
{
$request = new Request('GET', '/example', [
'X-Expose-Request-ID' => 'request-one'
'X-Expose-Request-ID' => 'request-one',
]);
$httpClient = m::mock(HttpClient::class);
@@ -74,7 +71,7 @@ class DashboardTest extends TestCase
$this->logRequest($request);
$this->assertSame(200,
$this->await($this->browser->get("http://127.0.0.1:4040/api/replay/request-one"))
$this->await($this->browser->get('http://127.0.0.1:4040/api/replay/request-one'))
->getStatusCode()
);
}
@@ -87,7 +84,7 @@ class DashboardTest extends TestCase
$this->expectException(ResponseException::class);
$this->expectExceptionMessage(404);
$this->await($this->browser->get("http://127.0.0.1:4040/api/replay/invalid-request"));
$this->await($this->browser->get('http://127.0.0.1:4040/api/replay/invalid-request'));
}
/** @test */
@@ -101,7 +98,7 @@ class DashboardTest extends TestCase
$this->assertCount(3, $this->requestLogger->getData());
$this->await($this->browser->get("http://127.0.0.1:4040/api/logs/clear"));
$this->await($this->browser->get('http://127.0.0.1:4040/api/logs/clear'));
$this->assertCount(0, $this->requestLogger->getData());
}
@@ -113,15 +110,15 @@ class DashboardTest extends TestCase
$loggedRequest = $this->logRequest(new Request('GET', '/foo'));
$this->await($this->browser->post("http://127.0.0.1:4040/api/logs/{$loggedRequest->id()}/data", [
'Content-Type' => 'application/json'
'Content-Type' => 'application/json',
], json_encode([
'data' => [
'foo' => 'bar',
]
],
])));
$this->assertSame([
'foo' => 'bar'
'foo' => 'bar',
], $this->requestLogger->findLoggedRequest($loggedRequest->id())->getAdditionalData());
}

View File

@@ -3,7 +3,6 @@
namespace Tests\Feature\Server;
use App\Contracts\ConnectionManager;
use App\Http\Server;
use App\Server\Factory;
use Clue\React\Buzz\Browser;
use Clue\React\Buzz\Message\ResponseException;
@@ -11,7 +10,6 @@ use GuzzleHttp\Psr7\Response;
use Illuminate\Support\Str;
use Psr\Http\Message\ResponseInterface;
use Ratchet\Server\IoConnection;
use React\Socket\Connector;
use Tests\Feature\TestCase;
class AdminTest extends TestCase
@@ -19,7 +17,7 @@ class AdminTest extends TestCase
/** @var Browser */
protected $browser;
/** @var Factory */
/** @var Factory */
protected $serverFactory;
public function setUp(): void
@@ -49,7 +47,7 @@ class AdminTest extends TestCase
/** @var ResponseInterface $response */
$this->await($this->browser->get('http://127.0.0.1:8080', [
'Host' => 'expose.localhost'
'Host' => 'expose.localhost',
]));
}
@@ -59,7 +57,7 @@ class AdminTest extends TestCase
/** @var ResponseInterface $response */
$response = $this->await($this->browser->get('http://127.0.0.1:8080/', [
'Host' => 'expose.localhost',
'Authorization' => base64_encode("username:secret"),
'Authorization' => base64_encode('username:secret'),
]));
$this->assertSame(301, $response->getStatusCode());
}
@@ -72,8 +70,8 @@ class AdminTest extends TestCase
/** @var ResponseInterface $response */
$this->await($this->browser->post('http://127.0.0.1:8080/api/settings', [
'Host' => 'expose.localhost',
'Authorization' => base64_encode("username:secret"),
'Content-Type' => 'application/json'
'Authorization' => base64_encode('username:secret'),
'Content-Type' => 'application/json',
], json_encode([
'validate_auth_tokens' => true,
])));
@@ -87,8 +85,8 @@ class AdminTest extends TestCase
/** @var Response $response */
$response = $this->await($this->browser->post('http://127.0.0.1:8080/api/users', [
'Host' => 'expose.localhost',
'Authorization' => base64_encode("username:secret"),
'Content-Type' => 'application/json'
'Authorization' => base64_encode('username:secret'),
'Content-Type' => 'application/json',
], json_encode([
'name' => 'Marcel',
])));
@@ -105,17 +103,16 @@ class AdminTest extends TestCase
/** @var Response $response */
$this->await($this->browser->post('http://127.0.0.1:8080/api/users', [
'Host' => 'expose.localhost',
'Authorization' => base64_encode("username:secret"),
'Content-Type' => 'application/json'
'Authorization' => base64_encode('username:secret'),
'Content-Type' => 'application/json',
], json_encode([
'name' => 'Marcel',
])));
$this->await($this->browser->delete('http://127.0.0.1:8080/api/users/1', [
'Host' => 'expose.localhost',
'Authorization' => base64_encode("username:secret"),
'Content-Type' => 'application/json'
'Authorization' => base64_encode('username:secret'),
'Content-Type' => 'application/json',
]));
$this->assertDatabaseHasNoResults('SELECT * FROM users WHERE name = "Marcel"');
@@ -127,8 +124,8 @@ class AdminTest extends TestCase
/** @var Response $response */
$this->await($this->browser->post('http://127.0.0.1:8080/api/users', [
'Host' => 'expose.localhost',
'Authorization' => base64_encode("username:secret"),
'Content-Type' => 'application/json'
'Authorization' => base64_encode('username:secret'),
'Content-Type' => 'application/json',
], json_encode([
'name' => 'Marcel',
])));
@@ -136,8 +133,8 @@ class AdminTest extends TestCase
/** @var Response $response */
$response = $this->await($this->browser->get('http://127.0.0.1:8080/users', [
'Host' => 'expose.localhost',
'Authorization' => base64_encode("username:secret"),
'Content-Type' => 'application/json'
'Authorization' => base64_encode('username:secret'),
'Content-Type' => 'application/json',
]));
$body = $response->getBody()->getContents();
@@ -157,8 +154,8 @@ class AdminTest extends TestCase
/** @var Response $response */
$response = $this->await($this->browser->get('http://127.0.0.1:8080/sites', [
'Host' => 'expose.localhost',
'Authorization' => base64_encode("username:secret"),
'Content-Type' => 'application/json'
'Authorization' => base64_encode('username:secret'),
'Content-Type' => 'application/json',
]));
$body = $response->getBody()->getContents();

View File

@@ -3,18 +3,13 @@
namespace Tests\Feature\Server;
use App\Client\Client;
use App\Contracts\ConnectionManager;
use App\Server\Factory;
use Clue\React\Buzz\Browser;
use Clue\React\Buzz\Message\ResponseException;
use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\ServerRequestInterface;
use Ratchet\Client\WebSocket;
use Ratchet\ConnectionInterface;
use React\EventLoop\LoopInterface;
use React\Http\Server;
use Tests\Feature\TestCase;
use function Ratchet\Client\connect;
class TunnelTest extends TestCase
{
@@ -54,7 +49,7 @@ class TunnelTest extends TestCase
$this->expectExceptionMessage(404);
$response = $this->await($this->browser->get('http://127.0.0.1:8080/', [
'Host' => 'tunnel.localhost'
'Host' => 'tunnel.localhost',
]));
}
@@ -65,7 +60,7 @@ class TunnelTest extends TestCase
/**
* We create an expose client that connects to our server and shares
* the created test HTTP server
* the created test HTTP server.
*/
$client = $this->createClient();
$this->await($client->connectToServer('127.0.0.1:8085', 'tunnel'));
@@ -75,7 +70,7 @@ class TunnelTest extends TestCase
* created tunnel.
*/
$response = $this->await($this->browser->get('http://127.0.0.1:8080/', [
'Host' => 'tunnel.localhost'
'Host' => 'tunnel.localhost',
]));
$this->assertSame('Hello World!', $response->getBody()->getContents());
@@ -92,7 +87,7 @@ class TunnelTest extends TestCase
/**
* We create an expose client that connects to our server and shares
* the created test HTTP server
* the created test HTTP server.
*/
$client = $this->createClient();
$result = $this->await($client->connectToServer('127.0.0.1:8085', 'tunnel'));
@@ -109,7 +104,7 @@ class TunnelTest extends TestCase
/**
* We create an expose client that connects to our server and shares
* the created test HTTP server
* the created test HTTP server.
*/
$client = $this->createClient();
$this->await($client->connectToServer('127.0.0.1:8085', 'tunnel'));
@@ -141,7 +136,7 @@ class TunnelTest extends TestCase
protected function createTestHttpServer()
{
$server = new Server(function (ServerRequestInterface $request) {
return new Response(200, ['Content-Type' => 'text/plain'], "Hello World!");
return new Response(200, ['Content-Type' => 'text/plain'], 'Hello World!');
});
$this->testHttpServer = new \React\Socket\Server(8085, $this->loop);

View File

@@ -2,17 +2,12 @@
namespace Tests\Feature;
use function Clue\React\Block\await;
use Clue\React\SQLite\DatabaseInterface;
use GuzzleHttp\Psr7\Response;
use Illuminate\Support\Str;
use Psr\Http\Message\ResponseInterface;
use React\EventLoop\Factory;
use React\EventLoop\LoopInterface;
use React\EventLoop\StreamSelectLoop;
use React\Promise\PromiseInterface;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use function Clue\React\Block\await;
abstract class TestCase extends \Tests\TestCase
{
@@ -25,7 +20,7 @@ abstract class TestCase extends \Tests\TestCase
{
parent::setUp();
$this->app->bind(ConsoleOutputInterface::class, function() {
$this->app->bind(ConsoleOutputInterface::class, function () {
return new ConsoleOutput();
});

View File

@@ -2,7 +2,6 @@
namespace Tests;
use Clue\React\SQLite\DatabaseInterface;
use LaravelZero\Framework\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase

View File

@@ -4,11 +4,9 @@ namespace Tests\Unit;
use App\Logger\LoggedRequest;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use Laminas\Http\Request as LaminasRequest;
use Laminas\Http\Response as LaminasResponse;
use Tests\TestCase;
use function GuzzleHttp\Psr7\str;
use Laminas\Http\Request as LaminasRequest;
use Tests\TestCase;
class LoggedRequestTest extends TestCase
{
@@ -16,7 +14,7 @@ class LoggedRequestTest extends TestCase
public function it_retrieves_the_request_id()
{
$rawRequest = str(new Request(200, '/expose', [
'X-Expose-Request-ID' => 'example-request'
'X-Expose-Request-ID' => 'example-request',
]));
$parsedRequest = LaminasRequest::fromString($rawRequest);
@@ -29,11 +27,11 @@ class LoggedRequestTest extends TestCase
{
$postData = [
'name' => 'Marcel',
'project' => 'expose'
'project' => 'expose',
];
$rawRequest = str(new Request(200, '/expose', [
'Content-Type' => 'application/json'
'Content-Type' => 'application/json',
], json_encode($postData)));
$parsedRequest = LaminasRequest::fromString($rawRequest);
@@ -42,12 +40,12 @@ class LoggedRequestTest extends TestCase
$this->assertSame([
[
'name' => 'name',
'value' => 'Marcel'
'value' => 'Marcel',
],
[
'name' => 'project',
'value' => 'expose'
]
'value' => 'expose',
],
], $loggedRequest->getPostData());
}
@@ -55,7 +53,7 @@ class LoggedRequestTest extends TestCase
public function it_returns_the_raw_request()
{
$rawRequest = str(new Request(200, '/expose', [
'X-Expose-Request-ID' => 'example-request'
'X-Expose-Request-ID' => 'example-request',
]));
$parsedRequest = LaminasRequest::fromString($rawRequest);
@@ -67,7 +65,7 @@ class LoggedRequestTest extends TestCase
public function it_returns_the_parsed_request()
{
$rawRequest = str(new Request(200, '/expose', [
'X-Expose-Request-ID' => 'example-request'
'X-Expose-Request-ID' => 'example-request',
]));
$parsedRequest = LaminasRequest::fromString($rawRequest);

View File

@@ -7,10 +7,10 @@ use App\Logger\RequestLogger;
use Clue\React\Buzz\Browser;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use Laminas\Http\Request as LaminasRequest;
use Tests\TestCase;
use function GuzzleHttp\Psr7\str;
use Laminas\Http\Request as LaminasRequest;
use Mockery as m;
use Tests\TestCase;
class RequestLoggerTest extends TestCase
{