Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
Keyring_Result_Controller
0.00% covered (danger)
0.00%
0 / 50
0.00% covered (danger)
0.00%
0 / 4
90
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 register_routes
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
2
 get_keyring_result_permissions_check
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 get_keyring_result
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2/**
3 * The Publicize Keyring Result Controller class.
4 *
5 * @package automattic/jetpack-publicize
6 */
7
8namespace Automattic\Jetpack\Publicize\REST_API;
9
10use Automattic\Jetpack\Connection\Traits\WPCOM_REST_API_Proxy_Request;
11use Automattic\Jetpack\Publicize\Publicize_Utils;
12use WP_REST_Request;
13use WP_REST_Response;
14use WP_REST_Server;
15
16if ( ! defined( 'ABSPATH' ) ) {
17    exit( 0 );
18}
19
20/**
21 * Keyring Result Controller.
22 *
23 * Returns the verified keyring connection item for a just-completed connect request
24 * (auth_flow=v2). The connect popup no longer posts the result back through
25 * window.opener; instead the same-origin completion page broadcasts the request_id and the
26 * client fetches the result here once.
27 *
28 * @phan-constructor-used-for-side-effects
29 */
30class Keyring_Result_Controller extends Base_Controller {
31
32    use WPCOM_REST_API_Proxy_Request;
33
34    /**
35     * Constructor.
36     */
37    public function __construct() {
38        parent::__construct();
39
40        $this->base_api_path = 'wpcom';
41        $this->version       = 'v2';
42
43        $this->namespace = "{$this->base_api_path}/{$this->version}";
44        $this->rest_base = 'publicize/keyring-result';
45
46        add_action( 'rest_api_init', array( $this, 'register_routes' ) );
47    }
48
49    /**
50     * Register the routes.
51     */
52    public function register_routes() {
53        register_rest_route(
54            $this->namespace,
55            '/' . $this->rest_base,
56            array(
57                array(
58                    'methods'             => WP_REST_Server::READABLE,
59                    'callback'            => array( $this, 'get_keyring_result' ),
60                    'permission_callback' => array( $this, 'get_keyring_result_permissions_check' ),
61                    'args'                => array(
62                        'request_id' => array(
63                            'type'        => 'string',
64                            'required'    => true,
65                            'description' => __( 'ID of the connect request.', 'jetpack-publicize-pkg' ),
66                        ),
67                    ),
68                ),
69            )
70        );
71    }
72
73    /**
74     * Verify that the request has access to the keyring result.
75     *
76     * @param WP_REST_Request $request Full details about the request.
77     * @return true|\WP_Error
78     */
79    public function get_keyring_result_permissions_check( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
80        return $this->publicize_permissions_check() && (bool) get_current_user_id();
81    }
82
83    /**
84     * Get the keyring result for a completed connect request.
85     *
86     * @param WP_REST_Request $request Full details about the request.
87     *
88     * @return WP_REST_Response The response object: { code, data }.
89     */
90    public function get_keyring_result( $request ) {
91        if ( ! Publicize_Utils::is_wpcom() ) {
92            return rest_ensure_response( $this->proxy_request_to_wpcom_as_user( $request ) );
93        }
94
95        $response = array(
96            'code' => 'unknown',
97            'data' => null,
98        );
99
100        require_lib( 'external-connections' );
101
102        $external_connections = \WPCOM_External_Connections::init();
103
104        $request_id = $request->get_param( 'request_id' );
105
106        // The transient is keyed by current user + request_id, so a hit already proves ownership.
107        $data = $external_connections->get_last_keyring_token_details( $request_id );
108
109        if ( ! $data ) {
110            $response['code'] = 'no_data_found';
111            return rest_ensure_response( $response );
112        }
113
114        $token_id = $data['token_id'] ?? null;
115
116        if ( ! $token_id ) {
117            $response['code'] = 'token_id_missing';
118            return rest_ensure_response( $response );
119        }
120
121        // On reconnect of a broken connection, re-test so the cached failure is overwritten.
122        $force_connection_test = $external_connections->has_failing_cached_connection_test( $token_id );
123
124        $item = $external_connections->get_keyring_connection_item( $token_id, false, $force_connection_test );
125
126        if ( ! $item ) {
127            $response['code'] = 'token_not_found';
128            return rest_ensure_response( $response );
129        }
130
131        $response['code'] = 'success';
132        $response['data'] = $item;
133
134        return rest_ensure_response( $response );
135    }
136}