Completed
Push — try/block-editor-iframe ( 1dfec3...ea56f5 )
by
unknown
35:00 queued 28:31
created

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

Complexity

Conditions 5
Paths 5

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 5
nop 2
dl 0
loc 37
rs 9.0168
c 0
b 0
f 0
1
<?php
2
/**
3
 * Module Name: WordPress.com Block Editor Iframe
4
 * Module Description: Allow new block editor posts to be composed on WordPress.com.
5
 * Jumpstart Description: Allow new block editor posts to be composed on WordPress.com.
6
 * Sort Order: 15
7
 * First Introduced: 7.3
8
 * Requires Connection: Yes
9
 * Auto Activate: Yes
10
 * Module Tags: Writing
11
 * Feature: Writing
12
 * Additional Search Queries: iframes, allow, compose, WordPress.com, block, editor, post
13
 *
14
 * @package Jetpack
15
 */
16
17
/**
18
 * Prevents frame options header from firing if this is a whitelisted iframe request.
19
 */
20
function jetpack_disable_send_frame_options_header() {
21
	if ( jetpack_framing_allowed() ) {
22
		remove_action( 'admin_init', 'send_frame_options_header' );
23
	}
24
}
25
add_action( 'admin_init', 'jetpack_disable_send_frame_options_header', 9 );
26
27
/**
28
 * Adds custom admin body class if this is a whitelisted iframe request.
29
 *
30
 * @param string $classes Admin body classes.
31
 * @return string
32
 */
33
function jetpack_add_iframed_body_class( $classes ) {
34
	if ( jetpack_framing_allowed() ) {
35
		$classes .= ' is-iframed ';
36
	}
37
38
	return $classes;
39
}
40
add_filter( 'admin_body_class', 'jetpack_add_iframed_body_class' );
41
42
/**
43
 * Checks whether this is a whitelisted iframe request.
44
 *
45
 * @return bool
46
 */
47
function jetpack_framing_allowed() {
48
	if ( empty( $_GET['frame-nonce'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
49
		return false;
50
	}
51
52
	$verified = jetpack_verify_frame_nonce(
53
		wp_slash( $_GET['frame-nonce'] ),  // phpcs:ignore WordPress.Security.NonceVerification
54
		'frame-' . Jetpack_Options::get_option( 'id' )
55
	);
56
57
	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...
58
		define( 'IFRAME_REQUEST', true );
59
	}
60
61
	return (bool) $verified;
62
}
63
64
/**
65
 * Verify that correct nonce was used with time limit.
66
 *
67
 * The user is given an amount of time to use the token, so therefore, since the
68
 * UID and $action remain the same, the independent variable is the time.
69
 *
70
 * @param string     $nonce  Nonce that was used in the form to verify.
71
 * @param string|int $action Should give context to what is taking place and be the same when nonce was created.
72
 * @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
73
 *                   0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
74
 */
75
function jetpack_verify_frame_nonce( $nonce, $action = -1 ) {
76
	$nonce = (string) $nonce;
77
	if ( empty( $nonce ) ) {
78
		return false;
79
	}
80
81
	$user    = wp_get_current_user();
82
	$user_id = (int) get_user_meta( $user->ID, 'wpcom_user_id', true );
83
	if ( ! $user_id ) {
84
		return false;
85
	}
86
87
	$i = wp_nonce_tick();
88
	add_filter( 'salt', 'jetpack_filter_salt' );
89
90
	// Nonce generated 0-12 hours ago.
91
	$expected = substr( wp_hash( $i . $action . $user_id, 'nonce' ), -12, 10 );
92
	if ( hash_equals( $expected, $nonce ) ) {
93
		remove_filter( 'salt', 'jetpack_filter_salt' );
94
		return 1;
95
	}
96
97
	// Nonce generated 12-24 hours ago.
98
	$expected = substr( wp_hash( ( $i - 1 ) . $action . $user_id, 'nonce' ), -12, 10 );
99
	if ( hash_equals( $expected, $nonce ) ) {
100
		remove_filter( 'salt', 'jetpack_filter_salt' );
101
		return 2;
102
	}
103
104
	remove_filter( 'salt', 'jetpack_filter_salt' );
105
106
	/** This filter is documented in wp-includes/pluggable.php */
107
	do_action( 'wp_verify_nonce_failed', $nonce, $action, $user, '' );
108
109
	// Invalid nonce.
110
	return false;
111
}
112
113
/**
114
 * Filters `wp_salt()` to use the user token secret.
115
 *
116
 * @return string
117
 */
118
function jetpack_filter_salt() {
119
	$token = Jetpack_Data::get_access_token( get_current_user_id() );
120
	return $token->secret;
121
}
122