From 8844a720df624b8acd5c8ebea2d08d4d932a1abc Mon Sep 17 00:00:00 2001 From: Sebastian Molenda Date: Wed, 19 Jun 2024 22:25:04 +0200 Subject: [PATCH] Lockable immutable config --- src/PubNub/PNConfiguration.php | 170 ++++++++++++++++++++++----------- src/PubNub/PubNub.php | 1 + 2 files changed, 113 insertions(+), 58 deletions(-) diff --git a/src/PubNub/PNConfiguration.php b/src/PubNub/PNConfiguration.php index a24b0544..3b4a5858 100755 --- a/src/PubNub/PNConfiguration.php +++ b/src/PubNub/PNConfiguration.php @@ -14,49 +14,52 @@ class PNConfiguration private const DEFAULT_CONNECT_TIMEOUT = 10; private const DEFAULT_USE_RANDOM_IV = true; + private bool $disableImmutableCheck = false; + private bool $isLocked = false; + /** @var string Subscribe key provided by PubNub */ - private $subscribeKey; + private string $subscribeKey; /** @var string Publish key provided by PubNub */ - private $publishKey; + private ?string $publishKey = null; /** @var string Secret key provided by PubNub */ - private $secretKey; + private ?string $secretKey = null; /** @var string */ - private $authKey; + private ?string $authKey = null; /** @var string */ - private $uuid; + private string $userId; /** @var string */ - private $origin; + private ?string $origin = null; /** @var bool Set to true to switch the client to HTTPS:// based communications. */ - private $secure = true; + private bool $secure = true; /** @var PubNubCryptoCore */ - private $crypto; + private ?PubNubCryptoCore $crypto; /** @var string */ - private $filterExpression; + private ?string $filterExpression = null; /** @var int */ - protected $nonSubscribeRequestTimeout; + protected int $nonSubscribeRequestTimeout; /** @var int */ - protected $connectTimeout; + protected int $connectTimeout; /** @var int */ - protected $subscribeTimeout; + protected int $subscribeTimeout; /** @var Transport */ - protected $transport; + protected ?Transport $transport = null; /** @var bool */ - protected $useRandomIV; + protected bool $useRandomIV; - private $usingUserId = null; + private ?bool $usingUserId = null; /** * PNConfiguration constructor. @@ -74,7 +77,7 @@ public function __construct() * * @return PNConfiguration config */ - public static function demoKeys() + public static function demoKeys(): PNConfiguration { $config = new self(); $config->setSubscribeKey("demo"); @@ -84,12 +87,29 @@ public static function demoKeys() return $config; } + + /** + * Returns a unlocked clone of the current configuration. + * This is useful when you want to create a new configuration based on an existing one. + * + * @return PNConfiguration + */ + public function clone(): PNConfiguration + { + $lockState = $this->isLocked; + $this->isLocked = false; + $result = clone $this; + $this->isLocked = $lockState; + return $result; + } + /** * @param string $subscribeKey * @return $this */ - public function setSubscribeKey($subscribeKey) + public function setSubscribeKey(string $subscribeKey): self { + $this->checkLock(); $this->subscribeKey = $subscribeKey; return $this; @@ -99,8 +119,9 @@ public function setSubscribeKey($subscribeKey) * @param string $publishKey * @return $this */ - public function setPublishKey($publishKey) + public function setPublishKey(string $publishKey): self { + $this->checkLock(); $this->publishKey = $publishKey; return $this; @@ -110,8 +131,9 @@ public function setPublishKey($publishKey) * @param string $secretKey * @return $this */ - public function setSecretKey($secretKey) + public function setSecretKey(string $secretKey): self { + $this->checkLock(); $this->secretKey = $secretKey; return $this; @@ -120,12 +142,12 @@ public function setSecretKey($secretKey) /** * @return string */ - public function getCipherKey() + public function getCipherKey(): string { return $this->getCrypto()->getCipherKey(); } - public function isAesEnabled() + public function isAesEnabled(): bool { return !!$this->crypto; } @@ -134,8 +156,9 @@ public function isAesEnabled() * @param string $cipherKey * @return $this */ - public function setCipherKey($cipherKey) + public function setCipherKey(string $cipherKey): self { + $this->checkLock(); if ($this->crypto == null) { $this->crypto = CryptoModule::legacyCryptor($cipherKey, $this->getUseRandomIV()); } else { @@ -148,7 +171,7 @@ public function setCipherKey($cipherKey) /** * @return int */ - public function getNonSubscribeRequestTimeout() + public function getNonSubscribeRequestTimeout(): int { return $this->nonSubscribeRequestTimeout; } @@ -156,7 +179,7 @@ public function getNonSubscribeRequestTimeout() /** * @return int */ - public function getSubscribeTimeout() + public function getSubscribeTimeout(): int { return $this->subscribeTimeout; } @@ -164,7 +187,7 @@ public function getSubscribeTimeout() /** * @return int */ - public function getConnectTimeout() + public function getConnectTimeout(): int { return $this->connectTimeout; } @@ -172,7 +195,7 @@ public function getConnectTimeout() /** * @return string */ - public function getOrigin() + public function getOrigin(): ?string { return $this->origin; } @@ -181,8 +204,9 @@ public function getOrigin() * @param string $origin * @return $this */ - public function setOrigin($origin) + public function setOrigin($origin): self { + $this->checkLock(); $this->origin = $origin; return $this; @@ -191,7 +215,7 @@ public function setOrigin($origin) /** * @return string */ - public function getSubscribeKey() + public function getSubscribeKey(): string { return $this->subscribeKey; } @@ -199,7 +223,7 @@ public function getSubscribeKey() /** * @return string */ - public function getPublishKey() + public function getPublishKey(): string | null { return $this->publishKey; } @@ -207,7 +231,7 @@ public function getPublishKey() /** * @return string */ - public function getSecretKey() + public function getSecretKey(): string | null { return $this->secretKey; } @@ -215,18 +239,19 @@ public function getSecretKey() /** * @return bool */ - public function isSecure() + public function isSecure(): bool { return $this->secure; } /** - * @param $ssl + * @param $secure * @return $this */ - public function setSecure($ssl) + public function setSecure(bool $secure = true): self { - $this->secure = $ssl; + $this->checkLock(); + $this->secure = $secure; return $this; } @@ -234,25 +259,26 @@ public function setSecure($ssl) /** * @return string */ - public function getUuid() + public function getUuid(): string { - return $this->uuid; + return $this->userId; } /** * @param string $uuid * @return $this */ - public function setUuid($uuid) + public function setUuid(string $uuid): self { + $this->checkLock(); if (!is_null($this->usingUserId) && $this->usingUserId) { throw new PubNubConfigurationException("Cannot use UserId and UUID simultaneously"); } - if (!$this->validateNotEmptyString($uuid)) { + if (!$this->isNotEmptyString($uuid)) { throw new PubNubConfigurationException("UUID should not be empty"); } $this->usingUserId = false; - $this->uuid = $uuid; + $this->userId = $uuid; return $this; } @@ -260,25 +286,26 @@ public function setUuid($uuid) /** * @return string */ - public function getUserId() + public function getUserId(): string { - return $this->uuid; + return $this->userId; } /** * @param string $userId * @return $this */ - public function setUserId($userId) + public function setUserId(string $userId): self { + $this->checkLock(); if (!is_null($this->usingUserId) && !$this->usingUserId) { throw new PubNubConfigurationException("Cannot use UserId and UUID simultaneously"); } - if (!$this->validateNotEmptyString($userId)) { + if (!$this->isNotEmptyString($userId)) { throw new PubNubConfigurationException("UserID should not be empty"); } $this->usingUserId = true; - $this->uuid = $userId; + $this->userId = $userId; return $this; } @@ -286,7 +313,7 @@ public function setUserId($userId) /** * @return string|null authKey */ - public function getAuthKey() + public function getAuthKey(): ?string { return $this->authKey; } @@ -295,8 +322,9 @@ public function getAuthKey() * @param string|null $authKey * @return $this */ - public function setAuthKey($authKey) + public function setAuthKey(string $authKey): self { + $this->checkLock(); $this->authKey = $authKey; return $this; @@ -306,7 +334,7 @@ public function setAuthKey($authKey) * @return PubNubCryptoCore * @throws \Exception */ - public function getCrypto() + public function getCrypto(): PubNubCryptoCore { if (!$this->crypto) { throw new PubNubValidationException("You should set up either a cipher key or a crypto instance before"); @@ -318,7 +346,7 @@ public function getCrypto() /** * @return null|PubNubCryptoCore */ - public function getCryptoSafe() + public function getCryptoSafe(): PubNubCryptoCore | null { try { return $this->getCrypto(); @@ -331,8 +359,9 @@ public function getCryptoSafe() * @param PubNubCryptoCore $crypto * @return $this */ - public function setCrypto($crypto) + public function setCrypto(PubNubCryptoCore $crypto): self { + $this->checkLock(); $this->crypto = $crypto; return $this; @@ -341,7 +370,7 @@ public function setCrypto($crypto) /** * @return string */ - public function getFilterExpression() + public function getFilterExpression(): string | null { return $this->filterExpression; } @@ -350,8 +379,9 @@ public function getFilterExpression() * @param string $filterExpression * @return $this */ - public function setFilterExpression($filterExpression) + public function setFilterExpression(string $filterExpression): self { + $this->checkLock(); $this->filterExpression = $filterExpression; return $this; @@ -361,8 +391,9 @@ public function setFilterExpression($filterExpression) * @param int $nonSubscribeRequestTimeout * @return $this */ - public function setNonSubscribeRequestTimeout($nonSubscribeRequestTimeout) + public function setNonSubscribeRequestTimeout(int $nonSubscribeRequestTimeout): self { + $this->checkLock(); $this->nonSubscribeRequestTimeout = $nonSubscribeRequestTimeout; return $this; @@ -372,8 +403,9 @@ public function setNonSubscribeRequestTimeout($nonSubscribeRequestTimeout) * @param int $connectTimeout * @return $this */ - public function setConnectTimeout($connectTimeout) + public function setConnectTimeout(int $connectTimeout): self { + $this->checkLock(); $this->connectTimeout = $connectTimeout; return $this; @@ -383,8 +415,9 @@ public function setConnectTimeout($connectTimeout) * @param int $subscribeTimeout * @return $this */ - public function setSubscribeTimeout($subscribeTimeout) + public function setSubscribeTimeout(int $subscribeTimeout): self { + $this->checkLock(); $this->subscribeTimeout = $subscribeTimeout; return $this; @@ -393,7 +426,7 @@ public function setSubscribeTimeout($subscribeTimeout) /** * @return Transport */ - public function getTransport() + public function getTransport(): Transport | null { return $this->transport; } @@ -404,6 +437,7 @@ public function getTransport() */ public function setTransport($transport) { + $this->checkLock(); $this->transport = $transport; return $this; @@ -412,7 +446,7 @@ public function setTransport($transport) /** * @return bool */ - public function getUseRandomIV() + public function getUseRandomIV(): bool { return $this->useRandomIV; } @@ -421,8 +455,9 @@ public function getUseRandomIV() * @param bool $useRandomIV * @return $this */ - public function setUseRandomIV($useRandomIV) + public function setUseRandomIV($useRandomIV): self { + $this->checkLock(); $this->useRandomIV = $useRandomIV; if ($this->crypto != null) { @@ -432,8 +467,27 @@ public function setUseRandomIV($useRandomIV) return $this; } - private function validateNotEmptyString($value) + private function isNotEmptyString($value): bool { return (is_string($value) && strlen(trim($value)) > 0); } + + public function disableImmutableCheck(): self + { + $this->checkLock(); + $this->disableImmutableCheck = true; + return $this; + } + + public function lock() + { + $this->isLocked = true; + } + + protected function checkLock() + { + if ($this->isLocked && !$this->disableImmutableCheck) { + throw new PubNubConfigurationException("This configuration is locked and cannot be changed anymore."); + } + } } diff --git a/src/PubNub/PubNub.php b/src/PubNub/PubNub.php index 2bdf12b2..1e95eabc 100644 --- a/src/PubNub/PubNub.php +++ b/src/PubNub/PubNub.php @@ -92,6 +92,7 @@ class PubNub implements LoggerAwareInterface public function __construct($initialConfig) { $this->validateConfig($initialConfig); + $initialConfig->lock(); $this->configuration = $initialConfig; $this->basePathManager = new BasePathManager($initialConfig); $this->subscriptionManager = new SubscriptionManager($this);