Passed
Push — master ( 576703...c5b98b )
by Russell
13:36
created

VerifiableService   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 152
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 152
rs 10
c 0
b 0
f 0
wmc 15

10 Methods

Rating   Name   Duplication   Size   Complexity  
A hash() 0 6 1
A __construct() 0 3 1
A getExtra() 0 3 1
A setBackend() 0 21 4
A write() 0 3 1
A read() 0 3 1
A call() 0 9 2
A getBackend() 0 3 1
A setExtra() 0 10 2
A verify() 0 3 1
1
<?php
2
3
/**
4
 * @author  Russell Michell 2018 <[email protected]>
5
 * @package silverstripe-verifiable
6
 */
7
8
namespace PhpTek\Verifiable\Verify;
9
10
use SilverStripe\Core\Injector\Injector;
11
use SilverStripe\Core\Injector\Injectable;
12
use SilverStripe\Core\Config\Configurable;
13
use SilverStripe\Core\ClassInfo;
14
use PhpTek\Verifiable\Exception\VerifiableBackendException;
15
use PhpTek\Verifiable\Backend\BackendProvider;
16
17
/**
18
 * Service class that works as an intermediary between any data model and the
19
 * currently selected Merkle Tree storage backend.
20
 *
21
 * @todo Handle rate-limiting by the Chainpoint network and by repeated access to this controller
22
 */
23
class VerifiableService
24
{
25
    use Injectable;
26
    use Configurable;
27
28
    /**
29
     * @var BackendProvider
30
     */
31
    protected $backend;
32
33
    /**
34
     *
35
     * @var array
36
     */
37
    protected $extra = [];
38
39
    /**
40
     * @return void
41
     * @throws VerifiableBackendException
42
     */
43
    public function __construct()
44
    {
45
        $this->setBackend();
46
    }
47
48
    /**
49
     * Wrapper around all backend methods.
50
     *
51
     * @param  string $method The name of the method to call
52
     * @param  mixed  $arg    The argument to pass to $method
53
     * @return mixed
54
     * @throws InvalidArgumentException
55
     */
56
    public function call($method, $arg)
57
    {
58
        if (!method_exists($this, $method)) {
59
            throw new \InvalidArgumentException("$method doesn't exist.");
60
        }
61
62
        $this->backend->setDiscoveredNodes($this->getExtra());
0 ignored issues
show
Bug introduced by
The method setDiscoveredNodes() does not exist on PhpTek\Verifiable\Backend\BackendProvider. It seems like you code against a sub-type of PhpTek\Verifiable\Backend\BackendProvider such as PhpTek\Verifiable\Backend\Chainpoint. ( Ignorable by Annotation )

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

62
        $this->backend->/** @scrutinizer ignore-call */ 
63
                        setDiscoveredNodes($this->getExtra());
Loading history...
63
64
        return $this->$method($arg);
65
    }
66
67
    /**
68
     * Write a hash of data as per the "verifiable_fields" config static on each
69
     * {@link DataObject}.
70
     *
71
     * @param  array $data
72
     * @return mixed The result of this call to the backend.
73
     */
74
    protected function write(array $data)
75
    {
76
        return $this->backend->writeHash([$this->hash($data)]);
77
    }
78
79
    /**
80
     * Fetch a chainpoint proof for the passed $uuid.
81
     *
82
     * @param  string $uuid
83
     * @return string The JSON-LD chainpoint proof.
84
     */
85
    protected function read(string $uuid) : string
86
    {
87
        return $this->backend->getProof($uuid);
88
    }
89
90
    /**
91
     * Verify the given JSON-LD chainpoint proof against the backend.
92
     *
93
     * @param  string $proof A JSON-LD chainpoint proof.
94
     * @return mixed
95
     */
96
    protected function verify(string $proof)
97
    {
98
        return $this->backend->verifyProof($proof);
99
    }
100
101
    /**
102
     * @param  array $extra
103
     * @return VerifiableService
104
     */
105
    public function setExtra(array $extra = [])
106
    {
107
        if (!$extra) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $extra of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
108
            $this->backend->setDiscoveredNodes();
109
            $this->extra = $this->backend->getDiscoveredNodes();
0 ignored issues
show
Bug introduced by
The method getDiscoveredNodes() does not exist on PhpTek\Verifiable\Backend\BackendProvider. It seems like you code against a sub-type of PhpTek\Verifiable\Backend\BackendProvider such as PhpTek\Verifiable\Backend\Chainpoint. ( Ignorable by Annotation )

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

109
            /** @scrutinizer ignore-call */ 
110
            $this->extra = $this->backend->getDiscoveredNodes();
Loading history...
110
        } else {
111
            $this->extra = $extra;
112
        }
113
114
        return $this;
115
    }
116
117
    /**
118
     * @return array
119
     */
120
    public function getExtra()
121
    {
122
        return $this->extra;
123
    }
124
125
    /**
126
     * Set, configure and return a new Merkle Tree storage backend.
127
     *
128
     * @param  BackendProvider   $provider Optional manually passed backend.
129
     * @return VerifiableService
130
     * @throws VerifiableBackendException
131
     */
132
    public function setBackend(BackendProvider $provider = null)
133
    {
134
        if ($provider) {
135
            $this->backend = $provider;
136
137
            return $this;
138
        }
139
140
        $namedBackend = $this->config()->get('backend');
141
        $backends = ClassInfo::implementorsOf(BackendProvider::class);
142
143
        foreach ($backends as $backend) {
144
            if (singleton($backend)->name() === $namedBackend) {
145
                $this->backend = Injector::inst()->create($backend);
146
147
                return $this;
148
            }
149
        }
150
151
        // Cannot continue without a legit backend
152
        throw new VerifiableBackendException('No backend found');
153
    }
154
155
    /**
156
     * @return BackendProvider
157
     */
158
    public function getBackend()
159
    {
160
        return $this->backend;
161
    }
162
163
    /**
164
     * Hashes the data passed into the $hash param.
165
     *
166
     * @param  array  $data An array of data who's values should be hashed.
167
     * @return string       The resulting hashed data.
168
     */
169
    public function hash(array $data) : string
170
    {
171
        $func = $this->backend->hashFunc();
172
        $text = json_encode($data); // json_encode() to stringify arrays of arbitary depth
173
174
        return hash($func, $text);
175
    }
176
177
}
178