Completed
Push — try/block-editor-iframe ( 3eb55d...35a1c9 )
by
unknown
16:40 queued 10:04
created

wordpress-com-block-editor-iframe.php ➔ jetpack_verify_frame_nonce()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 5
nop 2
dl 0
loc 33
rs 9.0808
c 0
b 0
f 0
1
<?php
2
/**
3
 * WordPress.com Block Editor Iframe
4
 * Allow new block editor posts to be composed on WordPress.com.
5
 * This is auto-loaded as of Jetpack v7.4 for sites connected to WordPress.com only.
6
 *
7
 * @package Jetpack
8
 */
9
10
/**
11
 * Prevents frame options header from firing if this is a whitelisted iframe request.
12
 */
13
function jetpack_disable_send_frame_options_header() {
14
	if ( jetpack_framing_allowed() ) {
15
		remove_action( 'admin_init', 'send_frame_options_header' );
16
	}
17
}
18
add_action( 'admin_init', 'jetpack_disable_send_frame_options_header', 9 );
19
20
/**
21
 * Adds custom admin body class if this is a whitelisted iframe request.
22
 *
23
 * @param string $classes Admin body classes.
24
 * @return string
25
 */
26
function jetpack_add_iframed_body_class( $classes ) {
27
	if ( jetpack_framing_allowed() ) {
28
		$classes .= ' is-iframed ';
29
	}
30
31
	return $classes;
32
}
33
add_filter( 'admin_body_class', 'jetpack_add_iframed_body_class' );
34
35
/**
36
 * Checks whether this is a whitelisted iframe request.
37
 *
38
 * @return bool
39
 */
40
function jetpack_framing_allowed() {
41
	if ( empty( $_GET['frame-nonce'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
42
		return false;
43
	}
44
45
	$verified = jetpack_verify_frame_nonce(
46
		$_GET['frame-nonce'],  // phpcs:ignore WordPress.Security.NonceVerification
47
		'frame-' . Jetpack_Options::get_option( 'id' )
48
	);
49
50
	if ( $verified && ! defined( 'IFRAME_REQUEST' ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $verified of type false|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
51
		define( 'IFRAME_REQUEST', true );
52
	}
53
54
	return (bool) $verified;
55
}
56
57
/**
58
 * Verify that correct nonce was used with time limit.
59
 *
60
 * The user is given an amount of time to use the token, so therefore, since the
61
 * UID and $action remain the same, the independent variable is the time.
62
 *
63
 * @param string $nonce  Nonce that was used in the form to verify.
64
 * @param string $action Should give context to what is taking place and be the same when nonce was created.
65
 * @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
66
 *                   0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
67
 */
68
function jetpack_verify_frame_nonce( $nonce, $action ) {
69
	$nonce = (string) $nonce;
70
	if ( empty( $nonce ) ) {
71
		return false;
72
	}
73
74
	$user_id = get_current_user_id();
75
	if ( ! $user_id ) {
76
		return false;
77
	}
78
79
	$i = wp_nonce_tick();
80
	add_filter( 'salt', 'jetpack_filter_salt', 10, 2 );
81
82
	// Nonce generated 0-12 hours ago.
83
	$expected = substr( wp_hash( $i . $action . $user_id, 'jetpack_frame_nonce' ), -12, 10 );
84
	if ( hash_equals( $expected, $nonce ) ) {
85
		remove_filter( 'salt', 'jetpack_filter_salt' );
86
		return 1;
87
	}
88
89
	// Nonce generated 12-24 hours ago.
90
	$expected = substr( wp_hash( ( $i - 1 ) . $action . $user_id, 'jetpack_frame_nonce' ), -12, 10 );
91
	if ( hash_equals( $expected, $nonce ) ) {
92
		remove_filter( 'salt', 'jetpack_filter_salt' );
93
		return 2;
94
	}
95
96
	remove_filter( 'salt', 'jetpack_filter_salt' );
97
98
	// Invalid nonce.
99
	return false;
100
}
101
102
/**
103
 * Filters the WordPress salt.
104
 *
105
 * @param string $salt   Salt for the given scheme.
106
 * @param string $scheme Authentication scheme.
107
 * @return string
108
 */
109
function jetpack_filter_salt( $salt, $scheme ) {
110
	if ( 'jetpack_frame_nonce' === $scheme ) {
111
		$token = Jetpack_Data::get_access_token( get_current_user_id() );
112
113
		if ( $token ) {
114
			$salt = $token->secret;
115
		}
116
	}
117
118
	return $salt;
119
}
120