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.

Enigma   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 219
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 4
Bugs 3 Features 0
Metric Value
eloc 74
c 4
b 3
f 0
dl 0
loc 219
ccs 74
cts 74
cp 1
rs 10
wmc 17

10 Methods

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