mirror of
https://github.com/bitinflow/expose.git
synced 2026-03-13 13:35:54 +00:00
Added custom server host ability
This commit is contained in:
@@ -40,12 +40,12 @@ class Client
|
|||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function share(string $sharedUrl, array $subdomains = [])
|
public function share(string $sharedUrl, array $subdomains = [], $serverHost = null)
|
||||||
{
|
{
|
||||||
$sharedUrl = $this->prepareSharedUrl($sharedUrl);
|
$sharedUrl = $this->prepareSharedUrl($sharedUrl);
|
||||||
|
|
||||||
foreach ($subdomains as $subdomain) {
|
foreach ($subdomains as $subdomain) {
|
||||||
$this->connectToServer($sharedUrl, $subdomain, $this->configuration->auth());
|
$this->connectToServer($sharedUrl, $subdomain, $serverHost, $this->configuration->auth());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ class Client
|
|||||||
return $url;
|
return $url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function connectToServer(string $sharedUrl, $subdomain, $authToken = ''): PromiseInterface
|
public function connectToServer(string $sharedUrl, $subdomain, $serverHost = null, $authToken = ''): PromiseInterface
|
||||||
{
|
{
|
||||||
$deferred = new Deferred();
|
$deferred = new Deferred();
|
||||||
$promise = $deferred->promise();
|
$promise = $deferred->promise();
|
||||||
@@ -82,18 +82,18 @@ class Client
|
|||||||
connect($wsProtocol."://{$this->configuration->host()}:{$this->configuration->port()}/expose/control?authToken={$authToken}", [], [
|
connect($wsProtocol."://{$this->configuration->host()}:{$this->configuration->port()}/expose/control?authToken={$authToken}", [], [
|
||||||
'X-Expose-Control' => 'enabled',
|
'X-Expose-Control' => 'enabled',
|
||||||
], $this->loop)
|
], $this->loop)
|
||||||
->then(function (WebSocket $clientConnection) use ($sharedUrl, $subdomain, $deferred, $authToken) {
|
->then(function (WebSocket $clientConnection) use ($sharedUrl, $subdomain, $serverHost, $deferred, $authToken) {
|
||||||
$this->connectionRetries = 0;
|
$this->connectionRetries = 0;
|
||||||
|
|
||||||
$connection = ControlConnection::create($clientConnection);
|
$connection = ControlConnection::create($clientConnection);
|
||||||
|
|
||||||
$connection->authenticate($sharedUrl, $subdomain);
|
$connection->authenticate($sharedUrl, $subdomain, $serverHost);
|
||||||
|
|
||||||
$clientConnection->on('close', function () use ($sharedUrl, $subdomain, $authToken) {
|
$clientConnection->on('close', function () use ($sharedUrl, $subdomain, $serverHost, $authToken) {
|
||||||
$this->logger->error('Connection to server closed.');
|
$this->logger->error('Connection to server closed.');
|
||||||
|
|
||||||
$this->retryConnectionOrExit(function () use ($sharedUrl, $subdomain, $authToken) {
|
$this->retryConnectionOrExit(function () use ($sharedUrl, $subdomain, $serverHost, $authToken) {
|
||||||
$this->connectToServer($sharedUrl, $subdomain, $authToken);
|
$this->connectToServer($sharedUrl, $subdomain, $serverHost, $authToken);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ class Client
|
|||||||
|
|
||||||
$connection->on('authenticated', function ($data) use ($deferred, $sharedUrl) {
|
$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();
|
$host = $data->server_host;
|
||||||
|
|
||||||
if ($httpProtocol !== 'https') {
|
if ($httpProtocol !== 'https') {
|
||||||
$host .= ":{$this->configuration->port()}";
|
$host .= ":{$this->configuration->port()}";
|
||||||
@@ -119,7 +119,7 @@ class Client
|
|||||||
$this->logger->info("Expose-URL:\t\t{$httpProtocol}://{$data->subdomain}.{$host}");
|
$this->logger->info("Expose-URL:\t\t{$httpProtocol}://{$data->subdomain}.{$host}");
|
||||||
$this->logger->line('');
|
$this->logger->line('');
|
||||||
|
|
||||||
static::$subdomains[] = "{$httpProtocol}://{$data->subdomain}.{$host}";
|
static::$subdomains[] = "{$httpProtocol}://{$data->subdomain}.{$data->server_host}";
|
||||||
|
|
||||||
$deferred->resolve($data);
|
$deferred->resolve($data);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -57,13 +57,14 @@ class ControlConnection
|
|||||||
$this->proxyManager->createTcpProxy($this->clientId, $data);
|
$this->proxyManager->createTcpProxy($this->clientId, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function authenticate(string $sharedHost, string $subdomain)
|
public function authenticate(string $sharedHost, string $subdomain, $serverHost = null)
|
||||||
{
|
{
|
||||||
$this->socket->send(json_encode([
|
$this->socket->send(json_encode([
|
||||||
'event' => 'authenticate',
|
'event' => 'authenticate',
|
||||||
'data' => [
|
'data' => [
|
||||||
'type' => 'http',
|
'type' => 'http',
|
||||||
'host' => $sharedHost,
|
'host' => $sharedHost,
|
||||||
|
'server_host' => $serverHost,
|
||||||
'subdomain' => empty($subdomain) ? null : $subdomain,
|
'subdomain' => empty($subdomain) ? null : $subdomain,
|
||||||
],
|
],
|
||||||
]));
|
]));
|
||||||
|
|||||||
@@ -106,9 +106,9 @@ class Factory
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function share($sharedUrl, $subdomain = null)
|
public function share($sharedUrl, $subdomain = null, $serverHost = null)
|
||||||
{
|
{
|
||||||
app('expose.client')->share($sharedUrl, $subdomain);
|
app('expose.client')->share($sharedUrl, $subdomain, $serverHost);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@@ -120,11 +120,11 @@ class Factory
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function shareFolder(string $folder, string $name, $subdomain = null)
|
public function shareFolder(string $folder, string $name, $subdomain = null, $serverHost = null)
|
||||||
{
|
{
|
||||||
$host = $this->createFileServer($folder, $name);
|
$host = $this->createFileServer($folder, $name);
|
||||||
|
|
||||||
$this->share($host, $subdomain);
|
$this->share($host, $subdomain, $serverHost);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use React\EventLoop\LoopInterface;
|
|||||||
|
|
||||||
class ShareCommand extends ServerAwareCommand
|
class ShareCommand extends ServerAwareCommand
|
||||||
{
|
{
|
||||||
protected $signature = 'share {host} {--subdomain=} {--auth=} {--dns=}';
|
protected $signature = 'share {host} {--subdomain=} {--auth=} {--dns=} {--domain=}';
|
||||||
|
|
||||||
protected $description = 'Share a local url with a remote expose server';
|
protected $description = 'Share a local url with a remote expose server';
|
||||||
|
|
||||||
@@ -29,7 +29,11 @@ class ShareCommand extends ServerAwareCommand
|
|||||||
->setPort($this->getServerPort())
|
->setPort($this->getServerPort())
|
||||||
->setAuth($auth)
|
->setAuth($auth)
|
||||||
->createClient()
|
->createClient()
|
||||||
->share($this->argument('host'), explode(',', $this->option('subdomain')))
|
->share(
|
||||||
|
$this->argument('host'),
|
||||||
|
explode(',', $this->option('subdomain')),
|
||||||
|
$this->option('domain')
|
||||||
|
)
|
||||||
->createHttpServer()
|
->createHttpServer()
|
||||||
->run();
|
->run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace App\Commands;
|
|||||||
|
|
||||||
class ShareCurrentWorkingDirectoryCommand extends ShareCommand
|
class ShareCurrentWorkingDirectoryCommand extends ShareCommand
|
||||||
{
|
{
|
||||||
protected $signature = 'share-cwd {host?} {--subdomain=} {--auth=} {--dns=}';
|
protected $signature = 'share-cwd {host?} {--subdomain=} {--auth=} {--dns=} {--domain=}';
|
||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use React\EventLoop\LoopInterface;
|
|||||||
|
|
||||||
class ShareFilesCommand extends ServerAwareCommand
|
class ShareFilesCommand extends ServerAwareCommand
|
||||||
{
|
{
|
||||||
protected $signature = 'share-files {folder=.} {--name=} {--subdomain=} {--auth=}';
|
protected $signature = 'share-files {folder=.} {--name=} {--subdomain=} {--auth=} {--domain=}';
|
||||||
|
|
||||||
protected $description = 'Share a local folder with a remote expose server';
|
protected $description = 'Share a local folder with a remote expose server';
|
||||||
|
|
||||||
@@ -28,7 +28,8 @@ class ShareFilesCommand extends ServerAwareCommand
|
|||||||
->shareFolder(
|
->shareFolder(
|
||||||
$this->argument('folder'),
|
$this->argument('folder'),
|
||||||
$this->option('name') ?? '',
|
$this->option('name') ?? '',
|
||||||
explode(',', $this->option('subdomain'))
|
explode(',', $this->option('subdomain')),
|
||||||
|
$this->option('domain')
|
||||||
)
|
)
|
||||||
->createHttpServer()
|
->createHttpServer()
|
||||||
->run();
|
->run();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use Ratchet\ConnectionInterface;
|
|||||||
|
|
||||||
interface ConnectionManager
|
interface ConnectionManager
|
||||||
{
|
{
|
||||||
public function storeConnection(string $host, ?string $subdomain, ConnectionInterface $connection): ControlConnection;
|
public function storeConnection(string $host, ?string $subdomain, ?string $serverHost, ConnectionInterface $connection): ControlConnection;
|
||||||
|
|
||||||
public function storeTcpConnection(int $port, ConnectionInterface $connection): ControlConnection;
|
public function storeTcpConnection(int $port, ConnectionInterface $connection): ControlConnection;
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ interface ConnectionManager
|
|||||||
|
|
||||||
public function removeControlConnection($connection);
|
public function removeControlConnection($connection);
|
||||||
|
|
||||||
public function findControlConnectionForSubdomain($subdomain): ?ControlConnection;
|
public function findControlConnectionForSubdomainAndServerHost($subdomain, $serverHost): ?ControlConnection;
|
||||||
|
|
||||||
public function findControlConnectionForClientId(string $clientId): ?ControlConnection;
|
public function findControlConnectionForClientId(string $clientId): ?ControlConnection;
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use App\Contracts\ConnectionManager as ConnectionManagerContract;
|
|||||||
use App\Contracts\StatisticsCollector;
|
use App\Contracts\StatisticsCollector;
|
||||||
use App\Contracts\SubdomainGenerator;
|
use App\Contracts\SubdomainGenerator;
|
||||||
use App\Http\QueryParameters;
|
use App\Http\QueryParameters;
|
||||||
|
use App\Server\Configuration;
|
||||||
use App\Server\Exceptions\NoFreePortAvailable;
|
use App\Server\Exceptions\NoFreePortAvailable;
|
||||||
use Ratchet\ConnectionInterface;
|
use Ratchet\ConnectionInterface;
|
||||||
use React\EventLoop\LoopInterface;
|
use React\EventLoop\LoopInterface;
|
||||||
@@ -48,7 +49,7 @@ class ConnectionManager implements ConnectionManagerContract
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function storeConnection(string $host, ?string $subdomain, ConnectionInterface $connection): ControlConnection
|
public function storeConnection(string $host, ?string $subdomain, ?string $serverHost, ConnectionInterface $connection): ControlConnection
|
||||||
{
|
{
|
||||||
$clientId = (string) uniqid();
|
$clientId = (string) uniqid();
|
||||||
|
|
||||||
@@ -59,6 +60,7 @@ class ConnectionManager implements ConnectionManagerContract
|
|||||||
$host,
|
$host,
|
||||||
$subdomain ?? $this->subdomainGenerator->generateSubdomain(),
|
$subdomain ?? $this->subdomainGenerator->generateSubdomain(),
|
||||||
$clientId,
|
$clientId,
|
||||||
|
$serverHost,
|
||||||
$this->getAuthTokenFromConnection($connection)
|
$this->getAuthTokenFromConnection($connection)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -152,10 +154,10 @@ class ConnectionManager implements ConnectionManagerContract
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findControlConnectionForSubdomain($subdomain): ?ControlConnection
|
public function findControlConnectionForSubdomainAndServerHost($subdomain, $serverHost): ?ControlConnection
|
||||||
{
|
{
|
||||||
return collect($this->connections)->last(function ($connection) use ($subdomain) {
|
return collect($this->connections)->last(function ($connection) use ($subdomain, $serverHost) {
|
||||||
return $connection->subdomain == $subdomain;
|
return $connection->subdomain == $subdomain && $connection->serverHost === $serverHost;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,19 +12,21 @@ class ControlConnection
|
|||||||
/** @var ConnectionInterface */
|
/** @var ConnectionInterface */
|
||||||
public $socket;
|
public $socket;
|
||||||
public $host;
|
public $host;
|
||||||
|
public $serverHost;
|
||||||
public $authToken;
|
public $authToken;
|
||||||
public $subdomain;
|
public $subdomain;
|
||||||
public $client_id;
|
public $client_id;
|
||||||
public $proxies = [];
|
public $proxies = [];
|
||||||
protected $shared_at;
|
protected $shared_at;
|
||||||
|
|
||||||
public function __construct(ConnectionInterface $socket, string $host, string $subdomain, string $clientId, string $authToken = '')
|
public function __construct(ConnectionInterface $socket, string $host, string $subdomain, string $clientId, string $serverHost, string $authToken = '')
|
||||||
{
|
{
|
||||||
$this->socket = $socket;
|
$this->socket = $socket;
|
||||||
$this->host = $host;
|
$this->host = $host;
|
||||||
$this->subdomain = $subdomain;
|
$this->subdomain = $subdomain;
|
||||||
$this->client_id = $clientId;
|
$this->client_id = $clientId;
|
||||||
$this->authToken = $authToken;
|
$this->authToken = $authToken;
|
||||||
|
$this->serverHost = $serverHost;
|
||||||
$this->shared_at = now()->toDateTimeString();
|
$this->shared_at = now()->toDateTimeString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,6 +63,7 @@ class ControlConnection
|
|||||||
return [
|
return [
|
||||||
'type' => 'http',
|
'type' => 'http',
|
||||||
'host' => $this->host,
|
'host' => $this->host,
|
||||||
|
'server_host' => $this->serverHost,
|
||||||
'client_id' => $this->client_id,
|
'client_id' => $this->client_id,
|
||||||
'auth_token' => $this->authToken,
|
'auth_token' => $this->authToken,
|
||||||
'subdomain' => $this->subdomain,
|
'subdomain' => $this->subdomain,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use App\Contracts\ConnectionManager;
|
|||||||
use App\Contracts\SubdomainRepository;
|
use App\Contracts\SubdomainRepository;
|
||||||
use App\Contracts\UserRepository;
|
use App\Contracts\UserRepository;
|
||||||
use App\Http\QueryParameters;
|
use App\Http\QueryParameters;
|
||||||
|
use App\Server\Configuration;
|
||||||
use App\Server\Exceptions\NoFreePortAvailable;
|
use App\Server\Exceptions\NoFreePortAvailable;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
use Ratchet\ConnectionInterface;
|
use Ratchet\ConnectionInterface;
|
||||||
@@ -26,11 +27,15 @@ class ControlMessageController implements MessageComponentInterface
|
|||||||
/** @var SubdomainRepository */
|
/** @var SubdomainRepository */
|
||||||
protected $subdomainRepository;
|
protected $subdomainRepository;
|
||||||
|
|
||||||
public function __construct(ConnectionManager $connectionManager, UserRepository $userRepository, SubdomainRepository $subdomainRepository)
|
/** @var Configuration */
|
||||||
|
protected $configuration;
|
||||||
|
|
||||||
|
public function __construct(ConnectionManager $connectionManager, UserRepository $userRepository, SubdomainRepository $subdomainRepository, Configuration $configuration)
|
||||||
{
|
{
|
||||||
$this->connectionManager = $connectionManager;
|
$this->connectionManager = $connectionManager;
|
||||||
$this->userRepository = $userRepository;
|
$this->userRepository = $userRepository;
|
||||||
$this->subdomainRepository = $subdomainRepository;
|
$this->subdomainRepository = $subdomainRepository;
|
||||||
|
$this->configuration = $configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,6 +98,9 @@ class ControlMessageController implements MessageComponentInterface
|
|||||||
if (! isset($data->type)) {
|
if (! isset($data->type)) {
|
||||||
$data->type = 'http';
|
$data->type = 'http';
|
||||||
}
|
}
|
||||||
|
if (! isset($data->server_host) || is_null($data->server_host)) {
|
||||||
|
$data->server_host = $this->configuration->hostname();
|
||||||
|
}
|
||||||
|
|
||||||
$this->verifyAuthToken($connection)
|
$this->verifyAuthToken($connection)
|
||||||
->then(function ($user) use ($connection) {
|
->then(function ($user) use ($connection) {
|
||||||
@@ -139,14 +147,14 @@ class ControlMessageController implements MessageComponentInterface
|
|||||||
|
|
||||||
protected function handleHttpConnection(ConnectionInterface $connection, $data, $user = null)
|
protected function handleHttpConnection(ConnectionInterface $connection, $data, $user = null)
|
||||||
{
|
{
|
||||||
$this->hasValidSubdomain($connection, $data->subdomain, $user)->then(function ($subdomain) use ($data, $connection) {
|
$this->hasValidSubdomain($connection, $data->subdomain, $user, $data->server_host)->then(function ($subdomain) use ($data, $connection) {
|
||||||
if ($subdomain === false) {
|
if ($subdomain === false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data->subdomain = $subdomain;
|
$data->subdomain = $subdomain;
|
||||||
|
|
||||||
$connectionInfo = $this->connectionManager->storeConnection($data->host, $data->subdomain, $connection);
|
$connectionInfo = $this->connectionManager->storeConnection($data->host, $data->subdomain, $data->server_host, $connection);
|
||||||
|
|
||||||
$this->connectionManager->limitConnectionLength($connectionInfo, config('expose.admin.maximum_connection_length'));
|
$this->connectionManager->limitConnectionLength($connectionInfo, config('expose.admin.maximum_connection_length'));
|
||||||
|
|
||||||
@@ -155,6 +163,7 @@ class ControlMessageController implements MessageComponentInterface
|
|||||||
'data' => [
|
'data' => [
|
||||||
'message' => config('expose.admin.messages.message_of_the_day'),
|
'message' => config('expose.admin.messages.message_of_the_day'),
|
||||||
'subdomain' => $connectionInfo->subdomain,
|
'subdomain' => $connectionInfo->subdomain,
|
||||||
|
'server_host' => $connectionInfo->serverHost,
|
||||||
'client_id' => $connectionInfo->client_id,
|
'client_id' => $connectionInfo->client_id,
|
||||||
],
|
],
|
||||||
]));
|
]));
|
||||||
@@ -250,7 +259,7 @@ class ControlMessageController implements MessageComponentInterface
|
|||||||
return $deferred->promise();
|
return $deferred->promise();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function hasValidSubdomain(ConnectionInterface $connection, ?string $subdomain, ?array $user): PromiseInterface
|
protected function hasValidSubdomain(ConnectionInterface $connection, ?string $subdomain, ?array $user, string $serverHost): PromiseInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Check if the user can specify a custom subdomain in the first place.
|
* Check if the user can specify a custom subdomain in the first place.
|
||||||
@@ -271,7 +280,7 @@ class ControlMessageController implements MessageComponentInterface
|
|||||||
*/
|
*/
|
||||||
if (! is_null($subdomain)) {
|
if (! is_null($subdomain)) {
|
||||||
return $this->subdomainRepository->getSubdomainByName($subdomain)
|
return $this->subdomainRepository->getSubdomainByName($subdomain)
|
||||||
->then(function ($foundSubdomain) use ($connection, $subdomain, $user) {
|
->then(function ($foundSubdomain) use ($connection, $subdomain, $user, $serverHost) {
|
||||||
if (! is_null($foundSubdomain) && ! is_null($user) && $foundSubdomain['user_id'] !== $user['id']) {
|
if (! is_null($foundSubdomain) && ! is_null($user) && $foundSubdomain['user_id'] !== $user['id']) {
|
||||||
$message = config('expose.admin.messages.subdomain_reserved');
|
$message = config('expose.admin.messages.subdomain_reserved');
|
||||||
$message = str_replace(':subdomain', $subdomain, $message);
|
$message = str_replace(':subdomain', $subdomain, $message);
|
||||||
@@ -287,7 +296,7 @@ class ControlMessageController implements MessageComponentInterface
|
|||||||
return \React\Promise\resolve(false);
|
return \React\Promise\resolve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
$controlConnection = $this->connectionManager->findControlConnectionForSubdomain($subdomain);
|
$controlConnection = $this->connectionManager->findControlConnectionForSubdomainAndServerHost($subdomain, $serverHost);
|
||||||
|
|
||||||
if (! is_null($controlConnection) || $subdomain === config('expose.admin.subdomain') || in_array($subdomain, config('expose.admin.reserved_subdomains', []))) {
|
if (! is_null($controlConnection) || $subdomain === config('expose.admin.subdomain') || in_array($subdomain, config('expose.admin.reserved_subdomains', []))) {
|
||||||
$message = config('expose.admin.messages.subdomain_taken');
|
$message = config('expose.admin.messages.subdomain_taken');
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ class TunnelMessageController extends Controller
|
|||||||
public function handle(Request $request, ConnectionInterface $httpConnection)
|
public function handle(Request $request, ConnectionInterface $httpConnection)
|
||||||
{
|
{
|
||||||
$subdomain = $this->detectSubdomain($request);
|
$subdomain = $this->detectSubdomain($request);
|
||||||
|
$serverHost = $this->detectServerHost($request);
|
||||||
|
|
||||||
if (is_null($subdomain)) {
|
if (is_null($subdomain)) {
|
||||||
$httpConnection->send(
|
$httpConnection->send(
|
||||||
@@ -51,7 +52,7 @@ class TunnelMessageController extends Controller
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$controlConnection = $this->connectionManager->findControlConnectionForSubdomain($subdomain);
|
$controlConnection = $this->connectionManager->findControlConnectionForSubdomainAndServerHost($subdomain, $serverHost);
|
||||||
|
|
||||||
if (is_null($controlConnection)) {
|
if (is_null($controlConnection)) {
|
||||||
$httpConnection->send(
|
$httpConnection->send(
|
||||||
@@ -69,11 +70,16 @@ class TunnelMessageController extends Controller
|
|||||||
|
|
||||||
protected function detectSubdomain(Request $request): ?string
|
protected function detectSubdomain(Request $request): ?string
|
||||||
{
|
{
|
||||||
$subdomain = Str::before($request->getHost(), '.'.$this->configuration->hostname());
|
$subdomain = Str::before($request->getHost(), '.');
|
||||||
|
|
||||||
return $subdomain === $request->getHost() ? null : $subdomain;
|
return $subdomain === $request->getHost() ? null : $subdomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function detectServerHost(Request $request): ?string
|
||||||
|
{
|
||||||
|
return Str::after($request->getHost(), '.');
|
||||||
|
}
|
||||||
|
|
||||||
protected function sendRequestToClient(Request $request, ControlConnection $controlConnection, ConnectionInterface $httpConnection)
|
protected function sendRequestToClient(Request $request, ControlConnection $controlConnection, ConnectionInterface $httpConnection)
|
||||||
{
|
{
|
||||||
$request = $this->prepareRequest($request, $controlConnection);
|
$request = $this->prepareRequest($request, $controlConnection);
|
||||||
|
|||||||
@@ -284,11 +284,11 @@ class ApiTest extends TestCase
|
|||||||
|
|
||||||
$connection = \Mockery::mock(IoConnection::class);
|
$connection = \Mockery::mock(IoConnection::class);
|
||||||
$connection->httpRequest = new Request('GET', '/?authToken='.$createdUser->auth_token);
|
$connection->httpRequest = new Request('GET', '/?authToken='.$createdUser->auth_token);
|
||||||
$connectionManager->storeConnection('some-host.test', 'fixed-subdomain', $connection);
|
$connectionManager->storeConnection('some-host.test', 'fixed-subdomain', 'localhost', $connection);
|
||||||
|
|
||||||
$connection = \Mockery::mock(IoConnection::class);
|
$connection = \Mockery::mock(IoConnection::class);
|
||||||
$connection->httpRequest = new Request('GET', '/?authToken=some-other-token');
|
$connection->httpRequest = new Request('GET', '/?authToken=some-other-token');
|
||||||
$connectionManager->storeConnection('some-different-host.test', 'different-subdomain', $connection);
|
$connectionManager->storeConnection('some-different-host.test', 'different-subdomain', 'localhost', $connection);
|
||||||
|
|
||||||
$connection = \Mockery::mock(IoConnection::class);
|
$connection = \Mockery::mock(IoConnection::class);
|
||||||
$connection->httpRequest = new Request('GET', '/?authToken='.$createdUser->auth_token);
|
$connection->httpRequest = new Request('GET', '/?authToken='.$createdUser->auth_token);
|
||||||
@@ -307,6 +307,7 @@ class ApiTest extends TestCase
|
|||||||
$this->assertCount(1, $users[0]->sites);
|
$this->assertCount(1, $users[0]->sites);
|
||||||
$this->assertCount(1, $users[0]->tcp_connections);
|
$this->assertCount(1, $users[0]->tcp_connections);
|
||||||
$this->assertSame('some-host.test', $users[0]->sites[0]->host);
|
$this->assertSame('some-host.test', $users[0]->sites[0]->host);
|
||||||
|
$this->assertSame('localhost', $users[0]->sites[0]->server_host);
|
||||||
$this->assertSame('fixed-subdomain', $users[0]->sites[0]->subdomain);
|
$this->assertSame('fixed-subdomain', $users[0]->sites[0]->subdomain);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,7 +320,7 @@ class ApiTest extends TestCase
|
|||||||
$connection = \Mockery::mock(IoConnection::class);
|
$connection = \Mockery::mock(IoConnection::class);
|
||||||
$connection->httpRequest = new Request('GET', '/?authToken=some-token');
|
$connection->httpRequest = new Request('GET', '/?authToken=some-token');
|
||||||
|
|
||||||
$connectionManager->storeConnection('some-host.test', 'fixed-subdomain', $connection);
|
$connectionManager->storeConnection('some-host.test', 'fixed-subdomain', 'localhost', $connection);
|
||||||
|
|
||||||
/** @var Response $response */
|
/** @var Response $response */
|
||||||
$response = $this->await($this->browser->get('http://127.0.0.1:8080/api/sites', [
|
$response = $this->await($this->browser->get('http://127.0.0.1:8080/api/sites', [
|
||||||
@@ -346,7 +347,7 @@ class ApiTest extends TestCase
|
|||||||
$connection = \Mockery::mock(IoConnection::class);
|
$connection = \Mockery::mock(IoConnection::class);
|
||||||
$connection->httpRequest = new Request('GET', '/');
|
$connection->httpRequest = new Request('GET', '/');
|
||||||
|
|
||||||
$connectionManager->storeConnection('some-host.test', 'fixed-subdomain', $connection);
|
$connectionManager->storeConnection('some-host.test', 'fixed-subdomain', 'localhost', $connection);
|
||||||
|
|
||||||
/** @var Response $response */
|
/** @var Response $response */
|
||||||
$response = $this->await($this->browser->get('http://127.0.0.1:8080/api/sites', [
|
$response = $this->await($this->browser->get('http://127.0.0.1:8080/api/sites', [
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ class TunnelTest extends TestCase
|
|||||||
* the created test HTTP server.
|
* the created test HTTP server.
|
||||||
*/
|
*/
|
||||||
$client = $this->createClient();
|
$client = $this->createClient();
|
||||||
$response = $this->await($client->connectToServer('127.0.0.1:8085', 'tunnel', $user->auth_token));
|
$response = $this->await($client->connectToServer('127.0.0.1:8085', 'tunnel', null, $user->auth_token));
|
||||||
|
|
||||||
$this->assertSame('tunnel', $response->subdomain);
|
$this->assertSame('tunnel', $response->subdomain);
|
||||||
}
|
}
|
||||||
@@ -235,7 +235,7 @@ class TunnelTest extends TestCase
|
|||||||
* the created test HTTP server.
|
* the created test HTTP server.
|
||||||
*/
|
*/
|
||||||
$client = $this->createClient();
|
$client = $this->createClient();
|
||||||
$response = $this->await($client->connectToServer('127.0.0.1:8085', 'tunnel', $user->auth_token));
|
$response = $this->await($client->connectToServer('127.0.0.1:8085', 'tunnel', null, $user->auth_token));
|
||||||
|
|
||||||
$this->assertNotSame('tunnel', $response->subdomain);
|
$this->assertNotSame('tunnel', $response->subdomain);
|
||||||
}
|
}
|
||||||
@@ -272,11 +272,56 @@ class TunnelTest extends TestCase
|
|||||||
* the created test HTTP server.
|
* the created test HTTP server.
|
||||||
*/
|
*/
|
||||||
$client = $this->createClient();
|
$client = $this->createClient();
|
||||||
$response = $this->await($client->connectToServer('127.0.0.1:8085', 'reserved', $user->auth_token));
|
$response = $this->await($client->connectToServer('127.0.0.1:8085', 'reserved', null, $user->auth_token));
|
||||||
|
|
||||||
$this->assertSame('reserved', $response->subdomain);
|
$this->assertSame('reserved', $response->subdomain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @test */
|
||||||
|
public function it_rejects_users_that_want_to_use_a_subdomain_that_is_already_in_use()
|
||||||
|
{
|
||||||
|
$this->app['config']['expose.admin.validate_auth_tokens'] = true;
|
||||||
|
|
||||||
|
$user = $this->createUser([
|
||||||
|
'name' => 'Marcel',
|
||||||
|
'can_specify_subdomains' => 1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->createTestHttpServer();
|
||||||
|
|
||||||
|
$this->expectException(\UnexpectedValueException::class);
|
||||||
|
$client = $this->createClient();
|
||||||
|
|
||||||
|
$response = $this->await($client->connectToServer('127.0.0.1:8085', 'taken', null, $user->auth_token));
|
||||||
|
$this->assertSame('taken', $response->subdomain);
|
||||||
|
|
||||||
|
$response = $this->await($client->connectToServer('127.0.0.1:8085', 'taken', null, $user->auth_token));
|
||||||
|
$this->assertSame('taken', $response->subdomain);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @test */
|
||||||
|
public function it_allows_users_to_use_a_subdomain_that_is_already_in_use_on_a_different_shared_host()
|
||||||
|
{
|
||||||
|
$this->app['config']['expose.admin.validate_auth_tokens'] = true;
|
||||||
|
|
||||||
|
$user = $this->createUser([
|
||||||
|
'name' => 'Marcel',
|
||||||
|
'can_specify_subdomains' => 1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->createTestHttpServer();
|
||||||
|
|
||||||
|
$client = $this->createClient();
|
||||||
|
|
||||||
|
$response = $this->await($client->connectToServer('127.0.0.1:8085', 'taken', null, $user->auth_token));
|
||||||
|
$this->assertSame('localhost', $response->server_host);
|
||||||
|
$this->assertSame('taken', $response->subdomain);
|
||||||
|
|
||||||
|
$response = $this->await($client->connectToServer('127.0.0.1:8085', 'taken', 'share.beyondco.de', $user->auth_token));
|
||||||
|
$this->assertSame('share.beyondco.de', $response->server_host);
|
||||||
|
$this->assertSame('taken', $response->subdomain);
|
||||||
|
}
|
||||||
|
|
||||||
/** @test */
|
/** @test */
|
||||||
public function it_allows_users_to_use_their_own_reserved_subdomains()
|
public function it_allows_users_to_use_their_own_reserved_subdomains()
|
||||||
{
|
{
|
||||||
@@ -302,7 +347,7 @@ class TunnelTest extends TestCase
|
|||||||
* the created test HTTP server.
|
* the created test HTTP server.
|
||||||
*/
|
*/
|
||||||
$client = $this->createClient();
|
$client = $this->createClient();
|
||||||
$response = $this->await($client->connectToServer('127.0.0.1:8085', 'reserved', $user->auth_token));
|
$response = $this->await($client->connectToServer('127.0.0.1:8085', 'reserved', null, $user->auth_token));
|
||||||
|
|
||||||
$this->assertSame('reserved', $response->subdomain);
|
$this->assertSame('reserved', $response->subdomain);
|
||||||
}
|
}
|
||||||
@@ -363,7 +408,7 @@ class TunnelTest extends TestCase
|
|||||||
$this->createTestHttpServer();
|
$this->createTestHttpServer();
|
||||||
|
|
||||||
$client = $this->createClient();
|
$client = $this->createClient();
|
||||||
$response = $this->await($client->connectToServer('127.0.0.1:8085', 'foo', $user->auth_token));
|
$response = $this->await($client->connectToServer('127.0.0.1:8085', 'foo', null, $user->auth_token));
|
||||||
|
|
||||||
$this->assertNotSame('foo', $response->subdomain);
|
$this->assertNotSame('foo', $response->subdomain);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user