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.

Issues (4873)

Security Analysis    not enabled

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/common/valid/Rule.class.php (5 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
 * Copyright (c) STMicroelectronics, 2007. All Rights Reserved.
4
 *
5
 * Originally written by Manuel VACELET, 2007.
6
 *
7
 * This file is a part of Codendi.
8
 *
9
 * Codendi is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 2 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * Codendi is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with Codendi. If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
/**
24
 * @package Codendi
25
 */
26
abstract class Rule {
27
    /**
28
     * @access private
29
     */
30
    var $error;
31
32
    /**
33
     * Constructor
34
     */
35
    public function __construct() {
36
    }
37
38
    /**
39
     * Check if $val is a valid not.
40
     *
41
     * @param String $val Value to check.
42
     * @return Boolean
43
     */
44
    abstract function isValid($val);
45
46
    /**
47
     * Default error message if rule is not apply on value.
48
     *
49
     * @param String $val Value to check.
0 ignored issues
show
There is no parameter named $val. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
50
     * @return Boolean
51
     */
52
    function getErrorMessage($key='') {
53
        return $this->error;
54
    }
55
}
56
57
/**
58
 * Validate date provided by Codendi calendar.
59
 *
60
 * Note: this date format is more restrictive than php check date because in
61
 * this case, 2007-01-01 format (with zero in month or day) is not allowed.
62
 */
63
class Rule_Date extends Rule {
64
    const DAY_REGEX     = '/^(\d{1,4})-(\d{1,2})-(\d{1,2}?)$/';
65
66
    function isValid($val) {
67
        if (preg_match(self::DAY_REGEX, $val, $m)) {
68
            return checkdate($m[2], $m[3], $m[1]);
69
        } else {
70
            return false;
71
        }
72
    }
73
}
74
75
class Rule_Date_Time extends Rule {
76
    const DAYTIME_REGEX = '/^(\d{1,4})-(\d{1,2})-(\d{1,2}?) (\d{2}):(\d{2})(?::\d{2})?$/';
77
78
    function isValid($val) {
79
        if (! preg_match(self::DAYTIME_REGEX, $val, $m)) {
80
            return false;
81
        }
82
        return (bool)strtotime($val);
83
    }
84
}
85
86
class Rule_Timestamp extends Rule {
87
    const TIMESTAMP_REGEX = '/^[0-9]+$/';
88
89
    function isValid($val) {
90
        return preg_match(self::TIMESTAMP_REGEX, $val);
91
    }
92
}
93
94
/**
95
 * Abstract class that define left-hand operand for a comparison.
96
 */
97
abstract class Rule_Comparator
98
extends Rule {
99
    /**
100
     * @access private
101
     */
102
    var $ref;
103
    function Rule_Comparator($ref) {
104
        $this->ref = $ref;
105
    }
106
}
107
108
/**
109
 * Check that given value is strictly greater than the one defined in
110
 * constructor.
111
 */
112
class Rule_GreaterThan
113
extends Rule_Comparator {
114
    function isValid($val) {
115
        if(is_numeric($val) && $val > $this->ref) {
116
            return true;
117
        }
118
        return false;
119
    }
120
}
121
122
/**
123
 * Check that given value is strictly less than the one defined in constructor.
124
 */
125
class Rule_LessThan
126
extends Rule_Comparator {
127
    function isValid($val) {
128
        if(is_numeric($val) && $val < $this->ref) {
129
            return true;
130
        }
131
        return false;
132
    }
133
}
134
135
/**
136
 * Check that given value is greater or equal to the one defined in
137
 * constructor.
138
 */
139
class Rule_GreaterOrEqual
140
extends Rule_Comparator {
141
    function isValid($val) {
142
        if(is_numeric($val) && $val >= $this->ref) {
143
            return true;
144
        }
145
        return false;
146
    }
147
}
148
149
/**
150
 * Check that given value is strictly less or equal to the one defined in
151
 * constructor.
152
 */
153
class Rule_lessOrEqual
154
extends Rule_Comparator {
155
    function isValid($val) {
156
        if(is_numeric($val) && $val <= $this->ref) {
157
            return true;
158
        }
159
        return false;
160
    }
161
}
162
163
/**
164
 * Check that given value belong to the array defined in constructor.
165
 *
166
 * There is no type check.
167
 */
168
class Rule_WhiteList
169
extends Rule_Comparator {
170
    function isValid($val) {
171
        if(is_array($this->ref)
172
           && count($this->ref) > 0
173
           && in_array($val, $this->ref)) {
174
            return true;
175
        }
176
        return false;
177
    }
178
}
179
180
/**
181
 * Check that given value is a valid signed 32 bits decimal integer.
182
 */
183
class Rule_Int
184
extends Rule {
185
    /**
186
     * Check the format according to PHP definition of a decimal integer.
187
     * @see http://php.net/int
188
     * @access private
189
     */
190
    function checkFormat($val) {
191
        if(preg_match('/^([+-]?[1-9][0-9]*|[+-]?0)$/', $val)) {
192
            return true;
193
        } else {
194
            return false;
195
        }
196
    }
197
198
    function isValid($val) {
199
        // Need to check with the regexp because of octal form '0123' that is
200
        // equal to '123' with string '==' comparison.
201
        if($this->checkFormat($val)) {
202
            // Check (-2^31;2^31-1) range
203
            if(strval(intval($val)) == $val) {
204
                return true;
205
            } else {
206
                return false;
207
            }
208
        } else {
209
            return false;
210
        }
211
    }
212
}
213
214
/**
215
 * Check that given value is a string.
216
 */
217
class Rule_String
218
extends Rule {
219
    function isValid($val) {
220
        return is_string($val);
221
    }
222
}
223
224
/**
225
 * Check that given value is an array.
226
 */
227
class Rule_Array
228
extends Rule {
229
    function isValid($val) {
230
        return is_array($val);
231
    }
232
}
233
234
/**
235
 * Check if given string contains neither a carrige return nor a null char.
236
 */
237
class Rule_NoCr
238
extends Rule {
239
    function isValid($val) {
240
        if(is_string($val) && strpos($val, 0x0A) === false && strpos($val, 0x0D) === false
241
           && strpos($val, 0x00) === false) {
242
            return true;
243
        }
244
        return false;
245
    }
246
}
247
248
/**
249
 * Check if given string match a pattern
250
 */
251
class Rule_Regexp extends Rule {
252
    protected $pattern;
253
254
    public function __construct($pattern) {
255
        parent::__construct();
256
        $this->pattern = $pattern;
257
    }
258
259
    function isValid($val) {
260
        return preg_match($this->pattern, $val);
261
    }
262
}
263
264
/**
265
 * Check if an email address is valid or not in Codendi context.
266
 *
267
 * This rule is influenced by a global variable 'sys_disable_subdomain'. If
268
 * this variable is set (no subdomain for codendi) and only in this case, emails
269
 * like 'user@codendi' are allowed.
270
 *
271
 * The faulty email address is available with $this->getErrorMessage();
272
 */
273
class Rule_Email
274
extends Rule {
275
    var $separator;
276
277
    function Rule_Email($separator = null) {
278
        $this->separator = $separator;
279
    }
280
281
    function isValid($val) {
282
        if($this->separator !== null) {
283
            // If separator is defined, split the string and check each email.
284
            $emails = split($this->separator, $val);
285
            $valid = true;
286
            while((list($key,$email) = each($emails)) && $valid) {
287
                $valid = $valid & $this->validEmail(trim(rtrim($email)));
288
            }
289
        } else {
290
            // $val must contains only one email address
291
            $valid = $this->validEmail($val);
292
        }
293
        return $valid;
294
    }
295
296
    /**
297
     * Check email validity
298
     *
299
     * Important note: this is very important to keep the 'D' regexp modifier
300
     * as this is the only way not to be bothered by injections of \n into the
301
     * email address.
302
     *
303
     * Spaces are allowed at the beginning and the end of the address.
304
     */
305
    function validEmail($email) {
306
        $valid_chars='-!#$%&\'*+0-9=?A-Z^_`a-z{|}~\.';
307
        if (array_key_exists('sys_disable_subdomains', $GLOBALS)
308
            && $GLOBALS['sys_disable_subdomains']) {
309
            $valid_domain='['.$valid_chars.']+';
310
        } else {
311
            $valid_domain='['.$valid_chars.']+\.['.$valid_chars.']+';
312
        }
313
        $regexp = '/^['.$valid_chars.']+'.'@'.$valid_domain.'$/D';
314
        return preg_match($regexp, $email);
315
    }
316
}
317
318
319
/**
320
 * Check if value match Codendi user names format.
321
 *
322
 * This rule doesn't check that user actually exists.
323
 */
324
class Rule_UserName
325
extends Rule {
326
327
    const RESERVED_PREFIX = 'forge__';
328
329
    /**
330
     * Test if value is a name on underlying OS.
331
     *
332
     * @param String $val Value to test
333
     *
334
     * @return Boolean
335
     */
336
    public function isSystemName($val) {
337
        $backend = $this->_getBackend();
338
        if ($backend->unixUserExists($val) || $backend->unixGroupExists($val)) {
339
            $this->error = $this->_getErrorExists();
340
            return true;
341
        }
342
        return false;
343
    }
344
345
    /**
346
     * Test is the value is Codendi username
347
     *
348
     * @param String $val Value to test
349
     *
350
     * @return Boolean
351
     */
352
    public function isAlreadyUserName($val) {
353
        $um = $this->_getUserManager();
354
        if ($um->getUserByUserName($val) !== null) {
355
            $this->error = $this->_getErrorExists();
356
            return true;
357
        }
358
        return false;
359
    }
360
361
    /**
362
     * Test if the value is a project name
363
     *
364
     * @param String $val Value to test
365
     *
366
     * @return Boolean
367
     */
368
    public function isAlreadyProjectName($val) {
369
        $pm = $this->_getProjectManager();
370
        if ($pm->getProjectByUnixName($val) !== null) {
371
            $this->error = $this->_getErrorExists();
372
            return true;
373
        }
374
        return false;
375
    }
376
377
    /**
378
     * Test if the value contains spaces
379
     *
380
     * @param String $val Value to test
381
     *
382
     * @return Boolean
383
     */
384
    public function noSpaces($val) {
385
        if (strrpos($val,' ') !== false) {
386
            $this->error = $this->_getErrorNoSpaces();
387
            return false;
388
        }
389
        return true;
390
    }
391
392
    /**
393
     * Needs to check the name start by a char
394
     *
395
     * @param String $val
396
     *
397
     * @return Boolean
398
     */
399
    public function atLeastOneChar($val) {
400
        if (strspn($val,"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") == 0) {
401
            $this->error = $GLOBALS['Language']->getText('include_account','char_err');
402
            return false;
403
        }
404
        return true;
405
    }
406
407
    /**
408
     * Test if the name contains illegal chars
409
     *
410
     * @param String $val Value to test
411
     *
412
     * @return Boolean
413
     */
414
    public function containsIllegalChars($val) {
415
        if (strspn($val,"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.") != strlen($val)) {
416
            $this->error = $GLOBALS['Language']->getText('include_account','illegal_char');
417
            return true;
418
        }
419
        return false;
420
    }
421
422
    /**
423
     * Test if the name is already reserved
424
     *
425
     * @param String $val Value to test
426
     *
427
     * @return Boolean
428
     */
429
    public function isReservedName($val) {
430
        $is_reserved_name = preg_match('/^('.
431
             '(www[0-9]?)|(cvs[0-9]?)|(shell[0-9]?)|(ftp[0-9]?)|(irc[0-9]?)|(news[0-9]?)'.
432
             '|(mail[0-9]?)|(ns[0-9]?)|(download[0-9]?)|(pub)|(users)|(compile)|(lists)'.
433
             '|(slayer)|(orbital)|(tokyojoe)|(webdev)|(projects)|(cvs)|(monitor)|(mirrors?)'.
434
             '|(root)|(bin)|(daemon)|(adm)|(lp)|(sync)|(shutdown)|(halt)|(mail)'.
435
             '|(uucp)|(operator)|(games)|(mysql)|(httpd)|(nobody)|(dummy)|(debian)'.
436
             '|(munin)|(mailman)|(ftpadmin)|(codendiadm)|(imadmin-bot)|(apache)|(nscd)'.
437
             '|(git)|(gitolite)'.
438
             ')$/i', $val);
439
        $is_reserved_prefix = $this->isReservedPrefix($val);
440
441
        if ($is_reserved_name || $is_reserved_prefix) {
442
            $this->error = $GLOBALS['Language']->getText('include_account','reserved');
443
            return true;
444
        }
445
        return false;
446
    }
447
448
    /**
449
     * Test if the name begins with a reserved prefix
450
     *
451
     * @param string $val Value to test
452
     *
453
     * @return bool
454
     */
455
    private function isReservedPrefix($val) {
456
        if (strpos($val, self::RESERVED_PREFIX) === 0) {
457
            return true;
458
        }
459
        return false;
460
    }
461
462
    /**
463
     * Test if the name corresponds to a CVS user account
464
     *
465
     * @param String $val Value to test
466
     *
467
     * @return Boolean
468
     */
469
    public function isCvsAccount($val) {
470
        if (preg_match('/^anoncvs_/i', $val)) {
471
            $this->error = $GLOBALS['Language']->getText('include_account','reserved_cvs');
472
            return true;
473
        }
474
        return false;
475
    }
476
477
    /**
478
     * Test minimal length of name
479
     *
480
     * @param String $val Value to test
481
     *
482
     * @return Boolean
483
     */
484
    public function lessThanMin($val) {
485
        if (strlen($val) < 3) {
486
            $this->error = $GLOBALS['Language']->getText('include_account','name_too_short');
487
            return true;
488
        }
489
        return false;
490
    }
491
492
    /**
493
     * Test maximal length of name
494
     *
495
     * @param String  $val Value to test
496
     * @param Integer $max maximal length (default = 30)
497
     *
498
     * @return Boolean
499
     */
500
    public function greaterThanMax($val, $max = 30) {
501
        if (strlen($val) > $max) {
502
            $this->error = $GLOBALS['Language']->getText('include_account','name_too_long', $max);
503
            return true;
504
        }
505
        return false;
506
    }
507
    /**
508
     * Prevent from renaming two users on the same name
509
     * before that the rename is performed by the system
510
     *
511
     * @param String $val
512
     */
513
    public function getPendingUserRename($val) {
514
        $sm = $this->_getSystemEventManager();
515
        if (!$sm->isUserNameAvailable($val)) {
516
            $this->error = $GLOBALS['Language']->getText('rule_user_name', 'error_event_reserved', array($val));
517
            return false;
518
        }
519
        return true;
520
    }
521
    /**
522
     * Test if name is valid
523
     *
524
     * @param String $val Value to test
525
     *
526
     * @return Boolean
527
     */
528
    public function isValid($val) {
529
        return $this->noSpaces($val)
530
            && $this->atLeastOneChar($val)
531
            && !$this->isReservedName($val)
532
            && !$this->isCvsAccount($val)
533
            && !$this->lessThanMin($val)
534
            && !$this->greaterThanMax($val)
535
            && !$this->containsIllegalChars($val)
536
            && !$this->isAlreadyUserName($val)
537
            && !$this->isAlreadyProjectName($val)
538
            && !$this->isSystemName($val)
539
            && $this->getPendingUserRename($val);
540
    }
541
542
    /**
543
     * Error message
544
     *
545
     * @return String
546
     */
547
    public function getErrorMessage() {
548
        return $this->error;
549
    }
550
551
    /**
552
     * Returns error message when the username already exists
553
     *
554
     * Dedicate a method to be able to override it in descendent classes
555
     *
556
     * @param String $val Value to test
0 ignored issues
show
There is no parameter named $val. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
557
     *
558
     * @return Boolean
559
     */
560
    protected function _getErrorExists() {
561
        return $GLOBALS['Language']->getText('rule_user_name', 'error_exists');
562
    }
563
564
    /**
565
     * Returns error message when name contains a space
566
     *
567
     * Dedicate a method to be able to override it in descendent classes
568
     *
569
     * @param String $val Value to test
0 ignored issues
show
There is no parameter named $val. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
570
     *
571
     * @return Boolean
572
     */
573
    protected function _getErrorNoSpaces() {
574
        return $GLOBALS['Language']->getText('include_account', 'login_err');
575
    }
576
577
    /**
578
     * Wrapper
579
     *
580
     * @return ProjectManager
581
     */
582
    protected function _getProjectManager() {
583
        return ProjectManager::instance();
584
    }
585
586
    /**
587
     * Wrapper
588
     *
589
     * @return UserManager
590
     */
591
    protected function _getUserManager() {
592
        return UserManager::instance();
593
    }
594
595
    /**
596
     * Wrapper
597
     *
598
     * @return Backend
599
     */
600
    protected function _getBackend($type='') {
601
        return Backend::instance($type);
602
    }
603
604
    /**
605
     * Wrapper
606
     *
607
     * @return SystemEventManager
608
     */
609
    protected function _getSystemEventManager() {
610
        return SystemEventManager::instance();
611
    }
612
}
613
614
/**
615
 * Check if a project name is valid
616
 *
617
 * This extends the user name validation
618
 */
619
class Rule_ProjectName
620
extends Rule_UserName {
621
622
    /**
623
     * Group name cannot contain underscore or dots for DNS reasons.
624
     *
625
     * @param String $val
626
     *
627
     * @return Boolean
628
     */
629
    public function isDNSCompliant($val) {
630
        if (strpos($val, '_') === false && strpos($val, '.') === false) {
631
            return true;
632
        }
633
        $this->error = $GLOBALS['Language']->getText('include_account','dns_error');
634
        return false;
635
    }
636
637
    /**
638
     * Verify group name availability in the FS
639
     *
640
     * @param String $val
641
     *
642
     * @return Boolean
643
     */
644
    public function isNameAvailable($val) {
645
646
        $backendSVN = $this->_getBackend('SVN');
647
        if (!$backendSVN->isNameAvailable($val)){
648
            $this->error = $GLOBALS['Language']->getText('include_account','used_by_svn');
649
            return false;
650
        } else {
651
            $backendCVS = $this->_getBackend('CVS');
652
            if (!$backendCVS->isNameAvailable($val)) {
653
                $this->error = $GLOBALS['Language']->getText('include_account','used_by_cvs');
654
                return false;
655
            } else {
656
                $backendSystem = $this->_getBackend('System');
657
                if (!$backendSystem->isProjectNameAvailable($val)){
658
                    $this->error = $GLOBALS['Language']->getText('include_account','used_by_sys');
659
                    return false;
660
                } else {
661
                    $result = true;
662
                    // Add Hook for plugins to check the name validity under plugins directories
663
                    $this->getEventManager()->processEvent('file_exists_in_data_dir',
664
                        array('new_name'  => $val,
665
                              'result'     => &$result,
666
                              'error' => &$error)
0 ignored issues
show
The variable $error does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
667
668
                            );
669
                    if ($result == false){
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
670
                        $this->error = $error;
671
                        return false;
672
                    }
673
                }
674
            }
675
        }
676
        return true;
677
    }
678
679
    /**
680
     * Prevent from renaming two projects on the same name
681
     * before that the rename is performed by the system
682
     *
683
     * @param String $val
684
     */
685
    public function getPendingProjectRename($val) {
686
        $sm = $this->_getSystemEventManager();
687
        if (!$sm->isProjectNameAvailable($val)) {
688
            $this->error = $GLOBALS['Language']->getText('rule_user_name', 'error_event_reserved', array($val));
689
            return false;
690
        }
691
        return true;
692
    }
693
694
695
     /**
696
     * Wrapper for event manager
697
     *
698
     * @return EventManager
699
     */
700
    protected function getEventManager() {
701
        return EventManager::instance();
702
    }
703
    /**
704
     * Check validity
705
     *
706
     * @param String $val
707
     *
708
     * @return Boolean
709
     */
710
    public function isValid($val) {
711
        return $this->isDNSCompliant($val) && parent::isValid($val)  && $this->isNameAvailable($val)
712
                   && $this->getPendingProjectRename($val);
713
    }
714
715
    protected function _getErrorExists() {
716
        return $GLOBALS['Language']->getText('rule_group_name', 'error_exists');
717
    }
718
719
    protected function _getErrorNoSpaces() {
720
        return $GLOBALS['Language']->getText('include_account', 'project_spaces');
721
    }
722
}
723
724
/**
725
 * Check if a project full name is valid
726
 *
727
 * This extends the user name validation
728
 */
729
class Rule_ProjectFullName extends Rule_UserName {
730
731
    /**
732
     * Check validity
733
     *
734
     * @param String $val
735
     *
736
     * @return Boolean
737
     */
738
    public function isValid($val) {
739
        $val = trim($val);
740
        return !$this->lessThanMin($val) && !$this->greaterThanMax($val, 40);
741
    }
742
743
    /**
744
     * Error message
745
     *
746
     * @return String
747
     */
748
    public function getErrorMessage() {
749
        return $this->error;
750
    }
751
752
}
753
754
/**
755
 * Check that file was correctly uploaded doesn't by pass Codendi limits.
756
 *
757
 * Tests mainly rely on PHP $_FILES error code but add a double check of file
758
 * size because MAX_FILE_SIZE (used by PHP to check allowed size) is submitted
759
 * by the client.
760
 *
761
 * By default the maxSize is defined by 'sys_max_size_upload' Codendi
762
 * variable but may be customized with setMaxSize.
763
 */
764
require_once("www/file/file_utils.php"); // Needed for 2 GB workaround
765
class Rule_File
766
extends Rule {
767
    var $maxSize;
768
    var $i18nPageName;
769
770
    function Rule_File() {
771
        $this->maxSize = $GLOBALS['sys_max_size_upload'];
772
        $this->i18nPageName = 'rule_file';
773
    }
774
775
    function setMaxSize($max) {
776
        $this->maxSize = $max;
777
    }
778
779
    function geti18nError($key, $params="") {
780
        return $GLOBALS['Language']->getText($this->i18nPageName, $key, $params);
781
    }
782
783
    /**
784
     * Check file upload validity
785
     *
786
     * @param  Array   One entry in $_FILES superarray (e.g. $_FILES['test'])
787
     * @return Boolean Is file upload valid or not.
788
     */
789
    function isValid($file) {
790
        $ok = false;
791
        if(is_array($file)) {
792
            switch($file['error']) {
793
            case UPLOAD_ERR_OK:
794
                // all is OK
795
                $ok = true;
796
                break;
797
            case UPLOAD_ERR_INI_SIZE:
798
            case UPLOAD_ERR_FORM_SIZE:
799
                $this->error = $this->geti18nError('error_upload_size', $file['error']);
800
                break;
801
            case UPLOAD_ERR_PARTIAL:
802
                $this->error = $this->geti18nError('error_upload_partial', $file['error']);
803
                break;
804
            case UPLOAD_ERR_NO_FILE:
805
                $this->error = $this->geti18nError('error_upload_nofile', $file['error']);
806
                break;
807
                //case UPLOAD_ERR_NO_TMP_DIR: PHP 5.0.3
808
                //case UPLOAD_ERR_CANT_WRITE: PHP 5.1.0
809
                //case UPLOAD_ERR_EXTENSION: PHP 5.2.0
810
            default:
811
                $this->error = $this->geti18nError('error_upload_unknown', $file['error']);
812
            }
813
            if($ok && $file['name'] == '') {
814
                $ok = false;
815
                $this->error = $this->geti18nError('error_upload');
816
            }
817
            if($ok) {
818
                // Re-check filesize (do not trust uploaded MAX_FILE_SIZE)
819
                if(file_utils_get_size($file['tmp_name']) > $this->maxSize) {
820
                   $ok = false;
821
                   $this->error = $this->geti18nError('error_upload_size', 1);
822
                }
823
            }
824
        }
825
        return $ok;
826
    }
827
}
828
829
class Rule_FRSFileName
830
extends Rule {
831
    function isValid($val) {
832
        if (preg_match("/[]`!\"$%^,&*();=|[{}<>?\/]/", $val)) {
833
            return false;
834
        }
835
        if (strpos($val, '@') === 0) { // Starts with at sign
836
            return false;
837
        }
838
        if (strpos($val, '~') === 0) { // Starts with at sign
839
            return false;
840
        }
841
        if (strstr($val,'..')) {
842
            return false;
843
        } else {
844
            return true;
845
        }
846
    }
847
}
848
849
class Rule_RealName extends Rule {
850
851
    public function isValid($string) {
852
        if ($this->containsBackslashCharacter($string) || $this->containsNonPrintingCharacter($string)) {
853
            return false;
854
        }
855
        return true;
856
    }
857
858
    private function containsBackslashCharacter($string) {
859
        return strpos($string, "\\") !== false;
860
    }
861
862
    private function containsNonPrintingCharacter($string) {
863
        for ($i = 0; $i < strlen($string); $i++) {
864
            if ($this->isNonPrintingCharacter($string[$i])) {
865
                return true;
866
            }
867
        }
868
        return false;
869
    }
870
871
    private function isNonPrintingCharacter($char) {
872
        return hexdec(bin2hex($char)) < 32;
873
    }
874
}
875
876
?>
877