Completed
Push — master ( 84dee3...084275 )
by Michal
36:03
created

CookieCryptTrait::_explode()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 17
rs 8.8571
cc 6
eloc 12
nc 5
nop 1
1
<?php
2
/**
3
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
4
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
5
 *
6
 * Licensed under The MIT License
7
 * For full copyright and license information, please see the LICENSE.txt
8
 * Redistributions of files must retain the above copyright notice.
9
 *
10
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
11
 * @link          http://cakephp.org CakePHP(tm) Project
12
 * @since         3.1.6
13
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
14
 */
15
namespace Cake\Utility;
16
17
use RuntimeException;
18
19
/**
20
 * Cookie Crypt Trait.
21
 *
22
 * Provides the encrypt/decrypt logic for the CookieComponent.
23
 *
24
 * @link http://book.cakephp.org/3.0/en/controllers/components/cookie.html
25
 */
26
trait CookieCryptTrait
27
{
28
    /**
29
     * Valid cipher names for encrypted cookies.
30
     *
31
     * @var array
32
     */
33
    protected $_validCiphers = ['aes', 'rijndael'];
34
35
    /**
36
     * Returns the encryption key to be used.
37
     *
38
     * @return string
39
     */
40
    abstract protected function _getCookieEncryptionKey();
41
42
    /**
43
     * Encrypts $value using public $type method in Security class
44
     *
45
     * @param string $value Value to encrypt
46
     * @param string|bool $encrypt Encryption mode to use. False
47
     *   disabled encryption.
48
     * @param string|null $key Used as the security salt only in this time for tests if specified.
49
     * @return string Encoded values
50
     */
51
    protected function _encrypt($value, $encrypt, $key = null)
52
    {
53
        if (is_array($value)) {
54
            $value = $this->_implode($value);
55
        }
56
        if ($encrypt === false) {
57
            return $value;
58
        }
59
        $this->_checkCipher($encrypt);
0 ignored issues
show
Bug introduced by
It seems like $encrypt defined by parameter $encrypt on line 51 can also be of type boolean; however, Cake\Utility\CookieCryptTrait::_checkCipher() does only seem to accept 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...
60
        $prefix = "Q2FrZQ==.";
61
        $cipher = null;
62
        if (!isset($key)) {
63
            $key = $this->_getCookieEncryptionKey();
64
        }
65
        if ($encrypt === 'rijndael') {
66
            $cipher = Security::rijndael($value, $key, 'encrypt');
67
        }
68
        if ($encrypt === 'aes') {
69
            $cipher = Security::encrypt($value, $key);
70
        }
71
        return $prefix . base64_encode($cipher);
72
    }
73
74
    /**
75
     * Helper method for validating encryption cipher names.
76
     *
77
     * @param string $encrypt The cipher name.
78
     * @return void
79
     * @throws RuntimeException When an invalid cipher is provided.
80
     */
81
    protected function _checkCipher($encrypt)
82
    {
83
        if (!in_array($encrypt, $this->_validCiphers)) {
84
            $msg = sprintf(
85
                'Invalid encryption cipher. Must be one of %s.',
86
                implode(', ', $this->_validCiphers)
87
            );
88
            throw new RuntimeException($msg);
89
        }
90
    }
91
92
    /**
93
     * Decrypts $value using public $type method in Security class
94
     *
95
     * @param array $values Values to decrypt
96
     * @param string|bool $mode Encryption mode
97
     * @return string decrypted string
98
     */
99
    protected function _decrypt($values, $mode)
100
    {
101
        if (is_string($values)) {
102
            return $this->_decode($values, $mode);
0 ignored issues
show
Bug introduced by
It seems like $mode defined by parameter $mode on line 99 can also be of type boolean; however, Cake\Utility\CookieCryptTrait::_decode() does only seem to accept string|false, 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...
103
        }
104
105
        $decrypted = [];
106
        foreach ($values as $name => $value) {
107
            $decrypted[$name] = $this->_decode($value, $mode);
0 ignored issues
show
Bug introduced by
It seems like $mode defined by parameter $mode on line 99 can also be of type boolean; however, Cake\Utility\CookieCryptTrait::_decode() does only seem to accept string|false, 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...
108
        }
109
        return $decrypted;
110
    }
111
112
    /**
113
     * Decodes and decrypts a single value.
114
     *
115
     * @param string $value The value to decode & decrypt.
116
     * @param string|false $encrypt The encryption cipher to use.
117
     * @return string Decoded value.
118
     */
119
    protected function _decode($value, $encrypt)
120
    {
121
        if (!$encrypt) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $encrypt of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
122
            return $this->_explode($value);
123
        }
124
        $this->_checkCipher($encrypt);
125
        $prefix = 'Q2FrZQ==.';
126
        $value = base64_decode(substr($value, strlen($prefix)));
127
        if ($encrypt === 'rijndael') {
128
            $value = Security::rijndael($value, $this->_getCookieEncryptionKey(), 'decrypt');
129
        }
130
        if ($encrypt === 'aes') {
131
            $value = Security::decrypt($value, $this->_getCookieEncryptionKey());
132
        }
133
        return $this->_explode($value);
134
    }
135
136
    /**
137
     * Implode method to keep keys are multidimensional arrays
138
     *
139
     * @param array $array Map of key and values
140
     * @return string A json encoded string.
141
     */
142
    protected function _implode(array $array)
143
    {
144
        return json_encode($array);
145
    }
146
147
    /**
148
     * Explode method to return array from string set in CookieComponent::_implode()
149
     * Maintains reading backwards compatibility with 1.x CookieComponent::_implode().
150
     *
151
     * @param string $string A string containing JSON encoded data, or a bare string.
152
     * @return array Map of key and values
153
     */
154
    protected function _explode($string)
155
    {
156
        $first = substr($string, 0, 1);
157
        if ($first === '{' || $first === '[') {
158
            $ret = json_decode($string, true);
159
            return ($ret !== null) ? $ret : $string;
160
        }
161
        $array = [];
162
        foreach (explode(',', $string) as $pair) {
163
            $key = explode('|', $pair);
164
            if (!isset($key[1])) {
165
                return $key[0];
166
            }
167
            $array[$key[0]] = $key[1];
168
        }
169
        return $array;
170
    }
171
}
172