summaryrefslogtreecommitdiff
blob: f04397362027bd8a2c493fc9f22da95fe1d59bc3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
<?php

/**
 * Just a sack of functions.  Not actually an IXR_Server
 */
class Jetpack_XMLRPC_Server {
	/**
	 * A reference to $GLOBALS['wp_xmlrpc_server'];
	 */
	var $wp_xmlrpc_server = null;

	/**
	 * The current error object
	 */
	var $error = null;

	/**
	 * Since we're not extending wp_xmlrpc_server via wp_xmlrpc_server_class, store it as a reference.
	 */
	function Jetpack_XMLRPC_Server( $wp_xmlrpc_server ) {
		$this->wp_xmlrpc_server = $wp_xmlrpc_server;
	}

	/**
	 * Whitelist of the XML-RPC methods available to the Jetpack Server. If the 
	 * user is not authenticated (->login()) then the methods are never added,
	 * so they will get a "does not exist" error.
	 */
	function xmlrpc_methods() {
		if ( !$user = $this->login() ) {
			return array();
		}

		return apply_filters( 'jetpack_xmlrpc_methods', array(
			'jetpack.testConnection'    => array( $this, 'test_connection' ),
			'jetpack.featuresAvailable' => array( $this, 'features_available' ),
			'jetpack.featuresEnabled'   => array( $this, 'features_enabled' ),
			'jetpack.getPost'           => array( $this, 'get_post' ),
			'jetpack.getComment'        => array( $this, 'get_comment' ),  
		) );
	}

	/**
	 * Whitelist of the bootstrap XML-RPC methods
	 */
	function bootstrap_xmlrpc_methods() {
		return array(
			'jetpack.verifyRegistration' => array( $this, 'verify_registration' ),
		);
	}

	/**
	 * Verifies that Jetpack.WordPress.com received a registration request from this site
	 *
	 * @return WP_Error|string secret_2 on success, WP_Error( error_code => error_code, error_message => error description, error_data => status code ) on failure
	 *
	 * Possible error_codes:
	 *
	 * verify_secret_1_missing
	 * verify_secret_1_malformed
	 * verify_secrets_missing: No longer have verification secrets stored
	 * verify_secrets_mismatch: stored secret_1 does not match secret_1 sent by Jetpack.WordPress.com
	 */
	function verify_registration( $verify_secret ) {
		if ( empty( $verify_secret ) ) {
			return $this->error( new Jetpack_Error( 'verify_secret_1_missing', sprintf( 'The required "%s" parameter is missing.', 'secret_1' ), 400 ) );
		} else if ( !is_string( $verify_secret ) ) {
			return $this->error( new Jetpack_Error( 'verify_secret_1_malformed', sprintf( 'The required "%s" parameter is malformed.', 'secret_1' ), 400 ) );
		}

		$secrets = Jetpack::get_option( 'register' );
		if ( !$secrets || is_wp_error( $secrets ) ) {
			Jetpack::delete_option( 'register' );
			return $this->error( new Jetpack_Error( 'verify_secrets_missing', 'Verification took too long', 400 ) );
		}

		@list( $secret_1, $secret_2, $secret_eol ) = explode( ':', $secrets );
		if ( empty( $secret_1 ) || empty( $secret_2 ) || empty( $secret_eol ) || $secret_eol < time() ) {
			Jetpack::delete_option( 'register' );
			return $this->error( new Jetpack_Error( 'verify_secrets_missing', 'Verification took too long', 400 ) );
		}

		if ( $verify_secret !== $secret_1 ) {
			Jetpack::delete_option( 'register' );
			return $this->error( new Jetpack_Error( 'verify_secrets_mismatch', 'Secret mismatch', 400 ) );
		}

		Jetpack::delete_option( 'register' );

		return $secret_2;
	}

	/**
	 * Wrapper for wp_authenticate( $username, $password );
	 *
	 * @return WP_User|IXR_Error
	 */
	function login() {
		$user = wp_authenticate( 'username', 'password' );
		if ( is_wp_error( $user ) ) {
			if ( 'authentication_failed' == $user->get_error_code() ) { // Generic error could mean most anything.
				$this->error = new Jetpack_Error( 'invalid_request', 'Invalid Request', 403 );
			} else {
				$this->error = $user;
			}
			return false;
		} else if ( !$user ) { // Shouldn't happen.
			$this->error = new Jetpack_Error( 'invalid_request', 'Invalid Request', 403 );
			return false;
		}

		return $user;
	}

	/**
	 * Returns the current error as an IXR_Error
	 *
	 * @return null|IXR_Error
	 */
	function error( $error = null ) {
		if ( !is_null( $error ) ) {
			$this->error = $error;
		}

		if ( is_wp_error( $this->error ) ) {
			$code = $this->error->get_error_data();
			if ( !$code ) {
				$code = -10520;
			}
			$message = sprintf( 'Jetpack: [%s] %s', $this->error->get_error_code(), $this->error->get_error_message() );
			return new IXR_Error( $code, $message );
		} else if ( is_a( $this->error, 'IXR_Error' ) ) {
			return $this->error;
		}

		return false;
	}

/* API Methods */

	/**
	 * Just authenticates with the given Jetpack credentials.
	 *
	 * @return bool|IXR_Error
	 */
	function test_connection() {
		return true;
	}

	/**
	 * Returns what features are available. Uses the slug of the module files.
	 *
	 * @return array|IXR_Error
	 */
	function features_available() {
		$raw_modules = Jetpack::get_available_modules();
		$modules = array();
		foreach ( $raw_modules as $module ) {
			$modules[] = Jetpack::get_module_slug( $module );
		}

		return $modules;
	}

	/**
	 * Returns what features are enabled. Uses the slug of the modules files.
	 *
	 * @return array|IXR_Error
	 */
	function features_enabled() {
		$raw_modules = Jetpack::get_active_modules();
		$modules = array();
		foreach ( $raw_modules as $module ) {
			$modules[] = Jetpack::get_module_slug( $module );
		}

		return $modules;
	}
	
	function get_post( $id ) {
		if ( !$id = (int) $id ) {
			return false;
		}

		$jetpack = Jetpack::init();
		$post = $jetpack->get_post( $id );

		if ( $jetpack->is_post_public( $post ) )
			return $post;

		return false;
	}
	
	function get_comment( $id ) {
		if ( !$id = (int) $id ) {
			return false;
		}

		$jetpack = Jetpack::init();
		$comment = $jetpack->get_comment( $id );

		if ( !is_array( $comment ) )
			return false;

		if ( !$this->get_post( $comment['comment_post_ID'] ) )
			return false;

		return $comment;
	}
}