1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace LeKoala\Encrypt; |
4
|
|
|
|
5
|
|
|
use Exception; |
6
|
|
|
use SilverStripe\ORM\DB; |
7
|
|
|
use InvalidArgumentException; |
8
|
|
|
use SilverStripe\ORM\DataQuery; |
9
|
|
|
use ParagonIE\CipherSweet\CipherSweet; |
10
|
|
|
use ParagonIE\CipherSweet\EncryptedField; |
11
|
|
|
use SilverStripe\ORM\Filters\SearchFilter; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* A filter that helps searching against a full blind index |
15
|
|
|
* This can return false positive and is NOT recommended |
16
|
|
|
* @deprecated |
17
|
|
|
*/ |
18
|
|
|
class EncryptedSearchFilter extends SearchFilter |
19
|
|
|
{ |
20
|
|
|
/** |
21
|
|
|
* @param array<string> $modifiers |
22
|
|
|
* @return void |
23
|
|
|
*/ |
24
|
|
|
public function setModifiers(array $modifiers) |
25
|
|
|
{ |
26
|
|
|
if (!empty($modifiers)) { |
27
|
|
|
throw new InvalidArgumentException( |
28
|
|
|
get_class($this) . ' does not accept ' . implode(', ', $modifiers) . ' as modifiers' |
29
|
|
|
); |
30
|
|
|
} |
31
|
|
|
parent::setModifiers($modifiers); |
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
protected function getCaseSensitive() |
35
|
|
|
{ |
36
|
|
|
return null; |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
public function getDbName() |
40
|
|
|
{ |
41
|
|
|
$column = parent::getDbName(); |
42
|
|
|
$column = str_replace('"', '', $column); |
43
|
|
|
return '"' . $column . 'BlindIndex"'; |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* @param CipherSweet $engine |
48
|
|
|
* @param bool $fashHash |
49
|
|
|
* @return EncryptedField |
50
|
|
|
*/ |
51
|
|
|
public function getEncryptedField($engine = null, $fashHash = null) |
52
|
|
|
{ |
53
|
|
|
$singleton = singleton($this->model); |
54
|
|
|
return $singleton->dbObject($this->name)->getEncryptedField($engine, $fashHash); |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* Accessor for the current value to be filtered on. |
59
|
|
|
* |
60
|
|
|
* @return string |
61
|
|
|
*/ |
62
|
|
|
public function getEncryptedValue() |
63
|
|
|
{ |
64
|
|
|
$plaintext = $this->getValue(); |
65
|
|
|
if (is_array($plaintext)) { |
66
|
|
|
throw new Exception("Array value are not supported"); |
67
|
|
|
} |
68
|
|
|
$value = $this->getEncryptedField()->getBlindIndex($plaintext, $this->name . EncryptedDBField::INDEX_SUFFIX); |
69
|
|
|
if (is_array($value)) { |
70
|
|
|
return $value['value']; |
71
|
|
|
} |
72
|
|
|
return $value; |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* Applies an exact match (equals) on a field value. |
77
|
|
|
* |
78
|
|
|
* @return DataQuery |
79
|
|
|
*/ |
80
|
|
|
protected function applyOne(DataQuery $query) |
81
|
|
|
{ |
82
|
|
|
$this->model = $query->applyRelation($this->relation); |
83
|
|
|
$where = DB::get_conn()->comparisonClause( |
84
|
|
|
$this->getDbName(), |
85
|
|
|
'', |
86
|
|
|
true, // exact? |
87
|
|
|
false, // negate? |
88
|
|
|
$this->getCaseSensitive(), |
|
|
|
|
89
|
|
|
true |
90
|
|
|
); |
91
|
|
|
$array = array($where => $this->getEncryptedValue()); |
92
|
|
|
return $query->where($array); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* Applies an exact match (equals) on a field value against multiple |
97
|
|
|
* possible values. |
98
|
|
|
* |
99
|
|
|
* @return DataQuery |
100
|
|
|
*/ |
101
|
|
|
protected function applyMany(DataQuery $query) |
102
|
|
|
{ |
103
|
|
|
$this->model = $query->applyRelation($this->relation); |
104
|
|
|
$caseSensitive = $this->getCaseSensitive(); |
|
|
|
|
105
|
|
|
$values = [$this->getEncryptedValue()]; |
106
|
|
|
$column = $this->getDbName(); |
107
|
|
|
$placeholders = DB::placeholders($values); |
108
|
|
|
return $query->where(array( |
109
|
|
|
"$column IN ($placeholders)" => $values |
110
|
|
|
)); |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* Excludes an exact match (equals) on a field value. |
115
|
|
|
* |
116
|
|
|
* @return DataQuery |
117
|
|
|
*/ |
118
|
|
|
protected function excludeOne(DataQuery $query) |
119
|
|
|
{ |
120
|
|
|
$this->model = $query->applyRelation($this->relation); |
121
|
|
|
$column = $this->getDbName(); |
122
|
|
|
$where = DB::get_conn()->comparisonClause( |
123
|
|
|
$column, |
124
|
|
|
'', |
125
|
|
|
true, // exact? |
126
|
|
|
true, // negate? |
127
|
|
|
$this->getCaseSensitive(), |
|
|
|
|
128
|
|
|
true |
129
|
|
|
); |
130
|
|
|
$array = array($where => $this->getEncryptedValue()); |
131
|
|
|
return $query->where($array); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* Excludes an exact match (equals) on a field value against multiple |
136
|
|
|
* possible values. |
137
|
|
|
* |
138
|
|
|
* @return DataQuery |
139
|
|
|
*/ |
140
|
|
|
protected function excludeMany(DataQuery $query) |
141
|
|
|
{ |
142
|
|
|
$this->model = $query->applyRelation($this->relation); |
143
|
|
|
$caseSensitive = $this->getCaseSensitive(); |
|
|
|
|
144
|
|
|
$values = [$this->getEncryptedValue()]; |
145
|
|
|
$column = $this->getDbName(); |
146
|
|
|
if ($caseSensitive === null) { |
|
|
|
|
147
|
|
|
$placeholders = DB::placeholders($values); |
148
|
|
|
return $query->where(array( |
149
|
|
|
"$column NOT IN ($placeholders)" => $values |
150
|
|
|
)); |
151
|
|
|
} else { |
152
|
|
|
// Generate reusable comparison clause |
153
|
|
|
$comparisonClause = DB::get_conn()->comparisonClause( |
154
|
|
|
$column, |
155
|
|
|
'', |
156
|
|
|
true, // exact? |
157
|
|
|
true, // negate? |
158
|
|
|
$this->getCaseSensitive(), |
159
|
|
|
true |
160
|
|
|
); |
161
|
|
|
// Since query connective is ambiguous, use AND explicitly here |
162
|
|
|
$count = count($values); |
163
|
|
|
$predicate = implode(' AND ', array_fill(0, $count, $comparisonClause)); |
164
|
|
|
return $query->where(array($predicate => $values)); |
165
|
|
|
} |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
public function isEmpty() |
169
|
|
|
{ |
170
|
|
|
/** @var array<mixed>|string|null $v */ |
171
|
|
|
$v = $this->getValue(); |
172
|
|
|
return $v === array() || $v === null || $v === ''; |
173
|
|
|
} |
174
|
|
|
} |
175
|
|
|
|
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()
can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.