Making WordPress.org


Ignore:
Timestamp:
04/13/2021 07:23:31 AM (3 years ago)
Author:
dd32
Message:

Login: Add an interstitial to record ToS/CoC/Privacy policy acceptance upon login, blocking login if not accepted.

This is currently only enabled for super admins while the feature is debugged/finalised.

See #5618.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/common/includes/wporg-sso/wp-plugin.php

    r10844 r10889  
    2424            'linkexpired'  => '/linkexpired(/(?P<reason>register|lostpassword)/(?P<user>[^/]+))?',
    2525            'oauth'        => '/oauth',
     26
     27            // Only for logged in users, but prior to cookies.
     28            'updated-tos'  => '/updated-policies',
     29        );
     30
     31        /**
     32         * List of additional valid paths on login.wordpress.org for logged in requests.
     33         * @var array
     34         */
     35        public $valid_sso_paths_logged_in = array(
     36            'logout' => '/logout',
     37        );
     38
     39        /**
     40         * List of additional valid paths on login.wordpress.org for logged-out requests.
     41         * @var array
     42         */
     43        public $valid_sso_paths_registration = array(
     44            'pending-profile' => '/register/create-profile(/(?P<profile_user>[^/]+)/(?P<profile_key>[^/]+))?',
     45            'pending-create'  => '/register/create(/(?P<confirm_user>[^/]+)/(?P<confirm_key>[^/]+))?',
     46            'register'        => '/register(/(?P<user>[^/]+))?',
    2647        );
    2748
     
    7293                } else {
    7394                    add_filter( 'login_redirect', [ $this, 'maybe_add_remote_login_bounce_to_post_login_url' ], 10, 3 );
     95
     96                    // Updated TOS interceptor.
     97                    add_action( 'set_auth_cookie',   [ $this, 'maybe_block_auth_cookies_context_provider' ], 10, 4 );
     98                    add_filter( 'send_auth_cookies', [ $this, 'maybe_block_auth_cookies' ], 100 );
    7499                }
    75100            }
     
    85110            $value = get_network_option( 1, 'registration', 'none' );
    86111            add_filter( 'pre_site_option_registration', array( $this, 'inherit_registration_option' ) );
     112
    87113            return $value;
    88114        }
     115
    89116        /**
    90117         * Checks if the authenticated is "admin" and returns a nicer error message.
     
    197224            // Extend paths which are only available for logged in users.
    198225            if ( is_user_logged_in() ) {
    199                 $this->valid_sso_paths['logout'] = '/logout';
    200             }
     226                $this->valid_sso_paths = array_merge(
     227                    $this->valid_sso_paths,
     228                    $this->valid_sso_paths_logged_in
     229                );
    201230
    202231            // Extend registration paths only when registration is open.
    203             if ( 'user' === get_site_option( 'registration', 'none' ) ) {
    204                 // New "pending" registration flow.
    205                 $this->valid_sso_paths['pending-profile']  = '/register/create-profile(/(?P<profile_user>[^/]+)/(?P<profile_key>[^/]+))?';
    206                 $this->valid_sso_paths['pending-create']   = '/register/create(/(?P<confirm_user>[^/]+)/(?P<confirm_key>[^/]+))?';
    207 
    208                 // Primary registration route.
    209                 $this->valid_sso_paths['register']         = '/register(/(?P<user>[^/]+))?';
     232            } elseif ( 'user' === get_site_option( 'registration', 'none' ) ) {
     233                $this->valid_sso_paths = array_merge(
     234                    $this->valid_sso_paths,
     235                    $this->valid_sso_paths_registration
     236                );
    210237            }
    211238
     
    529556            return $hash;
    530557        }
     558
     559        /**
     560         * The `send_auth_cookies` action used for the below function has no user context.
     561         * This function provides user context to it via the local static.
     562         */
     563        public function maybe_block_auth_cookies_context_provider( $auth_cookie = null, $expire = null, $expiration = null, $user_id = null ) {
     564            static $_user_id_remember_me = false;
     565            if ( ! is_null( $auth_cookie ) ) {
     566                $remember_me = ( 0 !== $expire );
     567                $_user_id_remember_me = compact( 'user_id', 'remember_me' );
     568            } else {
     569                // Fetching the data.
     570                return $_user_id_remember_me;
     571            }
     572        }
     573
     574        /**
     575         * Hooked to 'send_auth_cookies' to prevent sending of the Authentication cookies and redirect
     576         * to the updated policy interstitial if required.
     577         *
     578         * Note: This action provides no context about the request, which is why the context is being
     579         * provided via the 'set_auth_cookie' filter hook above.
     580         */
     581        public function maybe_block_auth_cookies( $send_cookies ) {
     582            $user_id = $this->maybe_block_auth_cookies_context_provider()['user_id'] ?? false;
     583
     584            if (
     585                $user_id &&
     586                ! $this->has_agreed_to_tos( $user_id )
     587            ) {
     588                $send_cookies = false;
     589
     590                // Set a cookie so that we can keep the user in a auth'd (but not) state.
     591                $token_cookie = wp_generate_auth_cookie( $user_id, time() + HOUR_IN_SECONDS, 'tos_token' );
     592                $remember_me  = (int) $this->maybe_block_auth_cookies_context_provider()['remember_me'];
     593
     594                setcookie( self::LOGIN_TOS_COOKIE, $token_cookie, time() + HOUR_IN_SECONDS, '/', self::SSO_HOST, true, true );
     595                setcookie( self::LOGIN_TOS_COOKIE . '_remember', $remember_me, time() + HOUR_IN_SECONDS, '/', self::SSO_HOST, true, true );
     596
     597                // Redirect them to the interstitial.
     598                add_filter( 'login_redirect', [ $this, 'redirect_to_policy_update' ], 1000 );
     599            }
     600
     601            return $send_cookies;
     602        }
     603
     604        /**
     605         * Redirects the user to the policy update interstitial.
     606         */
     607        public function redirect_to_policy_update( $redirect ) {
     608            if ( false === strpos( $redirect, home_url( '/updated-policies' ) ) ) {
     609                $redirect = add_query_arg(
     610                    'redirect_to',
     611                    urlencode( $redirect ),
     612                    home_url( '/updated-policies' )
     613                );
     614            }
     615
     616            return $redirect;
     617        }
     618
     619        /**
     620         * Whether the given user_id has agreed to the current version of the TOS.
     621         */
     622        protected function has_agreed_to_tos( $user_id ) {
     623            // TEMPORARY: Limit to supes.
     624            if ( ! is_super_admin() ) {
     625                return true;
     626            }
     627
     628            $tos_agreed_to = get_user_meta( $user_id, self::TOS_USER_META_KEY, true ) ?: 0;
     629
     630            return $tos_agreed_to >= TOS_REVISION;
     631        }
     632
    531633    }
    532634
    533     new WP_WPOrg_SSO();
     635    WP_WPOrg_SSO::get_instance();
    534636}
Note: See TracChangeset for help on using the changeset viewer.