Passed
Push — master ( 7ae7c9...2de92c )
by Russell
12:43
created

VerifiableService::getExtra()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
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
 * @todo Write a __call() method that sets nodes to the backend once, rather than in each backend method call
23
 * @see https://github.com/chainpoint/chainpoint-node/wiki/Chainpoint-Node-API:-How-to-Create-a-Chainpoint-Proof
24
 */
25
class VerifiableService
26
{
27
    use Injectable;
28
    use Configurable;
29
30
    /**
31
     * @var BackendProvider
32
     */
33
    protected $backend;
34
35
    /**
36
     *
37
     * @var array
38
     */
39
    protected $extra = [];
40
41
    /**
42
     * @return void
43
     * @throws VerifiableBackendException
44
     */
45
    public function __construct()
46
    {
47
        $this->setBackend();
48
    }
49
50
    /**
51
     * Write a hash of data as per the "verifiable_fields" config static on each
52
     * {@link DataObject}.
53
     *
54
     * @param  array $data
55
     * @return mixed The result of this call to the backend.
56
     */
57
    public function write(array $data)
58
    {
59
        // TODO: Is there a better way of doing this?
60
        $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

60
        $this->backend->/** @scrutinizer ignore-call */ 
61
                        setDiscoveredNodes($this->getExtra());
Loading history...
61
62
        return $this->backend->writeHash([$this->hash($data)]);
63
    }
64
65
    /**
66
     * Fetch a chainpoint proof for the passed $uuid.
67
     *
68
     * @param  string $uuid
69
     * @return string The JSON-LD chainpoint proof.
70
     */
71
    public function read(string $uuid) : string
72
    {
73
        // TODO: Is there a better way of doing this?
74
        $this->backend->setDiscoveredNodes($this->getExtra());
75
76
        return $this->backend->getProof($uuid);
77
    }
78
79
    /**
80
     * Verify the given JSON-LD chainpoint proof against the backend.
81
     *
82
     * @param  string $proof A JSON-LD chainpoint proof.
83
     * @return mixed
84
     */
85
    public function verify(string $proof)
86
    {
87
        // TODO: Is there a better way of doing this?
88
        $this->backend->setDiscoveredNodes($this->getExtra());
89
90
        return $this->backend->verifyProof($proof);
91
    }
92
93
    /**
94
     * @param  array $extra
95
     * @return VerifiableService
96
     */
97
    public function setExtra(array $extra = [])
98
    {
99
        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...
100
            $this->backend->setDiscoveredNodes();
101
            $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

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