PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.7.5
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.7.5
3.7.5 3.7.4 3.7.3 3.7.2 1-final 3.7.1 3.7.0 3.6.8 3.6.7 3.6.6 3.6.5 3.6.4 3.6.3 3.6.2 3.6.1 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.10 All 111 releases
← All changes | includes/API/Checkout.php +31 -1 3.7.23.7.5 View file →
@@ -18,8 +18,23 @@
18 18 }
19 19
20 20 public function checkout() {
21 21 $purchase_type = $this->get_param( 'purchase_type', 'template' );
22 +
23 + /**
24 + * Buying a template is a content decision any contributor may make, but a
25 + * subscription is bought *for the account* and changes what everyone on it
26 + * pays. The base gate is `delete_posts`, so without this a Contributor
27 + * could start a plan purchase against the site owner's account.
28 + */
29 + if ( 'subscription' === $purchase_type && ! current_user_can( 'manage_options' ) ) {
30 + return $this->error(
31 + 'insufficient_permission',
32 + __( 'Only administrators can change the subscription.', 'templately' ),
33 + 'checkout',
34 + rest_authorization_required_code()
35 + );
36 + }
22 37 $id = $this->get_param( 'id', 0, 'intval' );
23 38 $return_url = $this->get_param( 'return_url', admin_url( 'admin.php?page=templately' ), 'esc_url_raw' );
24 39
25 40 if ( empty( $id ) ) {
@@ -49,9 +64,24 @@
49 64 $data = ! empty( $response['data'] ) ? json_decode( $response['data'], true ) : [];
50 65
51 66 // Frontend checkout URL created — the app redirects the buyer to it.
52 67 if ( ! empty( $data['url'] ) ) {
53 - return $this->success( [ 'url' => $data['url'] ] );
68 + /**
69 + * The client assigns this straight to `window.location.href`, so verify
70 + * it is an https URL on a Templately host before handing it over. The
71 + * response is our own API's, but a redirect target that arrives over the
72 + * wire and is followed unchecked is an open redirect waiting to happen.
73 + */
74 + $url = esc_url_raw( $data['url'] );
75 + $host = wp_parse_url( $url, PHP_URL_HOST );
76 +
77 + $allowed = $host && ( 'templately.com' === $host || 'templately.dev' === $host || str_ends_with( $host, '.templately.com' ) || str_ends_with( $host, '.templately.dev' ) );
78 +
79 + if ( ! $allowed || 'https' !== wp_parse_url( $url, PHP_URL_SCHEME ) ) {
80 + return $this->error( 'invalid_checkout_url', __( 'The checkout could not be verified. Please try again.', 'templately' ), 'checkout' );
81 + }
82 +
83 + return $this->success( [ 'url' => $url ] );
54 84 }
55 85
56 86 $message = ! empty( $response['message'] ) ? $response['message'] : __( 'Could not start the checkout. Please try again.', 'templately' );
57 87