diff --git a/app/Client/Support/ClearDomainNodeVisitor.php b/app/Client/Support/ClearDomainNodeVisitor.php new file mode 100644 index 0000000..04ad560 --- /dev/null +++ b/app/Client/Support/ClearDomainNodeVisitor.php @@ -0,0 +1,22 @@ +key && $node->key->value === 'default_domain') { + $node->value = new ConstFetch( + new Name('null') + ); + + return $node; + } + } +} diff --git a/app/Client/Support/DefaultDomainNodeVisitor.php b/app/Client/Support/DefaultDomainNodeVisitor.php new file mode 100644 index 0000000..4d2382f --- /dev/null +++ b/app/Client/Support/DefaultDomainNodeVisitor.php @@ -0,0 +1,27 @@ +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; + } + } +} diff --git a/app/Client/Support/DefaultServerNodeVisitor.php b/app/Client/Support/DefaultServerNodeVisitor.php new file mode 100644 index 0000000..d5f3b91 --- /dev/null +++ b/app/Client/Support/DefaultServerNodeVisitor.php @@ -0,0 +1,27 @@ +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; + } + } +} diff --git a/app/Client/Support/InsertDefaultDomainNodeVisitor.php b/app/Client/Support/InsertDefaultDomainNodeVisitor.php new file mode 100644 index 0000000..2e22188 --- /dev/null +++ b/app/Client/Support/InsertDefaultDomainNodeVisitor.php @@ -0,0 +1,28 @@ +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, + ]; + } + } +} diff --git a/app/Client/Support/InsertDefaultServerNodeVisitor.php b/app/Client/Support/InsertDefaultServerNodeVisitor.php new file mode 100644 index 0000000..657391f --- /dev/null +++ b/app/Client/Support/InsertDefaultServerNodeVisitor.php @@ -0,0 +1,28 @@ +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, + ]; + } + } +} diff --git a/app/Client/Support/TokenNodeVisitor.php b/app/Client/Support/TokenNodeVisitor.php index 40df5b8..74bf0be 100644 --- a/app/Client/Support/TokenNodeVisitor.php +++ b/app/Client/Support/TokenNodeVisitor.php @@ -3,6 +3,7 @@ namespace App\Client\Support; use PhpParser\Node; +use PhpParser\Node\Scalar\String_; use PhpParser\NodeVisitorAbstract; class TokenNodeVisitor extends NodeVisitorAbstract @@ -18,7 +19,7 @@ class TokenNodeVisitor extends NodeVisitorAbstract public function enterNode(Node $node) { 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; } diff --git a/app/Commands/ClearDefaultDomainCommand.php b/app/Commands/ClearDefaultDomainCommand.php new file mode 100644 index 0000000..6cc6688 --- /dev/null +++ b/app/Commands/ClearDefaultDomainCommand.php @@ -0,0 +1,83 @@ +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); + } +} diff --git a/app/Commands/ServerAwareCommand.php b/app/Commands/ServerAwareCommand.php index b9ccf2e..fd583fc 100644 --- a/app/Commands/ServerAwareCommand.php +++ b/app/Commands/ServerAwareCommand.php @@ -14,13 +14,13 @@ abstract class ServerAwareCommand extends Command { const DEFAULT_HOSTNAME = 'sharedwithexpose.com'; 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() { parent::__construct(); - $inheritedSignature = '{--server=default} {--server-host=} {--server-port=}'; + $inheritedSignature = '{--server=} {--server-host=} {--server-port=}'; $this->getDefinition()->addOptions(Parser::parse($inheritedSignature)[2]); @@ -51,7 +51,7 @@ abstract class ServerAwareCommand extends Command return static::DEFAULT_HOSTNAME; } - $server = $this->option('server'); + $server = $this->option('server') ?? config('expose.default_server'); $host = config('expose.servers.'.$server.'.host'); if (! is_null($host)) { @@ -76,7 +76,7 @@ abstract class ServerAwareCommand extends Command return static::DEFAULT_PORT; } - $server = $this->option('server'); + $server = $this->option('server') ?? config('expose.default_server'); $host = config('expose.servers.'.$server.'.port'); if (! is_null($host)) { diff --git a/app/Commands/SetDefaultDomainCommand.php b/app/Commands/SetDefaultDomainCommand.php new file mode 100644 index 0000000..579cbd5 --- /dev/null +++ b/app/Commands/SetDefaultDomainCommand.php @@ -0,0 +1,98 @@ +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); + } +} diff --git a/app/Commands/SetDefaultServerCommand.php b/app/Commands/SetDefaultServerCommand.php new file mode 100644 index 0000000..bb2109c --- /dev/null +++ b/app/Commands/SetDefaultServerCommand.php @@ -0,0 +1,94 @@ +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); + } +} diff --git a/app/Commands/ShareCommand.php b/app/Commands/ShareCommand.php index c668e1d..a17592f 100644 --- a/app/Commands/ShareCommand.php +++ b/app/Commands/ShareCommand.php @@ -23,6 +23,16 @@ class ShareCommand extends ServerAwareCommand 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()) ->setLoop(app(LoopInterface::class)) ->setHost($this->getServerHost()) @@ -32,7 +42,7 @@ class ShareCommand extends ServerAwareCommand ->share( $this->argument('host'), explode(',', $this->option('subdomain')), - $this->option('domain') + $domain ) ->createHttpServer() ->run(); diff --git a/app/Commands/StoreAuthenticationTokenCommand.php b/app/Commands/StoreAuthenticationTokenCommand.php index dfdfc61..d664ac9 100644 --- a/app/Commands/StoreAuthenticationTokenCommand.php +++ b/app/Commands/StoreAuthenticationTokenCommand.php @@ -14,7 +14,7 @@ class StoreAuthenticationTokenCommand extends Command { 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() { diff --git a/builds/expose b/builds/expose index 3ee298d..88c8235 100755 Binary files a/builds/expose and b/builds/expose differ diff --git a/composer.json b/composer.json index e706d97..e2907d5 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,8 @@ ], "require": { "php": "^7.3.0 || ^8.0", - "ext-json": "*" + "ext-json": "*", + "padraic/phar-updater": "^1.0.6" }, "require-dev": { "cboden/ratchet": "^0.4.3", diff --git a/config/expose.php b/config/expose.php index 1af51d2..e1b8713 100644 --- a/config/expose.php +++ b/config/expose.php @@ -13,7 +13,7 @@ return [ | */ 'servers' => [ - 'default' => [ + 'main' => [ 'host' => 'sharedwithexpose.com', 'port' => 443, ], @@ -32,7 +32,18 @@ return [ | 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' => '', + /* + |-------------------------------------------------------------------------- + | 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 diff --git a/resources/views/server/users/index.twig b/resources/views/server/users/index.twig index 6d5c6c7..166981e 100644 --- a/resources/views/server/users/index.twig +++ b/resources/views/server/users/index.twig @@ -25,6 +25,20 @@ +
+ +
+
+ +
+
+