@@ -151,6 +151,65 @@ public function testDebugEnabledWithCustomLogFile()
151151 $ this ->assertStringContainsString ('ck-debug.INFO: Finish request successfully ' , $ this ->getLogFileContents ());
152152 }
153153
154+ /**
155+ * Test that debug logging works when enabled and an API call is made, with email addresses and credentials
156+ * masked in the log file.
157+ *
158+ * @since 2.0.0
159+ *
160+ * @return void
161+ */
162+ public function testDebugCredentialsAndEmailsAreMasked ()
163+ {
164+ // Setup API with debugging enabled.
165+ $ api = new ConvertKit_API (
166+ clientID: $ _ENV ['CONVERTKIT_OAUTH_CLIENT_ID ' ],
167+ clientSecret: $ _ENV ['CONVERTKIT_OAUTH_CLIENT_SECRET ' ],
168+ accessToken: $ _ENV ['CONVERTKIT_OAUTH_ACCESS_TOKEN ' ],
169+ debug: true
170+ );
171+
172+ // Create log entries with Client ID, Client Secret, Access Token and Email Address, as if an API method
173+ // were to log this sensitive data.
174+ $ this ->callPrivateMethod ($ api , 'create_log ' , ['Client ID: ' . $ _ENV ['CONVERTKIT_OAUTH_CLIENT_ID ' ]]);
175+ $ this ->callPrivateMethod ($ api , 'create_log ' , ['Client Secret: ' . $ _ENV ['CONVERTKIT_OAUTH_CLIENT_SECRET ' ]]);
176+ $ this ->callPrivateMethod ($ api , 'create_log ' , ['Access Token: ' . $ _ENV ['CONVERTKIT_OAUTH_ACCESS_TOKEN ' ]]);
177+ $ this ->callPrivateMethod ($ api , 'create_log ' , ['Email: ' . $ _ENV ['CONVERTKIT_API_SUBSCRIBER_EMAIL ' ]]);
178+
179+ // Confirm that the log includes the masked Client ID, Secret, Access Token and Email Address.
180+ $ this ->assertStringContainsString (
181+ str_repeat (
182+ '* ' ,
183+ (strlen ($ _ENV ['CONVERTKIT_OAUTH_CLIENT_ID ' ]) - 4 )
184+ ) . substr ($ _ENV ['CONVERTKIT_OAUTH_CLIENT_ID ' ], -4 ),
185+ $ this ->getLogFileContents ()
186+ );
187+ $ this ->assertStringContainsString (
188+ str_repeat (
189+ '* ' ,
190+ (strlen ($ _ENV ['CONVERTKIT_OAUTH_CLIENT_SECRET ' ]) - 4 )
191+ ) . substr ($ _ENV ['CONVERTKIT_OAUTH_CLIENT_SECRET ' ], -4 ),
192+ $ this ->getLogFileContents ()
193+ );
194+ $ this ->assertStringContainsString (
195+ str_repeat (
196+ '* ' ,
197+ (strlen ($ _ENV ['CONVERTKIT_OAUTH_ACCESS_TOKEN ' ]) - 4 )
198+ ) . substr ($ _ENV ['CONVERTKIT_OAUTH_ACCESS_TOKEN ' ], -4 ),
199+ $ this ->getLogFileContents ()
200+ );
201+ $ this ->assertStringContainsString (
202+ 'o****@n********.c** ' ,
203+ $ this ->getLogFileContents ()
204+ );
205+
206+ // Confirm that the log does not include the unmasked Client ID, Secret, Access Token or Email Address.
207+ $ this ->assertStringNotContainsString ($ _ENV ['CONVERTKIT_OAUTH_CLIENT_ID ' ], $ this ->getLogFileContents ());
208+ $ this ->assertStringNotContainsString ($ _ENV ['CONVERTKIT_OAUTH_CLIENT_SECRET ' ], $ this ->getLogFileContents ());
209+ $ this ->assertStringNotContainsString ($ _ENV ['CONVERTKIT_OAUTH_ACCESS_TOKEN ' ], $ this ->getLogFileContents ());
210+ $ this ->assertStringNotContainsString ($ _ENV ['CONVERTKIT_API_SUBSCRIBER_EMAIL ' ], $ this ->getLogFileContents ());
211+ }
212+
154213 /**
155214 * Test that debug logging is not performed when disabled and an API call is made.
156215 *
@@ -2598,6 +2657,23 @@ private function getLogFileContents()
25982657 return file_get_contents ($ this ->logFile );
25992658 }
26002659
2660+ /**
2661+ * Helper method to call a class' private method.
2662+ *
2663+ * @since 2.0.0
2664+ *
2665+ * @param mixed $obj Class Object.
2666+ * @param string $name Method Name.
2667+ * @param array $args Method Arguments.
2668+ */
2669+ private function callPrivateMethod ($ obj , $ name , array $ args )
2670+ {
2671+ $ class = new \ReflectionClass ($ obj );
2672+ $ method = $ class ->getMethod ($ name );
2673+ $ method ->setAccessible (true );
2674+ return $ method ->invokeArgs ($ obj , $ args );
2675+ }
2676+
26012677 /**
26022678 * Generates a unique email address for use in a test, comprising of a prefix,
26032679 * date + time and PHP version number.
0 commit comments