mirror of
https://github.com/bitinflow/expose.git
synced 2026-03-16 15:05:56 +00:00
Merge branch 'master' into tcp
This commit is contained in:
@@ -8,12 +8,12 @@ class ShareCurrentWorkingDirectoryCommand extends ShareCommand
|
|||||||
|
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
$host = $this->prepareSharedHost(basename(getcwd()).'.'.$this->detectTld());
|
$subdomain = $this->detectName();
|
||||||
|
$host = $this->prepareSharedHost($subdomain.'.'.$this->detectTld());
|
||||||
|
|
||||||
$this->input->setArgument('host', $host);
|
$this->input->setArgument('host', $host);
|
||||||
|
|
||||||
if (! $this->option('subdomain')) {
|
if (! $this->option('subdomain')) {
|
||||||
$subdomain = str_replace('.', '-', basename(getcwd()));
|
|
||||||
$this->input->setOption('subdomain', $subdomain);
|
$this->input->setOption('subdomain', $subdomain);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +33,32 @@ class ShareCurrentWorkingDirectoryCommand extends ShareCommand
|
|||||||
return config('expose.default_tld', 'test');
|
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
|
protected function prepareSharedHost($host): string
|
||||||
{
|
{
|
||||||
$certificateFile = ($_SERVER['HOME'] ?? $_SERVER['USERPROFILE']).DIRECTORY_SEPARATOR.'.config'.DIRECTORY_SEPARATOR.'valet'.DIRECTORY_SEPARATOR.'Certificates'.DIRECTORY_SEPARATOR.$host.'.crt';
|
$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 findControlConnectionForClientId(string $clientId): ?ControlConnection;
|
||||||
|
|
||||||
public function getConnections(): array;
|
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\ConnectionManager as ConnectionManagerContract;
|
||||||
use App\Contracts\SubdomainGenerator;
|
use App\Contracts\SubdomainGenerator;
|
||||||
|
use App\Http\QueryParameters;
|
||||||
use Ratchet\ConnectionInterface;
|
use Ratchet\ConnectionInterface;
|
||||||
use React\EventLoop\LoopInterface;
|
use React\EventLoop\LoopInterface;
|
||||||
use React\Socket\Server;
|
use React\Socket\Server;
|
||||||
@@ -47,7 +48,13 @@ class ConnectionManager implements ConnectionManagerContract
|
|||||||
|
|
||||||
$connection->client_id = $clientId;
|
$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;
|
$this->connections[] = $storedConnection;
|
||||||
|
|
||||||
@@ -60,7 +67,13 @@ class ConnectionManager implements ConnectionManagerContract
|
|||||||
|
|
||||||
$connection->client_id = $clientId;
|
$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;
|
$this->connections[] = $storedConnection;
|
||||||
|
|
||||||
@@ -118,4 +131,21 @@ class ConnectionManager implements ConnectionManagerContract
|
|||||||
{
|
{
|
||||||
return $this->connections;
|
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 */
|
/** @var ConnectionInterface */
|
||||||
public $socket;
|
public $socket;
|
||||||
public $host;
|
public $host;
|
||||||
|
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)
|
public function __construct(ConnectionInterface $socket, string $host, string $subdomain, string $clientId, 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->shared_at = now()->toDateTimeString();
|
$this->shared_at = now()->toDateTimeString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,6 +60,7 @@ class ControlConnection
|
|||||||
'type' => 'http',
|
'type' => 'http',
|
||||||
'host' => $this->host,
|
'host' => $this->host,
|
||||||
'client_id' => $this->client_id,
|
'client_id' => $this->client_id,
|
||||||
|
'auth_token' => $this->authToken,
|
||||||
'subdomain' => $this->subdomain,
|
'subdomain' => $this->subdomain,
|
||||||
'shared_at' => $this->shared_at,
|
'shared_at' => $this->shared_at,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class TcpControlConnection extends ControlConnection
|
|||||||
public $shared_port;
|
public $shared_port;
|
||||||
public $shared_server;
|
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->socket = $socket;
|
||||||
$this->client_id = $clientId;
|
$this->client_id = $clientId;
|
||||||
@@ -22,6 +22,7 @@ class TcpControlConnection extends ControlConnection
|
|||||||
$this->port = $port;
|
$this->port = $port;
|
||||||
$this->shared_at = now()->toDateTimeString();
|
$this->shared_at = now()->toDateTimeString();
|
||||||
$this->shared_port = parse_url($sharedServer->getAddress(), PHP_URL_PORT);
|
$this->shared_port = parse_url($sharedServer->getAddress(), PHP_URL_PORT);
|
||||||
|
$this->authToken = $authToken;
|
||||||
|
|
||||||
$this->configureServer($sharedServer);
|
$this->configureServer($sharedServer);
|
||||||
}
|
}
|
||||||
@@ -85,7 +86,6 @@ class TcpControlConnection extends ControlConnection
|
|||||||
|
|
||||||
$this->once('tcp_proxy_ready_'.$requestId, function (ConnectionInterface $proxy) use ($connection) {
|
$this->once('tcp_proxy_ready_'.$requestId, function (ConnectionInterface $proxy) use ($connection) {
|
||||||
$this->proxy = $proxy;
|
$this->proxy = $proxy;
|
||||||
dump("Proxy ready");
|
|
||||||
|
|
||||||
$connection->on('data', function($data) use ($proxy) {
|
$connection->on('data', function($data) use ($proxy) {
|
||||||
$proxy->send($data);
|
$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\DisconnectSiteController;
|
||||||
use App\Server\Http\Controllers\Admin\GetSettingsController;
|
use App\Server\Http\Controllers\Admin\GetSettingsController;
|
||||||
use App\Server\Http\Controllers\Admin\GetSitesController;
|
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\GetUsersController;
|
||||||
use App\Server\Http\Controllers\Admin\ListSitesController;
|
use App\Server\Http\Controllers\Admin\ListSitesController;
|
||||||
use App\Server\Http\Controllers\Admin\ListUsersController;
|
use App\Server\Http\Controllers\Admin\ListUsersController;
|
||||||
@@ -124,6 +125,7 @@ class Factory
|
|||||||
$this->router->post('/api/settings', StoreSettingsController::class, $adminCondition);
|
$this->router->post('/api/settings', StoreSettingsController::class, $adminCondition);
|
||||||
$this->router->get('/api/users', GetUsersController::class, $adminCondition);
|
$this->router->get('/api/users', GetUsersController::class, $adminCondition);
|
||||||
$this->router->post('/api/users', StoreUsersController::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->delete('/api/users/{id}', DeleteUsersController::class, $adminCondition);
|
||||||
$this->router->get('/api/sites', GetSitesController::class, $adminCondition);
|
$this->router->get('/api/sites', GetSitesController::class, $adminCondition);
|
||||||
$this->router->delete('/api/sites/{id}', DisconnectSiteController::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 = [
|
$insertData = [
|
||||||
'name' => $request->get('name'),
|
'name' => $request->get('name'),
|
||||||
'auth_token' => (string) Str::uuid(),
|
'auth_token' => (string) Str::uuid(),
|
||||||
|
'can_specify_subdomains' => (int) $request->get('can_specify_subdomains'),
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->userRepository
|
$this->userRepository
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ use App\Http\QueryParameters;
|
|||||||
use Ratchet\ConnectionInterface;
|
use Ratchet\ConnectionInterface;
|
||||||
use Ratchet\WebSocket\MessageComponentInterface;
|
use Ratchet\WebSocket\MessageComponentInterface;
|
||||||
use React\Promise\Deferred;
|
use React\Promise\Deferred;
|
||||||
use React\Promise\FulfilledPromise;
|
|
||||||
use React\Promise\PromiseInterface;
|
use React\Promise\PromiseInterface;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
|
|
||||||
@@ -81,11 +80,11 @@ class ControlMessageController implements MessageComponentInterface
|
|||||||
protected function authenticate(ConnectionInterface $connection, $data)
|
protected function authenticate(ConnectionInterface $connection, $data)
|
||||||
{
|
{
|
||||||
$this->verifyAuthToken($connection)
|
$this->verifyAuthToken($connection)
|
||||||
->then(function () use ($connection, $data) {
|
->then(function ($user) use ($connection, $data) {
|
||||||
if ($data->type === 'http') {
|
if ($data->type === 'http') {
|
||||||
$this->handleHttpConnection($connection, $data);
|
$this->handleHttpConnection($connection, $data, $user);
|
||||||
} elseif($data->type === 'tcp') {
|
} elseif($data->type === 'tcp') {
|
||||||
$this->handleTcpConnection($connection, $data);
|
$this->handleTcpConnection($connection, $data, $user);
|
||||||
}
|
}
|
||||||
}, function () use ($connection) {
|
}, function () use ($connection) {
|
||||||
$connection->send(json_encode([
|
$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;
|
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);
|
$connectionInfo = $this->connectionManager->storeTcpConnection($data->port, $connection);
|
||||||
|
|
||||||
@@ -167,7 +166,7 @@ class ControlMessageController implements MessageComponentInterface
|
|||||||
protected function verifyAuthToken(ConnectionInterface $connection): PromiseInterface
|
protected function verifyAuthToken(ConnectionInterface $connection): PromiseInterface
|
||||||
{
|
{
|
||||||
if (config('expose.admin.validate_auth_tokens') !== true) {
|
if (config('expose.admin.validate_auth_tokens') !== true) {
|
||||||
return new FulfilledPromise();
|
return \React\Promise\resolve(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
$deferred = new Deferred();
|
$deferred = new Deferred();
|
||||||
@@ -187,8 +186,20 @@ class ControlMessageController implements MessageComponentInterface
|
|||||||
return $deferred->promise();
|
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)) {
|
if (! is_null($subdomain)) {
|
||||||
$controlConnection = $this->connectionManager->findControlConnectionForSubdomain($subdomain);
|
$controlConnection = $this->connectionManager->findControlConnectionForSubdomain($subdomain);
|
||||||
if (! is_null($controlConnection) || $subdomain === config('expose.admin.subdomain')) {
|
if (! is_null($controlConnection) || $subdomain === config('expose.admin.subdomain')) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Server\UserRepository;
|
namespace App\Server\UserRepository;
|
||||||
|
|
||||||
|
use App\Contracts\ConnectionManager;
|
||||||
use App\Contracts\UserRepository;
|
use App\Contracts\UserRepository;
|
||||||
use Clue\React\SQLite\DatabaseInterface;
|
use Clue\React\SQLite\DatabaseInterface;
|
||||||
use Clue\React\SQLite\Result;
|
use Clue\React\SQLite\Result;
|
||||||
@@ -13,9 +14,13 @@ class DatabaseUserRepository implements UserRepository
|
|||||||
/** @var DatabaseInterface */
|
/** @var DatabaseInterface */
|
||||||
protected $database;
|
protected $database;
|
||||||
|
|
||||||
public function __construct(DatabaseInterface $database)
|
/** @var ConnectionManager */
|
||||||
|
protected $connectionManager;
|
||||||
|
|
||||||
|
public function __construct(DatabaseInterface $database, ConnectionManager $connectionManager)
|
||||||
{
|
{
|
||||||
$this->database = $database;
|
$this->database = $database;
|
||||||
|
$this->connectionManager = $connectionManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUsers(): PromiseInterface
|
public function getUsers(): PromiseInterface
|
||||||
@@ -46,8 +51,12 @@ class DatabaseUserRepository implements UserRepository
|
|||||||
$nextPage = $currentPage + 1;
|
$nextPage = $currentPage + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$users = collect($result->rows)->map(function ($user) {
|
||||||
|
return $this->getUserDetails($user);
|
||||||
|
})->toArray();
|
||||||
|
|
||||||
$paginated = [
|
$paginated = [
|
||||||
'users' => $result->rows,
|
'users' => $users,
|
||||||
'current_page' => $currentPage,
|
'current_page' => $currentPage,
|
||||||
'per_page' => $perPage,
|
'per_page' => $perPage,
|
||||||
'next_page' => $nextPage ?? null,
|
'next_page' => $nextPage ?? null,
|
||||||
@@ -60,6 +69,13 @@ class DatabaseUserRepository implements UserRepository
|
|||||||
return $deferred->promise();
|
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
|
public function getUserById($id): PromiseInterface
|
||||||
{
|
{
|
||||||
$deferred = new Deferred();
|
$deferred = new Deferred();
|
||||||
@@ -67,7 +83,13 @@ class DatabaseUserRepository implements UserRepository
|
|||||||
$this->database
|
$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) {
|
->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();
|
return $deferred->promise();
|
||||||
@@ -91,8 +113,8 @@ class DatabaseUserRepository implements UserRepository
|
|||||||
$deferred = new Deferred();
|
$deferred = new Deferred();
|
||||||
|
|
||||||
$this->database->query("
|
$this->database->query("
|
||||||
INSERT INTO users (name, auth_token, created_at)
|
INSERT INTO users (name, auth_token, can_specify_subdomains, created_at)
|
||||||
VALUES (:name, :auth_token, DATETIME('now'))
|
VALUES (:name, :auth_token, :can_specify_subdomains, DATETIME('now'))
|
||||||
", $data)
|
", $data)
|
||||||
->then(function (Result $result) use ($deferred) {
|
->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])
|
||||||
|
|||||||
@@ -17,8 +17,7 @@
|
|||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.3.0",
|
"php": "^7.3.0",
|
||||||
"ext-json": "*",
|
"ext-json": "*"
|
||||||
"padraic/phar-updater": "^1.0.6"
|
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"cboden/ratchet": "^0.4.2",
|
"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",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "29e5e7d9a7d406f7d34ef09a3b2836e9",
|
"content-hash": "dd987a6f4f036893204c0d006d66001b",
|
||||||
"packages": [
|
"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"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
{
|
{
|
||||||
"name": "cboden/ratchet",
|
"name": "cboden/ratchet",
|
||||||
@@ -478,6 +290,72 @@
|
|||||||
},
|
},
|
||||||
"time": "2020-05-10T03:16:55+00:00"
|
"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",
|
"name": "container-interop/container-interop",
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@@ -3258,6 +3136,75 @@
|
|||||||
],
|
],
|
||||||
"time": "2020-05-23T11:29:07+00:00"
|
"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",
|
"name": "paragonie/random_compat",
|
||||||
"version": "v9.99.99",
|
"version": "v9.99.99",
|
||||||
@@ -3981,6 +3928,7 @@
|
|||||||
"keywords": [
|
"keywords": [
|
||||||
"tokenizer"
|
"tokenizer"
|
||||||
],
|
],
|
||||||
|
"abandoned": true,
|
||||||
"time": "2019-09-17T06:23:10+00:00"
|
"time": "2019-09-17T06:23:10+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5060,12 +5008,12 @@
|
|||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/reactphp/socket.git",
|
"url": "https://github.com/reactphp/socket.git",
|
||||||
"reference": "842dcd71df86671ee9491734035b3d2cf4a80ece"
|
"reference": "e2b96b23a13ca9b41ab343268dbce3f8ef4d524a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/reactphp/socket/zipball/842dcd71df86671ee9491734035b3d2cf4a80ece",
|
"url": "https://api.github.com/repos/reactphp/socket/zipball/e2b96b23a13ca9b41ab343268dbce3f8ef4d524a",
|
||||||
"reference": "842dcd71df86671ee9491734035b3d2cf4a80ece",
|
"reference": "e2b96b23a13ca9b41ab343268dbce3f8ef4d524a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -5079,7 +5027,7 @@
|
|||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"clue/block-react": "^1.2",
|
"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"
|
"react/promise-stream": "^1.2"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
@@ -5092,6 +5040,28 @@
|
|||||||
"license": [
|
"license": [
|
||||||
"MIT"
|
"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",
|
"description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"Connection",
|
"Connection",
|
||||||
@@ -5100,7 +5070,17 @@
|
|||||||
"reactphp",
|
"reactphp",
|
||||||
"stream"
|
"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",
|
"name": "react/stream",
|
||||||
@@ -6134,16 +6114,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/deprecation-contracts",
|
"name": "symfony/deprecation-contracts",
|
||||||
"version": "v2.1.2",
|
"version": "v2.1.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/deprecation-contracts.git",
|
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||||
"reference": "dd99cb3a0aff6cadd2a8d7d7ed72c2161e218337"
|
"reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/dd99cb3a0aff6cadd2a8d7d7ed72c2161e218337",
|
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5e20b83385a77593259c9f8beb2c43cd03b2ac14",
|
||||||
"reference": "dd99cb3a0aff6cadd2a8d7d7ed72c2161e218337",
|
"reference": "5e20b83385a77593259c9f8beb2c43cd03b2ac14",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -6153,6 +6133,10 @@
|
|||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "2.1-dev"
|
"dev-master": "2.1-dev"
|
||||||
|
},
|
||||||
|
"thanks": {
|
||||||
|
"name": "symfony/contracts",
|
||||||
|
"url": "https://github.com/symfony/contracts"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -6190,20 +6174,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-05-27T08:34:37+00:00"
|
"time": "2020-06-06T08:49:21+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/error-handler",
|
"name": "symfony/error-handler",
|
||||||
"version": "v5.1.2",
|
"version": "v5.1.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/error-handler.git",
|
"url": "https://github.com/symfony/error-handler.git",
|
||||||
"reference": "7d0b927b9d3dc41d7d46cda38cbfcd20cdcbb896"
|
"reference": "525636d4b84e06c6ca72d96b6856b5b169416e6a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/error-handler/zipball/7d0b927b9d3dc41d7d46cda38cbfcd20cdcbb896",
|
"url": "https://api.github.com/repos/symfony/error-handler/zipball/525636d4b84e06c6ca72d96b6856b5b169416e6a",
|
||||||
"reference": "7d0b927b9d3dc41d7d46cda38cbfcd20cdcbb896",
|
"reference": "525636d4b84e06c6ca72d96b6856b5b169416e6a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -6261,20 +6245,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-05-30T20:35:19+00:00"
|
"time": "2020-08-17T10:01:29+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/event-dispatcher",
|
"name": "symfony/event-dispatcher",
|
||||||
"version": "v5.1.2",
|
"version": "v5.1.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||||
"reference": "cc0d059e2e997e79ca34125a52f3e33de4424ac7"
|
"reference": "94871fc0a69c3c5da57764187724cdce0755899c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/cc0d059e2e997e79ca34125a52f3e33de4424ac7",
|
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/94871fc0a69c3c5da57764187724cdce0755899c",
|
||||||
"reference": "cc0d059e2e997e79ca34125a52f3e33de4424ac7",
|
"reference": "94871fc0a69c3c5da57764187724cdce0755899c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -6347,20 +6331,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-05-20T17:43:50+00:00"
|
"time": "2020-08-13T14:19:42+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/event-dispatcher-contracts",
|
"name": "symfony/event-dispatcher-contracts",
|
||||||
"version": "v2.1.2",
|
"version": "v2.1.3",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
|
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
|
||||||
"reference": "405952c4e90941a17e52ef7489a2bd94870bb290"
|
"reference": "f6f613d74cfc5a623fc36294d3451eb7fa5a042b"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/405952c4e90941a17e52ef7489a2bd94870bb290",
|
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f6f613d74cfc5a623fc36294d3451eb7fa5a042b",
|
||||||
"reference": "405952c4e90941a17e52ef7489a2bd94870bb290",
|
"reference": "f6f613d74cfc5a623fc36294d3451eb7fa5a042b",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -6374,6 +6358,10 @@
|
|||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "2.1-dev"
|
"dev-master": "2.1-dev"
|
||||||
|
},
|
||||||
|
"thanks": {
|
||||||
|
"name": "symfony/contracts",
|
||||||
|
"url": "https://github.com/symfony/contracts"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@@ -6419,7 +6407,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-05-20T17:43:50+00:00"
|
"time": "2020-07-06T13:23:11+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/expression-language",
|
"name": "symfony/expression-language",
|
||||||
@@ -6552,16 +6540,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/http-foundation",
|
"name": "symfony/http-foundation",
|
||||||
"version": "v5.1.2",
|
"version": "v5.1.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/http-foundation.git",
|
"url": "https://github.com/symfony/http-foundation.git",
|
||||||
"reference": "f93055171b847915225bd5b0a5792888419d8d75"
|
"reference": "41a4647f12870e9d41d9a7d72ff0614a27208558"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/f93055171b847915225bd5b0a5792888419d8d75",
|
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/41a4647f12870e9d41d9a7d72ff0614a27208558",
|
||||||
"reference": "f93055171b847915225bd5b0a5792888419d8d75",
|
"reference": "41a4647f12870e9d41d9a7d72ff0614a27208558",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -6623,20 +6611,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-06-15T06:52:54+00:00"
|
"time": "2020-08-17T07:48:54+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/http-kernel",
|
"name": "symfony/http-kernel",
|
||||||
"version": "v5.1.2",
|
"version": "v5.1.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/http-kernel.git",
|
"url": "https://github.com/symfony/http-kernel.git",
|
||||||
"reference": "a18c27ace1ef344ffcb129a5b089bad7643b387a"
|
"reference": "3e32676e6cb5d2081c91a56783471ff8a7f7110b"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/a18c27ace1ef344ffcb129a5b089bad7643b387a",
|
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/3e32676e6cb5d2081c91a56783471ff8a7f7110b",
|
||||||
"reference": "a18c27ace1ef344ffcb129a5b089bad7643b387a",
|
"reference": "3e32676e6cb5d2081c91a56783471ff8a7f7110b",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -6736,7 +6724,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-06-15T13:51:38+00:00"
|
"time": "2020-09-02T08:15:18+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/mime",
|
"name": "symfony/mime",
|
||||||
@@ -6817,16 +6805,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-ctype",
|
"name": "symfony/polyfill-ctype",
|
||||||
"version": "v1.17.1",
|
"version": "v1.18.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||||
"reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d"
|
"reference": "1c302646f6efc070cd46856e600e5e0684d6b454"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d",
|
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454",
|
||||||
"reference": "2edd75b8b35d62fd3eeabba73b26b8f1f60ce13d",
|
"reference": "1c302646f6efc070cd46856e600e5e0684d6b454",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -6838,7 +6826,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "1.17-dev"
|
"dev-master": "1.18-dev"
|
||||||
},
|
},
|
||||||
"thanks": {
|
"thanks": {
|
||||||
"name": "symfony/polyfill",
|
"name": "symfony/polyfill",
|
||||||
@@ -6889,7 +6877,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-06-06T08:46:27+00:00"
|
"time": "2020-07-14T12:35:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-intl-grapheme",
|
"name": "symfony/polyfill-intl-grapheme",
|
||||||
@@ -7132,16 +7120,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-mbstring",
|
"name": "symfony/polyfill-mbstring",
|
||||||
"version": "v1.17.1",
|
"version": "v1.18.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||||
"reference": "7110338d81ce1cbc3e273136e4574663627037a7"
|
"reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7110338d81ce1cbc3e273136e4574663627037a7",
|
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/a6977d63bf9a0ad4c65cd352709e230876f9904a",
|
||||||
"reference": "7110338d81ce1cbc3e273136e4574663627037a7",
|
"reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -7153,7 +7141,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "1.17-dev"
|
"dev-master": "1.18-dev"
|
||||||
},
|
},
|
||||||
"thanks": {
|
"thanks": {
|
||||||
"name": "symfony/polyfill",
|
"name": "symfony/polyfill",
|
||||||
@@ -7205,7 +7193,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-06-06T08:46:27+00:00"
|
"time": "2020-07-14T12:35:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-php72",
|
"name": "symfony/polyfill-php72",
|
||||||
@@ -7278,16 +7266,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-php73",
|
"name": "symfony/polyfill-php73",
|
||||||
"version": "v1.17.1",
|
"version": "v1.18.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/polyfill-php73.git",
|
"url": "https://github.com/symfony/polyfill-php73.git",
|
||||||
"reference": "fa0837fe02d617d31fbb25f990655861bb27bd1a"
|
"reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fa0837fe02d617d31fbb25f990655861bb27bd1a",
|
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fffa1a52a023e782cdcc221d781fe1ec8f87fcca",
|
||||||
"reference": "fa0837fe02d617d31fbb25f990655861bb27bd1a",
|
"reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -7296,7 +7284,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "1.17-dev"
|
"dev-master": "1.18-dev"
|
||||||
},
|
},
|
||||||
"thanks": {
|
"thanks": {
|
||||||
"name": "symfony/polyfill",
|
"name": "symfony/polyfill",
|
||||||
@@ -7350,20 +7338,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-06-06T08:46:27+00:00"
|
"time": "2020-07-14T12:35:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-php80",
|
"name": "symfony/polyfill-php80",
|
||||||
"version": "v1.17.1",
|
"version": "v1.18.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||||
"reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2"
|
"reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4a5b6bba3259902e386eb80dd1956181ee90b5b2",
|
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/d87d5766cbf48d72388a9f6b85f280c8ad51f981",
|
||||||
"reference": "4a5b6bba3259902e386eb80dd1956181ee90b5b2",
|
"reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -7372,7 +7360,7 @@
|
|||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "1.17-dev"
|
"dev-master": "1.18-dev"
|
||||||
},
|
},
|
||||||
"thanks": {
|
"thanks": {
|
||||||
"name": "symfony/polyfill",
|
"name": "symfony/polyfill",
|
||||||
@@ -7430,7 +7418,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-06-06T08:46:27+00:00"
|
"time": "2020-07-14T12:35:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/process",
|
"name": "symfony/process",
|
||||||
@@ -7974,16 +7962,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/var-dumper",
|
"name": "symfony/var-dumper",
|
||||||
"version": "v5.1.2",
|
"version": "v5.1.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/var-dumper.git",
|
"url": "https://github.com/symfony/var-dumper.git",
|
||||||
"reference": "46a942903059b0b05e601f00eb64179e05578c0f"
|
"reference": "b43a3905262bcf97b2510f0621f859ca4f5287be"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/46a942903059b0b05e601f00eb64179e05578c0f",
|
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/b43a3905262bcf97b2510f0621f859ca4f5287be",
|
||||||
"reference": "46a942903059b0b05e601f00eb64179e05578c0f",
|
"reference": "b43a3905262bcf97b2510f0621f859ca4f5287be",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -8060,7 +8048,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-05-30T20:35:19+00:00"
|
"time": "2020-08-17T07:42:30+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/var-exporter",
|
"name": "symfony/var-exporter",
|
||||||
|
|||||||
@@ -230,6 +230,8 @@ return [
|
|||||||
'invalid_auth_token' => 'Authentication failed. Please check your authentication token and try again.',
|
'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.',
|
'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.
|
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.
|
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>
|
||||||
</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>
|
||||||
<div class="mt-8 border-t border-gray-200 pt-5">
|
<div class="mt-8 border-t border-gray-200 pt-5">
|
||||||
<div class="flex justify-end">
|
<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">
|
<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
|
Auth-Token
|
||||||
</th>
|
</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">
|
<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
|
Created At
|
||||||
</th>
|
</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">
|
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-sm leading-5 text-gray-500">
|
||||||
@{ user.auth_token }
|
@{ user.auth_token }
|
||||||
</td>
|
</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">
|
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-sm leading-5 text-gray-500">
|
||||||
@{ user.created_at }
|
@{ user.created_at }
|
||||||
</td>
|
</td>
|
||||||
@@ -113,6 +143,7 @@
|
|||||||
data: {
|
data: {
|
||||||
userForm: {
|
userForm: {
|
||||||
name: '',
|
name: '',
|
||||||
|
can_specify_subdomains: true,
|
||||||
errors: {},
|
errors: {},
|
||||||
},
|
},
|
||||||
paginated: {{ paginated|json_encode|raw }}
|
paginated: {{ paginated|json_encode|raw }}
|
||||||
@@ -140,7 +171,7 @@
|
|||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
return response.json();
|
return response.json();
|
||||||
}).then((data) => {
|
}).then((data) => {
|
||||||
this.users = this.users.filter(u => u.id !== user.id);
|
this.getUsers(1)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
saveUser() {
|
saveUser() {
|
||||||
@@ -155,6 +186,7 @@
|
|||||||
}).then((data) => {
|
}).then((data) => {
|
||||||
if (data.user) {
|
if (data.user) {
|
||||||
this.userForm.name = '';
|
this.userForm.name = '';
|
||||||
|
this.userForm.can_specify_subdomains = 0;
|
||||||
this.userForm.errors = {};
|
this.userForm.errors = {};
|
||||||
this.users.unshift(data.user);
|
this.users.unshift(data.user);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use Clue\React\Buzz\Browser;
|
|||||||
use Clue\React\Buzz\Message\ResponseException;
|
use Clue\React\Buzz\Message\ResponseException;
|
||||||
use GuzzleHttp\Psr7\Response;
|
use GuzzleHttp\Psr7\Response;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use Nyholm\Psr7\Request;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Ratchet\Server\IoConnection;
|
use Ratchet\Server\IoConnection;
|
||||||
use Tests\Feature\TestCase;
|
use Tests\Feature\TestCase;
|
||||||
@@ -149,6 +150,8 @@ class AdminTest extends TestCase
|
|||||||
$connectionManager = app(ConnectionManager::class);
|
$connectionManager = app(ConnectionManager::class);
|
||||||
|
|
||||||
$connection = \Mockery::mock(IoConnection::class);
|
$connection = \Mockery::mock(IoConnection::class);
|
||||||
|
$connection->httpRequest = new Request('GET', '/?authToken=some-token');
|
||||||
|
|
||||||
$connectionManager->storeConnection('some-host.text', 'fixed-subdomain', $connection);
|
$connectionManager->storeConnection('some-host.text', 'fixed-subdomain', $connection);
|
||||||
|
|
||||||
/** @var Response $response */
|
/** @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();
|
parent::setUp();
|
||||||
|
|
||||||
$this->browser = new Browser($this->loop);
|
$this->browser = new Browser($this->loop);
|
||||||
|
$this->browser = $this->browser->withOptions([
|
||||||
|
'followRedirects' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
$this->startServer();
|
$this->startServer();
|
||||||
}
|
}
|
||||||
@@ -58,6 +61,8 @@ class TunnelTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->createTestHttpServer();
|
$this->createTestHttpServer();
|
||||||
|
|
||||||
|
$this->app['config']['expose.admin.validate_auth_tokens'] = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We create an expose client that connects to our server and shares
|
* We create an expose client that connects to our server and shares
|
||||||
* the created test HTTP server.
|
* the created test HTTP server.
|
||||||
@@ -98,22 +103,96 @@ class TunnelTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->app['config']['expose.admin.validate_auth_tokens'] = true;
|
$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
|
* 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();
|
$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()
|
protected function startServer()
|
||||||
{
|
{
|
||||||
|
$this->app['config']['expose.admin.subdomain'] = 'expose';
|
||||||
$this->app['config']['expose.admin.database'] = ':memory:';
|
$this->app['config']['expose.admin.database'] = ':memory:';
|
||||||
|
|
||||||
|
$this->app['config']['expose.admin.users'] = [
|
||||||
|
'username' => 'secret',
|
||||||
|
];
|
||||||
|
|
||||||
$this->serverFactory = new Factory();
|
$this->serverFactory = new Factory();
|
||||||
|
|
||||||
$this->serverFactory->setLoop($this->loop)
|
$this->serverFactory->setLoop($this->loop)
|
||||||
|
|||||||
Reference in New Issue
Block a user