GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 17ed34...f4bd34 )
by Omar El
03:18
created

SecurityComponent::form()   D

Complexity

Conditions 9
Paths 33

Size

Total Lines 32
Code Lines 16

Duplication

Lines 8
Ratio 25 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 8
loc 32
rs 4.909
cc 9
eloc 16
nc 33
nop 1
1
<?php
2
3
/**
4
 * Security component class.
5
 *
6
 * Provides security methods for various tasks and validations.
7
 *
8
 * @license    http://opensource.org/licenses/MIT The MIT License (MIT)
9
 * @author     Omar El Gabry <[email protected]>
10
 */
11
12
class SecurityComponent extends Component{
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
13
14
    /**
15
     * Default configurations
16
     *
17
     * @var array
18
     */
19
    protected $config = [
20
        'form' => [],
21
        'requireSecure' => [],
22
        'requirePost' => [],
23
        'requireAjax' => [],
24
        'requireGet' => [],
25
        'validateForm' => true,
26
        'validateCsrfToken' => false
27
    ];
28
29
    /**
30
     * Auth startup
31
     * All security checking are done in this method
32
     *
33
     */
34
    public function startup(){
35
36
        $this->requestRequired();
37
        $this->secureRequired();
38
39
        $this->validateDomain();
40
41
        if($this->request->isPost() && $this->config["validateForm"]){
42
            if(!$this->form($this->config["form"])){
43
                $this->invalidRequest();
44
            }
45
        }
46
47
        if($this->config["validateCsrfToken"]){
48
            if(!$this->CsrfToken()){
49
                $this->invalidRequest();
50
            }
51
        }
52
    }
53
54
    /**
55
     * Check & validate from the required HTTP methods, like: Post, Ajax, Get
56
     *
57
     * If invalid, this will fire invalid request error.
58
     *
59
    */
60
    private function requestRequired(){
61
        foreach (['Post', 'Ajax', 'Get'] as $method) {
62
            $key = 'require' . $method;
63 View Code Duplication
            if (!empty($this->config[$key])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
64
                if (in_array($this->request->param('action'), $this->config[$key], true) || $this->config[$key] === ['*']) {
65
                    if (!$this->request->{"is" . $method}()) {
66
                        $this->invalidRequest();
67
                    }
68
                }
69
            }
70
        }
71
    }
72
73
    /**
74
     * Check & validate if secured connection is required.
75
     *
76
     * It calls forceSSL() method in the controller
77
     *
78
     */
79
    private function secureRequired(){
80
        $key = "requireSecure";
81 View Code Duplication
        if(!empty($this->config[$key])){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
82
            if (in_array($this->request->param('action'), $this->config[$key], true) || $this->config[$key] === ['*']) {
83
                if (!$this->request->isSSL()) {
84
                    $this->controller->forceSSL();
85
                }
86
            }
87
        }
88
    }
89
90
    /**
91
     * Check & validate if request is coming from the same domain; if equals to $this->request->host()
92
     * HTTP referer tells the domain where the request came from.
93
     *
94
     */
95
    private function validateDomain(){
96
97
        $isValid = true;
98
        $referer = $this->request->referer();
99
100
        if($this->request->isPost()){
101
            if(!isset($referer)) {
102
                $isValid = false;
103
            } else {
104
                $referer_host = parse_url($referer, PHP_URL_HOST);
105
                $server_host  = $this->request->host();
106
                $isValid = ($referer_host === $server_host)? true: false;
107
            }
108
        }
109
110
        if(!$isValid){
111
            Logger::log("Request Domain", "User: ". Session::getUserId() ." Request is not coming from the same domain with invalid HTTP referer", __FILE__, __LINE__);
112
            $this->invalidRequest();
113
        }
114
    }
115
116
    /**
117
     * Handles invalid request with a 400 Bad Request Error
118
     *
119
     */
120
    private function invalidRequest(){
121
        $this->controller->error("badrequest");
122
    }
123
124
    /**
125
     * Sets the actions that require secured connection(SSL)
126
     *
127
     * @param array $actions
128
     */
129
    public function requireSecure($actions = []){
130
        $this->config['requireSecure'] = (array)$actions;
131
    }
132
133
    /**
134
     * Sets the actions that require a POST request
135
     *
136
     * @param array $actions
137
     */
138
    public function requirePost($actions = []){
139
        $this->config['requirePost'] = (array)$actions;
140
    }
141
142
    /**
143
     * Sets the actions that require a Ajax request
144
     *
145
     * @param array $actions
146
     */
147
    public function requireAjax($actions = []){
148
        $this->config['requireAjax'] = (array)$actions;
149
    }
150
151
    /**
152
     * Sets the actions that require a GET request
153
     *
154
     * @param array $actions
155
     */
156
    public function requireGet($actions = []){
157
        $this->config['requireGet'] = (array)$actions;
158
    }
159
160
     /**
161
      * validate submitted form
162
      * - Unknown fields cannot be added to the form.
163
      * - Fields cannot be removed from the form.
164
      *
165
      * Use $exclude to exclude anything mightn't be sent with the form, like possible empty arrays, checkboxes, radio buttons, ...etc.
166
      * By default, the submit field will be excluded.
167
      *
168
      * @param array  $config  configuration data
169
      * @return boolean
170
      */
171
    public function form($config){
172
173
        if(empty($config['fields']) || $this->request->dataSizeOverflow()){
174
             return false;
175
        }
176
177
        if(!in_array('csrf_token', $config['fields'], true)){
178
            $config['fields'][] = 'csrf_token';
179
        }
180
181
        // exclude any checkboxes, radio buttons, possible empty arrays, ...etc.
182
        $exclude = empty($config["exclude"])? []: (array)$config["exclude"];
183
        if(!in_array('submit', $exclude, true)){
184
            $exclude[] = 'submit';
185
        }
186
187 View Code Duplication
        if($this->request->countData($exclude) !== count($config['fields'])){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
188
            Logger::log("Form Tampering", "User: ". Session::getUserId() ." is tampering the form with invalid number of fields", __FILE__, __LINE__);
189
            return false;
190
        }
191
192
        foreach($config['fields'] as $field){
193
194 View Code Duplication
            if(!array_key_exists($field, $this->request->data)){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
195
                Logger::log("Form Tampering", "User: ". Session::getUserId() ." is tampering the form with invalid fields", __FILE__, __LINE__);
196
                return false;
197
            }
198
        }
199
200
        // by default, validate csrf token as well.
201
        return $this->CsrfToken();
202
    }
203
204
     /**
205
      * validate CSRF token
206
      * CSRF token can be passed with submitted forms and links associated with sensitive server-side operations.
207
      *
208
      * In case of GET request, you need to set 'validateCsrfToken' in $config to true.
209
      *
210
      * @param array  $config  configuration data
211
      * @return boolean
212
      */
213
    public function CsrfToken($config = []){
0 ignored issues
show
Unused Code introduced by
The parameter $config is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
214
215
        $userToken = null;
0 ignored issues
show
Unused Code introduced by
$userToken is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
216
        if($this->request->isPost()){
217
            $userToken = $this->request->data('csrf_token');
218
        }else{
219
            $userToken = $this->request->query('csrf_token');
220
        }
221
222
        if(empty($userToken) || $userToken !== Session::getCsrfToken()){
223
            Logger::log("CSRF Attack", "User: ". Session::getUserId() ." provided invalid CSRF Token " . $userToken, __FILE__, __LINE__);
224
            return false;
225
        }
226
227
        return $userToken === Session::getCsrfToken();
228
    }
229
230
}
231