PluginProbe
Stream – Activity Log & Audit Trail / 4.0.2
Stream – Activity Log & Audit Trail v4.0.2
4.4.0 4.3.0 4.2.2 4.2.1 trunk 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.1 3.1.1 3.10.0 3.2.0 3.2.1 3.2.2 3.2.3 All 50 releases
← All changes | classes/class-connector.php +6 -158 trunk4.0.2 View file →
@@ -145,14 +145,14 @@
145 145
146 146 /**
147 147 * Log handler
148 148 *
149 - * @param string $message sprintf-ready error message string.
150 - * @param array $args sprintf (and extra) arguments to use.
151 - * @param int|null $object_id Target object id (if any).
152 - * @param string $context Context of the event.
153 - * @param string $action Action of the event.
154 - * @param int $user_id User responsible for the event.
149 + * @param string $message sprintf-ready error message string.
150 + * @param array $args sprintf (and extra) arguments to use.
151 + * @param int $object_id Target object id.
152 + * @param string $context Context of the event.
153 + * @param string $action Action of the event.
154 + * @param int $user_id User responsible for the event.
155 155 *
156 156 * @return bool
157 157 */
158 158 public function log( $message, $args, $object_id, $context, $action, $user_id = null ) {
@@ -157,16 +157,8 @@
157 157 */
158 158 public function log( $message, $args, $object_id, $context, $action, $user_id = null ) {
159 159 $connector = $this->name;
160 160
161 - /**
162 - * Override the data logged. Returning false to this filter will stop the data from being logged.
163 - * Examples of this filter in use can be found in some of the custom connectors.
164 - *
165 - * @see Connector_ACF::log_override()
166 - *
167 - * @return array|false An array of the data to be logged or false if it should not be logged.
168 - */
169 161 $data = apply_filters(
170 162 'wp_stream_log_data',
171 163 compact( 'connector', 'message', 'args', 'object_id', 'context', 'action', 'user_id' )
172 164 );
@@ -183,152 +175,8 @@
183 175 $user_id = $data['user_id'];
184 176 }
185 177
186 178 return call_user_func_array( array( wp_stream_get_instance()->log, 'log' ), compact( 'connector', 'message', 'args', 'object_id', 'context', 'action', 'user_id' ) );
187 - }
188 -
189 - /**
190 - * Substrings that mark a setting name as holding a credential.
191 - *
192 - * Deliberately matched as substrings so unknown third-party settings are
193 - * covered by default: connectors log arbitrary option arrays from other
194 - * plugins, and an allowlist cannot anticipate every field a payment gateway
195 - * or integration might add. Over-redacting a harmless field only costs a
196 - * little detail in the audit log; under-redacting persists a live credential
197 - * in a table that lower-privileged Stream viewers can read.
198 - *
199 - * @const array
200 - */
201 - const SECRET_KEY_PATTERNS = array(
202 - 'pass',
203 - 'secret',
204 - 'private_key',
205 - 'apikey',
206 - 'token',
207 - 'webhook',
208 - 'license',
209 - 'salt',
210 - 'credential',
211 - 'oauth',
212 - // PayPal NVP `api_signature`; over-matches e.g. `email_signature`.
213 - 'signature',
214 - );
215 -
216 - /**
217 - * Setting names, or suffixes of them, that hold a credential but do not
218 - * contain any of the substrings above.
219 - *
220 - * Matched against the end of the name so option prefixes used by individual
221 - * plugins (rg_gforms_key, woocommerce_..._key) are covered without treating
222 - * every name that merely contains "key" as sensitive.
223 - *
224 - * @const array
225 - */
226 - const SECRET_KEY_SUFFIXES = array(
227 - '_key',
228 - );
229 -
230 - /**
231 - * Names that end in a secret-looking suffix but are not credentials.
232 - *
233 - * Public halves of key pairs are meant to be published, and redacting them
234 - * removes useful audit detail for no benefit. Matched as substrings so the
235 - * various plugin prefixes are covered.
236 - *
237 - * Only consulted after SECRET_KEY_PATTERNS, so a name containing an
238 - * explicit secret marker is never exempted by appearing "public" too.
239 - *
240 - * @const array
241 - */
242 - const PUBLIC_KEY_PATTERNS = array(
243 - 'public_key',
244 - 'publishable_key',
245 - 'site_key',
246 - );
247 -
248 - /**
249 - * Placeholder stored in place of a redacted value.
250 - *
251 - * A distinct marker rather than an empty string, so a reader of the audit
252 - * trail can tell "this credential changed, value withheld" apart from "this
253 - * field was cleared" -- an empty string would conflate the two.
254 - *
255 - * @const string
256 - */
257 - const REDACTED_PLACEHOLDER = '[redacted]';
258 -
259 - /**
260 - * Whether a setting/field name looks like it holds a credential.
261 - *
262 - * @param string $key Setting or field name.
263 - * @return bool
264 - */
265 - public function is_secret_key( $key ) {
266 - if ( ! is_string( $key ) || '' === $key ) {
267 - return false;
268 - }
269 -
270 - $needle = strtolower( $key );
271 -
272 - // An explicit secret marker always wins. The public-name exemption
273 - // below is only there to stop the broad "_key" suffix rule from
274 - // swallowing published key halves, so it must not be able to rescue a
275 - // name that also says "secret", "private_key" or "webhook" -- that
276 - // would invert the over-redact-rather-than-under-redact preference.
277 - foreach ( self::SECRET_KEY_PATTERNS as $pattern ) {
278 - if ( false !== strpos( $needle, $pattern ) ) {
279 - return true;
280 - }
281 - }
282 -
283 - foreach ( self::PUBLIC_KEY_PATTERNS as $pattern ) {
284 - if ( false !== strpos( $needle, $pattern ) ) {
285 - return false;
286 - }
287 - }
288 -
289 - foreach ( self::SECRET_KEY_SUFFIXES as $suffix ) {
290 - if ( substr( $needle, -strlen( $suffix ) ) === $suffix ) {
291 - return true;
292 - }
293 - }
294 -
295 - return false;
296 - }
297 -
298 - /**
299 - * Redact credential values before they are persisted as record metadata.
300 - *
301 - * Accepts either a scalar (redacted when $key itself looks secret) or an
302 - * array of settings (each secret-looking member redacted, recursively).
303 - * Values are replaced rather than removed so the audit trail still shows
304 - * that the field changed, without retaining the credential.
305 - *
306 - * @param mixed $value Value about to be logged.
307 - * @param string $key Setting or field name the value belongs to.
308 - * @return mixed
309 - */
310 - public function redact_secret_values( $value, $key = '' ) {
311 - if ( is_array( $value ) ) {
312 - // A secret parent may key credentials by opaque IDs (e.g. Jetpack
313 - // `user_tokens` by user ID), so pass it down over child names.
314 - $inherited_key = $this->is_secret_key( $key ) ? $key : null;
315 -
316 - foreach ( $value as $child_key => $child_value ) {
317 - $value[ $child_key ] = $this->redact_secret_values(
318 - $child_value,
319 - null !== $inherited_key ? $inherited_key : (string) $child_key
320 - );
321 - }
322 -
323 - return $value;
324 - }
325 -
326 - if ( $this->is_secret_key( $key ) && ! empty( $value ) ) {
327 - return self::REDACTED_PLACEHOLDER;
328 - }
329 -
330 - return $value;
331 179 }
332 180
333 181 /**
334 182 * Save log data till shutdown, so other callbacks would be able to override