Passed
Push — master ( 2ce6bc...9c94e5 )
by Russell
11:27
created

VerifiableService::getVerificationStatus()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 16
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 13
nc 4
nop 1
dl 0
loc 16
rs 8.8571
c 0
b 0
f 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A VerifiableService::hash() 0 6 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\Job\BackendVerificationJob;
16
use Symbiote\QueuedJobs\Services\QueuedJobService;
17
use PhpTek\Verifiable\Backend\BackendProvider;
18
use SilverStripe\ORM\DataObject;
19
20
/**
21
 * Service class that works as an intermediary between any data model and the
22
 * currently selected Merkle Tree storage backend.
23
 *
24
 * @todo Handle rate-limiting by the Chainpoint network and by repeated access to this controller
25
 * @see https://github.com/chainpoint/chainpoint-node/wiki/Chainpoint-Node-API:-How-to-Create-a-Chainpoint-Proof
26
 */
27
class VerifiableService
28
{
29
    use Injectable;
30
    use Configurable;
31
32
    /**
33
     * @var BackendProvider
34
     */
35
    protected $backend;
36
37
    /**
38
     * @return void
39
     * @throws VerifiableBackendException
40
     */
41
    public function __construct()
42
    {
43
        $this->setBackend();
44
    }
45
46
    /**
47
     * Write a hash of data as per the "verifiable_fields" config static on each
48
     * {@link DataObject}.
49
     *
50
     * @param  array $data
51
     * @return mixed The result of this call to the backend.
52
     */
53
    public function write(array $data)
54
    {
55
        return $this->backend->writeHash([$this->hash($data)]);
56
    }
57
58
    /**
59
     * Fetch a chainpoint proof for the passed $hash.
60
     *
61
     * @param  string $hashId
62
     * @return string The JSON-LD chainpoint proof.
63
     */
64
    public function read(string $hashId) : string
65
    {
66
        return $this->backend->getProof($hashId);
67
    }
68
69
    /**
70
     * Verify the given JSON-LD chainpoint proof against the backend.
71
     *
72
     * @param  string $proof A JSON-LD chainpoint proof.
73
     * @return mixed
74
     */
75
    public function verify(string $proof)
76
    {
77
        return $this->backend->verifyProof($proof);
78
    }
79
80
    /**
81
     * Set, instantiate and return a new Merkle Tree storage backend.
82
     *
83
     * @param  BackendProvider $provider Optional manually pased backend.
84
     * @return VerifiableService
85
     * @throws VerifiableBackendException
86
     */
87
    public function setBackend(BackendProvider $provider = null)
88
    {
89
        if ($provider) {
90
            $this->backend = $provider;
91
92
            return $this;
93
        }
94
95
        $namedBackend = $this->config()->get('backend');
96
        $backends = ClassInfo::implementorsOf(BackendProvider::class);
97
98
        foreach ($backends as $backend) {
99
            if (singleton($backend)->name() === $namedBackend) {
100
                $this->backend = Injector::inst()->create($backend);
101
102
                return $this;
103
            }
104
        }
105
106
        // Cannt continue without a legit backend
107
        throw new VerifiableBackendException('No backend found');
108
    }
109
110
    /**
111
     * @return BackendProvider
112
     */
113
    public function getBackend()
114
    {
115
        return $this->backend;
116
    }
117
118
    /**
119
     * Hashes the data passed into the $hash param.
120
     *
121
     * @param  array $data An array of data who's values should be hashed.
122
     * @return string      The resulting hashed data.
123
     * @todo               Take user input in the form of a digital signature
124
     */
125
    public function hash(array $data) : string
126
    {
127
        $func = $this->backend->hashFunc();
128
        $text = json_encode($data); // Simply used to stringify arrays of arbitary depth
129
130
        return hash($func, $text);
131
    }
132
133
    /**
134
     * Setup a {@link QueuedJob} to ping a backend and update the passed dataobject's
135
     * "Proof" field when a chainpoint proof has been generated.
136
     *
137
     * @param  DataObject $model The {@link DataObject} model subclass with a "Proof" field
138
     * @return void
139
     */
140
    public function queueVerification(DataObject $model)
141
    {
142
        $job = new BackendVerificationJob();
143
        $job->setObject($model);
144
        // Ping the backend 1 hour hence
145
        $time = date('Y-m-d H:i:s', time() + 3600);
146
147
        singleton(QueuedJobService::class)->queueJob($job, $time);
148
    }
149
150
}
151