mirror of
https://github.com/bitinflow/expose.git
synced 2026-03-13 21:45:55 +00:00
Merge branch 'master' into tcp
This commit is contained in:
@@ -8,12 +8,12 @@ class ShareCurrentWorkingDirectoryCommand extends ShareCommand
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$host = $this->prepareSharedHost(basename(getcwd()).'.'.$this->detectTld());
|
||||
$subdomain = $this->detectName();
|
||||
$host = $this->prepareSharedHost($subdomain.'.'.$this->detectTld());
|
||||
|
||||
$this->input->setArgument('host', $host);
|
||||
|
||||
if (! $this->option('subdomain')) {
|
||||
$subdomain = str_replace('.', '-', basename(getcwd()));
|
||||
$this->input->setOption('subdomain', $subdomain);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,32 @@ class ShareCurrentWorkingDirectoryCommand extends ShareCommand
|
||||
return config('expose.default_tld', 'test');
|
||||
}
|
||||
|
||||
protected function detectName(): string
|
||||
{
|
||||
$projectPath = getcwd();
|
||||
$valetSitesPath = ($_SERVER['HOME'] ?? $_SERVER['USERPROFILE']).DIRECTORY_SEPARATOR.'.config'.DIRECTORY_SEPARATOR.'valet'.DIRECTORY_SEPARATOR.'Sites';
|
||||
|
||||
if (is_dir($valetSitesPath)) {
|
||||
$site = collect(scandir($valetSitesPath))
|
||||
->skip(2)
|
||||
->map(function ($site) use ($valetSitesPath) {
|
||||
return $valetSitesPath.DIRECTORY_SEPARATOR.$site;
|
||||
})->mapWithKeys(function ($site) {
|
||||
return [$site => readlink($site)];
|
||||
})->filter(function ($sourcePath) use ($projectPath) {
|
||||
return $sourcePath === $projectPath;
|
||||
})
|
||||
->keys()
|
||||
->first();
|
||||
|
||||
if ($site) {
|
||||
$projectPath = $site;
|
||||
}
|
||||
}
|
||||
|
||||
return str_replace('.', '-', basename($projectPath));
|
||||
}
|
||||
|
||||
protected function prepareSharedHost($host): string
|
||||
{
|
||||
$certificateFile = ($_SERVER['HOME'] ?? $_SERVER['USERPROFILE']).DIRECTORY_SEPARATOR.'.config'.DIRECTORY_SEPARATOR.'valet'.DIRECTORY_SEPARATOR.'Certificates'.DIRECTORY_SEPARATOR.$host.'.crt';
|
||||
|
||||
@@ -25,4 +25,6 @@ interface ConnectionManager
|
||||
public function findControlConnectionForClientId(string $clientId): ?ControlConnection;
|
||||
|
||||
public function getConnections(): array;
|
||||
|
||||
public function getConnectionsForAuthToken(string $authToken): array;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Server\Connections;
|
||||
|
||||
use App\Contracts\ConnectionManager as ConnectionManagerContract;
|
||||
use App\Contracts\SubdomainGenerator;
|
||||
use App\Http\QueryParameters;
|
||||
use Ratchet\ConnectionInterface;
|
||||
use React\EventLoop\LoopInterface;
|
||||
use React\Socket\Server;
|
||||
@@ -47,7 +48,13 @@ class ConnectionManager implements ConnectionManagerContract
|
||||
|
||||
$connection->client_id = $clientId;
|
||||
|
||||
$storedConnection = new ControlConnection($connection, $host, $subdomain ?? $this->subdomainGenerator->generateSubdomain(), $clientId);
|
||||
$storedConnection = new ControlConnection(
|
||||
$connection,
|
||||
$host,
|
||||
$subdomain ?? $this->subdomainGenerator->generateSubdomain(),
|
||||
$clientId,
|
||||
$this->getAuthTokenFromConnection($connection)
|
||||
);
|
||||
|
||||
$this->connections[] = $storedConnection;
|
||||
|
||||
@@ -60,7 +67,13 @@ class ConnectionManager implements ConnectionManagerContract
|
||||
|
||||
$connection->client_id = $clientId;
|
||||
|
||||
$storedConnection = new TcpControlConnection($connection, $port, $this->getSharedTcpServer(), $clientId);
|
||||
$storedConnection = new TcpControlConnection(
|
||||
$connection,
|
||||
$port,
|
||||
$this->getSharedTcpServer(),
|
||||
$clientId,
|
||||
$this->getAuthTokenFromConnection($connection)
|
||||
);
|
||||
|
||||
$this->connections[] = $storedConnection;
|
||||
|
||||
@@ -118,4 +131,21 @@ class ConnectionManager implements ConnectionManagerContract
|
||||
{
|
||||
return $this->connections;
|
||||
}
|
||||
|
||||
protected function getAuthTokenFromConnection(ConnectionInterface $connection): string
|
||||
{
|
||||
return QueryParameters::create($connection->httpRequest)->get('authToken');
|
||||
}
|
||||
|
||||
public function getConnectionsForAuthToken(string $authToken): array
|
||||
{
|
||||
return collect($this->connections)
|
||||
->filter(function ($connection) use ($authToken) {
|
||||
return $connection->authToken === $authToken;
|
||||
})
|
||||
->map(function ($connection) {
|
||||
return $connection->toArray();
|
||||
})
|
||||
->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,17 +12,19 @@ class ControlConnection
|
||||
/** @var ConnectionInterface */
|
||||
public $socket;
|
||||
public $host;
|
||||
public $authToken;
|
||||
public $subdomain;
|
||||
public $client_id;
|
||||
public $proxies = [];
|
||||
protected $shared_at;
|
||||
|
||||
public function __construct(ConnectionInterface $socket, string $host, string $subdomain, string $clientId)
|
||||
public function __construct(ConnectionInterface $socket, string $host, string $subdomain, string $clientId, string $authToken = '')
|
||||
{
|
||||
$this->socket = $socket;
|
||||
$this->host = $host;
|
||||
$this->subdomain = $subdomain;
|
||||
$this->client_id = $clientId;
|
||||
$this->authToken = $authToken;
|
||||
$this->shared_at = now()->toDateTimeString();
|
||||
}
|
||||
|
||||
@@ -58,6 +60,7 @@ class ControlConnection
|
||||
'type' => 'http',
|
||||
'host' => $this->host,
|
||||
'client_id' => $this->client_id,
|
||||
'auth_token' => $this->authToken,
|
||||
'subdomain' => $this->subdomain,
|
||||
'shared_at' => $this->shared_at,
|
||||
];
|
||||
|
||||
@@ -14,7 +14,7 @@ class TcpControlConnection extends ControlConnection
|
||||
public $shared_port;
|
||||
public $shared_server;
|
||||
|
||||
public function __construct(ConnectionInterface $socket, int $port, Server $sharedServer, string $clientId)
|
||||
public function __construct(ConnectionInterface $socket, int $port, Server $sharedServer, string $clientId, string $authToken = '')
|
||||
{
|
||||
$this->socket = $socket;
|
||||
$this->client_id = $clientId;
|
||||
@@ -22,6 +22,7 @@ class TcpControlConnection extends ControlConnection
|
||||
$this->port = $port;
|
||||
$this->shared_at = now()->toDateTimeString();
|
||||
$this->shared_port = parse_url($sharedServer->getAddress(), PHP_URL_PORT);
|
||||
$this->authToken = $authToken;
|
||||
|
||||
$this->configureServer($sharedServer);
|
||||
}
|
||||
@@ -85,7 +86,6 @@ class TcpControlConnection extends ControlConnection
|
||||
|
||||
$this->once('tcp_proxy_ready_'.$requestId, function (ConnectionInterface $proxy) use ($connection) {
|
||||
$this->proxy = $proxy;
|
||||
dump("Proxy ready");
|
||||
|
||||
$connection->on('data', function($data) use ($proxy) {
|
||||
$proxy->send($data);
|
||||
|
||||
@@ -12,6 +12,7 @@ use App\Server\Http\Controllers\Admin\DeleteUsersController;
|
||||
use App\Server\Http\Controllers\Admin\DisconnectSiteController;
|
||||
use App\Server\Http\Controllers\Admin\GetSettingsController;
|
||||
use App\Server\Http\Controllers\Admin\GetSitesController;
|
||||
use App\Server\Http\Controllers\Admin\GetUserDetailsController;
|
||||
use App\Server\Http\Controllers\Admin\GetUsersController;
|
||||
use App\Server\Http\Controllers\Admin\ListSitesController;
|
||||
use App\Server\Http\Controllers\Admin\ListUsersController;
|
||||
@@ -124,6 +125,7 @@ class Factory
|
||||
$this->router->post('/api/settings', StoreSettingsController::class, $adminCondition);
|
||||
$this->router->get('/api/users', GetUsersController::class, $adminCondition);
|
||||
$this->router->post('/api/users', StoreUsersController::class, $adminCondition);
|
||||
$this->router->get('/api/users/{id}', GetUserDetailsController::class, $adminCondition);
|
||||
$this->router->delete('/api/users/{id}', DeleteUsersController::class, $adminCondition);
|
||||
$this->router->get('/api/sites', GetSitesController::class, $adminCondition);
|
||||
$this->router->delete('/api/sites/{id}', DisconnectSiteController::class, $adminCondition);
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Server\Http\Controllers\Admin;
|
||||
|
||||
use App\Contracts\UserRepository;
|
||||
use Illuminate\Http\Request;
|
||||
use Ratchet\ConnectionInterface;
|
||||
|
||||
class GetUserDetailsController extends AdminController
|
||||
{
|
||||
protected $keepConnectionOpen = true;
|
||||
|
||||
/** @var UserRepository */
|
||||
protected $userRepository;
|
||||
|
||||
public function __construct(UserRepository $userRepository)
|
||||
{
|
||||
$this->userRepository = $userRepository;
|
||||
}
|
||||
|
||||
public function handle(Request $request, ConnectionInterface $httpConnection)
|
||||
{
|
||||
$this->userRepository
|
||||
->getUserById($request->get('id'))
|
||||
->then(function ($user) use ($httpConnection) {
|
||||
$httpConnection->send(
|
||||
respond_json(['user' => $user])
|
||||
);
|
||||
|
||||
$httpConnection->close();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ class StoreUsersController extends AdminController
|
||||
$insertData = [
|
||||
'name' => $request->get('name'),
|
||||
'auth_token' => (string) Str::uuid(),
|
||||
'can_specify_subdomains' => (int) $request->get('can_specify_subdomains'),
|
||||
];
|
||||
|
||||
$this->userRepository
|
||||
|
||||
@@ -8,7 +8,6 @@ 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;
|
||||
|
||||
@@ -81,11 +80,11 @@ class ControlMessageController implements MessageComponentInterface
|
||||
protected function authenticate(ConnectionInterface $connection, $data)
|
||||
{
|
||||
$this->verifyAuthToken($connection)
|
||||
->then(function () use ($connection, $data) {
|
||||
->then(function ($user) use ($connection, $data) {
|
||||
if ($data->type === 'http') {
|
||||
$this->handleHttpConnection($connection, $data);
|
||||
$this->handleHttpConnection($connection, $data, $user);
|
||||
} elseif($data->type === 'tcp') {
|
||||
$this->handleTcpConnection($connection, $data);
|
||||
$this->handleTcpConnection($connection, $data, $user);
|
||||
}
|
||||
}, function () use ($connection) {
|
||||
$connection->send(json_encode([
|
||||
@@ -98,9 +97,9 @@ class ControlMessageController implements MessageComponentInterface
|
||||
});
|
||||
}
|
||||
|
||||
protected function handleHttpConnection(ConnectionInterface $connection, $data)
|
||||
protected function handleHttpConnection(ConnectionInterface $connection, $data, $user = null)
|
||||
{
|
||||
if (! $this->hasValidSubdomain($connection, $data->subdomain)) {
|
||||
if (! $this->hasValidSubdomain($connection, $data->subdomain, $user)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -118,7 +117,7 @@ class ControlMessageController implements MessageComponentInterface
|
||||
]));
|
||||
}
|
||||
|
||||
protected function handleTcpConnection(ConnectionInterface $connection, $data)
|
||||
protected function handleTcpConnection(ConnectionInterface $connection, $data, $user = null)
|
||||
{
|
||||
$connectionInfo = $this->connectionManager->storeTcpConnection($data->port, $connection);
|
||||
|
||||
@@ -167,7 +166,7 @@ class ControlMessageController implements MessageComponentInterface
|
||||
protected function verifyAuthToken(ConnectionInterface $connection): PromiseInterface
|
||||
{
|
||||
if (config('expose.admin.validate_auth_tokens') !== true) {
|
||||
return new FulfilledPromise();
|
||||
return \React\Promise\resolve(null);
|
||||
}
|
||||
|
||||
$deferred = new Deferred();
|
||||
@@ -187,8 +186,20 @@ class ControlMessageController implements MessageComponentInterface
|
||||
return $deferred->promise();
|
||||
}
|
||||
|
||||
protected function hasValidSubdomain(ConnectionInterface $connection, ?string $subdomain): bool
|
||||
protected function hasValidSubdomain(ConnectionInterface $connection, ?string $subdomain, ?array $user): bool
|
||||
{
|
||||
if (! is_null($user) && $user['can_specify_subdomains'] === 0 && ! is_null($subdomain)) {
|
||||
$connection->send(json_encode([
|
||||
'event' => 'subdomainTaken',
|
||||
'data' => [
|
||||
'message' => config('expose.admin.messages.custom_subdomain_unauthorized'),
|
||||
],
|
||||
]));
|
||||
$connection->close();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! is_null($subdomain)) {
|
||||
$controlConnection = $this->connectionManager->findControlConnectionForSubdomain($subdomain);
|
||||
if (! is_null($controlConnection) || $subdomain === config('expose.admin.subdomain')) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Server\UserRepository;
|
||||
|
||||
use App\Contracts\ConnectionManager;
|
||||
use App\Contracts\UserRepository;
|
||||
use Clue\React\SQLite\DatabaseInterface;
|
||||
use Clue\React\SQLite\Result;
|
||||
@@ -13,9 +14,13 @@ class DatabaseUserRepository implements UserRepository
|
||||
/** @var DatabaseInterface */
|
||||
protected $database;
|
||||
|
||||
public function __construct(DatabaseInterface $database)
|
||||
/** @var ConnectionManager */
|
||||
protected $connectionManager;
|
||||
|
||||
public function __construct(DatabaseInterface $database, ConnectionManager $connectionManager)
|
||||
{
|
||||
$this->database = $database;
|
||||
$this->connectionManager = $connectionManager;
|
||||
}
|
||||
|
||||
public function getUsers(): PromiseInterface
|
||||
@@ -46,8 +51,12 @@ class DatabaseUserRepository implements UserRepository
|
||||
$nextPage = $currentPage + 1;
|
||||
}
|
||||
|
||||
$users = collect($result->rows)->map(function ($user) {
|
||||
return $this->getUserDetails($user);
|
||||
})->toArray();
|
||||
|
||||
$paginated = [
|
||||
'users' => $result->rows,
|
||||
'users' => $users,
|
||||
'current_page' => $currentPage,
|
||||
'per_page' => $perPage,
|
||||
'next_page' => $nextPage ?? null,
|
||||
@@ -60,6 +69,13 @@ class DatabaseUserRepository implements UserRepository
|
||||
return $deferred->promise();
|
||||
}
|
||||
|
||||
protected function getUserDetails(array $user)
|
||||
{
|
||||
$user['sites'] = $user['auth_token'] !== '' ? $this->connectionManager->getConnectionsForAuthToken($user['auth_token']) : [];
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function getUserById($id): PromiseInterface
|
||||
{
|
||||
$deferred = new Deferred();
|
||||
@@ -67,7 +83,13 @@ class DatabaseUserRepository implements UserRepository
|
||||
$this->database
|
||||
->query('SELECT * FROM users WHERE id = :id', ['id' => $id])
|
||||
->then(function (Result $result) use ($deferred) {
|
||||
$deferred->resolve($result->rows[0] ?? null);
|
||||
$user = $result->rows[0] ?? null;
|
||||
|
||||
if (! is_null($user)) {
|
||||
$user = $this->getUserDetails($user);
|
||||
}
|
||||
|
||||
$deferred->resolve($user);
|
||||
});
|
||||
|
||||
return $deferred->promise();
|
||||
@@ -91,8 +113,8 @@ class DatabaseUserRepository implements UserRepository
|
||||
$deferred = new Deferred();
|
||||
|
||||
$this->database->query("
|
||||
INSERT INTO users (name, auth_token, created_at)
|
||||
VALUES (:name, :auth_token, DATETIME('now'))
|
||||
INSERT INTO users (name, auth_token, can_specify_subdomains, created_at)
|
||||
VALUES (:name, :auth_token, :can_specify_subdomains, DATETIME('now'))
|
||||
", $data)
|
||||
->then(function (Result $result) use ($deferred) {
|
||||
$this->database->query('SELECT * FROM users WHERE id = :id', ['id' => $result->insertId])
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
],
|
||||
"require": {
|
||||
"php": "^7.3.0",
|
||||
"ext-json": "*",
|
||||
"padraic/phar-updater": "^1.0.6"
|
||||
"ext-json": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"cboden/ratchet": "^0.4.2",
|
||||
|
||||
496
composer.lock
generated
496
composer.lock
generated
@@ -4,196 +4,8 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "29e5e7d9a7d406f7d34ef09a3b2836e9",
|
||||
"packages": [
|
||||
{
|
||||
"name": "composer/ca-bundle",
|
||||
"version": "1.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/ca-bundle.git",
|
||||
"reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/95c63ab2117a72f48f5a55da9740a3273d45b7fd",
|
||||
"reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-openssl": "*",
|
||||
"ext-pcre": "*",
|
||||
"php": "^5.3.2 || ^7.0 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8",
|
||||
"psr/log": "^1.0",
|
||||
"symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Composer\\CaBundle\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jordi Boggiano",
|
||||
"email": "j.boggiano@seld.be",
|
||||
"homepage": "http://seld.be"
|
||||
}
|
||||
],
|
||||
"description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.",
|
||||
"keywords": [
|
||||
"cabundle",
|
||||
"cacert",
|
||||
"certificate",
|
||||
"ssl",
|
||||
"tls"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://packagist.com",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-04-08T08:27:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "padraic/humbug_get_contents",
|
||||
"version": "1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/humbug/file_get_contents.git",
|
||||
"reference": "dcb086060c9dd6b2f51d8f7a895500307110b7a7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/humbug/file_get_contents/zipball/dcb086060c9dd6b2f51d8f7a895500307110b7a7",
|
||||
"reference": "dcb086060c9dd6b2f51d8f7a895500307110b7a7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer/ca-bundle": "^1.0",
|
||||
"ext-openssl": "*",
|
||||
"php": "^5.3 || ^7.0 || ^7.1 || ^7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.1",
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"phpunit/phpunit": "^4.8 || ^5.7 || ^6.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"bamarni-bin": {
|
||||
"bin-links": false
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Humbug\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/function.php",
|
||||
"src/functions.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Pádraic Brady",
|
||||
"email": "padraic.brady@gmail.com",
|
||||
"homepage": "http://blog.astrumfutura.com"
|
||||
},
|
||||
{
|
||||
"name": "Théo Fidry",
|
||||
"email": "theo.fidry@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Secure wrapper for accessing HTTPS resources with file_get_contents for PHP 5.3+",
|
||||
"homepage": "https://github.com/padraic/file_get_contents",
|
||||
"keywords": [
|
||||
"download",
|
||||
"file_get_contents",
|
||||
"http",
|
||||
"https",
|
||||
"ssl",
|
||||
"tls"
|
||||
],
|
||||
"time": "2018-02-12T18:47:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "padraic/phar-updater",
|
||||
"version": "v1.0.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/humbug/phar-updater.git",
|
||||
"reference": "d01d3b8f26e541ac9b9eeba1e18d005d852f7ff1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/humbug/phar-updater/zipball/d01d3b8f26e541ac9b9eeba1e18d005d852f7ff1",
|
||||
"reference": "d01d3b8f26e541ac9b9eeba1e18d005d852f7ff1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"padraic/humbug_get_contents": "^1.0",
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Humbug\\SelfUpdate\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Pádraic Brady",
|
||||
"email": "padraic.brady@gmail.com",
|
||||
"homepage": "http://blog.astrumfutura.com"
|
||||
}
|
||||
],
|
||||
"description": "A thing to make PHAR self-updating easy and secure.",
|
||||
"keywords": [
|
||||
"humbug",
|
||||
"phar",
|
||||
"self-update",
|
||||
"update"
|
||||
],
|
||||
"time": "2018-03-30T12:52:15+00:00"
|
||||
}
|
||||
],
|
||||
"content-hash": "dd987a6f4f036893204c0d006d66001b",
|
||||
"packages": [],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "cboden/ratchet",
|
||||
@@ -478,6 +290,72 @@
|
||||
},
|
||||
"time": "2020-05-10T03:16:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/ca-bundle",
|
||||
"version": "1.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/ca-bundle.git",
|
||||
"reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/ca-bundle/zipball/95c63ab2117a72f48f5a55da9740a3273d45b7fd",
|
||||
"reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-openssl": "*",
|
||||
"ext-pcre": "*",
|
||||
"php": "^5.3.2 || ^7.0 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8",
|
||||
"psr/log": "^1.0",
|
||||
"symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Composer\\CaBundle\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jordi Boggiano",
|
||||
"email": "j.boggiano@seld.be",
|
||||
"homepage": "http://seld.be"
|
||||
}
|
||||
],
|
||||
"description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.",
|
||||
"keywords": [
|
||||
"cabundle",
|
||||
"cacert",
|
||||
"certificate",
|
||||
"ssl",
|
||||
"tls"
|
||||
],
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://packagist.com",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-04-08T08:27:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "container-interop/container-interop",
|
||||
"version": "1.2.0",
|
||||
@@ -3258,6 +3136,75 @@
|
||||
],
|
||||
"time": "2020-05-23T11:29:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "padraic/humbug_get_contents",
|
||||
"version": "1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/humbug/file_get_contents.git",
|
||||
"reference": "dcb086060c9dd6b2f51d8f7a895500307110b7a7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/humbug/file_get_contents/zipball/dcb086060c9dd6b2f51d8f7a895500307110b7a7",
|
||||
"reference": "dcb086060c9dd6b2f51d8f7a895500307110b7a7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"composer/ca-bundle": "^1.0",
|
||||
"ext-openssl": "*",
|
||||
"php": "^5.3 || ^7.0 || ^7.1 || ^7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"bamarni/composer-bin-plugin": "^1.1",
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"phpunit/phpunit": "^4.8 || ^5.7 || ^6.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"bamarni-bin": {
|
||||
"bin-links": false
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Humbug\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/function.php",
|
||||
"src/functions.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Pádraic Brady",
|
||||
"email": "padraic.brady@gmail.com",
|
||||
"homepage": "http://blog.astrumfutura.com"
|
||||
},
|
||||
{
|
||||
"name": "Théo Fidry",
|
||||
"email": "theo.fidry@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Secure wrapper for accessing HTTPS resources with file_get_contents for PHP 5.3+",
|
||||
"homepage": "https://github.com/padraic/file_get_contents",
|
||||
"keywords": [
|
||||
"download",
|
||||
"file_get_contents",
|
||||
"http",
|
||||
"https",
|
||||
"ssl",
|
||||
"tls"
|
||||
],
|
||||
"time": "2018-02-12T18:47:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "v9.99.99",
|
||||
@@ -3981,6 +3928,7 @@
|
||||
"keywords": [
|
||||
"tokenizer"
|
||||
],
|
||||
"abandoned": true,
|
||||
"time": "2019-09-17T06:23:10+00:00"
|
||||
},
|
||||
{
|
||||
@@ -5060,12 +5008,12 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reactphp/socket.git",
|
||||
"reference": "842dcd71df86671ee9491734035b3d2cf4a80ece"
|
||||
"reference": "e2b96b23a13ca9b41ab343268dbce3f8ef4d524a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/reactphp/socket/zipball/842dcd71df86671ee9491734035b3d2cf4a80ece",
|
||||
"reference": "842dcd71df86671ee9491734035b3d2cf4a80ece",
|
||||
"url": "https://api.github.com/repos/reactphp/socket/zipball/e2b96b23a13ca9b41ab343268dbce3f8ef4d524a",
|
||||
"reference": "e2b96b23a13ca9b41ab343268dbce3f8ef4d524a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5079,7 +5027,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"clue/block-react": "^1.2",
|
||||
"phpunit/phpunit": "^9.0 || ^5.7 || ^4.8.35",
|
||||
"phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
|
||||
"react/promise-stream": "^1.2"
|
||||
},
|
||||
"type": "library",
|
||||
@@ -5092,6 +5040,28 @@
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christian Lück",
|
||||
"email": "christian@clue.engineering",
|
||||
"homepage": "https://clue.engineering/"
|
||||
},
|
||||
{
|
||||
"name": "Cees-Jan Kiewiet",
|
||||
"email": "reactphp@ceesjankiewiet.nl",
|
||||
"homepage": "https://wyrihaximus.net/"
|
||||
},
|
||||
{
|
||||
"name": "Jan Sorgalla",
|
||||
"email": "jsorgalla@gmail.com",
|
||||
"homepage": "https://sorgalla.com/"
|
||||
},
|
||||
{
|
||||
"name": "Chris Boden",
|
||||
"email": "cboden@gmail.com",
|
||||
"homepage": "https://cboden.dev/"
|
||||
}
|
||||
],
|
||||
"description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP",
|
||||
"keywords": [
|
||||
"Connection",
|
||||
@@ -5100,7 +5070,17 @@
|
||||
"reactphp",
|
||||
"stream"
|
||||
],
|
||||
"time": "2020-07-01T12:50:00+00:00"
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/WyriHaximus",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/clue",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-08-28T12:49:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "react/stream",
|
||||
@@ -6134,16 +6114,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
"version": "v2.1.2",
|
||||
"version": "v2.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||
"reference": "dd99cb3a0aff6cadd2a8d7d7ed72c2161e218337"
|
||||
"reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/dd99cb3a0aff6cadd2a8d7d7ed72c2161e218337",
|
||||
"reference": "dd99cb3a0aff6cadd2a8d7d7ed72c2161e218337",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5e20b83385a77593259c9f8beb2c43cd03b2ac14",
|
||||
"reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6153,6 +6133,10 @@
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/contracts",
|
||||
"url": "https://github.com/symfony/contracts"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -6190,20 +6174,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-05-27T08:34:37+00:00"
|
||||
"time": "2020-06-06T08:49:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/error-handler",
|
||||
"version": "v5.1.2",
|
||||
"version": "v5.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/error-handler.git",
|
||||
"reference": "7d0b927b9d3dc41d7d46cda38cbfcd20cdcbb896"
|
||||
"reference": "525636d4b84e06c6ca72d96b6856b5b169416e6a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/error-handler/zipball/7d0b927b9d3dc41d7d46cda38cbfcd20cdcbb896",
|
||||
"reference": "7d0b927b9d3dc41d7d46cda38cbfcd20cdcbb896",
|
||||
"url": "https://api.github.com/repos/symfony/error-handler/zipball/525636d4b84e06c6ca72d96b6856b5b169416e6a",
|
||||
"reference": "525636d4b84e06c6ca72d96b6856b5b169416e6a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6261,20 +6245,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-05-30T20:35:19+00:00"
|
||||
"time": "2020-08-17T10:01:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v5.1.2",
|
||||
"version": "v5.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "cc0d059e2e997e79ca34125a52f3e33de4424ac7"
|
||||
"reference": "94871fc0a69c3c5da57764187724cdce0755899c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/cc0d059e2e997e79ca34125a52f3e33de4424ac7",
|
||||
"reference": "cc0d059e2e997e79ca34125a52f3e33de4424ac7",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/94871fc0a69c3c5da57764187724cdce0755899c",
|
||||
"reference": "94871fc0a69c3c5da57764187724cdce0755899c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6347,20 +6331,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-05-20T17:43:50+00:00"
|
||||
"time": "2020-08-13T14:19:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher-contracts",
|
||||
"version": "v2.1.2",
|
||||
"version": "v2.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
|
||||
"reference": "405952c4e90941a17e52ef7489a2bd94870bb290"
|
||||
"reference": "f6f613d74cfc5a623fc36294d3451eb7fa5a042b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/405952c4e90941a17e52ef7489a2bd94870bb290",
|
||||
"reference": "405952c4e90941a17e52ef7489a2bd94870bb290",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f6f613d74cfc5a623fc36294d3451eb7fa5a042b",
|
||||
"reference": "f6f613d74cfc5a623fc36294d3451eb7fa5a042b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6374,6 +6358,10 @@
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/contracts",
|
||||
"url": "https://github.com/symfony/contracts"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -6419,7 +6407,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-05-20T17:43:50+00:00"
|
||||
"time": "2020-07-06T13:23:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/expression-language",
|
||||
@@ -6552,16 +6540,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-foundation",
|
||||
"version": "v5.1.2",
|
||||
"version": "v5.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-foundation.git",
|
||||
"reference": "f93055171b847915225bd5b0a5792888419d8d75"
|
||||
"reference": "41a4647f12870e9d41d9a7d72ff0614a27208558"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/f93055171b847915225bd5b0a5792888419d8d75",
|
||||
"reference": "f93055171b847915225bd5b0a5792888419d8d75",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/41a4647f12870e9d41d9a7d72ff0614a27208558",
|
||||
"reference": "41a4647f12870e9d41d9a7d72ff0614a27208558",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6623,20 +6611,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-06-15T06:52:54+00:00"
|
||||
"time": "2020-08-17T07:48:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-kernel",
|
||||
"version": "v5.1.2",
|
||||
"version": "v5.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-kernel.git",
|
||||
"reference": "a18c27ace1ef344ffcb129a5b089bad7643b387a"
|
||||
"reference": "3e32676e6cb5d2081c91a56783471ff8a7f7110b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/a18c27ace1ef344ffcb129a5b089bad7643b387a",
|
||||
"reference": "a18c27ace1ef344ffcb129a5b089bad7643b387a",
|
||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/3e32676e6cb5d2081c91a56783471ff8a7f7110b",
|
||||
"reference": "3e32676e6cb5d2081c91a56783471ff8a7f7110b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6736,7 +6724,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-06-15T13:51:38+00:00"
|
||||
"time": "2020-09-02T08:15:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/mime",
|
||||
@@ -6817,16 +6805,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
"version": "v1.17.1",
|
||||
"version": "v1.18.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||
"reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d"
|
||||
"reference": "1c302646f6efc070cd46856e600e5e0684d6b454"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d",
|
||||
"reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454",
|
||||
"reference": "1c302646f6efc070cd46856e600e5e0684d6b454",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6838,7 +6826,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.17-dev"
|
||||
"dev-master": "1.18-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -6889,7 +6877,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-06-06T08:46:27+00:00"
|
||||
"time": "2020-07-14T12:35:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-grapheme",
|
||||
@@ -7132,16 +7120,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.17.1",
|
||||
"version": "v1.18.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "7110338d81ce1cbc3e273136e4574663627037a7"
|
||||
"reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7110338d81ce1cbc3e273136e4574663627037a7",
|
||||
"reference": "7110338d81ce1cbc3e273136e4574663627037a7",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/a6977d63bf9a0ad4c65cd352709e230876f9904a",
|
||||
"reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7153,7 +7141,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.17-dev"
|
||||
"dev-master": "1.18-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -7205,7 +7193,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-06-06T08:46:27+00:00"
|
||||
"time": "2020-07-14T12:35:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php72",
|
||||
@@ -7278,16 +7266,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php73",
|
||||
"version": "v1.17.1",
|
||||
"version": "v1.18.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php73.git",
|
||||
"reference": "fa0837fe02d617d31fbb25f990655861bb27bd1a"
|
||||
"reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fa0837fe02d617d31fbb25f990655861bb27bd1a",
|
||||
"reference": "fa0837fe02d617d31fbb25f990655861bb27bd1a",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fffa1a52a023e782cdcc221d781fe1ec8f87fcca",
|
||||
"reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7296,7 +7284,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.17-dev"
|
||||
"dev-master": "1.18-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -7350,20 +7338,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-06-06T08:46:27+00:00"
|
||||
"time": "2020-07-14T12:35:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php80",
|
||||
"version": "v1.17.1",
|
||||
"version": "v1.18.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||
"reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2"
|
||||
"reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4a5b6bba3259902e386eb80dd1956181ee90b5b2",
|
||||
"reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/d87d5766cbf48d72388a9f6b85f280c8ad51f981",
|
||||
"reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7372,7 +7360,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.17-dev"
|
||||
"dev-master": "1.18-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -7430,7 +7418,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-06-06T08:46:27+00:00"
|
||||
"time": "2020-07-14T12:35:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
@@ -7974,16 +7962,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/var-dumper",
|
||||
"version": "v5.1.2",
|
||||
"version": "v5.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/var-dumper.git",
|
||||
"reference": "46a942903059b0b05e601f00eb64179e05578c0f"
|
||||
"reference": "b43a3905262bcf97b2510f0621f859ca4f5287be"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/46a942903059b0b05e601f00eb64179e05578c0f",
|
||||
"reference": "46a942903059b0b05e601f00eb64179e05578c0f",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/b43a3905262bcf97b2510f0621f859ca4f5287be",
|
||||
"reference": "b43a3905262bcf97b2510f0621f859ca4f5287be",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -8060,7 +8048,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2020-05-30T20:35:19+00:00"
|
||||
"time": "2020-08-17T07:42:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/var-exporter",
|
||||
|
||||
@@ -230,6 +230,8 @@ 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.',
|
||||
|
||||
'custom_subdomain_unauthorized' => 'You are not allowed to specify custom subdomains. Please upgrade to Expose Pro.',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE users ADD can_specify_subdomains BOOLEAN DEFAULT 1;
|
||||
@@ -7,7 +7,9 @@ order: 2
|
||||
|
||||
Once your Expose server is running, you can only access it over the port that you configure when the server gets started.
|
||||
|
||||
If you want to enable SSL support, you will need to use a proxy service - like Nginx, HAProxy or Caddy - to handle the SSL configurations and proxy all non-SSL requests to your expose server.
|
||||
If you want to enable SSL support, you will need to use a proxy service - like Nginx, HAProxy, Apache2 or Caddy - to handle the SSL configurations and proxy all non-SSL requests to your expose server.
|
||||
|
||||
## Nginx configuration
|
||||
|
||||
A basic Nginx configuration would look like this, but you might want to tweak the SSL parameters to your liking.
|
||||
|
||||
@@ -40,3 +42,47 @@ server {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Apache2 configuration
|
||||
|
||||
A basic Apache configuration would look like this, but you might want to tweak the SSL parameters to your liking.
|
||||
|
||||
```
|
||||
Listen 80
|
||||
Listen 443
|
||||
|
||||
<IfModule mod_ssl.c>
|
||||
<VirtualHost *:443>
|
||||
ServerName expose.domain.tld
|
||||
ServerAlias *.expose.domain.tld
|
||||
LoadModule proxy_module modules/mod_proxy.so
|
||||
LoadModule proxy_http_module modules/mod_proxy_http.so
|
||||
|
||||
ServerAdmin admin@domain.tld
|
||||
|
||||
ProxyPass "/" "http://localhost:8080/"
|
||||
ProxyPassReverse "/" "http://localhost:8080/"
|
||||
ProxyPreserveHost On
|
||||
|
||||
|
||||
# Needed for websocket support
|
||||
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC,OR]
|
||||
RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC]
|
||||
RewriteRule .* ws://127.0.0.1:8080%{REQUEST_URI} [P,QSA,L]
|
||||
|
||||
<Proxy http://localhost:8080>
|
||||
|
||||
Require all granted
|
||||
|
||||
Options none
|
||||
</Proxy>
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/expose.domain.tld-error.log
|
||||
CustomLog ${APACHE_LOG_DIR}/expose.domain.tld-access.log combined
|
||||
|
||||
SSLCertificateFile /etc/letsencrypt/live/expose.domain.tld-0001/fullchain.pem
|
||||
SSLCertificateKeyFile /etc/letsencrypt/live/expose.domain.tld-0001/privkey.pem
|
||||
Include /etc/letsencrypt/options-ssl-apache.conf
|
||||
</VirtualHost>
|
||||
</IfModule>
|
||||
```
|
||||
|
||||
@@ -24,6 +24,25 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:pt-5">
|
||||
<label for="can_specify_subdomains"
|
||||
class="block text-sm font-medium leading-5 text-gray-700 sm:mt-px sm:pt-2">
|
||||
Can specify custom subdomains
|
||||
</label>
|
||||
<div class="mt-1 sm:mt-0 sm:col-span-2">
|
||||
<div class="mt-2 flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<input id="can_specify_subdomains"
|
||||
v-model="userForm.can_specify_subdomains"
|
||||
name="can_specify_subdomains"
|
||||
value="1" type="checkbox" class="form-checkbox h-4 w-4 text-indigo-600 transition duration-150 ease-in-out" />
|
||||
<label for="can_specify_subdomains" class="ml-2 block text-sm leading-5 text-gray-900">
|
||||
Yes
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-8 border-t border-gray-200 pt-5">
|
||||
<div class="flex justify-end">
|
||||
@@ -51,6 +70,9 @@
|
||||
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
|
||||
Auth-Token
|
||||
</th>
|
||||
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
|
||||
Custom Subdomains
|
||||
</th>
|
||||
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
|
||||
Created At
|
||||
</th>
|
||||
@@ -65,6 +87,14 @@
|
||||
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-sm leading-5 text-gray-500">
|
||||
@{ user.auth_token }
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-sm leading-5 text-gray-500">
|
||||
<span v-if="user.can_specify_subdomains === 0">
|
||||
No
|
||||
</span>
|
||||
<span v-else>
|
||||
Yes
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-sm leading-5 text-gray-500">
|
||||
@{ user.created_at }
|
||||
</td>
|
||||
@@ -113,6 +143,7 @@
|
||||
data: {
|
||||
userForm: {
|
||||
name: '',
|
||||
can_specify_subdomains: true,
|
||||
errors: {},
|
||||
},
|
||||
paginated: {{ paginated|json_encode|raw }}
|
||||
@@ -140,7 +171,7 @@
|
||||
}).then((response) => {
|
||||
return response.json();
|
||||
}).then((data) => {
|
||||
this.users = this.users.filter(u => u.id !== user.id);
|
||||
this.getUsers(1)
|
||||
});
|
||||
},
|
||||
saveUser() {
|
||||
@@ -155,6 +186,7 @@
|
||||
}).then((data) => {
|
||||
if (data.user) {
|
||||
this.userForm.name = '';
|
||||
this.userForm.can_specify_subdomains = 0;
|
||||
this.userForm.errors = {};
|
||||
this.users.unshift(data.user);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use Clue\React\Buzz\Browser;
|
||||
use Clue\React\Buzz\Message\ResponseException;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Illuminate\Support\Str;
|
||||
use Nyholm\Psr7\Request;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Ratchet\Server\IoConnection;
|
||||
use Tests\Feature\TestCase;
|
||||
@@ -149,6 +150,8 @@ class AdminTest extends TestCase
|
||||
$connectionManager = app(ConnectionManager::class);
|
||||
|
||||
$connection = \Mockery::mock(IoConnection::class);
|
||||
$connection->httpRequest = new Request('GET', '/?authToken=some-token');
|
||||
|
||||
$connectionManager->storeConnection('some-host.text', 'fixed-subdomain', $connection);
|
||||
|
||||
/** @var Response $response */
|
||||
|
||||
201
tests/Feature/Server/ApiTest.php
Normal file
201
tests/Feature/Server/ApiTest.php
Normal file
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Server;
|
||||
|
||||
use App\Contracts\ConnectionManager;
|
||||
use App\Server\Factory;
|
||||
use Clue\React\Buzz\Browser;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Nyholm\Psr7\Request;
|
||||
use Ratchet\Server\IoConnection;
|
||||
use Tests\Feature\TestCase;
|
||||
|
||||
class ApiTest extends TestCase
|
||||
{
|
||||
/** @var Browser */
|
||||
protected $browser;
|
||||
|
||||
/** @var Factory */
|
||||
protected $serverFactory;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->browser = new Browser($this->loop);
|
||||
$this->browser = $this->browser->withOptions([
|
||||
'followRedirects' => false,
|
||||
]);
|
||||
|
||||
$this->startServer();
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
$this->serverFactory->getSocket()->close();
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_list_all_registered_users()
|
||||
{
|
||||
/** @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',
|
||||
], json_encode([
|
||||
'name' => 'Marcel',
|
||||
])));
|
||||
|
||||
/** @var Response $response */
|
||||
$response = $this->await($this->browser->get('http://127.0.0.1:8080/api/users', [
|
||||
'Host' => 'expose.localhost',
|
||||
'Authorization' => base64_encode('username:secret'),
|
||||
'Content-Type' => 'application/json',
|
||||
]));
|
||||
|
||||
$body = json_decode($response->getBody()->getContents());
|
||||
$users = $body->paginated->users;
|
||||
|
||||
$this->assertCount(1, $users);
|
||||
$this->assertSame('Marcel', $users[0]->name);
|
||||
$this->assertSame([], $users[0]->sites);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_get_user_details()
|
||||
{
|
||||
/** @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',
|
||||
], json_encode([
|
||||
'name' => 'Marcel',
|
||||
])));
|
||||
|
||||
/** @var Response $response */
|
||||
$response = $this->await($this->browser->get('http://127.0.0.1:8080/api/users/1', [
|
||||
'Host' => 'expose.localhost',
|
||||
'Authorization' => base64_encode('username:secret'),
|
||||
'Content-Type' => 'application/json',
|
||||
]));
|
||||
|
||||
$body = json_decode($response->getBody()->getContents());
|
||||
$user = $body->user;
|
||||
|
||||
$this->assertSame('Marcel', $user->name);
|
||||
$this->assertSame([], $user->sites);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_list_all_currently_connected_sites_from_all_users()
|
||||
{
|
||||
/** @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',
|
||||
], json_encode([
|
||||
'name' => 'Marcel',
|
||||
])));
|
||||
|
||||
$createdUser = json_decode($response->getBody()->getContents())->user;
|
||||
|
||||
/** @var ConnectionManager $connectionManager */
|
||||
$connectionManager = app(ConnectionManager::class);
|
||||
|
||||
$connection = \Mockery::mock(IoConnection::class);
|
||||
$connection->httpRequest = new Request('GET', '/?authToken='.$createdUser->auth_token);
|
||||
$connectionManager->storeConnection('some-host.test', 'fixed-subdomain', $connection);
|
||||
|
||||
$connection = \Mockery::mock(IoConnection::class);
|
||||
$connection->httpRequest = new Request('GET', '/?authToken=some-other-token');
|
||||
$connectionManager->storeConnection('some-different-host.test', 'different-subdomain', $connection);
|
||||
|
||||
/** @var Response $response */
|
||||
$response = $this->await($this->browser->get('http://127.0.0.1:8080/api/users', [
|
||||
'Host' => 'expose.localhost',
|
||||
'Authorization' => base64_encode('username:secret'),
|
||||
'Content-Type' => 'application/json',
|
||||
]));
|
||||
|
||||
$body = json_decode($response->getBody()->getContents());
|
||||
$users = $body->paginated->users;
|
||||
|
||||
$this->assertCount(1, $users[0]->sites);
|
||||
$this->assertSame('some-host.test', $users[0]->sites[0]->host);
|
||||
$this->assertSame('fixed-subdomain', $users[0]->sites[0]->subdomain);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_list_all_currently_connected_sites()
|
||||
{
|
||||
/** @var ConnectionManager $connectionManager */
|
||||
$connectionManager = app(ConnectionManager::class);
|
||||
|
||||
$connection = \Mockery::mock(IoConnection::class);
|
||||
$connection->httpRequest = new Request('GET', '/?authToken=some-token');
|
||||
|
||||
$connectionManager->storeConnection('some-host.test', 'fixed-subdomain', $connection);
|
||||
|
||||
/** @var Response $response */
|
||||
$response = $this->await($this->browser->get('http://127.0.0.1:8080/api/sites', [
|
||||
'Host' => 'expose.localhost',
|
||||
'Authorization' => base64_encode('username:secret'),
|
||||
'Content-Type' => 'application/json',
|
||||
]));
|
||||
|
||||
$body = json_decode($response->getBody()->getContents());
|
||||
$sites = $body->sites;
|
||||
|
||||
$this->assertCount(1, $sites);
|
||||
$this->assertSame('some-host.test', $sites[0]->host);
|
||||
$this->assertSame('some-token', $sites[0]->auth_token);
|
||||
$this->assertSame('fixed-subdomain', $sites[0]->subdomain);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_list_all_currently_connected_sites_without_auth_tokens()
|
||||
{
|
||||
/** @var ConnectionManager $connectionManager */
|
||||
$connectionManager = app(ConnectionManager::class);
|
||||
|
||||
$connection = \Mockery::mock(IoConnection::class);
|
||||
$connection->httpRequest = new Request('GET', '/');
|
||||
|
||||
$connectionManager->storeConnection('some-host.test', 'fixed-subdomain', $connection);
|
||||
|
||||
/** @var Response $response */
|
||||
$response = $this->await($this->browser->get('http://127.0.0.1:8080/api/sites', [
|
||||
'Host' => 'expose.localhost',
|
||||
'Authorization' => base64_encode('username:secret'),
|
||||
'Content-Type' => 'application/json',
|
||||
]));
|
||||
|
||||
$body = json_decode($response->getBody()->getContents());
|
||||
$sites = $body->sites;
|
||||
|
||||
$this->assertCount(1, $sites);
|
||||
$this->assertSame('some-host.test', $sites[0]->host);
|
||||
$this->assertSame('', $sites[0]->auth_token);
|
||||
$this->assertSame('fixed-subdomain', $sites[0]->subdomain);
|
||||
}
|
||||
|
||||
protected function startServer()
|
||||
{
|
||||
$this->app['config']['expose.admin.subdomain'] = 'expose';
|
||||
$this->app['config']['expose.admin.database'] = ':memory:';
|
||||
|
||||
$this->app['config']['expose.admin.users'] = [
|
||||
'username' => 'secret',
|
||||
];
|
||||
|
||||
$this->serverFactory = new Factory();
|
||||
|
||||
$this->serverFactory->setLoop($this->loop)
|
||||
->createServer();
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,9 @@ class TunnelTest extends TestCase
|
||||
parent::setUp();
|
||||
|
||||
$this->browser = new Browser($this->loop);
|
||||
$this->browser = $this->browser->withOptions([
|
||||
'followRedirects' => false,
|
||||
]);
|
||||
|
||||
$this->startServer();
|
||||
}
|
||||
@@ -58,6 +61,8 @@ class TunnelTest extends TestCase
|
||||
{
|
||||
$this->createTestHttpServer();
|
||||
|
||||
$this->app['config']['expose.admin.validate_auth_tokens'] = false;
|
||||
|
||||
/**
|
||||
* We create an expose client that connects to our server and shares
|
||||
* the created test HTTP server.
|
||||
@@ -98,22 +103,96 @@ class TunnelTest extends TestCase
|
||||
{
|
||||
$this->app['config']['expose.admin.validate_auth_tokens'] = true;
|
||||
|
||||
$this->createTestHttpServer();
|
||||
$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',
|
||||
], json_encode([
|
||||
'name' => 'Marcel',
|
||||
'can_specify_subdomains' => 1,
|
||||
])));
|
||||
|
||||
$this->expectException(\UnexpectedValueException::class);
|
||||
$user = json_decode($response->getBody()->getContents())->user;
|
||||
|
||||
$this->createTestHttpServer();
|
||||
|
||||
/**
|
||||
* We create an expose client that connects to our server and shares
|
||||
* the created test HTTP server.
|
||||
*/
|
||||
$client = $this->createClient();
|
||||
$this->await($client->connectToServer('127.0.0.1:8085', 'tunnel'));
|
||||
$response = $this->await($client->connectToServer('127.0.0.1:8085', 'tunnel', $user->auth_token));
|
||||
|
||||
$this->assertSame('tunnel', $response->subdomain);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_rejects_clients_to_specify_custom_subdomains()
|
||||
{
|
||||
$this->app['config']['expose.admin.validate_auth_tokens'] = true;
|
||||
|
||||
$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',
|
||||
], json_encode([
|
||||
'name' => 'Marcel',
|
||||
'can_specify_subdomains' => 0,
|
||||
])));
|
||||
|
||||
$this->expectException(\UnexpectedValueException::class);
|
||||
|
||||
$user = json_decode($response->getBody()->getContents())->user;
|
||||
|
||||
$this->createTestHttpServer();
|
||||
|
||||
/**
|
||||
* We create an expose client that connects to our server and shares
|
||||
* the created test HTTP server.
|
||||
*/
|
||||
$client = $this->createClient();
|
||||
$response = $this->await($client->connectToServer('127.0.0.1:8085', 'tunnel', $user->auth_token));
|
||||
|
||||
$this->assertSame('tunnel', $response->subdomain);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_allows_clients_to_use_random_subdomains_if_custom_subdomains_are_forbidden()
|
||||
{
|
||||
$this->app['config']['expose.admin.validate_auth_tokens'] = true;
|
||||
|
||||
$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',
|
||||
], json_encode([
|
||||
'name' => 'Marcel',
|
||||
'can_specify_subdomains' => 0,
|
||||
])));
|
||||
|
||||
$user = json_decode($response->getBody()->getContents())->user;
|
||||
|
||||
$this->createTestHttpServer();
|
||||
|
||||
/**
|
||||
* We create an expose client that connects to our server and shares
|
||||
* the created test HTTP server.
|
||||
*/
|
||||
$client = $this->createClient();
|
||||
$response = $this->await($client->connectToServer('127.0.0.1:8085', '', $user->auth_token));
|
||||
|
||||
$this->assertInstanceOf(\stdClass::class, $response);
|
||||
}
|
||||
|
||||
protected function startServer()
|
||||
{
|
||||
$this->app['config']['expose.admin.subdomain'] = 'expose';
|
||||
$this->app['config']['expose.admin.database'] = ':memory:';
|
||||
|
||||
$this->app['config']['expose.admin.users'] = [
|
||||
'username' => 'secret',
|
||||
];
|
||||
|
||||
$this->serverFactory = new Factory();
|
||||
|
||||
$this->serverFactory->setLoop($this->loop)
|
||||
|
||||
Reference in New Issue
Block a user