Issues (1)

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/GenericFeatureContext.php (1 issue)

Labels
Severity

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
declare(strict_types=1);
4
5
namespace samsonframework\behatextension;
6
7
use Behat\Behat\Hook\Scope\AfterStepScope;
8
use Behat\Mink\Driver\Selenium2Driver;
9
use Behat\Mink\Element\NodeElement;
10
use Behat\MinkExtension\Context\MinkContext;
11
12
/**
13
 * Defines generic feature steps.
14
 */
15
class GenericFeatureContext extends MinkContext
16
{
17
    /** @var int UI generic delay duration in milliseconds */
18
    const DELAY = 1000;
19
    /** @var 0.1 sec spin delay */
20
    const SPIN_DELAY = 100000;
21
    /** @var int UI javascript generic delay duration in milliseconds */
22
    const JS_DELAY = self::DELAY / 5;
23
    /** @var int UI spin function timeout for ex 30*0.1s = 15 sec timeout */
24
    const SPIN_TIMEOUT = 150;
25
26
    /** @var mixed */
27
    protected $session;
28
29
    /** @var array Pages collection */
30
    protected $pages = [];
31
32
    /**
33
     * Initializes context.
34
     *
35
     * Every scenario gets its own context instance.
36
     * You can also pass arbitrary arguments to the
37
     * context constructor through behat.yml.
38
     *
39
     * @param mixed $session
40
     */
41
    public function __construct($session = null)
42
    {
43
        $this->session = $session;
44
45
        ini_set('xdebug.max_nesting_level', '1000');
46
    }
47
48
    /**
49
     * Get Symfony service instance.
50
     *
51
     * @param string $serviceName Service identifier
52
     * @param string $session     Behat Symfony session name
53
     *
54
     * @return object Symfony service instance
55
     */
56
    public function getSymfonyService(string $serviceName, string $session = 'symfony2')
57
    {
58
        return $this->getSession($session)
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Behat\Mink\Driver\DriverInterface as the method getClient() does only exist in the following implementations of said interface: Behat\Mink\Driver\BrowserKitDriver, Behat\Symfony2Extension\Driver\KernelDriver.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
59
            ->getDriver()
60
            ->getClient()
61
            ->getContainer()
62
            ->get($serviceName);
63
    }
64
65
    /**
66
     * Spin function to avoid Selenium fails.
67
     *
68
     * @param callable $lambda
69
     * @param null     $data
70
     * @param int      $delay
71
     * @param int      $timeout
72
     *
73
     * @throws \Exception
74
     *
75
     * @return bool
76
     */
77
    public function spin(callable $lambda, $data = null, $delay = self::SPIN_DELAY, $timeout = self::SPIN_TIMEOUT)
78
    {
79
        $failedExceptions = [];
80
        for ($i = 0; $i < $timeout; $i++) {
81
            try {
82
                if ($lambda($this, $data)) {
83
                    return true;
84
                }
85
            } catch (\Exception $e) { // Gather unique exceptions
86
                $failedExceptions[$e->getMessage()] = $e->getMessage();
87
            }
88
89
            usleep($delay);
90
        }
91
92
        $backtrace = debug_backtrace();
93
94
        throw new \Exception(
95
            'Timeout thrown by '.$backtrace[1]['class'].'::'.$backtrace[1]['function']."()\n"
96
            .(array_key_exists('file', $backtrace[1]) ? $backtrace[1]['file'].', line '.$backtrace[1]['line'] : '')."\n"
97
            .implode("\n", $failedExceptions)
98
        );
99
    }
100
101
    /**
102
     * @AfterStep
103
     *
104
     * @param AfterStepScope $scope
105
     */
106
    public function takeScreenShotAfterFailedStep(AfterStepScope $scope)
107
    {
108
        if (99 === $scope->getTestResult()->getResultCode()) {
109
            $driver = $this->getSession()->getDriver();
110
111
            if (!($driver instanceof Selenium2Driver)) {
112
                return;
113
            }
114
115
            $step = $scope->getStep();
116
            $fileName = 'Fail.'.preg_replace('/[^a-zA-Z0-9-_\.]/', '_', $scope->getName().'-'.$step->getText()).'.jpg';
117
            file_put_contents($fileName, $driver->getScreenshot());
118
        }
119
    }
120
121
    /**
122
     * Find all elements by CSS selector.
123
     *
124
     * @param string $selector CSS selector
125
     *
126
     * @throws \InvalidArgumentException If element not found
127
     *
128
     * @return \Behat\Mink\Element\NodeElement[]
129
     */
130
    protected function findAllByCssSelector(string $selector)
131
    {
132
        $elements = [];
133
134
        $this->spin(function (MinkContext $context) use ($selector, &$elements) {
135
            $session = $context->getSession();
136
137
            $elements = $session->getPage()->findAll('css', $context->fixStepArgument($selector));
138
139
            // If element with current selector is not found then print error
140
            if (count($elements) === 0) {
141
                throw new \InvalidArgumentException(sprintf('Could not evaluate CSS selector: "%s"', $selector));
142
            }
143
144
            return true;
145
        });
146
147
148
        return $elements;
149
    }
150
151
    /**
152
     * Find element by CSS selector.
153
     *
154
     * @param string $selector CSS selector
155
     *
156
     * @throws \InvalidArgumentException If element not found
157
     *
158
     * @return \Behat\Mink\Element\NodeElement
159
     */
160
    public function findByCssSelector(string $selector) : NodeElement
161
    {
162
        return $this->findAllByCssSelector($selector)[0];
163
    }
164
165
    /**
166
     * @Given /^I set browser window size to "([^"]*)" x "([^"]*)"$/
167
     *
168
     * @param int $width  Browser window width
169
     * @param int $height Browser window height
170
     */
171
    public function iSetBrowserWindowSizeToX($width, $height)
172
    {
173
        $this->getSession()->resizeWindow((int) $width, (int) $height, 'current');
174
    }
175
176
    /**
177
     * @Given /^I wait "([^"]*)" milliseconds for response$/
178
     *
179
     * @param int $delay Amount of milliseconds to wait
180
     */
181
    public function iWaitMillisecondsForResponse($delay = self::DELAY)
182
    {
183
        $this->getSession()->wait((int) $delay);
184
    }
185
186
    /**
187
     * Click on the element with the provided xpath query.
188
     *
189
     * @When I click on the element :arg1
190
     *
191
     * @param string $selector CSS element selector
192
     *
193
     * @throws \InvalidArgumentException
194
     */
195
    public function iClickOnTheElement(string $selector)
196
    {
197
        // Click on the founded element
198
        $this->findByCssSelector($selector)->click();
199
    }
200
201
    /**
202
     * Checks, that current page PATH is equal to specified
203
     * Example: Then I should be on "/"
204
     * Example: And I should be on "/bats"
205
     * Example: And I should be on "http://google.com"
206
     *
207
     * @param string $page Page for assertion
208
     */
209
    public function assertPageAddress($page) {
210
        $this->spin(function (MinkContext $context) use ($page) {
211
            $context->assertSession()->addressEquals($this->locatePath($page));
212
            return true;
213
        });
214
    }
215
216
    /**
217
     * @When /^I hover over the element "([^"]*)"$/
218
     *
219
     * @param string $selector CSS element selector
220
     *
221
     * @throws \InvalidArgumentException
222
     */
223
    public function iHoverOverTheElement(string $selector)
224
    {
225
        $this->findByCssSelector($selector)->mouseOver();
226
    }
227
228
    /**
229
     * Fill in input with the provided info.
230
     *
231
     * @When I fill in the input :arg1 with :arg2
232
     *
233
     * @param string $selector CSS element selector
234
     * @param string $value    Element value for filling in
235
     *
236
     * @throws \InvalidArgumentException
237
     */
238
    public function iFillInTheElement(string $selector, string $value)
239
    {
240
        $this->findByCssSelector($selector)->setValue($this->fixStepArgument($value));
241
    }
242
243
    /**
244
     * @When I scroll vertically to :arg1 px
245
     *
246
     * @param mixed $yPos Vertical scrolling position in pixels
247
     */
248
    public function iScrollVerticallyToPx($yPos)
249
    {
250
        $this->getSession()->executeScript('window.scrollTo(0, Math.min(document.documentElement.scrollHeight, document.body.scrollHeight, '.((int) $yPos).'));');
251
    }
252
253
    /**
254
     * @When I scroll horizontally to :arg1 px
255
     *
256
     * @param mixed $xPos Horizontal scrolling position in pixels
257
     */
258
    public function iScrollHorizontallyToPx($xPos)
259
    {
260
        $this->getSession()->executeScript('window.scrollTo('.((int) $xPos).', 0);');
261
    }
262
263
    /**
264
     * @Given /^I fill hidden field "([^"]*)" with "([^"]*)"$/
265
     *
266
     * @param string $field Field name
267
     * @param string $value Field value
268
     */
269
    public function iFillHiddenFieldWith(string $field, string $value)
270
    {
271
        // TODO: Change to Mink implementation
272
        $this->getSession()->executeScript("
273
            $('input[name=".$field."]').val('".$value."');
274
        ");
275
    }
276
277
    /**
278
     * @Then I check custom checkbox with :id
279
     *
280
     * @param string $id Checkbox identifier
281
     *
282
     * @throws \InvalidArgumentException If checkbox with provided identifier does not exists
283
     */
284
    public function iCheckCustomCheckboxWith(string $id)
285
    {
286
        // Find label for checkbox by chekbox identifier
287
        $element = null;
288
        foreach ($this->findAllByCssSelector('label') as $label) {
289
            if ($label->getAttribute('for') === $id) {
290
                $element = $label;
291
            }
292
        }
293
294
        // Imitate checkbox checking by clicking its label
295
        $element->click();
296
    }
297
298
    /**
299
     * @Then I drag element :selector to :target
300
     *
301
     * @param string $selector Source element for dragging
302
     * @param string $target   Target element to drag to
303
     *
304
     * @throws \InvalidArgumentException
305
     */
306
    public function dragElementTo(string $selector, string $target)
307
    {
308
        $this->findByCssSelector($selector)->dragTo($this->findByCssSelector($target));
309
310
        // $this->iWaitMillisecondsForResponse(self::JS_DELAY);
311
    }
312
313
    /**
314
     * Fill in input with the provided info.
315
     *
316
     * @When I fill in the element :arg1 with value :arg2 using js
317
     *
318
     * @param string $selector CSS element selector
319
     * @param string $value    Element value for filling in
320
     */
321
    public function iFillInTheElementUsingJs(string $selector, string $value)
322
    {
323
        $this->getSession()->executeScript('document.querySelectorAll("'.$selector.'")[0].value="'.$value.'";');
324
    }
325
326
    /**
327
     * @Given /^I should be on "(?P<page>(?:[^"]|\\")*)" page$/
328
     *
329
     * @param string $page Page name
330
     *
331
     * @throws \Exception If page is not defined
332
     */
333
    public function iShouldBeOnPage(string $page)
334
    {
335
        $page = strtolower(trim($page));
336
        if (array_key_exists($page, $this->pages)) {
337
            $this->assertPageAddress($this->pages[$page]);
338
        } else {
339
            throw new \Exception('Page [' . $page . '] is not defined');
340
        }
341
    }
342
343
    /**
344
     * Add pages collection.
345
     *
346
     * @param array $pages Pages collection
347
     */
348
    public function addPages(array $pages)
349
    {
350
        $this->pages = array_merge($this->pages, $pages);
351
    }
352
}
353