diff --git a/src/ConvertKit_API.php b/src/ConvertKit_API.php index 84d1cc1..7350406 100644 --- a/src/ConvertKit_API.php +++ b/src/ConvertKit_API.php @@ -77,11 +77,12 @@ class ConvertKit_API /** * Constructor for ConvertKitAPI instance * - * @param string $api_key ConvertKit API Key. - * @param string $api_secret ConvertKit API Secret. - * @param boolean $debug Log requests to debugger. + * @param string $api_key ConvertKit API Key. + * @param string $api_secret ConvertKit API Secret. + * @param boolean $debug Log requests to debugger. + * @param string $debugLogFileLocation Path and filename of debug file to write to. */ - public function __construct(string $api_key, string $api_secret, bool $debug = false) + public function __construct(string $api_key, string $api_secret, bool $debug = false, string $debugLogFileLocation = '') { $this->api_key = $api_key; $this->api_secret = $api_secret; @@ -97,8 +98,13 @@ public function __construct(string $api_key, string $api_secret, bool $debug = f ); if ($debug) { + // If no debug log file location specified, define a default. + if (empty($debugLogFileLocation)) { + $debugLogFileLocation = __DIR__ . '/logs/debug.log'; + } + $this->debug_logger = new Logger('ck-debug'); - $stream_handler = new StreamHandler(__DIR__ . '/logs/debug.log', Logger::DEBUG); + $stream_handler = new StreamHandler($debugLogFileLocation, Logger::DEBUG); $this->debug_logger->pushHandler( $stream_handler // phpcs:ignore Squiz.Objects.ObjectInstantiation.NotAssigned ); @@ -114,9 +120,25 @@ public function __construct(string $api_key, string $api_secret, bool $debug = f */ private function create_log(string $message) { - if ($this->debug) { - $this->debug_logger->info($message); + // Don't log anything if debugging isn't enabled. + if (!$this->debug) { + return; } + + // Mask the API Key and Secret. + $message = str_replace( + $this->api_key, + str_repeat('*', (strlen($this->api_key) - 4)) . substr($this->api_key, - 4), + $message + ); + $message = str_replace( + $this->api_secret, + str_repeat('*', (strlen($this->api_secret) - 4)) . substr($this->api_secret, - 4), + $message + ); + + // Add to log. + $this->debug_logger->info($message); } /** diff --git a/tests/ConvertKitAPITest.php b/tests/ConvertKitAPITest.php index 56483c2..9c081f8 100644 --- a/tests/ConvertKitAPITest.php +++ b/tests/ConvertKitAPITest.php @@ -65,6 +65,75 @@ public function testDebugEnabled() $this->assertStringContainsString('ck-debug.INFO: Finish request successfully', $this->getLogFileContents()); } + /** + * Test that debug logging works when enabled, a custom debug log file and path is specified + * and an API call is made. + * + * @since 1.3.0 + * + * @return void + */ + public function testDebugEnabledWithCustomLogFile() + { + // Define custom log file location. + $this->logFile = dirname(dirname(__FILE__)) . '/src/logs/debug-custom.log'; + + // Setup API with debugging enabled. + $api = new \ConvertKit_API\ConvertKit_API( + $_ENV['CONVERTKIT_API_KEY'], + $_ENV['CONVERTKIT_API_SECRET'], + true, + $this->logFile + ); + $result = $api->get_account(); + + // Confirm log file exists. + $this->assertFileExists($this->logFile); + + // Confirm that the log includes expected data. + $this->assertStringContainsString('ck-debug.INFO: GET account', $this->getLogFileContents()); + $this->assertStringContainsString('ck-debug.INFO: Finish request successfully', $this->getLogFileContents()); + } + + /** + * Test that debug logging works when enabled and an API call is made, with the API Key and Secret + * masked in the log file. + * + * @since 1.3.0 + * + * @return void + */ + public function testDebugAPIKeyAndSecretAreMasked() + { + // Setup API with debugging enabled. + $api = new \ConvertKit_API\ConvertKit_API($_ENV['CONVERTKIT_API_KEY'], $_ENV['CONVERTKIT_API_SECRET'], true); + + // Make requests that utilizes both the API Key and Secret. + $api->get_forms(); // API Key. + $api->get_account(); // API Secret. + + // Define masked versions of API Key and Secret that we expect to see in the log file. + $maskedAPIKey = str_replace( + $_ENV['CONVERTKIT_API_KEY'], + str_repeat('*', strlen($_ENV['CONVERTKIT_API_KEY']) - 4) . substr($_ENV['CONVERTKIT_API_KEY'], - 4), + $_ENV['CONVERTKIT_API_KEY'] + ); + $maskedAPISecret = str_replace( + $_ENV['CONVERTKIT_API_SECRET'], + str_repeat('*', strlen($_ENV['CONVERTKIT_API_SECRET']) - 4) . substr($_ENV['CONVERTKIT_API_SECRET'], - 4), + $_ENV['CONVERTKIT_API_SECRET'] + ); + + + // Confirm that the log includes the masked API Key and Secret. + $this->assertStringContainsString($maskedAPIKey, $this->getLogFileContents()); + $this->assertStringContainsString($maskedAPISecret, $this->getLogFileContents()); + + // Confirm that the log does not include the unmasked API Key and Secret. + $this->assertStringNotContainsString($_ENV['CONVERTKIT_API_KEY'], $this->getLogFileContents()); + $this->assertStringNotContainsString($_ENV['CONVERTKIT_API_SECRET'], $this->getLogFileContents()); + } + /** * Test that debug logging is not performed when disabled and an API call is made. *