Completed
Branch Version3 (f01875)
by Sam
05:18
created

NSEC3::setUnsignedDelegationsCovered()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Badcow DNS Library.
7
 *
8
 * (c) Samuel Williams <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Badcow\DNS\Rdata;
15
16
use Badcow\DNS\Parser\Tokens;
17
use Badcow\DNS\Validator;
18
19
/**
20
 * {@link https://tools.ietf.org/html/rfc5155}.
21
 */
22
class NSEC3 implements RdataInterface
23
{
24
    use RdataTrait;
25
26
    const TYPE = 'NSEC3';
27
    const TYPE_CODE = 50;
28
29
    /**
30
     * @var int
31
     */
32
    private $hashAlgorithm;
33
34
    /**
35
     * @var bool
36
     */
37
    private $unsignedDelegationsCovered = false;
38
39
    /**
40
     * @var int
41
     */
42
    private $iterations;
43
44
    /**
45
     * @var string Binary encoded string
46
     */
47
    private $salt;
48
49
    /**
50
     * @var string Binary encoded hash
51
     */
52
    private $nextHashedOwnerName;
53
54
    /**
55
     * @var array
56
     */
57
    private $types = [];
58
59
    /**
60
     * @var \Base2n
61
     */
62
    private static $base32;
63
64 4
    private static function base32(): \Base2n
65
    {
66 4
        if (!isset(self::$base32)) {
67 1
            self::$base32 = new \Base2n(5, '0123456789abcdefghijklmnopqrstuv', false, true, true);
68
        }
69
70 4
        return self::$base32;
71
    }
72
73
    public function getHashAlgorithm(): int
74
    {
75
        return $this->hashAlgorithm;
76
    }
77
78 4
    public function setHashAlgorithm(int $hashAlgorithm): void
79
    {
80 4
        if (!Validator::isUnsignedInteger($hashAlgorithm, 8)) {
81
            throw new \InvalidArgumentException('Hash algorithm must be 8-bit integer.');
82
        }
83 4
        $this->hashAlgorithm = $hashAlgorithm;
84 4
    }
85
86
    public function isUnsignedDelegationsCovered(): bool
87
    {
88
        return $this->unsignedDelegationsCovered;
89
    }
90
91 4
    public function setUnsignedDelegationsCovered(bool $unsignedDelegationsCovered): void
92
    {
93 4
        $this->unsignedDelegationsCovered = $unsignedDelegationsCovered;
94 4
    }
95
96
    public function getIterations(): int
97
    {
98
        return $this->iterations;
99
    }
100
101 4
    public function setIterations(int $iterations): void
102
    {
103 4
        if (!Validator::isUnsignedInteger($iterations, 16)) {
104
            throw new \InvalidArgumentException('Hash algorithm must be 16-bit integer.');
105
        }
106 4
        $this->iterations = $iterations;
107 4
    }
108
109
    /**
110
     * @return string Base16 string
111
     */
112 2
    public function getSalt(): string
113
    {
114 2
        return bin2hex($this->salt);
115
    }
116
117
    /**
118
     * @param string $salt Hexadecimal string
119
     */
120 4
    public function setSalt(string $salt): void
121
    {
122 4
        if (false === $bin = hex2bin($salt)) {
123
            throw new \InvalidArgumentException('Salt must be a hexadecimal string.');
124
        }
125 4
        $this->salt = $bin;
126 4
    }
127
128
    /**
129
     * @return string Base32 hashed string
130
     */
131 2
    public function getNextHashedOwnerName(): string
132
    {
133 2
        return self::base32encode($this->nextHashedOwnerName);
134
    }
135
136 4
    public function setNextHashedOwnerName(string $nextHashedOwnerName): void
137
    {
138 4
        if (!Validator::isBase32HexEncoded($nextHashedOwnerName)) {
139
            throw new \InvalidArgumentException('Next hashed owner name must be a base32 encoded string.');
140
        }
141
142 4
        $this->nextHashedOwnerName = self::base32decode($nextHashedOwnerName);
143 4
    }
144
145
    /**
146
     * @param string $type
147
     */
148 4
    public function addType(string $type): void
149
    {
150 4
        $this->types[] = $type;
151 4
    }
152
153
    /**
154
     * Clears the types from the RDATA.
155
     */
156
    public function clearTypes(): void
157
    {
158
        $this->types = [];
159
    }
160
161
    public function getTypes(): array
162
    {
163
        return $this->types;
164
    }
165
166
    /**
167
     * {@inheritdoc}
168
     */
169 2
    public function toText(): string
170
    {
171 2
        return sprintf('%d %d %d %s %s %s',
172 2
            $this->hashAlgorithm,
173 2
            (int) $this->unsignedDelegationsCovered,
174 2
            $this->iterations,
175 2
            $this->getSalt(),
176 2
            $this->getNextHashedOwnerName(),
177 2
            implode(Tokens::SPACE, $this->types)
178
        );
179
    }
180
181
    /**
182
     * {@inheritdoc}
183
     *
184
     * @throws UnsupportedTypeException
185
     */
186 1
    public function toWire(): string
187
    {
188 1
        $wire = pack('CCnC',
189 1
            $this->hashAlgorithm,
190 1
            (int) $this->unsignedDelegationsCovered,
191 1
            $this->iterations,
192 1
            strlen($this->salt)
193
        );
194 1
        $wire .= $this->salt;
195 1
        $wire .= chr(strlen($this->nextHashedOwnerName));
196 1
        $wire .= $this->nextHashedOwnerName;
197 1
        $wire .= NSEC::renderBitmap($this->types);
198
199 1
        return $wire;
200
    }
201
202
    /**
203
     * {@inheritdoc}
204
     *
205
     * @return NSEC3
206
     */
207 1
    public static function fromText(string $text): RdataInterface
208
    {
209 1
        $rdata = explode(Tokens::SPACE, $text);
210 1
        $nsec3 = new self();
211 1
        $nsec3->setHashAlgorithm((int) array_shift($rdata));
212 1
        $nsec3->setUnsignedDelegationsCovered((bool) array_shift($rdata));
213 1
        $nsec3->setIterations((int) array_shift($rdata));
214 1
        $nsec3->setSalt((string) array_shift($rdata));
215 1
        $nsec3->setNextHashedOwnerName((string) array_shift($rdata));
216 1
        array_map([$nsec3, 'addType'], $rdata);
217
218 1
        return $nsec3;
219
    }
220
221
    /**
222
     * {@inheritdoc}
223
     *
224
     * @return NSEC3
225
     *
226
     * @throws UnsupportedTypeException
227
     */
228 1
    public static function fromWire(string $rdata): RdataInterface
229
    {
230 1
        $offset = 0;
231 1
        $values = unpack('C<hashAlgo>/C<flags>/n<iterations>/C<saltLen>', $rdata, $offset);
232 1
        $offset += 5;
233 1
        $nsec3 = new self();
234 1
        $nsec3->setHashAlgorithm((int) $values['<hashAlgo>']);
235 1
        $nsec3->setUnsignedDelegationsCovered((bool) $values['<flags>']);
236 1
        $nsec3->setIterations((int) $values['<iterations>']);
237
238 1
        $saltLen = (int) $values['<saltLen>'];
239 1
        $salt = unpack('H*', substr($rdata, $offset, $saltLen))[1];
240 1
        $nsec3->setSalt($salt);
241 1
        $offset += $saltLen;
242
243 1
        $hashLen = ord(substr($rdata, $offset, 1));
244 1
        ++$offset;
245 1
        $hash = substr($rdata, $offset, $hashLen);
246 1
        $offset += $hashLen;
247 1
        $nsec3->setNextHashedOwnerName(self::base32encode($hash));
248
249 1
        $types = NSEC::parseBitmap($rdata, $offset);
250 1
        array_map([$nsec3, 'addType'], $types);
251
252 1
        return $nsec3;
253
    }
254
255 3
    public static function base32encode(string $data): string
256
    {
257 3
        return self::base32()->encode($data);
258
    }
259
260 4
    public static function base32decode(string $data): string
261
    {
262 4
        return self::base32()->decode($data);
263
    }
264
}
265