*/ public static function build( array $result, AgentStamp_Request $request, $via, $now, $version ) { $path = wp_parse_url( $request->url, PHP_URL_PATH ); $ua = $request->user_agent; if ( strlen( $ua ) > 1024 ) { $ua = substr( $ua, 0, 1024 ); } return array( 'format' => self::FORMAT, 'stamped_at' => gmdate( 'c', (int) $now ), 'stamp' => AgentStamp_Classifier::label( $result ), 'verdict' => $result['verdict'], 'confidence' => $result['confidence'], 'detail' => $result['detail'], 'request' => array( 'method' => $request->method, 'path' => is_string( $path ) ? $path : '', 'created_via' => (string) $via, 'presence' => isset( $result['presence'] ) ? (string) $result['presence'] : '', ), 'user_agent' => $ua, 'signature' => self::signature( $result, $request ), 'plugin_version' => (string) $version, ); } /** * @param array $evidence * @return string */ public static function encode( array $evidence ) { return (string) json_encode( $evidence, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); } /** * @param string $encoded * @return string */ public static function fingerprint( $encoded ) { return 'sha256:' . hash( 'sha256', (string) $encoded ); } /** * The evidence download for one order: the order, the saved record, and whether the fingerprint still matches it. * * @param array $order_fields * @param string $stored Evidence JSON saved on the order. * @param string $fingerprint Fingerprint saved on the order. * @return array */ public static function file( array $order_fields, $stored, $fingerprint ) { $stored = (string) $stored; return array( 'order' => $order_fields, 'evidence' => '' !== $stored ? json_decode( $stored, true ) : null, 'fingerprint' => (string) $fingerprint, 'fingerprint_checks' => '' !== $stored && self::fingerprint( $stored ) === (string) $fingerprint, ); } /** * The signature as it arrived. Null when the request carried none. * * @param array{verdict:string,confidence:string} $result * @return array|null */ private static function signature( array $result, AgentStamp_Request $request ) { $input = isset( $request->headers['signature-input'] ) ? (string) $request->headers['signature-input'] : ''; $agent = isset( $request->headers['signature-agent'] ) ? (string) $request->headers['signature-agent'] : ''; if ( '' === trim( $input ) && '' === trim( $agent ) && ! isset( $request->headers['signature'] ) ) { return null; } $out = array( 'verified' => 'agent' === $result['verdict'] && 'signed' === $result['confidence'], 'signature_agent' => substr( $agent, 0, 300 ), 'directory_host' => '', 'members' => array(), ); $directory = AgentStamp_Directory::directory_url_from_agent_header( $agent ); if ( is_array( $directory ) ) { $out['directory_host'] = $directory['host']; } foreach ( array_slice( AgentStamp_Signature::split_dictionary( $input ), 0, 4 ) as $member ) { $parsed = AgentStamp_Signature::parse_member( $member['raw'] ); if ( null === $parsed ) { $out['members'][] = array( 'label' => $member['label'], 'raw' => substr( $member['raw'], 0, 500 ), ); continue; } $params = $parsed['params']; $covered = array(); foreach ( $parsed['components'] as $component ) { $covered[] = $component['name'] . $component['params']; } $out['members'][] = array( 'label' => $member['label'], 'keyid' => isset( $params['keyid'] ) ? $params['keyid'] : '', 'alg' => isset( $params['alg'] ) ? $params['alg'] : '', 'tag' => isset( $params['tag'] ) ? $params['tag'] : '', 'nonce' => isset( $params['nonce'] ) ? $params['nonce'] : '', 'created' => self::time_param( $params, 'created' ), 'expires' => self::time_param( $params, 'expires' ), 'covered' => $covered, ); } return $out; } /** * @param array $params * @param string $key * @return string */ private static function time_param( array $params, $key ) { if ( ! isset( $params[ $key ] ) || ! preg_match( '/^[0-9]{1,12}$/', (string) $params[ $key ] ) ) { return ''; } return gmdate( 'c', (int) $params[ $key ] ); } }