This commit is contained in:
Marcel Pociot
2021-06-17 13:17:32 +02:00
parent 7742658527
commit 19606a78af
16 changed files with 470 additions and 10 deletions

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Client\Support;
use PhpParser\Node;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Name;
use PhpParser\NodeVisitorAbstract;
class ClearDomainNodeVisitor extends NodeVisitorAbstract
{
public function enterNode(Node $node)
{
if ($node instanceof Node\Expr\ArrayItem && $node->key && $node->key->value === 'default_domain') {
$node->value = new ConstFetch(
new Name('null')
);
return $node;
}
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Client\Support;
use PhpParser\Node;
use PhpParser\Node\Scalar\String_;
use PhpParser\NodeVisitorAbstract;
class DefaultDomainNodeVisitor extends NodeVisitorAbstract
{
/** @var string */
protected $domain;
public function __construct(string $domain)
{
$this->domain = $domain;
}
public function leaveNode(Node $node)
{
if ($node instanceof Node\Expr\ArrayItem && $node->key && $node->key->value === 'default_domain') {
$node->value = new String_($this->domain);
return $node;
}
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Client\Support;
use PhpParser\Node;
use PhpParser\Node\Scalar\String_;
use PhpParser\NodeVisitorAbstract;
class DefaultServerNodeVisitor extends NodeVisitorAbstract
{
/** @var string */
protected $server;
public function __construct(string $server)
{
$this->server = $server;
}
public function enterNode(Node $node)
{
if ($node instanceof Node\Expr\ArrayItem && $node->key && $node->key->value === 'default_server') {
$node->value = new String_($this->server);
return $node;
}
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Client\Support;
use PhpParser\Node;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Name;
use PhpParser\NodeVisitorAbstract;
class InsertDefaultDomainNodeVisitor extends NodeVisitorAbstract
{
public function leaveNode(Node $node)
{
if ($node instanceof Node\Expr\ArrayItem && $node->key && $node->key->value === 'auth_token') {
$defaultDomainNode = new Node\Expr\ArrayItem(
new ConstFetch(
new Name('null')
),
new Node\Scalar\String_('default_domain')
);
return [
$node,
$defaultDomainNode,
];
}
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Client\Support;
use PhpParser\Node;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Name;
use PhpParser\NodeVisitorAbstract;
class InsertDefaultServerNodeVisitor extends NodeVisitorAbstract
{
public function leaveNode(Node $node)
{
if ($node instanceof Node\Expr\ArrayItem && $node->key && $node->key->value === 'auth_token') {
$defaultServerNode = new Node\Expr\ArrayItem(
new ConstFetch(
new Name('null')
),
new Node\Scalar\String_('default_server')
);
return [
$node,
$defaultServerNode,
];
}
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Client\Support; namespace App\Client\Support;
use PhpParser\Node; use PhpParser\Node;
use PhpParser\Node\Scalar\String_;
use PhpParser\NodeVisitorAbstract; use PhpParser\NodeVisitorAbstract;
class TokenNodeVisitor extends NodeVisitorAbstract class TokenNodeVisitor extends NodeVisitorAbstract
@@ -18,7 +19,7 @@ class TokenNodeVisitor extends NodeVisitorAbstract
public function enterNode(Node $node) public function enterNode(Node $node)
{ {
if ($node instanceof Node\Expr\ArrayItem && $node->key && $node->key->value === 'auth_token') { if ($node instanceof Node\Expr\ArrayItem && $node->key && $node->key->value === 'auth_token') {
$node->value->value = $this->token; $node->value = new String_($this->token);
return $node; return $node;
} }

View File

@@ -0,0 +1,83 @@
<?php
namespace App\Commands;
use App\Client\Support\ClearDomainNodeVisitor;
use App\Client\Support\DefaultDomainNodeVisitor;
use App\Client\Support\DefaultServerNodeVisitor;
use App\Client\Support\InsertDefaultDomainNodeVisitor;
use Illuminate\Console\Command;
use PhpParser\Lexer\Emulative;
use PhpParser\Node;
use PhpParser\NodeFinder;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\CloningVisitor;
use PhpParser\Parser\Php7;
use PhpParser\PrettyPrinter\Standard;
class ClearDefaultDomainCommand extends Command
{
protected $signature = 'default-domain:clear';
protected $description = 'Clear the default domain to use with Expose.';
public function handle()
{
$this->info('Clearing the default Expose domain.');
$configFile = implode(DIRECTORY_SEPARATOR, [
$_SERVER['HOME'] ?? $_SERVER['USERPROFILE'],
'.expose',
'config.php',
]);
if (! file_exists($configFile)) {
@mkdir(dirname($configFile), 0777, true);
$updatedConfigFile = $this->modifyConfigurationFile(base_path('config/expose.php'));
} else {
$updatedConfigFile = $this->modifyConfigurationFile($configFile);
}
file_put_contents($configFile, $updatedConfigFile);
}
protected function modifyConfigurationFile(string $configFile)
{
$lexer = new Emulative([
'usedAttributes' => [
'comments',
'startLine', 'endLine',
'startTokenPos', 'endTokenPos',
],
]);
$parser = new Php7($lexer);
$oldStmts = $parser->parse(file_get_contents($configFile));
$oldTokens = $lexer->getTokens();
$nodeTraverser = new NodeTraverser;
$nodeTraverser->addVisitor(new CloningVisitor());
$newStmts = $nodeTraverser->traverse($oldStmts);
$nodeFinder = new NodeFinder;
$defaultDomainNode = $nodeFinder->findFirst($newStmts, function(Node $node) {
return ($node instanceof Node\Expr\ArrayItem && $node->key && $node->key->value === 'default_domain');
});
if (is_null($defaultDomainNode)) {
$nodeTraverser = new NodeTraverser;
$nodeTraverser->addVisitor(new InsertDefaultDomainNodeVisitor());
$newStmts = $nodeTraverser->traverse($newStmts);
}
$nodeTraverser = new NodeTraverser;
$nodeTraverser->addVisitor(new ClearDomainNodeVisitor());
$newStmts = $nodeTraverser->traverse($newStmts);
$prettyPrinter = new Standard();
return $prettyPrinter->printFormatPreserving($newStmts, $oldStmts, $oldTokens);
}
}

View File

@@ -14,13 +14,13 @@ abstract class ServerAwareCommand extends Command
{ {
const DEFAULT_HOSTNAME = 'sharedwithexpose.com'; const DEFAULT_HOSTNAME = 'sharedwithexpose.com';
const DEFAULT_PORT = 443; const DEFAULT_PORT = 443;
const DEFAULT_SERVER_ENDPOINT = 'https://beyondco.de/api/expose/servers'; const DEFAULT_SERVER_ENDPOINT = 'https://expose.beyondco.de/api/servers';
public function __construct() public function __construct()
{ {
parent::__construct(); parent::__construct();
$inheritedSignature = '{--server=default} {--server-host=} {--server-port=}'; $inheritedSignature = '{--server=} {--server-host=} {--server-port=}';
$this->getDefinition()->addOptions(Parser::parse($inheritedSignature)[2]); $this->getDefinition()->addOptions(Parser::parse($inheritedSignature)[2]);
@@ -51,7 +51,7 @@ abstract class ServerAwareCommand extends Command
return static::DEFAULT_HOSTNAME; return static::DEFAULT_HOSTNAME;
} }
$server = $this->option('server'); $server = $this->option('server') ?? config('expose.default_server');
$host = config('expose.servers.'.$server.'.host'); $host = config('expose.servers.'.$server.'.host');
if (! is_null($host)) { if (! is_null($host)) {
@@ -76,7 +76,7 @@ abstract class ServerAwareCommand extends Command
return static::DEFAULT_PORT; return static::DEFAULT_PORT;
} }
$server = $this->option('server'); $server = $this->option('server') ?? config('expose.default_server');
$host = config('expose.servers.'.$server.'.port'); $host = config('expose.servers.'.$server.'.port');
if (! is_null($host)) { if (! is_null($host)) {

View File

@@ -0,0 +1,98 @@
<?php
namespace App\Commands;
use App\Client\Support\DefaultDomainNodeVisitor;
use App\Client\Support\DefaultServerNodeVisitor;
use App\Client\Support\InsertDefaultDomainNodeVisitor;
use Illuminate\Console\Command;
use PhpParser\Lexer\Emulative;
use PhpParser\Node;
use PhpParser\NodeFinder;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\CloningVisitor;
use PhpParser\Parser\Php7;
use PhpParser\PrettyPrinter\Standard;
class SetDefaultDomainCommand extends Command
{
protected $signature = 'default-domain {domain?} {--server=}';
protected $description = 'Set or retrieve the default domain to use with Expose.';
public function handle()
{
$domain = $this->argument('domain');
$server = $this->option('server');
if (! is_null($domain)) {
$this->info('Setting the Expose default domain to "'.$domain.'"');
$configFile = implode(DIRECTORY_SEPARATOR, [
$_SERVER['HOME'] ?? $_SERVER['USERPROFILE'],
'.expose',
'config.php',
]);
if (! file_exists($configFile)) {
@mkdir(dirname($configFile), 0777, true);
$updatedConfigFile = $this->modifyConfigurationFile(base_path('config/expose.php'), $domain, $server);
} else {
$updatedConfigFile = $this->modifyConfigurationFile($configFile, $domain, $server);
}
file_put_contents($configFile, $updatedConfigFile);
return;
}
if (is_null($domain = config('expose.default_domain'))) {
$this->info('There is no default domain specified.');
} else {
$this->info('Current default domain: '.$domain);
}
}
protected function modifyConfigurationFile(string $configFile, string $domain, ?string $server)
{
$lexer = new Emulative([
'usedAttributes' => [
'comments',
'startLine', 'endLine',
'startTokenPos', 'endTokenPos',
],
]);
$parser = new Php7($lexer);
$oldStmts = $parser->parse(file_get_contents($configFile));
$oldTokens = $lexer->getTokens();
$nodeTraverser = new NodeTraverser;
$nodeTraverser->addVisitor(new CloningVisitor());
$newStmts = $nodeTraverser->traverse($oldStmts);
$nodeFinder = new NodeFinder;
$defaultDomainNode = $nodeFinder->findFirst($newStmts, function(Node $node) {
return ($node instanceof Node\Expr\ArrayItem && $node->key && $node->key->value === 'default_domain');
});
if (is_null($defaultDomainNode)) {
$nodeTraverser = new NodeTraverser;
$nodeTraverser->addVisitor(new InsertDefaultDomainNodeVisitor());
$newStmts = $nodeTraverser->traverse($newStmts);
}
$nodeTraverser = new NodeTraverser;
$nodeTraverser->addVisitor(new DefaultDomainNodeVisitor($domain));
if (! is_null($server)) {
$nodeTraverser->addVisitor(new DefaultServerNodeVisitor($server));
}
$newStmts = $nodeTraverser->traverse($newStmts);
$prettyPrinter = new Standard();
return $prettyPrinter->printFormatPreserving($newStmts, $oldStmts, $oldTokens);
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace App\Commands;
use App\Client\Support\DefaultDomainNodeVisitor;
use App\Client\Support\DefaultServerNodeVisitor;
use App\Client\Support\InsertDefaultDomainNodeVisitor;
use App\Client\Support\InsertDefaultServerNodeVisitor;
use Illuminate\Console\Command;
use PhpParser\Lexer\Emulative;
use PhpParser\Node;
use PhpParser\NodeFinder;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\CloningVisitor;
use PhpParser\Parser\Php7;
use PhpParser\PrettyPrinter\Standard;
class SetDefaultServerCommand extends Command
{
protected $signature = 'default-server {server?}';
protected $description = 'Set or retrieve the default server to use with Expose.';
public function handle()
{
$server = $this->argument('server');
if (! is_null($server)) {
$this->info('Setting the Expose default server to "'.$server.'"');
$configFile = implode(DIRECTORY_SEPARATOR, [
$_SERVER['HOME'] ?? $_SERVER['USERPROFILE'],
'.expose',
'config.php',
]);
if (! file_exists($configFile)) {
@mkdir(dirname($configFile), 0777, true);
$updatedConfigFile = $this->modifyConfigurationFile(base_path('config/expose.php'), $server);
} else {
$updatedConfigFile = $this->modifyConfigurationFile($configFile, $server);
}
file_put_contents($configFile, $updatedConfigFile);
return;
}
if (is_null($server = config('expose.default_server'))) {
$this->info('There is no default server specified.');
} else {
$this->info('Current default server: '.$server);
}
}
protected function modifyConfigurationFile(string $configFile, string $server)
{
$lexer = new Emulative([
'usedAttributes' => [
'comments',
'startLine', 'endLine',
'startTokenPos', 'endTokenPos',
],
]);
$parser = new Php7($lexer);
$oldStmts = $parser->parse(file_get_contents($configFile));
$oldTokens = $lexer->getTokens();
$nodeTraverser = new NodeTraverser;
$nodeTraverser->addVisitor(new CloningVisitor());
$newStmts = $nodeTraverser->traverse($oldStmts);
$nodeFinder = new NodeFinder;
$defaultServerNode = $nodeFinder->findFirst($newStmts, function(Node $node) {
return ($node instanceof Node\Expr\ArrayItem && $node->key && $node->key->value === 'default_server');
});
if (is_null($defaultServerNode)) {
$nodeTraverser = new NodeTraverser;
$nodeTraverser->addVisitor(new InsertDefaultServerNodeVisitor());
$newStmts = $nodeTraverser->traverse($newStmts);
}
$nodeTraverser = new NodeTraverser;
$nodeTraverser->addVisitor(new DefaultServerNodeVisitor($server));
$newStmts = $nodeTraverser->traverse($newStmts);
$prettyPrinter = new Standard();
return $prettyPrinter->printFormatPreserving($newStmts, $oldStmts, $oldTokens);
}
}

View File

@@ -23,6 +23,16 @@ class ShareCommand extends ServerAwareCommand
config(['expose.dns' => empty($this->option('dns')) ? true : $this->option('dns')]); config(['expose.dns' => empty($this->option('dns')) ? true : $this->option('dns')]);
} }
$domain = config('expose.default_domain');
if (! is_null($this->option('server'))) {
$domain = null;
}
if (! is_null($this->option('domain'))) {
$domain = $this->option('domain');
}
(new Factory()) (new Factory())
->setLoop(app(LoopInterface::class)) ->setLoop(app(LoopInterface::class))
->setHost($this->getServerHost()) ->setHost($this->getServerHost())
@@ -32,7 +42,7 @@ class ShareCommand extends ServerAwareCommand
->share( ->share(
$this->argument('host'), $this->argument('host'),
explode(',', $this->option('subdomain')), explode(',', $this->option('subdomain')),
$this->option('domain') $domain
) )
->createHttpServer() ->createHttpServer()
->run(); ->run();

View File

@@ -14,7 +14,7 @@ class StoreAuthenticationTokenCommand extends Command
{ {
protected $signature = 'token {token?}'; protected $signature = 'token {token?}';
protected $description = 'Set or retrieve the authentication token to use with expose.'; protected $description = 'Set or retrieve the authentication token to use with Expose.';
public function handle() public function handle()
{ {

Binary file not shown.

View File

@@ -17,7 +17,8 @@
], ],
"require": { "require": {
"php": "^7.3.0 || ^8.0", "php": "^7.3.0 || ^8.0",
"ext-json": "*" "ext-json": "*",
"padraic/phar-updater": "^1.0.6"
}, },
"require-dev": { "require-dev": {
"cboden/ratchet": "^0.4.3", "cboden/ratchet": "^0.4.3",

View File

@@ -13,7 +13,7 @@ return [
| |
*/ */
'servers' => [ 'servers' => [
'default' => [ 'main' => [
'host' => 'sharedwithexpose.com', 'host' => 'sharedwithexpose.com',
'port' => 443, 'port' => 443,
], ],
@@ -32,7 +32,18 @@ return [
| if available. | if available.
| |
*/ */
'server_endpoint' => 'https://expose.beyondco.de/api/expose/servers', 'server_endpoint' => 'https://expose.beyondco.de/api/servers',
/*
|--------------------------------------------------------------------------
| Default Server
|--------------------------------------------------------------------------
|
| The default server from the servers array,
| or the servers endpoint above.
|
*/
'default_server' => 'main',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@@ -60,6 +71,20 @@ return [
*/ */
'auth_token' => '', 'auth_token' => '',
/*
|--------------------------------------------------------------------------
| Default Domain
|--------------------------------------------------------------------------
|
| The custom domain to use when sharing sites with Expose.
| You can register your own custom domain using Expose Pro
| Learn more at: https://expose.beyondco.de/docs/TODO
|
| > expose default-domain YOUR-CUSTOM-WHITELABEL-DOMAIN
|
*/
'default_domain' => null,
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Default TLD | Default TLD

View File

@@ -25,6 +25,20 @@
</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="token"
class="block text-sm font-medium leading-5 text-gray-700 sm:mt-px sm:pt-2">
Token
</label>
<div class="mt-1 sm:mt-0 sm:col-span-2">
<div class="max-w-lg flex rounded-md shadow-sm">
<input id="token"
type="text"
v-model="userForm.token"
class="flex-1 border-gray-300 block w-full rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5"/>
</div>
</div>
</div>
<div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:pt-5"> <div class="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:pt-5">
<label for="can_specify_subdomains" <label for="can_specify_subdomains"
class="block text-sm font-medium leading-5 text-gray-700 sm:mt-px sm:pt-2"> class="block text-sm font-medium leading-5 text-gray-700 sm:mt-px sm:pt-2">
@@ -205,6 +219,7 @@
search: '', search: '',
userForm: { userForm: {
name: '', name: '',
token: '',
can_specify_subdomains: true, can_specify_subdomains: true,
can_share_tcp_ports: true, can_share_tcp_ports: true,
max_connections: 0, max_connections: 0,
@@ -262,6 +277,7 @@
}).then((data) => { }).then((data) => {
if (data.user) { if (data.user) {
this.userForm.name = ''; this.userForm.name = '';
this.userForm.token = '';
this.userForm.can_specify_subdomains = true; this.userForm.can_specify_subdomains = true;
this.userForm.can_share_tcp_ports = true; this.userForm.can_share_tcp_ports = true;
this.userForm.max_connections = 0; this.userForm.max_connections = 0;