forked from Automattic/vip-go-mu-plugins
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvip-rest-api.php
109 lines (90 loc) · 3.48 KB
/
vip-rest-api.php
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
<?php
/*
Plugin Name: REST API Enhancements
Plugin URI: https://vip.wordpress.com/
Description: Add custom REST API endpoints for VIP requests; these endpoints are private and only for the use of WordPress.com VIP
Author: Erick Hitter, Automattic
Version: 0.1
*/
/**
* Generate token for requests made from WordPress.com to a given REST API route namespace
*
* Follows the approach of `wp_create_nonce()`, with a shortened duration and sha256 instead of md5
*
* @param string $namespace REST API route's namespace
* @param string $nonce_salt Salt to use with this hash
* @return string
*/
function wpcom_vip_generate_go_rest_api_request_token( $namespace, $nonce_salt = NONCE_SALT ) {
// Copies of this function exist in places without MINUTE_IN_SECONDS
$minute_in_seconds = 60;
// Two-minute nonce tick
// Generate a four-minute tick per wp_nonce_tick(), but only accept the first half of the tick in wpcom_vip_verify_go_rest_api_request_authorization(), rendering it a two-minute tick
$tick = ceil( time() / ( ( 4 * $minute_in_seconds ) / 2 ) );
$hash_data = $tick . '|' . $namespace;
$hash = hash_hmac( 'sha256', $hash_data, $nonce_salt );
return $hash;
}
/**
* Verify that a given authorization header is valid for a REST API route namespace
*
* Follows the approach of `wp_verify_nonce()`, but only accepts the first half of the tick, for shorter durations
*
* @param string $namespace REST API route's namespace
* @param string $auth_header Authorization header to verify
* @return bool
*/
function wpcom_vip_verify_go_rest_api_request_authorization( $namespace, $auth_header ) {
$auth_header = explode( ' ', $auth_header );
// Malformed auth header
if ( 2 !== count( $auth_header ) ) {
return false;
}
list( $auth_mechanism, $token ) = $auth_header;
// Invalid auth mechanism
if ( 'VIP-MACHINE-TOKEN' !== $auth_mechanism ) {
return false;
}
$expected = wpcom_vip_generate_go_rest_api_request_token( $namespace );
return hash_equals( $expected, $token );
}
/**
* Check if necessary authentication header allows access to an endpoint
*
* Not always called as a REST API permission callback, hence going directly to the global
*
* @param string $namespace RESET API route's namespace
* @return bool
*/
function wpcom_vip_go_rest_api_request_allowed( $namespace, $cap = 'do_not_allow' ) {
// First check basic auth
$basic_auth_user = wpcom_vip_basic_auth_user();
if ( $basic_auth_user && ! is_wp_error( $basic_auth_user ) &&
$basic_auth_user->ID && $basic_auth_user->ID > 0 ) {
$user_id = $basic_auth_user->ID;
// Check current user has `vip_support` or the required capability.
// VIP Support users should be able to do anything on the site, but
// this cap check runs before that plugin is loaded.
// https://github.com/Automattic/vip-support
if ( user_can( $user_id, 'vip_support' ) || user_can( $user_id, $cap ) ) {
return true;
}
}
// Do we have a header to check?
if ( ! isset( $_SERVER['HTTP_AUTHORIZATION'] ) || empty( $_SERVER['HTTP_AUTHORIZATION'] ) ) {
return false;
}
return wpcom_vip_verify_go_rest_api_request_authorization( $namespace, $_SERVER['HTTP_AUTHORIZATION'] );
}
function wpcom_vip_basic_auth_user() {
if ( ! isset( $_SERVER['PHP_AUTH_USER'] ) || ! isset( $_SERVER['PHP_AUTH_PW'] ) ) {
return false;
}
$username = $_SERVER['PHP_AUTH_USER'];
$password = $_SERVER['PHP_AUTH_PW'];
return wp_authenticate( $username, $password );
}
/**
* Include customizations
*/
require_once __DIR__ . '/rest-api/vip-endpoints.php';