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.
Passed
Push — master ( 698fd2...95f32c )
by Christian
10:54 queued 08:21
created

Enigma::createHashes()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 14
c 0
b 0
f 0
nc 2
nop 4
dl 0
loc 25
ccs 13
cts 13
cp 1
crap 3
rs 9.7998
1
<?php
2
3
namespace Omatech\Enigma;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Illuminate\Support\Str;
7
use Omatech\Enigma\CipherSweet\Index;
8
use Omatech\Enigma\Database\Contracts\DBInterface;
9
use ParagonIE\CipherSweet\Backend\FIPSCrypto;
10
use ParagonIE\CipherSweet\Backend\ModernCrypto;
11
use ParagonIE\CipherSweet\BlindIndex;
12
use ParagonIE\CipherSweet\CipherSweet;
13
use ParagonIE\CipherSweet\EncryptedField;
14
use ParagonIE\CipherSweet\Exception\BlindIndexNameCollisionException;
15
use ParagonIE\CipherSweet\Exception\BlindIndexNotFoundException;
16
use ParagonIE\CipherSweet\Exception\CryptoOperationException;
17
use ParagonIE\CipherSweet\KeyProvider\StringProvider;
18
use ParagonIE\ConstantTime\Hex;
19
use SodiumException;
20
21 1
const TABLE = 'table';
22
23
class Enigma
24
{
25
    private $engine;
26
27
    /**
28
     * Enigma constructor.
29
     * @throws CryptoOperationException
30
     */
31 63
    public function __construct()
32
    {
33 63
        $key = new StringProvider(
34 63
            substr(Hex::encode(env('APP_KEY')), 0, 64)
35
        );
36
37 63
        $backend = (config('enigma.backend') === 'fips') ? new FIPSCrypto() : new ModernCrypto();
38 63
        $this->engine = new CipherSweet($key, $backend);
39 63
    }
40
41
    /**
42
     * @param string $tableName
43
     * @param string $columnName
44
     * @param string $value
45
     * @return string
46
     * @throws BlindIndexNotFoundException
47
     * @throws CryptoOperationException
48
     * @throws SodiumException
49
     */
50 51
    public function encrypt(string $tableName, string $columnName, string $value): string
51
    {
52 51
        [$value] = (new EncryptedField(
53 51
            $this->engine,
54
            $tableName,
55
            $columnName
56 51
        ))->prepareForStorage($value);
57
58 51
        return $value;
59
    }
60
61
    /**
62
     * @param string $tableName
63
     * @param string $columnName
64
     * @param string $value
65
     * @return Model
66
     * @throws CryptoOperationException
67
     */
68 50
    public function decrypt(string $tableName, string $columnName, string $value): string
69
    {
70 50
        return (new EncryptedField(
71 50
            $this->engine,
72
            $tableName,
73
            $columnName
74 50
        ))->decryptValue($value);
75
    }
76
77
    /**
78
     * @param string $tableName
79
     * @param string $columnName
80
     * @param string $value
81
     * @param Index $index
82
     * @return int|string
83
     * @throws BlindIndexNameCollisionException
84
     * @throws CryptoOperationException
85
     */
86 24
    public function search(string $tableName, string $columnName, string $value, Index $index)
87
    {
88 24
        $hash = $this->createHash($tableName, $columnName, $value, $index);
89
90 24
        $ids = (app()->makeWith(DBInterface::class, [
91 24
            TABLE => $tableName,
92 24
        ]))->findByHash($columnName, $hash);
93
94 24
        return (count($ids) === 0) ? -1 : implode(',', $ids);
95
    }
96
97
    /**
98
     * @param Model $model
99
     * @param string $columnName
100
     * @param string $value
101
     * @return int|string|null
102
     * @throws BlindIndexNameCollisionException
103
     * @throws CryptoOperationException
104
     */
105 20
    public function searchAsModel(Model $model, string $columnName, string $value)
106
    {
107 20
        $blindIndexMethod = $this->getBlindIndexMethod($columnName);
108
109 20
        if (method_exists($model, $blindIndexMethod)) {
110 16
            $index = new Index;
111 16
            $index->name($columnName);
112
113 16
            $model->{$blindIndexMethod}($index);
114
115 16
            return $this->search($model->getTable(), $columnName, $value, $index);
116
        }
117
118 4
        return -1;
119
    }
120
121
    /**
122
     * @param Model $model
123
     * @param string $columnName
124
     * @param string $value
125
     * @throws BlindIndexNameCollisionException
126
     * @throws CryptoOperationException
127
     */
128 44
    public function hydrateAsModel(Model $model, string $columnName, string $value): void
129
    {
130 44
        $blindIndexMethod = $this->getBlindIndexMethod($columnName);
131
132 44
        (app()->makeWith(DBInterface::class, [
133 44
            TABLE => $model->getTable(),
134 44
        ]))->deleteHashes($model->id, $columnName);
135
136 44
        if (method_exists($model, $blindIndexMethod)) {
137 44
            $index = new Index;
138 44
            $index->name($columnName);
139 44
            $model->{$blindIndexMethod}($index);
140
141 44
            $hashes = $this->createHashes($model->getTable(), $columnName, $value, $index);
142 44
            $hashes = array_unique($hashes);
143 44
            shuffle($hashes);
144
145 44
            (app()->makeWith(DBInterface::class, [
146 44
                TABLE => $model->getTable(),
147 44
            ]))->insertHashes($model->id, $columnName, $hashes);
148
        }
149 44
    }
150
151
    /**
152
     * @param $tableName
153
     * @param $columnName
154
     * @param $index
155
     * @return array
156
     * @throws BlindIndexNameCollisionException
157
     * @throws CryptoOperationException
158
     */
159 44
    private function transform(string $tableName, string $columnName, Index $index): array
160
    {
161 44
        $field = new EncryptedField(
162 44
            $this->engine,
163
            $tableName,
164
            $columnName
165
        );
166
167 44
        $index->name($columnName);
168
169 44
        $blindIndex = new BlindIndex(
170 44
            $index->name,
171 44
            $index->transformers,
172 44
            $index->bits,
173 44
            $index->fast
174
        );
175
176 44
        $field->addBlindIndex($blindIndex);
177
178 44
        return [$field, $blindIndex];
179
    }
180
181
    /**
182
     * @param string $tableName
183
     * @param string $columnName
184
     * @param string $value
185
     * @param Index $index
186
     * @return mixed
187
     * @throws BlindIndexNameCollisionException
188
     * @throws CryptoOperationException
189
     */
190 24
    private function createHash(string $tableName, string $columnName, string $value, Index $index)
191
    {
192 24
        [$field] = $this->transform($tableName, $columnName, $index);
193
194 24
        return $field->prepareForStorage($value)[1][$index->name];
195
    }
196
197
    /**
198
     * @param string $tableName
199
     * @param string $columnName
200
     * @param string $value
201
     * @param Index $index
202
     * @return array
203
     * @throws BlindIndexNameCollisionException
204
     * @throws CryptoOperationException
205
     */
206 44
    private function createHashes(string $tableName, string $columnName, string $value, Index $index): array
207
    {
208 44
        [$field, $blindIndex] = $this->transform($tableName, $columnName, $index);
209
210 44
        $value = $blindIndex->getTransformed($value);
211
212 44
        $hash = [$field->prepareForStorage($value)[1][$index->name]];
213
214
        $hashes = array_map(static function ($strategy) use ($value, $field, $index) {
215 44
            $strategy = $strategy->__invoke($value);
216
217 44
            if (is_array($strategy)) {
218
                return array_map(static function ($val) use ($field, $index) {
219 44
                    return $field->prepareForStorage($val)[1][$index->name];
220 44
                }, $strategy ?? []);
221
            }
222
223 44
            return [$field->prepareForStorage($strategy)[1][$index->name]];
224 44
        }, $index->strategies ?? []);
225
226 44
        if (count($hashes)) {
227 44
            $hashes = call_user_func_array('array_merge', $hashes);
228
        }
229
230 44
        return array_merge($hash, $hashes);
231
    }
232
233
    /**
234
     * @param string $column
235
     * @return string
236
     */
237 44
    private function getBlindIndexMethod(string $column): string
238
    {
239 44
        return lcfirst(str_replace('_', '', Str::title($column))).'BlindIndex';
240
    }
241
}
242