Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
33.33% covered (danger)
33.33%
20 / 60
20.00% covered (danger)
20.00%
1 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
VideoPressToken
33.33% covered (danger)
33.33%
20 / 60
20.00% covered (danger)
20.00%
1 / 5
260.30
0.00% covered (danger)
0.00%
0 / 1
 check_connection
60.00% covered (warning)
60.00%
3 / 5
0.00% covered (danger)
0.00%
0 / 1
5.02
 blog_id
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
3.14
 videopress_playback_jwt
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
12
 videopress_onetime_upload_token
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
210
 videopress_upload_jwt
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2/**
3 * VideoPress Token
4 *
5 * @package automattic/jetpack-videopress
6 */
7
8namespace Automattic\Jetpack\VideoPress;
9
10use Automattic\Jetpack\Connection\Client;
11use Automattic\Jetpack\Connection\Manager as Connection_Manager;
12use Jetpack_Options;
13/**
14 * VideoPress token utility class
15 */
16class VideoPressToken {
17    /**
18     * Check if user is connected.
19     *
20     * @return bool
21     * @throws Upload_Exception - If user is not connected.
22     */
23    private static function check_connection() {
24        if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
25            return true;
26        }
27        if ( ! ( new Connection_Manager() )->has_connected_owner() ) {
28            throw new Upload_Exception( __( 'You need to connect Jetpack before being able to upload a video to VideoPress.', 'jetpack-videopress-pkg' ) );
29        }
30        return true;
31    }
32
33    /**
34     * Get current blog id.
35     *
36     * @return string - Blog id.
37     */
38    public static function blog_id() {
39        if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
40            $blog_id = get_current_blog_id();
41        } else {
42            $blog_id = Jetpack_Options::get_option( 'id' );
43        }
44
45        return $blog_id;
46    }
47
48    /**
49     * Retrieve a Playback JWT via WPCOM api.
50     *
51     * @param string $guid The VideoPress GUID.
52     * @return string
53     */
54    public static function videopress_playback_jwt( $guid ) {
55        $blog_id = static::blog_id();
56
57        $args = array(
58            'method' => 'POST',
59        );
60
61        $endpoint = "sites/{$blog_id}/media/videopress-playback-jwt/{$guid}";
62
63        $result = Client::wpcom_json_api_request_as_blog( $endpoint, 'v2', $args, null, 'wpcom' );
64
65        if ( is_wp_error( $result ) ) {
66            return $result;
67        }
68
69        $response = json_decode( $result['body'], true );
70
71        if ( empty( $response['metadata_token'] ) ) {
72            return false;
73        }
74
75        return $response['metadata_token'];
76    }
77
78    /**
79     * Retrieve a One Time Upload Token via WPCOM api.
80     *
81     * @return string
82     * @throws Upload_Exception If token is empty or is had an error.
83     */
84    public static function videopress_onetime_upload_token() {
85        if ( static::check_connection() ) {
86            $blog_id = static::blog_id();
87
88            /*
89             * On WordPress.com the classic `sites/{id}/media/token` (rest/v1.1) endpoint
90             * isn't reachable in-process: `Client::wpcom_json_api_request_as_blog` routes
91             * through `WPCOM_API_Direct`, which only dispatches WP-REST routes. Mint the
92             * one-time token straight from the same primitives that endpoint uses. Mirrors
93             * the IS_WPCOM branches already in this class (`blog_id()`) and its sibling AJAX
94             * playback-JWT handler (`AJAX::request_jwt_from_wpcom()`).
95             */
96            if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
97                if ( ! class_exists( '\Jetpack_Server_Upload_Token' ) && defined( 'ABSPATH' ) ) {
98                    // file_exists-guarded so a relocated wpcom mu-plugins file degrades
99                    // to the friendly exception below instead of a require fatal.
100                    $upload_token_file = ABSPATH . 'wp-content/mu-plugins/jetpack/class.jetpack-server-upload-token.php';
101                    if ( file_exists( $upload_token_file ) ) {
102                        require_once $upload_token_file;
103                    }
104                }
105                if ( class_exists( '\Jetpack_Data' ) && class_exists( '\Jetpack_Server_Upload_Token' ) && defined( 'JETPACK__ANY_USER_TOKEN' ) ) {
106                    // blog_id() types as int|string (the Jetpack-option path), but on
107                    // WPCOM it's get_current_blog_id() — narrow for the int-typed stubs.
108                    $wpcom_blog_id = (int) $blog_id;
109                    $jetpack_token = \Jetpack_Data::get_access_token_by_blog_id_user_id( $wpcom_blog_id, JETPACK__ANY_USER_TOKEN );
110                    $token         = \Jetpack_Server_Upload_Token::create_token( $wpcom_blog_id, $jetpack_token );
111                    if ( is_array( $token ) && ! empty( $token['hash'] ) ) {
112                        return $token['hash'];
113                    }
114                }
115                throw new Upload_Exception( __( 'Could not obtain a VideoPress upload token. Please try again later.', 'jetpack-videopress-pkg' ) );
116            }
117
118            $args = array(
119                'method' => 'POST',
120            );
121
122            $endpoint = "sites/{$blog_id}/media/token";
123            $result   = Client::wpcom_json_api_request_as_blog( $endpoint, Client::WPCOM_JSON_API_VERSION, $args );
124
125            if ( is_wp_error( $result ) ) {
126                throw new Upload_Exception( __( 'Could not obtain a VideoPress upload token. Please try again later.', 'jetpack-videopress-pkg' ) );
127            }
128
129            $response = json_decode( $result['body'], true );
130
131            if ( empty( $response['upload_token'] ) ) {
132                throw new Upload_Exception( __( 'Could not obtain a VideoPress upload token. Please try again later.', 'jetpack-videopress-pkg' ) );
133            }
134
135            return $response['upload_token'];
136        }
137    }
138
139    /**
140     * Gets the VideoPress Upload JWT
141     *
142     * @return string
143     * @throws Upload_Exception - If user is not connected, if token is empty or failed to obtain.
144     */
145    public static function videopress_upload_jwt() {
146        if ( static::check_connection() ) {
147            $blog_id  = static::blog_id();
148            $endpoint = "sites/{$blog_id}/media/videopress-upload-jwt";
149            $args     = array( 'method' => 'POST' );
150            $result   = Client::wpcom_json_api_request_as_blog( $endpoint, 'v2', $args, null, 'wpcom' );
151
152            if ( is_wp_error( $result ) ) {
153                throw new Upload_Exception(
154                    __( 'Could not obtain a VideoPress upload JWT. Please try again later.', 'jetpack-videopress-pkg' ) .
155                    '(' . $result->get_error_message() . ')'
156                );
157            }
158
159            $response = json_decode( $result['body'], true );
160
161            if ( empty( $response['upload_token'] ) ) {
162                throw new Upload_Exception( __( 'Could not obtain a VideoPress upload JWT. Please try again later. (empty upload token)', 'jetpack-videopress-pkg' ) );
163            }
164
165            return $response['upload_token'];
166        }
167    }
168}