← All changes
|
jetpack_vendor/automattic/jetpack-publicize/src/class-keyring-result-handler.php
+86
-0
16.2-beta
→
16.3
View file →
| @@ -1,0 +1,86 @@ | ||
| 1 | +<?php | |
| 2 | +/** | |
| 3 | + * Same-origin completion handler for the publicize auth_flow=v2 connect flow. | |
| 4 | + * | |
| 5 | + * @package automattic/jetpack-publicize | |
| 6 | + */ | |
| 7 | + | |
| 8 | +namespace Automattic\Jetpack\Publicize; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * Handles the popup landing page that public-api redirects back to after a connection is | |
| 12 | + * verified (auth_flow=v2). | |
| 13 | + * | |
| 14 | + * Because Meta/Threads sever `window.opener` via COOP, the popup cannot post its result back | |
| 15 | + * to the opener tab. Instead public-api redirects the popup to this same-origin admin-post | |
| 16 | + * endpoint, which broadcasts the request_id over a BroadcastChannel that the opener is | |
| 17 | + * listening on, then closes itself. The opener then fetches the verified result once. | |
| 18 | + */ | |
| 19 | +class Keyring_Result_Handler { | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * The admin-post action that the connect popup is redirected back to. | |
| 23 | + */ | |
| 24 | + const ACTION = 'jetpack_social_keyring_done'; | |
| 25 | + | |
| 26 | + /** | |
| 27 | + * The BroadcastChannel name shared with the client. | |
| 28 | + * | |
| 29 | + * Must match KEYRING_BROADCAST_CHANNEL in _inc/utils/request-external-access.js. | |
| 30 | + */ | |
| 31 | + const CHANNEL = 'jetpack-social-keyring'; | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * Register the handler. | |
| 35 | + */ | |
| 36 | + public static function init() { | |
| 37 | + add_action( 'admin_post_' . self::ACTION, array( __CLASS__, 'handle' ) ); | |
| 38 | + } | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * Output a minimal page that broadcasts the request_id to the opener and closes the popup. | |
| 42 | + * | |
| 43 | + * @return never | |
| 44 | + */ | |
| 45 | + public static function handle() { | |
| 46 | + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only: the request_id is an opaque token reflected back to a same-origin BroadcastChannel; nothing is mutated. | |
| 47 | + $request_id = isset( $_GET['request_id'] ) ? sanitize_key( wp_unslash( $_GET['request_id'] ) ) : ''; | |
| 48 | + | |
| 49 | + nocache_headers(); | |
| 50 | + | |
| 51 | + if ( ! headers_sent() ) { | |
| 52 | + header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) ); | |
| 53 | + } | |
| 54 | + | |
| 55 | + $close_warning = esc_html__( 'You can close this window now.', 'jetpack-publicize-pkg' ); | |
| 56 | + ?> | |
| 57 | +<!DOCTYPE html> | |
| 58 | +<html <?php language_attributes(); ?>> | |
| 59 | +<head> | |
| 60 | + <meta charset="<?php echo esc_attr( get_option( 'blog_charset' ) ); ?>" /> | |
| 61 | + <title></title> | |
| 62 | +</head> | |
| 63 | +<body> | |
| 64 | + <p><?php echo $close_warning; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- already escaped above. ?></p> | |
| 65 | + <script> | |
| 66 | + ( function () { | |
| 67 | + try { | |
| 68 | + var channel = new BroadcastChannel( <?php echo wp_json_encode( self::CHANNEL, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?> ); | |
| 69 | + channel.postMessage( { | |
| 70 | + type: 'keyring-result', | |
| 71 | + requestId: <?php echo wp_json_encode( $request_id, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?>, | |
| 72 | + } ); | |
| 73 | + channel.close(); | |
| 74 | + } catch ( e ) {} | |
| 75 | + | |
| 76 | + window.setTimeout( function () { | |
| 77 | + window.close(); | |
| 78 | + }, 50 ); | |
| 79 | + } )(); | |
| 80 | + </script> | |
| 81 | +</body> | |
| 82 | +</html> | |
| 83 | + <?php | |
| 84 | + exit; | |
| 85 | + } | |
| 86 | +} | |