Issues (14)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/CanvasPest.php (12 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/** smtech\CanvasPest\CanvasPest */
4
5
namespace smtech\CanvasPest;
6
7
/**
8
 * An object to handle interactions with the Canvas API.
9
 *
10
 * For more information on the Canvas API refer to the offical
11
 * {@link https://canvas.instructure.com/doc/api/ Canvas API documentation} or
12
 * to the (slightly more up-to-date and pleasingly interactive)
13
 * {@link https://canvas.instructure.com/doc/api/live live documentation}.
14
 *
15
 * You can access the live documentation for your own Canvas instance and make
16
 * actual API calls to it at `https://<path-to-your-instance>/doc/api/live`
17
 *
18
 * @author Seth Battis <[email protected]>
19
 **/
20
class CanvasPest extends \Battis\Educoder\Pest
21
{
22
23
    /** Name of the parameter controlling the number of responses per page */
24
    const PARAM_PER_PAGE = 'per_page';
25
26
    /** @var string[] $headers Additional headers to be passed to the API with each call */
27
    protected $headers;
28
29
    /**
30
     * Construct a new CanvasPest
31
     *
32
     * @api
33
     *
34
     * @param string $apiInstanceUrl URL of the API instance (e.g.
35
     *        `'https://canvas.instructure.com/api/v1'`)
36
     * @param string $apiAuthorizationToken (Optional) API access token for the
37
     *        API instance (if not provided now, it will need to be provided later)
38
     *
39
     * @see CanvasPest::setupToken() To configure the API access token later
40
     **/
41 14
    public function __construct($apiInstanceUrl, $apiAuthorizationToken = null)
42
    {
43 14
        parent::__construct($apiInstanceUrl);
44 14
        if (!empty($apiAuthorizationToken)) {
45 12
            $this->setupToken($apiAuthorizationToken);
46 12
        }
47 14
    }
48
49
    /**
50
     * Set up a new API access token to access this instance
51
     *
52
     * @param string $token API access token
53
     *
54
     * @return boolean
55
     *
56
     * @throws CanvasPest_Exception INVALID_TOKEN on an empty or non-string token value
57
     **/
58 14
    public function setupToken($token)
59
    {
60 14
        if (!empty($token)) {
61 12
            $this->headers['Authorization'] = "Bearer $token";
62 12
            return true;
63
        } else {
64 2
            if ($this->throw_exceptions) {
65 1
                throw new CanvasPest_Exception(
66 1
                    'API authorization token must be a non-zero-length string',
67
                    CanvasPest_Exception::INVALID_TOKEN
68 1
                );
69
            }
70 2
            return false;
71
        }
72
    }
73
74
    /**
75
     * Preprocess API call parameters before use
76
     *
77
     * Force maximum response page size, if not already defined.
78
     *
79
     * @param string[] $data Array of parameters for the next API call
80
     *
81
     * @return string[] Updated array of parameters
82
     *
83
     * @see CanvasArray::MAXIMUM_PER_PAGE Maximum number of responses per page
84
     * @see CanvasPest::PARAM_PER_PAGE Page size parameter
85
     **/
86 18
    private function preprocessData($data)
87
    {
88 18
        if (is_array($data) && !array_key_exists(self::PARAM_PER_PAGE, $data)) {
89 13
            $data[self::PARAM_PER_PAGE] = CanvasArray::MAXIMUM_PER_PAGE;
90 13
        }
91 18
        return $data;
92
    }
93
94
    /**
95
     * Prepare API request headers
96
     *
97
     * Flatten headers from an associative array to a numerically indexed array
98
     * of `"Name: Value"` style entries like `CURLOPT_HTTPHEADER` expects.
99
     * Numerically indexed arrays are not modified.
100
     *
101
     * Extended by CanvasPest to include the API access token in the
102
     * `Authorization` header.
103
     *
104
     * @param string[] $headers
105
     * @return string[]
106
     **/
107 20
    protected function prepHeaders($headers)
108
    {
109 20
        return parent::prepHeaders(array_merge($this->headers, $headers));
110
    }
111
112
    /**
113
     * Parse the API response into an object (or collection of objects).
114
     *
115
     * For queries to individually identified endpoints (e.g.
116
     * `accounts/1/users/123`), return a CanvasObject representing the API response
117
     * describing _that_ individually identified object affected by the query.
118
     *
119
     * For queries to generic endpoints (e.g. `accounts/1/users`), return a
120
     * traversable CanvasArray (of CanvasObjects) representing the API response
121
     * describing the list of objects affected by the query.
122
     *
123
     * @param string $response JSON-encoded response from the API
124
     *
125
     * @return CanvasObject|CanvasArray|false
126
     *
127
     * @throws CanvasPest_Exception INVALID_JSON_RESPONSE if an
128
     *         non-JSON-formatted response is received (and
129
     *         $this->throw_exceptions is true -- otherwise it returns false)
130
     **/
131 20
    protected function postprocessResponse($response)
132
    {
133 20
        if (substr($response, 0, 1) == '{') {
134 11
            return new CanvasObject($response);
135 9
        } elseif (substr($response, 0, 1) == '[') {
136 7
            return new CanvasArray($response, $this);
137
        } else {
138 2
            if ($this->throw_exceptions) {
139 1
                throw new CanvasPest_Exception(
140 1
                    $response,
141
                    CanvasPest_Exception::INVALID_JSON_RESPONSE
142 1
                );
143
            }
144 1
            return false;
145
        }
146
    }
147
148
    /**
149
     * Reformat query parameters for Canvas
150
     *
151
     * Specifically, Canvas expects no numeric indices for base array parameters.
152
     *
153
     * @param mixed $data
154
     *
155
     * @return string
156
     * @codingStandardsIgnoreStart
157
     **/
158 20
    protected function http_build_query($data)
159
    {
160
        // @codingStandardsIgnoreEnd
161 20
        return preg_replace('/%5B\d+%5D/simU', '[]', http_build_query($data));
162
    }
163
164
    /**
165
     * Make a GET call to the API
166
     *
167
     * For queries to individually identified endpoints (e.g.
168
     * `accounts/1/users/123`), return a CanvasObject representing the API response
169
     * describing _that_ individually identified object affected by the query.
170
     *
171
     * For queries to generic endpoints (e.g. `accounts/1/users`), return a
172
     * traversable CanvasArray (of CanvasObjects) representing the API response
173
     * describing the list of objects affected by the query.
174
     *
175
     * @api
176
     *
177
     * @param string $path Path to the API endpoint of this call
178
     * @param string|string[] $data (Optional) Query parameters for this call
179
     * @param string|string[] $headers (Optional) Any additional HTTP headers for this call
180
     *
181
     * @return CanvasObject|CanvasArray|false
182
     **/
183 12
    public function get($path, $data = array(), $headers = array())
184
    {
185 12
        return $this->postprocessResponse(
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->postproces...ata($data), $headers)); (smtech\CanvasPest\Canvas...sPest\CanvasArray|false) is incompatible with the return type of the parent method Battis\Educoder\Pest::get of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
186 12
            parent::get($path, $this->preprocessData($data), $headers)
0 ignored issues
show
It seems like $data defined by parameter $data on line 183 can also be of type string; however, smtech\CanvasPest\CanvasPest::preprocessData() does only seem to accept array<integer,string>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
It seems like $headers defined by parameter $headers on line 183 can also be of type string; however, Battis\Educoder\Pest::get() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
187 12
        );
188
    }
189
190
    /**
191
     * Make a POST call to the API
192
     *
193
     * For queries to individually identified endpoints (e.g.
194
     * `accounts/1/users/123`), return a CanvasObject representing the API response
195
     * describing _that_ individually identified object affected by the query.
196
     *
197
     * @api
198
     *
199
     * @param string $path Path to the API endpoint of this call
200
     * @param string|string[] $data (Optional) Query parameters for this call
201
     * @param string|string[] $headers (Optional) Any additional HTTP headers for this call
202
     *
203
     * @return CanvasObject|false
204
     **/
205 4
    public function post($path, $data = array(), $headers = array())
206
    {
207 4
        return $this->postprocessResponse(
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->postproces...ata($data), $headers)); (smtech\CanvasPest\Canvas...sPest\CanvasArray|false) is incompatible with the return type of the parent method Battis\Educoder\Pest::post of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
208 4
            parent::post($path, $this->preprocessData($data), $headers)
0 ignored issues
show
It seems like $data defined by parameter $data on line 205 can also be of type string; however, smtech\CanvasPest\CanvasPest::preprocessData() does only seem to accept array<integer,string>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
It seems like $headers defined by parameter $headers on line 205 can also be of type string; however, Battis\Educoder\Pest::post() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
209 4
        );
210
    }
211
212
    /**
213
     * Make a PUT call to the API
214
     *
215
     * For queries to individually identified endpoints (e.g.
216
     * `accounts/1/users/123`), return a CanvasObject representing the API response
217
     * describing _that_ individually identified object affected by the query.
218
     *
219
     * @api
220
     *
221
     * @param string $path Path to the API endpoint of this call
222
     * @param string|string[] $data (Optional) Query parameters for this call
223
     * @param string|string[] $headers (Optional) Any additional HTTP headers for this call
224
     *
225
     * @return CanvasObject|false
226
     **/
227 2
    public function put($path, $data = array(), $headers = array())
228
    {
229 2
        return $this->postprocessResponse(
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->postproces...ata($data), $headers)); (smtech\CanvasPest\Canvas...sPest\CanvasArray|false) is incompatible with the return type of the parent method Battis\Educoder\Pest::put of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
230 2
            parent::put($path, $this->preprocessData($data), $headers)
0 ignored issues
show
It seems like $data defined by parameter $data on line 227 can also be of type string; however, smtech\CanvasPest\CanvasPest::preprocessData() does only seem to accept array<integer,string>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
It seems like $headers defined by parameter $headers on line 227 can also be of type string; however, Battis\Educoder\Pest::put() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
231 2
        );
232
    }
233
234
    /**
235
     * Make a DELETE call to the API
236
     *
237
     * For queries to individually identified endpoints (e.g.
238
     * `accounts/1/users/123`), return a CanvasObject representing the API
239
     * response describing _that_ individually identified object affected by
240
     * the query.
241
     *
242
     * @api
243
     *
244
     * @param string $path Path to the API endpoint of this call
245
     * @param string|string[] $data (Optional) Query parameters for this call
246
     * @param string|string[] $headers (Optional) Any additional HTTP headers for this call
247
     *
248
     * @return CanvasObject|false
249
     **/
250 4
    public function delete($path, $data = array(), $headers = array())
251
    {
252 4
        if (!empty($data)) {
253 4
            $pathData = [];
254 4
            $pos = strpos($path, '?');
255 4
            if ($pos !== false) {
256 2
                parse_str(substr($path, $pos + 1), $pathData);
257 2
                $path = substr($path, 0, $pos);
258 2
            }
259 4
            $path .= '?' . $this->http_build_query(array_merge($pathData, $data));
260 4
        }
261 4
        return $this->postprocessResponse(
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->postproces...lete($path, $headers)); (smtech\CanvasPest\Canvas...sPest\CanvasArray|false) is incompatible with the return type of the parent method Battis\Educoder\Pest::delete of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
262 4
            parent::delete($path, $headers)
0 ignored issues
show
It seems like $headers defined by parameter $headers on line 250 can also be of type string; however, Battis\Educoder\Pest::delete() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
263 4
        );
264
    }
265
266
    /**
267
     * Make a PATCH call to the API
268
     *
269
     * @deprecated The Canvas API does not currently support PATCH calls
270
     *
271
     * @param string $path Path to the API endpoint of this call
272
     * @param string|string[] $data (Optional) Query parameters for this call
273
     * @param string|string[] $headers (Optional) Any additional HTTP headers for this call
274
     *
275
     * @return false
276
     *
277
     * @throws CanvasPest_Exception UNSUPPORTED_METHOD All calls to this method will cause an exception
278
     **/
279 2
    public function patch($path, $data = array(), $headers = array())
280
    {
281 2
        if ($this->throw_exceptions) {
282 1
            throw new CanvasPest_Exception(
283 1
                'The Canvas API does not support the PATCH method',
284
                CanvasPest_Exception::UNSUPPORTED_METHOD
285 1
            );
286
        }
287 1
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type of the parent method Battis\Educoder\Pest::patch of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
288
    }
289
}
290