Passed
Push — master ( 45a3bb...2cf7c0 )
by Thomas
03:37
created

EncryptedSearchFilter::setModifiers()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 8
rs 10
cc 2
nc 2
nop 1
1
<?php
2
3
namespace LeKoala\Encrypt;
4
5
use SilverStripe\ORM\DB;
6
use InvalidArgumentException;
7
use SilverStripe\ORM\DataQuery;
8
use ParagonIE\CipherSweet\BlindIndex;
9
use ParagonIE\CipherSweet\EncryptedField;
10
use SilverStripe\ORM\DataObject;
11
use SilverStripe\ORM\Filters\SearchFilter;
12
13
/**
14
 * A filter that helps searching against a full blind index
15
 */
16
class EncryptedSearchFilter extends SearchFilter
17
{
18
    public function setModifiers(array $modifiers)
19
    {
20
        if (!empty($modifiers)) {
21
            throw new InvalidArgumentException(
22
                get_class($this) . ' does not accept ' . implode(', ', $modifiers) . ' as modifiers'
23
            );
24
        }
25
        parent::setModifiers($modifiers);
26
    }
27
28
    protected function getCaseSensitive()
29
    {
30
        return null;
31
    }
32
33
    public function getDbName()
34
    {
35
        $column = parent::getDbName();
36
        $column = str_replace('"', '', $column);
37
        return '"' . $column . 'BlindIndex"';
38
    }
39
40
    /**
41
     * @return EncryptedField
42
     */
43
    public function getEncryptedField()
44
    {
45
        $engine = EncryptHelper::getCipherSweet();
46
        $table = DataObject::getSchema()->tableName($this->model);
47
        $encryptedField = (new EncryptedField($engine, $table, $this->name))
48
            ->addBlindIndex(new BlindIndex($this->name . "BlindIndex", [], 32));
49
        return $encryptedField;
50
    }
51
52
    /**
53
     * Accessor for the current value to be filtered on.
54
     *
55
     * @return string|array
56
     */
57
    public function getEncryptedValue()
58
    {
59
        return $this->getEncryptedField()->getBlindIndex($this->getValue(), $this->name . 'BlindIndex');
0 ignored issues
show
Bug introduced by
It seems like $this->getValue() can also be of type array; however, parameter $plaintext of ParagonIE\CipherSweet\En...dField::getBlindIndex() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

59
        return $this->getEncryptedField()->getBlindIndex(/** @scrutinizer ignore-type */ $this->getValue(), $this->name . 'BlindIndex');
Loading history...
60
    }
61
62
    /**
63
     * Applies an exact match (equals) on a field value.
64
     *
65
     * @return DataQuery
66
     */
67
    protected function applyOne(DataQuery $query)
68
    {
69
        $this->model = $query->applyRelation($this->relation);
70
        $where = DB::get_conn()->comparisonClause(
71
            $this->getDbName(),
72
            null,
73
            true, // exact?
74
            false, // negate?
75
            $this->getCaseSensitive(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getCaseSensitive() targeting LeKoala\Encrypt\Encrypte...ter::getCaseSensitive() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

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.

Loading history...
76
            true
77
        );
78
        $array = array($where => $this->getEncryptedValue());
79
        return $query->where($array);
80
    }
81
82
    /**
83
     * Applies an exact match (equals) on a field value against multiple
84
     * possible values.
85
     *
86
     * @return DataQuery
87
     */
88
    protected function applyMany(DataQuery $query)
89
    {
90
        $this->model = $query->applyRelation($this->relation);
91
        $caseSensitive = $this->getCaseSensitive();
0 ignored issues
show
Unused Code introduced by
The assignment to $caseSensitive is dead and can be removed.
Loading history...
Bug introduced by
Are you sure the assignment to $caseSensitive is correct as $this->getCaseSensitive() targeting LeKoala\Encrypt\Encrypte...ter::getCaseSensitive() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
92
        $values = $this->getEncryptedValue();
93
        $column = $this->getDbName();
94
        // For queries using the default collation (no explicit case) we can use the WHERE .. IN .. syntax,
95
        // providing simpler SQL than many WHERE .. OR .. fragments.
96
        // If values is an empty array, fall back to 3.1 behaviour and use empty string comparison
97
        if (empty($values)) {
98
            $values = array('');
99
        }
100
        $placeholders = DB::placeholders($values);
0 ignored issues
show
Bug introduced by
It seems like $values can also be of type string; however, parameter $input of SilverStripe\ORM\DB::placeholders() does only seem to accept array|integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

100
        $placeholders = DB::placeholders(/** @scrutinizer ignore-type */ $values);
Loading history...
101
        return $query->where(array(
102
            "$column IN ($placeholders)" => $values
103
        ));
104
    }
105
106
    /**
107
     * Excludes an exact match (equals) on a field value.
108
     *
109
     * @return DataQuery
110
     */
111
    protected function excludeOne(DataQuery $query)
112
    {
113
        $this->model = $query->applyRelation($this->relation);
114
        $column = $this->getDbName();
115
        $where = DB::get_conn()->comparisonClause(
116
            $column,
117
            null,
118
            true, // exact?
119
            true, // negate?
120
            $this->getCaseSensitive(),
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getCaseSensitive() targeting LeKoala\Encrypt\Encrypte...ter::getCaseSensitive() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

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.

Loading history...
121
            true
122
        );
123
        $array = array($where => $this->getEncryptedValue());
124
        return $query->where($array);
125
    }
126
127
    /**
128
     * Excludes an exact match (equals) on a field value against multiple
129
     * possible values.
130
     *
131
     * @return DataQuery
132
     */
133
    protected function excludeMany(DataQuery $query)
134
    {
135
        $this->model = $query->applyRelation($this->relation);
136
        $caseSensitive = $this->getCaseSensitive();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $caseSensitive is correct as $this->getCaseSensitive() targeting LeKoala\Encrypt\Encrypte...ter::getCaseSensitive() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
137
        $values = $this->getEncryptedValue();
138
        $column = $this->getDbName();
139
        if ($caseSensitive === null) {
0 ignored issues
show
introduced by
The condition $caseSensitive === null is always true.
Loading history...
140
            // For queries using the default collation (no explicit case) we can use the WHERE .. NOT IN .. syntax,
141
            // providing simpler SQL than many WHERE .. AND .. fragments.
142
            // If values is an empty array, fall back to 3.1 behaviour and use empty string comparison
143
            if (empty($values)) {
144
                $values = array('');
145
            }
146
            $placeholders = DB::placeholders($values);
0 ignored issues
show
Bug introduced by
It seems like $values can also be of type string; however, parameter $input of SilverStripe\ORM\DB::placeholders() does only seem to accept array|integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

146
            $placeholders = DB::placeholders(/** @scrutinizer ignore-type */ $values);
Loading history...
147
            return $query->where(array(
148
                "$column NOT IN ($placeholders)" => $values
149
            ));
150
        } else {
151
            // Generate reusable comparison clause
152
            $comparisonClause = DB::get_conn()->comparisonClause(
153
                $column,
154
                null,
155
                true, // exact?
156
                true, // negate?
157
                $this->getCaseSensitive(),
158
                true
159
            );
160
            // Since query connective is ambiguous, use AND explicitly here
161
            $count = count($values);
162
            $predicate = implode(' AND ', array_fill(0, $count, $comparisonClause));
163
            return $query->where(array($predicate => $values));
164
        }
165
    }
166
167
    public function isEmpty()
168
    {
169
        return $this->getValue() === array() || $this->getValue() === null || $this->getValue() === '';
170
    }
171
}
172