Making WordPress.org

Changeset 15080


Ignore:
Timestamp:
08/17/2026 01:37:56 AM (8 days ago)
Author:
obenland
Message:

Slack: Stop unauthenticated requests from fataling the webhook endpoints.

Closes https://github.com/WordPress/wordpress.org/pull/811.

Location:
sites/trunk/api.wordpress.org/public_html/dotorg/slack
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/api.wordpress.org/public_html/dotorg/slack/announce.php

    r14583 r15080  
    11<?php
     2/**
     3 * Slack slash-command handler for @here and @channel announcements.
     4 *
     5 * Standalone handler: WordPress is not loaded, so request data is never slashed. Slack
     6 * authenticates itself with one of the shared `WEBHOOK_TOKEN_*` secrets below; nonces do
     7 * not exist in server-to-server webhooks.
     8 *
     9 * phpcs:disable WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
     10 *
     11 * @package WordPressdotorg\API\Slack
     12 */
    213
    3 namespace {
    4         require dirname( dirname( __DIR__ ) ) . '/includes/hyperdb/bb-10-hyper-db.php';
    5         require dirname( dirname( __DIR__ ) ) . '/includes/slack-config.php';
     14namespace Dotorg\Slack\Announce;
     15
     16require dirname( __DIR__, 2 ) . '/includes/hyperdb/bb-10-hyper-db.php';
     17require dirname( __DIR__, 2 ) . '/includes/slack-config.php';
     18require dirname( __DIR__, 2 ) . '/includes/slack/announce/lib.php';
     19
     20/**
     21 * Returns the Gravatar URL for the WordPress.org account linked to a Slack user.
     22 *
     23 * Defined in this namespace so that `run()` in lib.php picks it up as an optional hook;
     24 * it falls back to the Slack profile image when this function is not available.
     25 *
     26 * @param string $username The Slack user name. Unused, part of the hook signature.
     27 * @param string $slack_id The Slack user ID to look up.
     28 * @param string $team_id  The Slack team ID. Unused, part of the hook signature.
     29 * @return string The Gravatar URL, or an empty string when the Slack account is not linked.
     30 */
     31function get_avatar( $username, $slack_id, $team_id ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter -- Signature is fixed by the call in lib.php.
     32        global $wpdb;
     33
     34        $wp_user_id = $wpdb->get_var(
     35                $wpdb->prepare(
     36                        'SELECT user_id FROM slack_users WHERE slack_id = %s',
     37                        $slack_id
     38                )
     39        );
     40
     41        if ( ! $wp_user_id ) {
     42                return '';
     43        }
     44
     45        $email = $wpdb->get_var(
     46                $wpdb->prepare(
     47                        "SELECT user_email FROM $wpdb->users WHERE ID = %d",
     48                        $wp_user_id
     49                )
     50        );
     51
     52        if ( ! $email ) {
     53                return '';
     54        }
     55
     56        $hash = hash( 'sha256', strtolower( trim( $email ) ) );
     57        return sprintf( 'https://secure.gravatar.com/avatar/%s?s=96&d=mm&r=G&%s', $hash, time() );
    658}
    759
    8 namespace Dotorg\Slack\Announce {
    9 
    10 require dirname( dirname( __DIR__ ) ) . '/includes/slack/announce/lib.php';
    11 
    12 function get_avatar( $username, $slack_id, $team_id ) {
    13         global $wpdb;
    14 
    15         $wp_user_id = $wpdb->get_var( $wpdb->prepare(
    16                 "SELECT user_id FROM slack_users WHERE slack_id = %s",
    17                 $slack_id
    18         ) );
    19 
    20         $email = $wpdb->get_var( $wpdb->prepare(
    21                 "SELECT user_email FROM $wpdb->users WHERE ID = %d",
    22                 $wp_user_id
    23         ) );
    24 
    25         $hash = hash( 'sha256', strtolower( trim( $email ) ) );
    26         return sprintf( 'https://secure.gravatar.com/avatar/%s?s=96d=mm&r=G&%s', $hash, time() );
     60// Slack sends the token as POST data; anything else is not a webhook request.
     61if ( ! isset( $_POST['token'] ) || ! is_string( $_POST['token'] ) || '' === $_POST['token'] ) {
     62        return;
    2763}
    2864
    2965$i = 0;
    3066// WEBHOOK_TOKEN_1, WEBHOOK_TOKEN_2, etc.
    31 while ( defined( __NAMESPACE__ . '\\WEBHOOK_TOKEN_' . ++$i ) ) {
     67while ( defined( __NAMESPACE__ . '\\WEBHOOK_TOKEN_' . ( ++$i ) ) ) {
    3268        if ( hash_equals( constant( __NAMESPACE__ . '\\WEBHOOK_TOKEN_' . $i ), $_POST['token'] ) ) {
    3369                run( $_POST );
     70                break;
    3471        }
    3572}
    36 
    37 }
    38 
  • sites/trunk/api.wordpress.org/public_html/dotorg/slack/committers.php

    r14583 r15080  
    11<?php
    2 
    3 // Allow committers to publicly mention other committers via @committers.
     2/**
     3 * Slack outgoing-webhook handler that redirects @committers mentions to the slash command.
     4 *
     5 * Standalone handler: WordPress is not loaded, so request data is never slashed. Slack
     6 * authenticates itself with the shared `WEBHOOK_TOKEN` secret below; nonces do not exist
     7 * in server-to-server webhooks.
     8 *
     9 * phpcs:disable WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
     10 *
     11 * @package WordPressdotorg\API\Slack
     12 */
    413
    514namespace Dotorg\Slack\Committers;
    615
    7 require dirname( dirname( __DIR__ ) ) . '/includes/slack-config.php';
     16require dirname( __DIR__, 2 ) . '/includes/slack-config.php';
     17
     18// Slack sends the token as POST data; anything else is not a webhook request.
     19if ( ! isset( $_POST['token'] ) || ! is_string( $_POST['token'] ) || '' === $_POST['token'] ) {
     20        return;
     21}
    822
    923if ( ! hash_equals( WEBHOOK_TOKEN, $_POST['token'] ) ) {
     
    1125}
    1226
    13 echo json_encode( array(
    14         'username'   => 'wordpressdotorg',
    15         'link_names' => 1,
    16         'text'       => sprintf( '@%s: Use the `/committers` command.', $_POST['user_name'] ),
    17 ) );
     27// The Slack user name of whoever triggered the webhook, echoed back in the JSON response below.
     28$user_name = (string) filter_var( $_POST['user_name'] ?? '', FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW );
     29
     30// phpcs:ignore WordPress.WP.AlternativeFunctions.json_encode_json_encode -- No WP loaded.
     31echo json_encode(
     32        array(
     33                'username'   => 'wordpressdotorg',
     34                'link_names' => 1,
     35                'text'       => sprintf( '@%s: Use the `/committers` command.', $user_name ),
     36        )
     37);
    1838
    1939exit;
Note: See TracChangeset for help on using the changeset viewer.