| @@ -97,19 +97,45 @@ | ||
| 97 | 97 | |
| 98 | 98 | $name = trim( (string) ( $data['name'] ?? '' ) ); |
| 99 | 99 | $email = trim( (string) ( $data['email'] ?? '' ) ); |
| 100 | 100 | $statuses = array_map( 'sanitize_key', is_array( $data['statuses'] ?? null ) ? $data['statuses'] : array() ); |
| 101 | - $in_house = (bool) ( $data['_inHouse'] ?? false ); | |
| 101 | + $user_id = absint( $data['id'] ?? 0 ); | |
| 102 | + $in_house = (bool) ( $data['_inHouse'] ?? false ) && $user_id > 0; | |
| 102 | 103 | |
| 103 | 104 | if ( '' === $name || ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) { |
| 104 | 105 | return new Response( false, array( 'message' => esc_html__( 'Invalid recipient data.', 'defender-security' ) ) ); |
| 105 | 106 | } |
| 106 | 107 | |
| 107 | - if ( empty( $statuses ) ) { | |
| 108 | + if ( ! $in_house && ! preg_match( '/^[\p{L}\s\-\']+$/u', $name ) ) { | |
| 109 | + return new Response( false, array( 'message' => esc_html__( 'Only letters, spaces, hyphens and apostrophes allowed.', 'defender-security' ) ) ); | |
| 110 | + } | |
| 111 | + | |
| 112 | + // Block duplicate recipient emails. Messages render as React text, so keep them unescaped. | |
| 113 | + if ( $this->recipient_directory->email_exists( $email ) ) { | |
| 114 | + return new Response( | |
| 115 | + false, | |
| 116 | + array( | |
| 117 | + 'message' => __( 'This email address is already added as a recipient. Edit the existing recipient to add more report types.', 'defender-security' ), | |
| 118 | + 'code' => 'recipient_notice', | |
| 119 | + ) | |
| 120 | + ); | |
| 121 | + } | |
| 122 | + | |
| 123 | + // Registered users must be added via user search, not invited by email. | |
| 124 | + if ( ! $in_house && get_user_by( 'email', $email ) ) { | |
| 125 | + return new Response( | |
| 126 | + false, | |
| 127 | + array( | |
| 128 | + 'message' => __( "Registered user email can't be invited, you can add them directly at Search WordPress user tab.", 'defender-security' ), | |
| 129 | + 'code' => 'recipient_notice', | |
| 130 | + ) | |
| 131 | + ); | |
| 132 | + } | |
| 133 | + | |
| 134 | + if ( array() === $statuses ) { | |
| 108 | 135 | return new Response( false, array( 'message' => esc_html__( 'Please enable at least one notification module before inviting a recipient.', 'defender-security' ) ) ); |
| 109 | 136 | } |
| 110 | 137 | |
| 111 | - $user_id = $in_house ? absint( $data['id'] ?? 0 ) : 0; | |
| 112 | 138 | $subscriber = array( |
| 113 | 139 | 'name' => $name, |
| 114 | 140 | 'email' => $email, |
| 115 | 141 | ); |
| @@ -154,9 +180,9 @@ | ||
| 154 | 180 | if ( '' === $recipient_id ) { |
| 155 | 181 | return new Response( false, array( 'message' => esc_html__( 'Invalid recipient ID.', 'defender-security' ) ) ); |
| 156 | 182 | } |
| 157 | 183 | |
| 158 | - $name = trim( (string) ( $profile['name'] ?? '' ) ); | |
| 184 | + $name = sanitize_text_field( trim( (string) ( $profile['name'] ?? '' ) ) ); | |
| 159 | 185 | $email = sanitize_email( trim( (string) ( $profile['email'] ?? '' ) ) ); |
| 160 | 186 | $in_house = is_numeric( $recipient_id ); |
| 161 | 187 | |
| 162 | 188 | if ( '' === $name || ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) { |
| @@ -162,8 +188,12 @@ | ||
| 162 | 188 | if ( '' === $name || ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) { |
| 163 | 189 | return new Response( false, array( 'message' => esc_html__( 'Invalid recipient data.', 'defender-security' ) ) ); |
| 164 | 190 | } |
| 165 | 191 | |
| 192 | + if ( ! $in_house && ! preg_match( '/^[\p{L}\s\-\']+$/u', $name ) ) { | |
| 193 | + return new Response( false, array( 'message' => esc_html__( 'Only letters, spaces, hyphens and apostrophes allowed.', 'defender-security' ) ) ); | |
| 194 | + } | |
| 195 | + | |
| 166 | 196 | $subscriber = array( |
| 167 | 197 | 'name' => $name, |
| 168 | 198 | 'email' => $email, |
| 169 | 199 | ); |
| @@ -310,8 +340,19 @@ | ||
| 310 | 340 | 'slug' => $result['redirect_slug'], |
| 311 | 341 | 'context' => 'subscribed', |
| 312 | 342 | ), |
| 313 | 343 | get_edit_profile_url() |
| 344 | + ) | |
| 345 | + ); | |
| 346 | + } elseif ( $result['processed'] ) { | |
| 347 | + wp_safe_redirect( | |
| 348 | + add_query_arg( | |
| 349 | + array( | |
| 350 | + 'defender_subscription' => 'confirmed', | |
| 351 | + 'slug' => $result['redirect_slug'], | |
| 352 | + 'hash' => HTTP::get( 'hash', '' ), | |
| 353 | + ), | |
| 354 | + home_url() | |
| 314 | 355 | ) |
| 315 | 356 | ); |
| 316 | 357 | } else { |
| 317 | 358 | wp_safe_redirect( home_url() ); |