Changeset 14262
- Timestamp:
- 12/11/2024 05:36:31 AM (4 months ago)
- Location:
- sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory
- Files:
-
- 1 deleted
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/api/routes/class-plugin-release-confirmation.php
r14218 r14262 7 7 use WordPressdotorg\Plugin_Directory\Tools; 8 8 use WordPressdotorg\Plugin_Directory\Jobs\Plugin_Import; 9 use WordPressdotorg\Plugin_Directory\Shortcodes\Release_Confirmation as Release_Confirmation_Shortcode;10 9 use WordPressdotorg\Plugin_Directory\Email\Release_Confirmation_Enabled as Release_Confirmation_Enabled_Email; 11 use WordPressdotorg\Plugin_Directory\Email\Release_Confirmation_Access as Release_Confirmation_Access_Email; 10 use Two_Factor_Core; 11 use function WordPressdotorg\Two_Factor\Revalidation\{ 12 get_status as get_revalidation_status, 13 get_url as get_revalidation_url, 14 }; 12 15 13 16 /** … … 80 83 return false; 81 84 }, 82 ] );83 84 register_rest_route( 'plugins/v1', '/release-confirmation-access', [85 'methods' => \WP_REST_Server::READABLE,86 'callback' => [ $this, 'send_access_email' ],87 'args' => [88 ],89 'permission_callback' => 'is_user_logged_in',90 85 ] ); 91 86 … … 119 114 $plugin = Plugin_Directory::get_plugin_post( $request['plugin_slug'] ); 120 115 121 return ( 122 Release_Confirmation_Shortcode::can_access() && 123 current_user_can( 'plugin_manage_releases', $plugin ) 124 ); 116 if ( ! $plugin || ! current_user_can( 'plugin_manage_releases', $plugin ) ) { 117 return false; 118 } 119 120 // Check to see if they've confirmed their 2FA status recently.. 121 $status = get_revalidation_status(); 122 if ( $status && $status['can_save'] ) { 123 return true; 124 } 125 126 // Before we say no, check if the user just needs to validate their 2FA. 127 if ( $status && $status['needs_revalidate'] && 'GET' === $request->get_method() ) { 128 $current_rest_url = add_query_arg( 129 array( 130 '_wpnonce' => wp_create_nonce( 'wp_rest' ), 131 '_wp_http_referer' => wp_get_referer(), 132 ), 133 get_rest_url( null, $request->get_route() ) 134 ); 135 136 wp_safe_redirect( get_revalidation_url( $current_rest_url ) ); 137 exit; 138 } 139 140 return false; 125 141 } 126 142 … … 300 316 } 301 317 302 /**303 * Send a Access email304 */305 public function send_access_email( $request ) {306 $result = [307 'location' => wp_get_referer() ?: home_url( '/developers/releases/' ),308 ];309 $result['location'] = add_query_arg( 'send_access_email', '1', $result['location'] );310 header( 'Location: ' . $result['location'] );311 312 $email = new Release_Confirmation_Access_Email(313 wp_get_current_user()314 );315 $result['sent'] = $email->send();316 317 return $result;318 }319 320 318 public function validate_plugin_tag_callback( $tag, $request ) { 321 319 $plugin = Plugin_Directory::get_plugin_post( $request['plugin_slug'] ); -
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-template.php
r14218 r14262 999 999 array( '_wpnonce' => wp_create_nonce( 'wp_rest' ) ), 1000 1000 $url 1001 );1002 }1003 1004 /**1005 * Generates a link to email the release confirmation link.1006 *1007 * @param int|\WP_Post|null $post Optional. Post ID or post object. Defaults to global $post.1008 * @return string URL to enable confirmations.1009 */1010 public static function get_release_confirmation_access_link() {1011 return add_query_arg(1012 array( '_wpnonce' => wp_create_nonce( 'wp_rest' ) ),1013 home_url( 'wp-json/plugins/v1/release-confirmation-access' )1014 1001 ); 1015 1002 } -
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/shortcodes/class-release-confirmation.php
r14245 r14262 5 5 use WordPressdotorg\Plugin_Directory\Template; 6 6 use WordPressdotorg\Plugin_Directory\Tools; 7 use Two_Factor_Core; 8 use function WordPressdotorg\Two_Factor\{ 9 Revalidation\get_status as get_revalidation_status, 10 Revalidation\get_js_url as get_revalidation_js_url, 11 get_onboarding_account_url as get_2fa_onboarding_url 12 }; 7 13 8 14 /** … … 14 20 15 21 const SHORTCODE = 'release-confirmation'; 16 const COOKIE = 'release_confirmation_access_token';17 const META_KEY = '_release_confirmation_access_token';18 22 const URL_PARAM = 'access_token'; 19 23 … … 59 63 ob_start(); 60 64 61 $should_show_access_notice = false; 62 foreach ( $plugins as $plugin ) { 63 if ( $plugin->release_confirmation ) { 64 $should_show_access_notice = true; 65 } 66 } 67 68 if ( ! self::can_access() && $should_show_access_notice ) { 69 if ( isset( $_REQUEST['send_access_email'] ) ) { 70 printf( 71 '<div class="plugin-notice notice notice-info notice-alt"><p>%s</p></div>', 72 __( 'Check your email for an access link to perform actions.', 'wporg-plugins') 73 ); 74 } else { 75 printf( 76 '<div class="plugin-notice notice notice-info notice-alt"><p>%s</p></div>', 77 sprintf( 78 /* translators: %s: URL */ 79 __( 'Check your email for an access link, or <a href="%s">request a new email</a> to perform actions.', 'wporg-plugins'), 80 Template::get_release_confirmation_access_link() 81 ) 82 ); 83 } 65 // If the user is not using 2FA, show a notice. 66 if ( ! Two_Factor_Core::is_user_using_two_factor( get_current_user_id() ) ) { 67 printf( 68 '<div class="plugin-notice notice notice-error notice-alt"><p>%s</p></div>', 69 sprintf( 70 __( 'Your account has elevated privileges and requires extra security before you can manage plugin releases. Please <a href="%s">enable two-factor authentication now</a>.', 'wporg-plugins' ), 71 get_2fa_onboarding_url() 72 ) 73 ); 84 74 } 85 75 … … 246 236 $buttons = []; 247 237 248 if ( $data['confirmations_required'] && empty( $data['discarded'] ) ) { 238 if ( 239 ! is_user_logged_in() || 240 ! Two_Factor_Core::is_user_using_two_factor( get_current_user_id() ) || 241 ! current_user_can( 'plugin_manage_releases', $plugin ) || 242 243 // No need to show actions if the release can't be confirmed, or is already confirmed 244 ! $data['confirmations_required'] || 245 $data['confirmed'] 246 ) { 247 return ''; 248 } 249 250 if ( empty( $data['discarded'] ) ) { 249 251 $current_user_confirmed = isset( $data['confirmations'][ wp_get_current_user()->user_login ] ); 250 252 251 if ( ! $current_user_confirmed && ! $data['confirmed'] ) { 252 if ( 253 self::can_access() && 254 current_user_can( 'plugin_manage_releases', $plugin ) 255 ) { 256 $buttons[] = sprintf( 257 '<a href="%s" class="wp-element-button button approve-release">%s</a>', 258 Template::get_release_confirmation_link( $data['tag'], $plugin ), 259 __( 'Confirm', 'wporg-plugins' ) 260 ); 261 $buttons[] = sprintf( 262 '<a href="%s" class="wp-element-button button approve-release">%s</a>', 263 Template::get_release_confirmation_link( $data['tag'], $plugin, 'discard' ), 264 __( 'Discard', 'wporg-plugins' ) 265 ); 266 } else { 267 $buttons[] = sprintf( 268 '<a class="wp-element-button button approve-release disabled">%s</a>', 269 __( 'Confirm', 'wporg-plugins' ) 270 ); 271 $buttons[] = sprintf( 272 '<a class="wp-element-button button approve-release disabled">%s</a>', 273 __( 'Discard', 'wporg-plugins' ) 274 ); 275 } 276 277 } elseif ( $current_user_confirmed ) { 253 if ( ! $current_user_confirmed ) { 254 $confirm_link = Template::get_release_confirmation_link( $data['tag'], $plugin ); 255 $discard_link = Template::get_release_confirmation_link( $data['tag'], $plugin, 'discard' ); 256 257 $confirm_link = get_revalidation_js_url( $confirm_link ); 258 $discard_link = get_revalidation_js_url( $discard_link ); 259 278 260 $buttons[] = sprintf( 279 '<a class="wp-element-button button approve-release disabled">%s</a>', 280 __( 'Confirmed', 'wporg-plugins' ) 281 ); 261 '<a href="%s" class="wp-element-button button approve-release" data-2fa-required data-2fa-message="%s">%s</a>', 262 $confirm_link, 263 esc_attr( 264 sprintf( 265 /* translators: 1: Version number, 2: Plugin name. */ 266 __( 'Confirm your Two-Factor Authentication to release version %1$s of %2$s.', 'wporg-plugins' ), 267 esc_html( $data['version'] ), 268 $plugin->post_title 269 ) 270 ), 271 __( 'Confirm', 'wporg-plugins' ) 272 ); 273 274 $buttons[] = sprintf( 275 '<a href="%s" class="wp-element-button button approve-release" data-2fa-required data-2fa-message="%s">%s</a>', 276 $discard_link, 277 esc_attr( 278 sprintf( 279 /* translators: 1: Version number, 2: Plugin name. */ 280 __( 'Confirm your Two-Factor Authentication to discard the release %1$s for %2$s.', 'wporg-plugins' ), 281 esc_html( $data['version'] ), 282 $plugin->post_title 283 ) 284 ), 285 __( 'Discard', 'wporg-plugins' ) 286 ); 287 282 288 } 283 289 } elseif ( … … 297 303 } 298 304 299 static function can_access() {300 if ( ! is_user_logged_in() ) {301 return false;302 }303 304 // Plugin reviewers can always access the release management functionality, in wp-admin.305 if ( current_user_can( 'plugin_review' ) && ( is_admin() || wp_is_serving_rest_request() ) ) {306 return true;307 }308 309 // Must have an access token..310 if ( empty( $_COOKIE[ self::COOKIE ] ) ) {311 return false;312 }313 314 // ...and it be valid..315 $token = get_user_meta( get_current_user_id(), self::META_KEY, true );316 if (317 $token &&318 $token['time'] > ( time() - DAY_IN_SECONDS ) &&319 wp_check_password( $_COOKIE[ self::COOKIE ], $token['token'] )320 ) {321 return true;322 }323 324 return false;325 }326 327 305 static function generate_access_url( $user = null ) { 328 if ( ! $user ) { 329 $user = wp_get_current_user(); 330 } 331 if ( ! $user || ! $user->exists() ) { 332 return false; 333 } 334 335 $time = time(); 336 $plaintext = wp_generate_password( 24, false ); 337 $token = wp_hash_password( $plaintext ); 338 update_user_meta( $user->ID, self::META_KEY, compact( 'token', 'time' ) ); 339 340 $url = add_query_arg( 341 self::URL_PARAM, 342 urlencode( $plaintext ), 343 home_url( '/developers/releases/' ) 344 ); 345 346 return $url; 306 return home_url( '/developers/releases/' ); 347 307 } 348 308 … … 351 311 if ( ! $post || ! is_page() || ! has_shortcode( $post->post_content, self::SHORTCODE ) ) { 352 312 return; 353 }354 355 // Migrate URL param to cookie.356 if ( isset( $_REQUEST[ self::URL_PARAM ] ) ) {357 setcookie( self::COOKIE, $_REQUEST[ self::URL_PARAM ], time() + DAY_IN_SECONDS, '/plugins/', 'wordpress.org', true, true );358 }359 360 // Expire the cookie when needed. This is not for security, only performance / cleanliness.361 if ( isset( $_COOKIE[ self::COOKIE ] ) && ! self::can_access() ) {362 unset( $_COOKIE[ self::COOKIE ] );363 setcookie( self::COOKIE, false, time() - DAY_IN_SECONDS );364 313 } 365 314
Note: See TracChangeset
for help on using the changeset viewer.