From da450b510a36452d13d74b392b8ed6812cf6241a Mon Sep 17 00:00:00 2001 From: Christopher Vagnetoft Date: Tue, 12 Mar 2024 00:28:31 +0100 Subject: [PATCH] Updated dependencies, improved config * Configuration now key-value map with friendly accessors. * Configuration file maps 1:1 --- bin/mercureactd | 19 ++++------- composer.lock | 8 ++--- mercureactd.conf.dist | 24 +++++++------- src/Configuration.php | 77 +++++++++++++++++++------------------------ src/Daemon.php | 10 +++--- 5 files changed, 62 insertions(+), 76 deletions(-) diff --git a/bin/mercureactd b/bin/mercureactd index de75302..4532d1c 100755 --- a/bin/mercureactd +++ b/bin/mercureactd @@ -31,8 +31,9 @@ if (isset($opts['C'])) { exit(1); } file_put_contents($file, <<addListener([ - 'address' => '127.0.0.1:8888', - 'subscribe' => [ - 'anonymous' => true - ] - ]) + ->setListenAddress('127.0.0.1:8888') + ->setAllowOriginHeader("*") + ->setContentSecurityPolicyHeader("default-src * 'self' http: 'unsafe-eval' 'unsafe-inline'; connect-src * 'self'") ->setAllowAnonymousSubscribe(true) ->setJwtSecret("!ChangeThisMercureHubJWTSecretKey!"); } -if (count($config->getListeners()) == 0) { - fwrite(STDERR, "No listeners available\n"); - exit(1); -} - $daemon = new Daemon($config); $daemon->start(); \ No newline at end of file diff --git a/composer.lock b/composer.lock index a059db8..2cf496c 100644 --- a/composer.lock +++ b/composer.lock @@ -249,11 +249,11 @@ }, { "name": "noccylabs/simple-jwt", - "version": "0.2.1", + "version": "0.2.2", "dist": { "type": "zip", - "url": "https://dev.noccylabs.info/api/packages/noccy/composer/files/noccylabs%2Fsimple-jwt/0.2.1/noccylabs-simple-jwt.0.2.1.zip", - "shasum": "d55b26f9c8dbe8be4b49786492818085982a5089" + "url": "https://dev.noccylabs.info/api/packages/noccy/composer/files/noccylabs%2Fsimple-jwt/0.2.2/noccylabs-simple-jwt.0.2.2.zip", + "shasum": "57d3fd6f5c3bebb62f15477beffc5425f6f5b7d9" }, "require": { "ext-json": "*", @@ -279,7 +279,7 @@ } ], "description": "Simple library for generating and verifying JWT tokens", - "time": "2023-04-10T00:31:31+00:00" + "time": "2024-03-11T22:37:17+00:00" }, { "name": "psr/http-message", diff --git a/mercureactd.conf.dist b/mercureactd.conf.dist index 66a68fb..20228d4 100644 --- a/mercureactd.conf.dist +++ b/mercureactd.conf.dist @@ -1,20 +1,20 @@ # Mercureact default configuration file # Please make a copy of me before editing -listeners: - - address: 0.0.0.0:9000 +server: + address: 0.0.0.0:9000 - # Setup CORS headers - cors: - # Access-Control-Allow-Origin - allow_origin: '*' - # Content-Security-Policy - csp: "default-src * 'self' http: 'unsafe-eval' 'unsafe-inline'; connect-src * 'self'" + # Setup CORS headers + cors: + # Access-Control-Allow-Origin + allow_origin: '*' + # Content-Security-Policy + csp: "default-src * 'self' http: 'unsafe-eval' 'unsafe-inline'; connect-src * 'self'" - # Setup encryption - encryption: - cert: foo.pem - key: foo.key + # Setup encryption + encryption: + cert: foo.pem + key: foo.key # Enable websockets websocket: diff --git a/src/Configuration.php b/src/Configuration.php index 2437b4b..6c7ade1 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -6,13 +6,8 @@ use Symfony\Component\Yaml\Yaml; class Configuration { - private ?string $publicUrl = null; + private array $config = []; - private ?string $jwtSecret = null; - - private bool $allowAnonymousSubscribe = false; - - private array $listeners = []; public static function createDefault(): Configuration { @@ -30,81 +25,77 @@ class Configuration $data = file_get_contents($file); $yaml = Yaml::parse($data); - if (isset($yaml['security'])) { - $security = $yaml['security']; - if (isset($security['jwt_secret'])) - $config->setJwtSecret($security['jwt_secret']); - } - - if (isset($yaml['subscribe'])) { - $subscribe = $yaml['subscribe']; - if (isset($subscribe['allow_anonymous'])) - $config->setAllowAnonymousSubscribe(boolval($subscribe['allow_anonymous'])); - } - - if (isset($yaml['listeners'])) { - foreach ($yaml['listeners'] as $listener) { - if (!is_array($listener)) { - throw new \Exception("Bad listener config"); + $unwrap = null; // mute IDE complains about $unwrap not defined + $unwrap = function (array $array, Configuration $target, array $path=[]) use (&$unwrap) { + foreach ($array as $key=>$value) { + if (is_array($value)) { + $unwrap($value, $target, [ ...$path, $key ]); + } else { + $key = join(".", [ ...$path, $key ]); + $target->config[$key] = $value; } - $config->addListener($listener); } - } + }; + $unwrap($yaml, $config); return $config; } public function setPublicUrl(string $publicUrl): self { - $this->publicUrl = $publicUrl; + $this->config['server.public_url'] = $publicUrl; return $this; } public function getPublicUrl(): ?string { - return $this->publicUrl; + return $this->config['server.public_url']??null; } public function setJwtSecret(string $secret): self { - $this->jwtSecret = $secret; + $this->config['security.jwt_secret'] = $secret; return $this; } public function getJwtSecret(): ?string { - return $this->jwtSecret; + return $this->config['security.jwt_secret']??null; } function getAllowAnonymousSubscribe():bool { - return $this->allowAnonymousSubscribe; + return $this->config['subscribe.allow_anonymous']??false; } function setAllowAnonymousSubscribe(bool $allowAnonymousSubscribe): self { - $this->allowAnonymousSubscribe = $allowAnonymousSubscribe; + $this->config['subscribe.allow_anonymous'] = $allowAnonymousSubscribe; return $this; } - function addListener(array $config): self + public function setListenAddress(string $address): self { - $this->listeners[] = [ - 'address' => $config['address']??throw new \Exception("Address can't be empty"), - 'cors' => isset($config['cors'])?[ - 'allow_origin' => $config['cors']['allow_origin']??'*', - 'csp' => $config['cors']['csp']??'default-src * \'self\'', - ]:[ - 'allow_origin' => '*', - 'csp' => 'default-src * \'self\'', - ], - ]; + $this->config['server.address'] = $address; return $this; } - public function getListeners(): array + public function getListenAddress(): ?string { - return $this->listeners; + return $this->config['server.address']??null; } + + public function setAllowOriginHeader(string $value): self + { + $this->config['headers.allow_origin'] = $value; + return $this; + } + + public function setContentSecurityPolicyHeader(string $value): self + { + $this->config['headers.csp'] = $value; + return $this; + } + } diff --git a/src/Daemon.php b/src/Daemon.php index 261acba..5fa7d70 100644 --- a/src/Daemon.php +++ b/src/Daemon.php @@ -25,11 +25,13 @@ class Daemon { $this->server = new Server($this->config, $this->loop); - $listeners = $this->config->getListeners(); - foreach ($listeners as $listener) { - $socket = new SocketServer("tcp://".$listener['address']); - $this->server->listen($socket); + $listenAddress = $this->config->getListenAddress(); + if (!$listenAddress) { + fwrite(STDERR, "Warning: Empty listening address. You won't make it far.\n"); + return; } + $socket = new SocketServer("tcp://".$listenAddress); + $this->server->listen($socket); } public function stop(): void