UseMuffin / Obfuscate

@@ -1,10 +1,18 @@
Loading
1 1
<?php
2 +
declare(strict_types=1);
3 +
2 4
namespace Muffin\Obfuscate\Model\Behavior\Strategy;
3 5
6 +
use InvalidArgumentException;
4 7
use Jenssegers\Optimus\Optimus;
5 8
6 9
class OptimusStrategy implements StrategyInterface
7 10
{
11 +
    /**
12 +
     * Obfuscator.
13 +
     *
14 +
     * @var \Jenssegers\Optimus\Optimus
15 +
     */
8 16
    protected $_optimus;
9 17
10 18
    /**
@@ -14,30 +22,32 @@
Loading
14 22
     * @param int $inverse Inverse number.
15 23
     * @param int $random Random number.
16 24
     */
17 -
    public function __construct($prime, $inverse, $random)
25 +
    public function __construct(int $prime, int $inverse, int $random)
18 26
    {
19 27
        $this->_optimus = new Optimus($prime, $inverse, $random);
20 28
    }
21 29
22 30
    /**
23 -
     * {@inheritdoc}
24 -
     *
25 -
     * @param string $str String to obfuscate.
26 -
     * @return int
31 +
     * @inheritDoc
27 32
     */
28 -
    public function obfuscate($str)
33 +
    public function obfuscate($str): string
29 34
    {
30 -
        return $this->_optimus->encode($str);
35 +
        if (!is_numeric($str)) {
36 +
            throw new InvalidArgumentException('Argument should be an integer');
37 +
        }
38 +
39 +
        return (string)$this->_optimus->encode((int)$str);
31 40
    }
32 41
33 42
    /**
34 -
     * {@inheritdoc}
35 -
     *
36 -
     * @param string $str String to elucidate.
37 -
     * @return int
43 +
     * @inheritDoc
38 44
     */
39 -
    public function elucidate($str)
45 +
    public function elucidate($str): int
40 46
    {
41 -
        return $this->_optimus->decode($str);
47 +
        if (!is_numeric($str)) {
48 +
            throw new InvalidArgumentException('Argument should be an integer');
49 +
        }
50 +
51 +
        return $this->_optimus->decode((int)$str);
42 52
    }
43 53
}

@@ -1,15 +1,15 @@
Loading
1 1
<?php
2 +
declare(strict_types=1);
3 +
2 4
namespace Muffin\Obfuscate\Model\Behavior\Strategy;
3 5
4 6
use Cake\ORM\Table;
5 7
6 8
/**
7 9
 * Class UuidStrategy
8 -
 *
9 10
 */
10 11
class UuidStrategy implements StrategyInterface
11 12
{
12 -
13 13
    /**
14 14
     * UUID field to use.
15 15
     *
@@ -20,30 +20,28 @@
Loading
20 20
    /**
21 21
     * Table using this strategy.
22 22
     *
23 -
     * @var Table
23 +
     * @var \Cake\ORM\Table
24 24
     */
25 25
    protected $_table;
26 26
27 27
    /**
28 28
     * Constructor.
29 29
     *
30 -
     * @param Table $table Instance of the table using the strategy.
30 +
     * @param \Cake\ORM\Table $table Instance of the table using the strategy.
31 31
     * @param string $field Name of the UUID field on the table.
32 32
     */
33 -
    public function __construct($table, $field = 'uuid')
33 +
    public function __construct(Table $table, string $field = 'uuid')
34 34
    {
35 35
        $this->_table = $table;
36 36
        $this->_field = $field;
37 37
    }
38 38
39 39
    /**
40 -
     * {@inheritdoc}
41 -
     *
42 -
     * @param string $str String to obfuscate.
43 -
     * @return string
40 +
     * @inheritDoc
44 41
     */
45 -
    public function obfuscate($str)
42 +
    public function obfuscate($str): string
46 43
    {
44 +
        /** @psalm-suppress InvalidArrayOffset */
47 45
        $record = $this->_table
48 46
            ->find()
49 47
            ->where([$this->_table->getPrimaryKey() => $str])
@@ -54,12 +52,9 @@
Loading
54 52
    }
55 53
56 54
    /**
57 -
     * {@inheritdoc}
58 -
     *
59 -
     * @param string $str String to elucidate.
60 -
     * @return string
55 +
     * @inheritDoc
61 56
     */
62 -
    public function elucidate($str)
57 +
    public function elucidate($str): int
63 58
    {
64 59
        $pk = $this->_table->getPrimaryKey();
65 60

@@ -1,15 +1,15 @@
Loading
1 1
<?php
2 +
declare(strict_types=1);
3 +
2 4
namespace Muffin\Obfuscate\Model\Behavior\Strategy;
3 5
4 6
use ZackKitzmiller\Tiny;
5 7
6 8
/**
7 9
 * Class TinyStrategy
8 -
 *
9 10
 */
10 11
class TinyStrategy implements StrategyInterface
11 12
{
12 -
13 13
    /**
14 14
     * Random alpha-numeric set where each character must only be
15 15
     * used exactly once.
@@ -30,30 +30,24 @@
Loading
30 30
     *
31 31
     * @param string $set Random alpha-numeric set.
32 32
     */
33 -
    public function __construct($set)
33 +
    public function __construct(string $set)
34 34
    {
35 35
        $this->_set = $set;
36 36
        $this->_tiny = new Tiny($set);
37 37
    }
38 38
39 39
    /**
40 -
     * {@inheritdoc}
41 -
     *
42 -
     * @param string $str String to obfuscate.
43 -
     * @return string
40 +
     * @inheritDoc
44 41
     */
45 -
    public function obfuscate($str)
42 +
    public function obfuscate($str): string
46 43
    {
47 -
        return $this->_tiny->to($str);
44 +
        return $this->_tiny->to((string)$str);
48 45
    }
49 46
50 47
    /**
51 -
     * {@inheritdoc}
52 -
     *
53 -
     * @param string $str String to elucidate.
54 -
     * @return string
48 +
     * @inheritDoc
55 49
     */
56 -
    public function elucidate($str)
50 +
    public function elucidate($str): int
57 51
    {
58 52
        return $this->_tiny->from($str);
59 53
    }

@@ -1,24 +1,25 @@
Loading
1 1
<?php
2 +
declare(strict_types=1);
3 +
2 4
namespace Muffin\Obfuscate\Model\Behavior;
3 5
4 6
use ArrayObject;
5 -
use Cake\Core\Exception\Exception;
7 +
use Cake\Database\Expression\ComparisonExpression;
6 8
use Cake\Datasource\EntityInterface;
7 -
use Cake\Event\Event;
9 +
use Cake\Event\EventInterface;
8 10
use Cake\ORM\Behavior;
9 11
use Cake\ORM\Query;
10 -
use Cake\ORM\ResultSet;
12 +
use InvalidArgumentException;
11 13
use Muffin\Obfuscate\Model\Behavior\Strategy\StrategyInterface;
14 +
use RuntimeException;
12 15
13 16
/**
14 17
 * Class ObfuscateBehavior
15 -
 *
16 18
 */
17 19
class ObfuscateBehavior extends Behavior
18 20
{
19 -
20 21
    /**
21 -
     * {@inheritdoc}
22 +
     * @inheritDoc
22 23
     */
23 24
    protected $_defaultConfig = [
24 25
        'strategy' => null,
@@ -38,7 +39,7 @@
Loading
38 39
     * @param array $config Behavior's configuration.
39 40
     * @return void
40 41
     */
41 -
    public function initialize(array $config)
42 +
    public function initialize(array $config): void
42 43
    {
43 44
        $this->verifyConfig();
44 45
    }
@@ -48,16 +49,16 @@
Loading
48 49
     *
49 50
     * @return void
50 51
     */
51 -
    public function verifyConfig()
52 +
    public function verifyConfig(): void
52 53
    {
53 54
        $strategy = $this->getConfig('strategy');
54 -
        if (!$strategy) {
55 -
            throw new Exception('Missing required obfuscation strategy.');
55 +
        if (empty($strategy)) {
56 +
            throw new InvalidArgumentException('Missing required obfuscation strategy.');
56 57
        }
57 58
58 59
        if (!($strategy instanceof StrategyInterface)) {
59 -
            throw new Exception(
60 -
                'Strategy must implement the `Muffin\Obfuscate\Model\Behavior\Strategy\StrategyInterface`'
60 +
            throw new InvalidArgumentException(
61 +
                'Strategy must implement ' . StrategyInterface::class
61 62
            );
62 63
        }
63 64
@@ -67,14 +68,17 @@
Loading
67 68
    /**
68 69
     * Callback to obfuscate the record(s)' primary key returned after a save operation.
69 70
     *
70 -
     * @param \Cake\ORM\Behavior\Event $event Event.
71 -
     * @param \Cake\ORM\Behavior\EntityInterface $entity Entity.
71 +
     * @param \Cake\Event\EventInterface $event EventInterface.
72 +
     * @param \Cake\Datasource\EntityInterface $entity Entity.
72 73
     * @param \ArrayObject $options Options.
73 74
     * @return void
74 75
     */
75 -
    public function afterSave(Event $event, EntityInterface $entity, ArrayObject $options)
76 +
    public function afterSave(EventInterface $event, EntityInterface $entity, ArrayObject $options)
76 77
    {
77 78
        $pk = $this->_table->getPrimaryKey();
79 +
        if (is_array($pk)) {
80 +
            throw new RuntimeException('Composite primary keys are not supported.');
81 +
        }
78 82
        $entity->set($pk, $this->obfuscate($entity->{$pk}));
79 83
        $entity->setDirty($pk, false);
80 84
    }
@@ -82,13 +86,13 @@
Loading
82 86
    /**
83 87
     * Callback to set the `obfuscated` finder on all associations.
84 88
     *
85 -
     * @param \Cake\ORM\Behavior\Event $event Event.
89 +
     * @param \Cake\Event\EventInterface $event EventInterface.
86 90
     * @param \Cake\ORM\Query $query Query.
87 91
     * @param \ArrayObject $options Options.
88 92
     * @param bool $primary True if this is the primary table.
89 93
     * @return void
90 94
     */
91 -
    public function beforeFind(Event $event, Query $query, ArrayObject $options, $primary)
95 +
    public function beforeFind(EventInterface $event, Query $query, ArrayObject $options, bool $primary)
92 96
    {
93 97
        if (empty($options['obfuscate']) || !$primary) {
94 98
            return;
@@ -96,8 +100,12 @@
Loading
96 100
97 101
        $query->traverseExpressions(function ($expression) {
98 102
            $pk = $this->_table->getPrimaryKey();
103 +
            if (is_array($pk)) {
104 +
                throw new RuntimeException('Composite primary keys are not supported.');
105 +
            }
106 +
99 107
            if (
100 -
                method_exists($expression, 'getField')
108 +
                $expression instanceof ComparisonExpression
101 109
                && in_array($expression->getField(), [$pk, $this->_table->aliasField($pk)])
102 110
            ) {
103 111
                $expression->setValue($this->elucidate($expression->getValue()));
@@ -151,10 +159,10 @@
Loading
151 159
    /**
152 160
     * Proxy to the obfuscating strategy's `obfuscate()`.
153 161
     *
154 -
     * @param string $str String to obfuscate.
162 +
     * @param string|int $str String to obfuscate.
155 163
     * @return string
156 164
     */
157 -
    public function obfuscate($str)
165 +
    public function obfuscate($str): string
158 166
    {
159 167
        return $this->strategy()->obfuscate($str);
160 168
    }
@@ -162,10 +170,10 @@
Loading
162 170
    /**
163 171
     * Proxy to the obfuscating strategy's `elucidate()`.
164 172
     *
165 -
     * @param string $str String to elucidate.
166 -
     * @return string
173 +
     * @param int|string $str String to elucidate.
174 +
     * @return int
167 175
     */
168 -
    public function elucidate($str)
176 +
    public function elucidate($str): int
169 177
    {
170 178
        return $this->strategy()->elucidate($str);
171 179
    }
@@ -173,9 +181,9 @@
Loading
173 181
    /**
174 182
     * Get the configured strategy.
175 183
     *
176 -
     * @return \Muffin\Obfuscate\Model\Behavior\ObfuscateStrategy\StrategyInterface
184 +
     * @return \Muffin\Obfuscate\Model\Behavior\Strategy\StrategyInterface
177 185
     */
178 -
    public function strategy()
186 +
    public function strategy(): StrategyInterface
179 187
    {
180 188
        return $this->getConfig('strategy');
181 189
    }

@@ -1,39 +1,22 @@
Loading
1 1
<?php
2 +
declare(strict_types=1);
3 +
2 4
namespace Muffin\Obfuscate\Model\Behavior\Strategy;
3 5
4 6
use Cake\Core\Configure;
5 7
use Hashids\Hashids;
6 8
7 9
/**
8 -
 * Class DefaultStrategy
9 -
 *
10 +
 * Class HashidStrategy
10 11
 */
11 12
class HashidStrategy implements StrategyInterface
12 13
{
13 -
14 -
    protected $_hashid;
15 -
16 -
    /**
17 -
     * Random alpha-numeric set where each character must only be
18 -
     * used exactly once.
19 -
     *
20 -
     * @var string
21 -
     */
22 -
    protected $_salt;
23 -
24 14
    /**
25 -
     * The minimum hash length.
15 +
     * Obfuscator.
26 16
     *
27 -
     * @var int
17 +
     * @var \Hashids\Hashids
28 18
     */
29 -
    protected $_minLength;
30 -
31 -
    /**
32 -
     * Custom alphabet to use.
33 -
     *
34 -
     * @var string
35 -
     */
36 -
    protected $_alphabet;
19 +
    protected $_hashid;
37 20
38 21
    /**
39 22
     * Constructor.
@@ -43,7 +26,7 @@
Loading
43 26
     * @param string $alphabet Custom alphabet to use.
44 27
     * @throws \Exception
45 28
     */
46 -
    public function __construct($salt = null, $minLength = 0, $alphabet = null)
29 +
    public function __construct(?string $salt = null, int $minLength = 0, ?string $alphabet = null)
47 30
    {
48 31
        if ($salt === null) {
49 32
            $salt = Configure::read('Obfuscate.salt');
@@ -51,9 +34,6 @@
Loading
51 34
        if (empty($salt)) {
52 35
            throw new \Exception('Missing salt for Hashid strategy');
53 36
        }
54 -
        $this->_salt = $salt;
55 -
        $this->_minLength = $minLength;
56 -
        $this->_alphabet = $alphabet;
57 37
58 38
        if ($alphabet === null) {
59 39
            $this->_hashid = new Hashids($salt, $minLength);
@@ -63,24 +43,18 @@
Loading
63 43
    }
64 44
65 45
    /**
66 -
     * {@inheritdoc}
67 -
     *
68 -
     * @param string $str String to obfuscate.
69 -
     * @return string
46 +
     * @inheritDoc
70 47
     */
71 -
    public function obfuscate($str)
48 +
    public function obfuscate($str): string
72 49
    {
73 -
        return $this->_hashid->encode($str);
50 +
        return $this->_hashid->encode((string)$str);
74 51
    }
75 52
76 53
    /**
77 -
     * {@inheritdoc}
78 -
     *
79 -
     * @param string $str String to elucidate.
80 -
     * @return string
54 +
     * @inheritDoc
81 55
     */
82 -
    public function elucidate($str)
56 +
    public function elucidate($str): int
83 57
    {
84 -
        return current($this->_hashid->decode($str));
58 +
        return current($this->_hashid->decode((string)$str));
85 59
    }
86 60
}
Files Complexity Coverage
src/Model/Behavior 39 93.55%
Project Totals (5 files) 39 93.55%

No yaml found.

Create your codecov.yml to customize your Codecov experience

Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading