Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@
<exclude phpcbf-only="true" name="PEAR.Functions.FunctionCallSignature" />
</rule>

<!-- PHPUnit derives test class names from file names, and class names cannot contain hyphens. -->
<rule ref="WordPress.Files.FileName.NotHyphenatedLowercase">
<exclude-pattern>*/tests/*</exclude-pattern>
</rule>

<rule ref="WordPress-Docs">
<!-- Descriptive names make explicit comments unnecessary in many cases. -->
<exclude name="Squiz.Commenting.FunctionComment.MissingParamComment" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,22 @@ function validate_plugin_slug_callback( $value ) {
return is_string( $value ) && $value && Plugin_Directory::get_plugin_post( $value );
}

/**
* A sanitization callback for REST API locale parameters.
*
* Restricts the value to the characters present in WordPress locale slugs.
*
* @param string $value The requested locale.
* @return string The sanitized locale.
*/
public function sanitize_locale_callback( $value ) {
if ( ! is_scalar( $value ) ) {
return '';
}

return preg_replace( '/[^A-Za-z0-9_-]/', '', (string) $value );
}

/**
* A Permission Check callback which validates the request against the internal api-call token.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,48 @@ public function __construct() {
[
'methods' => \WP_REST_Server::CREATABLE,
'callback' => [ $this, 'scan_callback' ],

/*
* Fields are typed but not required, and tolerate nulls, so
* that malformed callbacks reach the callback and are recorded
* on the plugin instead of being rejected at the REST layer.
*/
'args' => [
'plugin_slug' => [
'plugin_slug' => [
'validate_callback' => [ $this, 'validate_plugin_slug_callback' ],
],
'scan_id' => [
'type' => 'string',
],
'version' => [
'type' => 'string',
],
'release_ref' => [
'type' => 'string',
],
'status' => [
'type' => 'string',
],
'findings_count' => [
'type' => [ 'integer', 'null' ],
],
'severity_counts' => [
'type' => [ 'object', 'null' ],
],
'verdict_hash' => [
'type' => [ 'string', 'null' ],
],
'report_url' => [
'type' => [ 'string', 'null' ],
'format' => 'uri',
],
'error' => [
'type' => [ 'object', 'null' ],
'properties' => [
'kind' => [ 'type' => 'string' ],
'message' => [ 'type' => 'string' ],
],
],
],
'permission_callback' => function ( $request ) {
return $this->permission_check_api_bearer( $request, 'WP_GANDALF_SCAN_SHARED_SECRET' );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ function __construct() {
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array( $this, 'bulk_update_stats' ),
'permission_callback' => array( $this, 'permission_check_internal_api_bearer' ),
'args' => array(
// Entries are unconstrained so one malformed plugin cannot reject the batch.
'plugins' => array(
'type' => 'object',
'required' => true,
),
),
) );
}

Expand All @@ -46,6 +53,10 @@ function bulk_update_stats( $request ) {
$data = $request['plugins'];

foreach ( $data as $plugin_slug => $stats ) {
if ( ! is_array( $stats ) ) {
continue;
}

$plugin = Plugin_Directory::get_plugin_post( $plugin_slug );
if ( ! $plugin ) {
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,19 @@ public function __construct() {
'plugin_slug' => array(
'validate_callback' => array( $this, 'validate_plugin_slug_callback' ),
),
'zip_hash' => array(
'type' => 'string',
),
'url_hash' => array(
'type' => 'string',
),
'type' => array(
'type' => 'string',
),
'lang' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
)
) );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ class Plugin_Committers extends Base {

function __construct() {
register_rest_route( 'plugins/v1', '/plugin/(?P<plugin_slug>[^/]+)/committers/?', array(
'args' => array(
'plugin_slug' => array(
'validate_callback' => array( $this, 'validate_plugin_slug_callback' ),
'required' => true,
),
),
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'list_committers' ),
Expand All @@ -28,12 +34,6 @@ function __construct() {
Plugin_Directory::get_plugin_post( $request['plugin_slug'] )
);
},
'args' => array(
'plugin_slug' => array(
'validate_callback' => array( $this, 'validate_plugin_slug_callback' ),
'required' => true,
),
),
),
array(
'methods' => WP_REST_Server::CREATABLE,
Expand All @@ -45,9 +45,10 @@ function __construct() {
);
},
'args' => array(
'plugin_slug' => array(
'validate_callback' => array( $this, 'validate_plugin_slug_callback' ),
'required' => true,
// The user_login, user_nicename, or user_email of the user to add.
'committer' => array(
'type' => 'string',
'required' => true,
),
),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use WP_REST_Response;
use WordPressdotorg\Plugin_Directory\Plugin_Directory;
use WordPressdotorg\Plugin_Directory\API\Base;
use WordPressdotorg\Plugin_Directory\Template;
use WordPressdotorg\Plugin_Directory\Tools;
use WordPressdotorg\Plugin_Directory\Jobs\Plugin_Import;
use WordPressdotorg\Plugin_Directory\Email\Release_Confirmation_Enabled as Release_Confirmation_Enabled_Email;
Expand All @@ -28,6 +29,10 @@ public function __construct() {
'plugin_slug' => [
'validate_callback' => [ $this, 'validate_plugin_slug_callback' ],
],
'confirmations_required' => [
'type' => 'integer',
'minimum' => 0,
],
],
'permission_callback' => function( $request ) {
$plugin = Plugin_Directory::get_plugin_post( $request['plugin_slug'] );
Expand All @@ -45,7 +50,11 @@ public function __construct() {
],
'plugin_tag' => [
'validate_callback' => [ $this, 'validate_plugin_tag_callback' ],
]
],
'rollout_strategy' => [
'type' => 'string',
'enum' => array_keys( Template::get_rollout_strategies() ),
],
],
'permission_callback' => [ $this, 'permission_can_access_plugin' ],
] );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ function __construct() {
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'plugin_review_info' ),
'permission_callback' => array( $this, 'plugin_info_permission_check' ),
'args' => array(
'plugin_id' => array(
'type' => 'integer',
),
'token' => array(
'type' => 'string',
'pattern' => '^[a-f0-9]{32}$',
),
),
) );
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ public function __construct() {
'plugin_slug' => [
'validate_callback' => [ $this, 'validate_plugin_slug_callback' ],
],
// Whether to dismiss the missing blueprint notice instead of toggling the preview.
'dismiss' => [
'type' => 'boolean',
],
],
'permission_callback' => function( $request ) {
$plugin = Plugin_Directory::get_plugin_post( $request['plugin_slug'] );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ class Plugin_Support_Reps extends Base {

function __construct() {
register_rest_route( 'plugins/v1', '/plugin/(?P<plugin_slug>[^/]+)/support-reps/?', array(
'args' => array(
'plugin_slug' => array(
'validate_callback' => array( $this, 'validate_plugin_slug_callback' ),
'required' => true,
),
),
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'list_support_reps' ),
Expand All @@ -28,12 +34,6 @@ function __construct() {
Plugin_Directory::get_plugin_post( $request['plugin_slug'] )
);
},
'args' => array(
'plugin_slug' => array(
'validate_callback' => array( $this, 'validate_plugin_slug_callback' ),
'required' => true,
),
),
),
array(
'methods' => WP_REST_Server::CREATABLE,
Expand All @@ -45,9 +45,10 @@ function __construct() {
);
},
'args' => array(
'plugin_slug' => array(
'validate_callback' => array( $this, 'validate_plugin_slug_callback' ),
'required' => true,
// The user_login, user_nicename, or user_email of the user to add.
'support_rep' => array(
'type' => 'string',
'required' => true,
),
),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ function __construct() {
'callback' => array( $this, 'upload' ),
'permission_callback' => array( $this, 'permission_check' ),
'args' => [
'ID' => [
'type' => 'integer',
],
'post_name' => [
'type' => 'string',
'required' => false,
Expand All @@ -38,6 +41,9 @@ function __construct() {
'callback' => array( $this, 'slug' ),
'permission_callback' => array( $this, 'permission_check' ),
'args' => [
'ID' => [
'type' => 'integer',
],
'post_name' => [
'type' => 'string',
'required' => true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ function __construct() {
'plugin_slug' => array(
'validate_callback' => array( $this, 'validate_plugin_slug_callback' ),
),
'locale' => array(
'type' => 'string',
'sanitize_callback' => array( $this, 'sanitize_locale_callback' ),
),
),
) );
}
Expand Down Expand Up @@ -373,7 +377,7 @@ protected function get_user_profile_link( $user ) {
*/
protected function get_plugin_reviews_markup( $plugin_slug ) {
$output = '';
foreach ( Tools::get_plugin_reviews( $plugin_slug, 10 ) as $review ) {
foreach ( Tools::get_plugin_reviews( $plugin_slug, 10 ) ?: array() as $review ) {
$output .= $this->get_plugin_reviews_markup_singular( $review );
}
return $output;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,60 @@ function __construct() {
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'query' ),
'permission_callback' => '__return_true',

/*
* api.wordpress.org proxies client input into this route verbatim,
* so all parameters coerce rather than reject: custom sanitize
* callbacks intentionally replace strict schema validation.
*/
'args' => array(
'paged' => array(
'type' => 'integer',
'sanitize_callback' => 'absint',
),
'posts_per_page' => array(
'type' => 'integer',
'sanitize_callback' => 'absint',
),
'browse' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'favorites_user' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'plugin_category' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
's' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'author_name' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'installed_plugins' => array(
'type' => array( 'string', 'array' ),
'items' => array( 'type' => 'string' ),
'sanitize_callback' => 'wp_parse_list',
),
'plugin_tags' => array(
'type' => array( 'string', 'array' ),
'items' => array( 'type' => 'string' ),
'sanitize_callback' => 'wp_parse_list',
),
'locale' => array(
'type' => 'string',
'sanitize_callback' => array( $this, 'sanitize_locale_callback' ),
),
'block' => array(
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
),
) );
}

Expand Down
Loading
Loading