diff --git a/app/Commands/ServerAwareCommand.php b/app/Commands/ServerAwareCommand.php new file mode 100644 index 0000000..317ad9f --- /dev/null +++ b/app/Commands/ServerAwareCommand.php @@ -0,0 +1,42 @@ +getDefinition()->addOptions(Parser::parse($inheritedSignature)[2]); + + $this->configureConnectionLogger(); + } + + protected function configureConnectionLogger() + { + app()->bind(CliRequestLogger::class, function () { + return new CliRequestLogger(new ConsoleOutput()); + }); + + return $this; + } + + protected function getServerHost() + { + return $this->option('server-host') ?? config('expose.servers.'.$this->option('server').'.host', 'localhost'); + } + + protected function getServerPort() + { + return $this->option('server-port') ?? config('expose.servers.'.$this->option('server').'.port', 8080); + } +} diff --git a/app/Commands/ShareCommand.php b/app/Commands/ShareCommand.php index 6275cfd..e1bc360 100644 --- a/app/Commands/ShareCommand.php +++ b/app/Commands/ShareCommand.php @@ -4,31 +4,17 @@ namespace App\Commands; use App\Client\Factory; use App\Logger\CliRequestLogger; -use LaravelZero\Framework\Commands\Command; use React\EventLoop\LoopInterface; use Symfony\Component\Console\Output\ConsoleOutput; -class ShareCommand extends Command +class ShareCommand extends ServerAwareCommand { - protected $signature = 'share {host} {--subdomain=} {--auth=} {--server-host=} {--server-port=} {--dns=}'; + protected $signature = 'share {host} {--subdomain=} {--auth=} {--dns=}'; protected $description = 'Share a local url with a remote expose server'; - protected function configureConnectionLogger() - { - app()->bind(CliRequestLogger::class, function () { - return new CliRequestLogger(new ConsoleOutput()); - }); - - return $this; - } - public function handle() { - $this->configureConnectionLogger(); - - $serverHost = $this->option('server-host') ?? config('expose.host', 'localhost'); - $serverPort = $this->option('server-port') ?? config('expose.port', 8080); $auth = $this->option('auth') ?? config('expose.auth_token', ''); if (strstr($this->argument('host'), 'host.docker.internal')) { @@ -41,8 +27,8 @@ class ShareCommand extends Command (new Factory()) ->setLoop(app(LoopInterface::class)) - ->setHost($serverHost) - ->setPort($serverPort) + ->setHost($this->getServerHost()) + ->setPort($this->getServerPort()) ->setAuth($auth) ->createClient() ->share($this->argument('host'), explode(',', $this->option('subdomain'))) diff --git a/app/Commands/ShareCurrentWorkingDirectoryCommand.php b/app/Commands/ShareCurrentWorkingDirectoryCommand.php index 5d2aad7..b682c3d 100644 --- a/app/Commands/ShareCurrentWorkingDirectoryCommand.php +++ b/app/Commands/ShareCurrentWorkingDirectoryCommand.php @@ -4,7 +4,7 @@ namespace App\Commands; class ShareCurrentWorkingDirectoryCommand extends ShareCommand { - protected $signature = 'share-cwd {host?} {--subdomain=} {--auth=} {--server-host=} {--server-port=}'; + protected $signature = 'share-cwd {host?} {--subdomain=} {--auth=}'; public function handle() { diff --git a/app/Commands/ShareFilesCommand.php b/app/Commands/ShareFilesCommand.php index 0dd48ad..43cf6da 100644 --- a/app/Commands/ShareFilesCommand.php +++ b/app/Commands/ShareFilesCommand.php @@ -8,37 +8,24 @@ use LaravelZero\Framework\Commands\Command; use React\EventLoop\LoopInterface; use Symfony\Component\Console\Output\ConsoleOutput; -class ShareFilesCommand extends Command +class ShareFilesCommand extends ServerAwareCommand { - protected $signature = 'share-files {folder=.} {--name=} {--subdomain=} {--auth=} {--server-host=} {--server-port=}'; + protected $signature = 'share-files {folder=.} {--name=} {--subdomain=} {--auth=}'; protected $description = 'Share a local folder with a remote expose server'; - protected function configureConnectionLogger() - { - app()->bind(CliRequestLogger::class, function () { - return new CliRequestLogger(new ConsoleOutput()); - }); - - return $this; - } - public function handle() { if (! is_dir($this->argument('folder'))) { throw new \InvalidArgumentException('The folder '.$this->argument('folder').' does not exist.'); } - $this->configureConnectionLogger(); - - $serverHost = $this->option('server-host') ?? config('expose.host', 'localhost'); - $serverPort = $this->option('server-port') ?? config('expose.port', 8080); $auth = $this->option('auth') ?? config('expose.auth_token', ''); (new Factory()) ->setLoop(app(LoopInterface::class)) - ->setHost($serverHost) - ->setPort($serverPort) + ->setHost($this->getServerHost()) + ->setPort($this->getServerPort()) ->setAuth($auth) ->createClient() ->shareFolder( diff --git a/app/Commands/SharePortCommand.php b/app/Commands/SharePortCommand.php index 40509c3..ac25685 100644 --- a/app/Commands/SharePortCommand.php +++ b/app/Commands/SharePortCommand.php @@ -3,36 +3,22 @@ namespace App\Commands; use App\Client\Factory; -use App\Logger\CliRequestLogger; -use LaravelZero\Framework\Commands\Command; use React\EventLoop\LoopInterface; -use Symfony\Component\Console\Output\ConsoleOutput; -class SharePortCommand extends Command +class SharePortCommand extends ServerAwareCommand { protected $signature = 'share-port {port} {--auth=}'; protected $description = 'Share a local port with a remote expose server'; - protected function configureConnectionLogger() - { - app()->bind(CliRequestLogger::class, function () { - return new CliRequestLogger(new ConsoleOutput()); - }); - - return $this; - } - public function handle() { - $this->configureConnectionLogger(); - $auth = $this->option('auth') ?? config('expose.auth_token', ''); (new Factory()) ->setLoop(app(LoopInterface::class)) - ->setHost(config('expose.host', 'localhost')) - ->setPort(config('expose.port', 8080)) + ->setHost($this->getServerHost()) + ->setPort($this->getServerPort()) ->setAuth($auth) ->createClient() ->sharePort($this->argument('port')) diff --git a/app/Server/Http/Controllers/ControlMessageController.php b/app/Server/Http/Controllers/ControlMessageController.php index dc8b34b..cfc2f85 100644 --- a/app/Server/Http/Controllers/ControlMessageController.php +++ b/app/Server/Http/Controllers/ControlMessageController.php @@ -251,7 +251,7 @@ class ControlMessageController implements MessageComponentInterface $controlConnection = $this->connectionManager->findControlConnectionForSubdomain($subdomain); - if (! is_null($controlConnection) || $subdomain === config('expose.admin.subdomain')) { + if (! is_null($controlConnection) || $subdomain === config('expose.admin.subdomain') || in_array($subdomain, config('expose.admin.reserved_subdomains', []))) { $message = config('expose.admin.messages.subdomain_taken'); $message = str_replace(':subdomain', $subdomain, $message); @@ -279,7 +279,7 @@ class ControlMessageController implements MessageComponentInterface $connection->send(json_encode([ 'event' => 'authenticationFailed', 'data' => [ - 'message' => config('expose.admin.messages.custom_subdomain_unauthorized'), + 'message' => config('expose.admin.messages.tcp_port_sharing_unauthorized'), ], ])); $connection->close(); diff --git a/config/expose.php b/config/expose.php index ec09423..20fdeaa 100644 --- a/config/expose.php +++ b/config/expose.php @@ -4,30 +4,20 @@ return [ /* |-------------------------------------------------------------------------- - | Host + | Servers |-------------------------------------------------------------------------- | - | The expose server to connect to. By default, expose is using the free - | sharedwithexpose.com server, offered by Beyond Code. You will need a free - | Beyond Code account in order to authenticate with the server. - | Feel free to host your own server and change this value. + | The available Expose servers that your client can connect to. + | When sharing sites or TCP ports, you can specify the server + | that should be used using the `--server=` option. | */ - 'host' => 'sharedwithexpose.com', - - /* - |-------------------------------------------------------------------------- - | Port - |-------------------------------------------------------------------------- - | - | The port that expose will try to connect to. If you want to bypass - | firewalls and have proper SSL encrypted tunnels, make sure to use - | port 443 and use a reverse proxy for Expose. - | - | The free default server is already running on port 443. - | - */ - 'port' => 443, + 'servers' => [ + 'default' => [ + 'host' => 'sharedwithexpose.com', + 'port' => 443, + ], + ], /* |-------------------------------------------------------------------------- @@ -218,6 +208,17 @@ return [ */ 'subdomain' => 'expose', + /* + |-------------------------------------------------------------------------- + | Reserved Subdomain + |-------------------------------------------------------------------------- + | + | Specify any subdomains that you don't want to be able to register + | on your expose server. + | + */ + 'reserved_subdomains' => [], + /* |-------------------------------------------------------------------------- | Subdomain Generator @@ -277,6 +278,8 @@ return [ 'custom_subdomain_unauthorized' => 'You are not allowed to specify custom subdomains. Please upgrade to Expose Pro. Assigning a random subdomain instead.', + 'tcp_port_sharing_unauthorized' => 'You are not allowed to share TCP ports. Please upgrade to Expose Pro.', + 'no_free_tcp_port_available' => 'There are no free TCP ports available on this server. Please try again later.', ], ], diff --git a/resources/views/client/dashboard.twig b/resources/views/client/dashboard.twig index e14d35c..a6cf14c 100644 --- a/resources/views/client/dashboard.twig +++ b/resources/views/client/dashboard.twig @@ -1,7 +1,7 @@
Expose
@@ -113,9 +116,32 @@ {% endfor %}@{ log.request.method } @@ -164,27 +193,31 @@ {% endif %} @{ log.performed_at }