64 || 1 !== preg_match( '/^[A-Za-z0-9_-]+$/D', $payload ) ) { return null; } if ( 1 === preg_match( '/^o([0-9a-z]{1,12})_([A-Za-z0-9_-]{' . self::MAC_LENGTH . '})$/D', $payload, $m ) ) { $id = (int) base_convert( $m[1], 36, 10 ); return $id > 0 ? array( 'type' => 'order', 'order_id' => $id, 'mac' => $m[2] ) : null; } if ( 1 === preg_match( '/^a([A-Za-z0-9]{24})$/D', $payload, $m ) ) { return array( 'type' => 'owner', 'code' => $m[1] ); } return null; } /** * Constant-time check of a customer payload against the order's key. * * @param int $order_id Order id. * @param string $order_key Order key. * @param string $mac MAC from the payload. * @param string $secret Site secret. * @return bool */ public static function verify_order( $order_id, $order_key, $mac, $secret ) { if ( '' === (string) $order_key ) { return false; } return hash_equals( self::mac( (int) $order_id, (string) $order_key, $secret ), (string) $mac ); } /** * MAC: HMAC-SHA256 over "order|{id}|{key}", base64url, first 16 characters (96 bits). * * @param int $order_id Order id. * @param string $order_key Order key. * @param string $secret Site secret. * @return string */ private static function mac( $order_id, $order_key, $secret ) { $raw = hash_hmac( 'sha256', 'order|' . $order_id . '|' . $order_key, $secret, true ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- URL-safe token, not obfuscation. return substr( rtrim( strtr( base64_encode( $raw ), '+/', '-_' ), '=' ), 0, self::MAC_LENGTH ); } /** * A new owner invite code (24 alphanumerics). * * @return string */ public static function new_owner_code() { $alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; $code = ''; for ( $i = 0; $i < 24; $i++ ) { $code .= $alphabet[ random_int( 0, strlen( $alphabet ) - 1 ) ]; } return $code; } }