Subversion Repositories oidplus

Rev

Rev 360 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
511 daniel-mar 5
 * Copyright 2019 - 2021 Daniel Marschall, ViaThinkSoft
2 daniel-mar 6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
511 daniel-mar 20
if (!defined('INSIDE_OIDPLUS')) die();
21
 
227 daniel-mar 22
class OIDplusOid extends OIDplusObject {
23
        private $oid;
24
 
2 daniel-mar 25
        public function __construct($oid) {
12 daniel-mar 26
                $bak_oid = $oid;
27
 
28
                $oid = sanitizeOID($oid, 'auto');
29
                if ($oid === false) {
360 daniel-mar 30
                        throw new OIDplusException(_L('Invalid OID %1',$bak_oid));
12 daniel-mar 31
                }
32
 
33
                if (($oid != '') && (!oid_valid_dotnotation($oid, false, true, 0))) {
34
                        // avoid OIDs like 3.0
360 daniel-mar 35
                        throw new OIDplusException(_L('Invalid OID %1',$bak_oid));
12 daniel-mar 36
                }
37
 
2 daniel-mar 38
                $this->oid = $oid;
39
        }
40
 
41
        public static function parse($node_id) {
42
                @list($namespace, $oid) = explode(':', $node_id, 2);
43
                if ($namespace !== 'oid') return false;
44
                return new self($oid);
45
        }
46
 
47
        public static function objectTypeTitle() {
360 daniel-mar 48
                return _L('Object Identifier (OID)');
2 daniel-mar 49
        }
50
 
51
        public static function objectTypeTitleShort() {
360 daniel-mar 52
                return _L('OID');
2 daniel-mar 53
        }
54
 
55
        public static function ns() {
56
                return 'oid';
57
        }
58
 
59
        public static function root() {
60
                return 'oid:';
61
        }
62
 
63
        public function isRoot() {
64
                return $this->oid == '';
65
        }
66
 
247 daniel-mar 67
        public function nodeId($with_ns=true) {
68
                return $with_ns ? 'oid:'.$this->oid : $this->oid;
2 daniel-mar 69
        }
70
 
71
        public function addString($str) {
72
                if (!$this->isRoot()) {
360 daniel-mar 73
                        if (strpos($str,'.') !== false) throw new OIDplusException(_L('Please only submit one arc (not an absolute OID or multiple arcs).'));
2 daniel-mar 74
                }
196 daniel-mar 75
 
199 daniel-mar 76
                return $this->appendArcs($str)->nodeId();
2 daniel-mar 77
        }
78
 
79
        public function crudShowId(OIDplusObject $parent) {
80
                return $this->deltaDotNotation($parent);
81
        }
82
 
83
        public function crudInsertPrefix() {
84
                return '';
85
        }
86
 
87
        public function jsTreeNodeName(OIDplusObject $parent = null) {
88
                if ($parent == null) return $this->objectTypeTitle();
89
                return $this->viewGetArcAsn1s($parent);
90
        }
91
 
92
        public function defaultTitle() {
360 daniel-mar 93
                return _L('OID %1',$this->oid);
2 daniel-mar 94
        }
95
 
16 daniel-mar 96
        public function isLeafNode() {
97
                return false;
98
        }
99
 
34 daniel-mar 100
        public function getContentPage(&$title, &$content, &$icon) {
55 daniel-mar 101
                $icon = file_exists(__DIR__.'/icon_big.png') ? 'plugins/objectTypes/'.basename(__DIR__).'/icon_big.png' : '';
102
 
2 daniel-mar 103
                if ($this->isRoot()) {
104
                        $title = OIDplusOid::objectTypeTitle();
105
 
261 daniel-mar 106
                        $res = OIDplus::db()->query("select id from ###objects where parent = ?", array(self::root()));
236 daniel-mar 107
                        if ($res->num_rows() > 0) {
360 daniel-mar 108
                                $content = _L('Please select an OID in the tree view at the left to show its contents.');
2 daniel-mar 109
                        } else {
360 daniel-mar 110
                                $content = _L('Currently, no OID is registered in the system.');
2 daniel-mar 111
                        }
112
 
16 daniel-mar 113
                        if (!$this->isLeafNode()) {
114
                                if (OIDplus::authUtils()::isAdminLoggedIn()) {
360 daniel-mar 115
                                        $content .= '<h2>'._L('Manage your root OIDs').'</h2>';
16 daniel-mar 116
                                } else {
360 daniel-mar 117
                                        $content .= '<h2>'._L('Root OIDs').'</h2>';
16 daniel-mar 118
                                }
119
                                $content .= '%%CRUD%%';
2 daniel-mar 120
                        }
121
                } else {
192 daniel-mar 122
                        $title = $this->getTitle();
123
 
360 daniel-mar 124
                        $content = '<h2>'._L('Technical information').'</h2>'.$this->oidInformation().
125
                                   '<h2>'._L('Description').'</h2>%%DESC%%'.
126
                                   '<h2>'._L('Registration Authority').'</h2>%%RA_INFO%%';
2 daniel-mar 127
 
16 daniel-mar 128
                        if (!$this->isLeafNode()) {
129
                                if ($this->userHasWriteRights()) {
360 daniel-mar 130
                                        $content .= '<h2>'._L('Create or change subsequent objects').'</h2>';
16 daniel-mar 131
                                } else {
360 daniel-mar 132
                                        $content .= '<h2>'._L('Subsequent objects').'</h2>';
16 daniel-mar 133
                                }
134
                                $content .= '%%CRUD%%';
2 daniel-mar 135
                        }
136
                }
137
        }
138
 
139
        # ---
140
 
197 daniel-mar 141
        public function isWeid($allow_root) {
61 daniel-mar 142
                $weid = WeidOidConverter::oid2weid($this->getDotNotation());
197 daniel-mar 143
                if (!$allow_root && ($weid === 'weid:4')) return false;
196 daniel-mar 144
                return $weid !== false;
2 daniel-mar 145
        }
146
 
196 daniel-mar 147
        public function weidArc() {
148
                $weid = WeidOidConverter::oid2weid($this->getDotNotation());
149
                if ($weid === false) return false;
197 daniel-mar 150
                list($ns,$weid) = explode(':', $weid, 2);
196 daniel-mar 151
                $x = explode('-', $weid);
197 daniel-mar 152
                if (count($x) < 2) return ''; // WEID root arc. Has no name
196 daniel-mar 153
                return $x[count($x)-2];
154
        }
155
 
156
        public function getWeidNotation($withAbbr=true) {
157
                $weid = WeidOidConverter::oid2weid($this->getDotNotation());
158
                if ($withAbbr) {
159
                        list($ns,$weid) = explode(':', $weid);
160
                        $weid_arcs = explode('-', $weid);
161
                        foreach ($weid_arcs as $i => &$weid) {
162
                                if ($i == count($weid_arcs)-1) {
360 daniel-mar 163
                                        $weid = '<abbr title="'._L('weLuhn check digit').'">'.$weid.'</abbr>';
196 daniel-mar 164
                                } else {
165
                                        $oid_arcs = explode('.',$this->oid);
166
                                        $weid_num = $oid_arcs[(count($oid_arcs)-1)-(count($weid_arcs)-1)+($i+1)];
167
                                        if ($weid_num != $weid) {
360 daniel-mar 168
                                                $weid = '<abbr title="'._L('Numeric value').': '.$weid_num.'">'.$weid.'</abbr>';
196 daniel-mar 169
                                        }
170
                                }
171
                        }
360 daniel-mar 172
                        $weid = '<abbr title="'._L('Root arc').': 1.3.6.1.4.1.37553.8">' . $ns . '</abbr>:' . implode('-',$weid_arcs);
196 daniel-mar 173
                }
174
                return $weid;
175
        }
176
 
177
        private function oidInformation() {
178
                $out = array();
360 daniel-mar 179
                $out[] = _L('Dot notation').': <code>' . $this->getDotNotation() . '</code>';
180
                $out[] = _L('ASN.1 notation').': <code>' . $this->getAsn1Notation(true) . '</code>';
181
                $out[] = _L('OID-IRI notation').': <code>' . $this->getIriNotation(true) . '</code>';
197 daniel-mar 182
                if ($this->isWeid(true)) {
360 daniel-mar 183
                        $out[] = _L('WEID notation').': <code>' . $this->getWeidNotation() . '</code>';
196 daniel-mar 184
                }
185
                return '<p>'.implode('<br>',$out).'</p>';
186
        }
187
 
2 daniel-mar 188
        public function __clone() {
189
                return new self($this->oid);
190
        }
191
 
192
        public function appendArcs(String $arcs) {
193
                $out = clone $this;
5 daniel-mar 194
 
2 daniel-mar 195
                if ($out->isRoot()) {
196
                        $out->oid .= $arcs;
197
                } else {
198
                        $out->oid .= '.' . $arcs;
199
                }
5 daniel-mar 200
 
13 daniel-mar 201
                $bak_oid = $out->oid;
5 daniel-mar 202
                $out->oid = sanitizeOID($out->oid);
360 daniel-mar 203
                if ($out->oid === false) throw new OIDplusException(_L('%1 is not a valid OID!',$bak_oid));
277 daniel-mar 204
 
261 daniel-mar 205
                if (strlen($out->oid) > OIDplus::baseConfig()->getValue('LIMITS_MAX_ID_LENGTH')-strlen('oid:')) {
360 daniel-mar 206
                        $maxlen = OIDplus::baseConfig()->getValue('LIMITS_MAX_ID_LENGTH')-strlen('oid:');
207
                        throw new OIDplusException(_L('The resulting OID "%1" is too long (max allowed length: %2).',$out->oid,$maxlen));
247 daniel-mar 208
                }
277 daniel-mar 209
 
247 daniel-mar 210
                $depth = 0;
211
                foreach (explode('.',$out->oid) as $arc) {
261 daniel-mar 212
                        if (strlen($arc) > OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_ARC_SIZE')) {
360 daniel-mar 213
                                $maxlen = OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_ARC_SIZE');
214
                                throw new OIDplusException(_L('Arc "%1" is too long and therefore cannot be appended to the OID "%2" (max allowed arc size is "%3")',$arc,$this->oid,$maxlen));
247 daniel-mar 215
                        }
216
                        $depth++;
217
                }
261 daniel-mar 218
                if ($depth > OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_DEPTH')) {
360 daniel-mar 219
                        $maxdepth = OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_DEPTH');
220
                        throw new OIDplusException(_L('OID %1 has too many arcs (current depth %2, max depth %3)',$out->oid,$depth,$maxdepth));
247 daniel-mar 221
                }
5 daniel-mar 222
 
2 daniel-mar 223
                return $out;
224
        }
225
 
226
        public function deltaDotNotation(OIDplusOid $parent) {
227
                if (!$parent->isRoot()) {
228
                        if (substr($this->oid, 0, strlen($parent->oid)+1) == $parent->oid.'.') {
229
                                return substr($this->oid, strlen($parent->oid)+1);
230
                        } else {
231
                                return false;
232
                        }
233
                } else {
234
                        return $this->oid;
235
                }
236
        }
237
 
238
        public function viewGetArcAsn1s(OIDplusOid $parent=null, $separator = ' | ') {
239
                $asn_ids = array();
240
 
241
                if (is_null($parent)) $parent = OIDplusOid::parse('oid:');
242
 
243
                $part = $this->deltaDotNotation($parent);
244
 
245
                if (strpos($part, '.') === false) {
261 daniel-mar 246
                        $res2 = OIDplus::db()->query("select name from ###asn1id where oid = ? order by lfd", array("oid:".$this->oid));
236 daniel-mar 247
                        while ($row2 = $res2->fetch_array()) {
2 daniel-mar 248
                                $asn_ids[] = $row2['name'].'('.$part.')';
249
                        }
250
                }
251
 
252
                if (count($asn_ids) == 0) $asn_ids = array($part);
239 daniel-mar 253
                return implode($separator, $asn_ids);
2 daniel-mar 254
        }
255
 
256
        public function getAsn1Notation($withAbbr=true) {
257
                $asn1_notation = '';
258
                $arcs = explode('.', $this->oid);
259
 
260
                foreach ($arcs as $arc) {
261 daniel-mar 261
                        $res = OIDplus::db()->query("select name, standardized from ###asn1id where oid = ? order by lfd", array('oid:'.implode('.',$arcs)));
2 daniel-mar 262
 
263
                        $names = array();
236 daniel-mar 264
                        while ($row = $res->fetch_array()) {
51 daniel-mar 265
                                $names[] = $row['name']."(".end($arcs).")";
266
                                if ($row['standardized']) {
267
                                        $names[] = $row['name'];
268
                                }
2 daniel-mar 269
                        }
270
 
52 daniel-mar 271
                        $numeric = array_pop($arcs);
2 daniel-mar 272
                        if (count($names) > 1) {
273
                                $first_name = array_shift($names);
360 daniel-mar 274
                                $abbr = _L('Other identifiers').':&#10;      '.implode('&#10;      ',$names);
2 daniel-mar 275
                                if ($withAbbr) {
51 daniel-mar 276
                                        $asn1_notation = '<abbr title="'.$abbr.'">'.$first_name.'</abbr> '.$asn1_notation;
2 daniel-mar 277
                                } else {
51 daniel-mar 278
                                        $asn1_notation = $first_name.' '.$asn1_notation;
2 daniel-mar 279
                                }
280
                        } else if (count($names) == 1) {
51 daniel-mar 281
                                $asn1_notation = array_shift($names).' '.$asn1_notation;
2 daniel-mar 282
                        } else {
52 daniel-mar 283
                                $asn1_notation = $numeric.' '.$asn1_notation;
2 daniel-mar 284
                        }
285
                }
286
 
339 daniel-mar 287
                return "{ $asn1_notation }";
2 daniel-mar 288
        }
289
 
290
        public function getIriNotation($withAbbr=true) {
291
                $iri_notation = '';
292
                $arcs = explode('.', $this->oid);
293
 
294
                foreach ($arcs as $arc) {
261 daniel-mar 295
                        $res = OIDplus::db()->query("select name, longarc from ###iri where oid = ? order by lfd", array('oid:'.implode('.',$arcs)));
2 daniel-mar 296
 
297
                        $is_longarc = false;
298
                        $names = array();
236 daniel-mar 299
                        while ($row = $res->fetch_array()) {
2 daniel-mar 300
                                $is_longarc = $row['longarc'];
301
                                $names[] = $row['name'];
51 daniel-mar 302
 
303
                                if ($is_longarc) {
304
                                        $names[] = 'Joint-ISO-ITU-T/'.$row['name']; // Long arcs can only be inside root OID 2
305
                                }
2 daniel-mar 306
                        }
307
 
308
                        $names[] = array_pop($arcs);
309
                        if (count($names) > 2) {
310
                                $first_name = array_shift($names);
52 daniel-mar 311
                                $numeric = array_pop($names);
360 daniel-mar 312
                                $abbr = _L('Other identifiers').':&#10;      '.implode('&#10;      ',$names).'&#10;'._L('Numeric value').': '.$numeric;
2 daniel-mar 313
                                $iri_notation = $withAbbr ? '<abbr title="'.$abbr.'">'.$first_name.'</abbr>/'.$iri_notation : $first_name.'/'.$iri_notation;
314
                        } else if (count($names) > 1) {
315
                                $first_name = array_shift($names);
360 daniel-mar 316
                                $abbr = _L('Numeric value').': '.array_shift($names);
2 daniel-mar 317
                                $iri_notation = $withAbbr ? '<abbr title="'.$abbr.'">'.$first_name.'</abbr>/'.$iri_notation : $first_name.'/'.$iri_notation;
318
                        } else if (count($names) == 1) {
319
                                $iri_notation = array_shift($names) . '/' . $iri_notation;
320
                        }
321
 
339 daniel-mar 322
                        if ($is_longarc) break; // we don't write /ITU-T/ at the beginning, when /ITU-T/xyz is a long arc
2 daniel-mar 323
                }
324
                $iri_notation = '/' . substr($iri_notation, 0, strlen($iri_notation)-1);
325
 
326
                return $iri_notation;
327
        }
328
 
329
        public function getDotNotation() {
330
                return $this->oid;
331
        }
332
 
13 daniel-mar 333
        public function isWellKnown() {
261 daniel-mar 334
                $res = OIDplus::db()->query("select oid from ###asn1id where oid = ? and well_known = ?", array("oid:".$this->oid,true));
236 daniel-mar 335
                if ($res->num_rows() > 0) return true;
13 daniel-mar 336
 
261 daniel-mar 337
                $res = OIDplus::db()->query("select oid from ###iri where oid = ? and well_known = ?", array("oid:".$this->oid,true));
236 daniel-mar 338
                if ($res->num_rows() > 0) return true;
13 daniel-mar 339
 
340
                return false;
341
        }
342
 
147 daniel-mar 343
        public function replaceAsn1Ids($demandedASN1s=array(), $simulate=false) {
13 daniel-mar 344
                if ($this->isWellKnown()) {
360 daniel-mar 345
                        throw new OIDplusException(_L('OID "%1" is a "well-known" OID. Its identifiers cannot be changed.',$this->oid));
13 daniel-mar 346
                }
347
 
2 daniel-mar 348
                // First do a few checks
349
                foreach ($demandedASN1s as &$asn1) {
350
                        $asn1 = trim($asn1);
351
 
261 daniel-mar 352
                        if (strlen($asn1) > OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_ASN1_ID_LEN')) {
360 daniel-mar 353
                                $maxlen = OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_ASN1_ID_LEN');
354
                                throw new OIDplusException(_L('ASN.1 alphanumeric identifier "%1" is too long (max allowed length %2)',$asn1,$maxlen));
247 daniel-mar 355
                        }
356
 
13 daniel-mar 357
                        // Validate identifier
360 daniel-mar 358
                        if (!oid_id_is_valid($asn1)) throw new OIDplusException(_L('"%1" is not a valid ASN.1 identifier!',$asn1));
13 daniel-mar 359
 
2 daniel-mar 360
                        // Check if the (real) parent has any conflict
201 daniel-mar 361
                        // Unlike IRI identifiers, ASN.1 identifiers may be used multiple times (not recommended), except if one of them is standardized
261 daniel-mar 362
                        $res = OIDplus::db()->query("select oid from ###asn1id where name = ? and standardized = ?", array($asn1,true));
236 daniel-mar 363
                        while ($row = $res->fetch_array()) {
2 daniel-mar 364
                                $check_oid = OIDplusOid::parse($row['oid'])->oid;
365
                                if ((oid_up($check_oid) === oid_up($this->oid)) && // same parent
366
                                   ($check_oid !== $this->oid))                    // different OID
367
                                {
360 daniel-mar 368
                                        throw new OIDplusException(_L('ASN.1 identifier "%1" is a standardized identifier belonging to OID %2',$asn1,$check_oid));
2 daniel-mar 369
                                }
370
                        }
371
                }
372
 
373
                // Now do the real replacement
147 daniel-mar 374
                if (!$simulate) {
261 daniel-mar 375
                        OIDplus::db()->query("delete from ###asn1id where oid = ?", array("oid:".$this->oid));
147 daniel-mar 376
                        foreach ($demandedASN1s as &$asn1) {
261 daniel-mar 377
                                OIDplus::db()->query("insert into ###asn1id (oid, name) values (?, ?)", array("oid:".$this->oid, $asn1));
2 daniel-mar 378
                        }
379
                }
380
        }
381
 
147 daniel-mar 382
        public function replaceIris($demandedIris=array(), $simulate=false) {
13 daniel-mar 383
                if ($this->isWellKnown()) {
360 daniel-mar 384
                        throw new OIDplusException(_L('OID "%1" is a "well-known" OID. Its identifiers cannot be changed.',$this->oid));
13 daniel-mar 385
                }
386
 
2 daniel-mar 387
                // First do a few checks
388
                foreach ($demandedIris as &$iri) {
389
                        $iri = trim($iri);
390
 
261 daniel-mar 391
                        if (strlen($iri) > OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_UNICODE_LABEL_LEN')) {
360 daniel-mar 392
                                $maxlen = OIDplus::baseConfig()->getValue('LIMITS_MAX_OID_UNICODE_LABEL_LEN');
393
                                throw new OIDplusException(_L('Unicode label "%1" is too long (max allowed length %2)',$iri,$maxlen));
247 daniel-mar 394
                        }
395
 
13 daniel-mar 396
                        // Validate identifier
360 daniel-mar 397
                        if (!iri_arc_valid($iri, false)) throw new OIDplusException(_L('"%1" is not a valid IRI!',$iri));
13 daniel-mar 398
 
2 daniel-mar 399
                        // Check if the (real) parent has any conflict
261 daniel-mar 400
                        $res = OIDplus::db()->query("select oid from ###iri where name = ?", array($iri));
236 daniel-mar 401
                        while ($row = $res->fetch_array()) {
2 daniel-mar 402
                                $check_oid = OIDplusOid::parse($row['oid'])->oid;
403
                                if ((oid_up($check_oid) === oid_up($this->oid)) && // same parent
404
                                   ($check_oid !== $this->oid))                    // different OID
405
                                {
360 daniel-mar 406
                                        throw new OIDplusException(_L('IRI "%1" is already used by another OID (%2)',$iri,$check_oid));
2 daniel-mar 407
                                }
408
                        }
409
                }
410
 
411
                // Now do the real replacement
147 daniel-mar 412
                if (!$simulate) {
261 daniel-mar 413
                        OIDplus::db()->query("delete from ###iri where oid = ?", array("oid:".$this->oid));
147 daniel-mar 414
                        foreach ($demandedIris as &$iri) {
261 daniel-mar 415
                                OIDplus::db()->query("insert into ###iri (oid, name) values (?, ?)", array("oid:".$this->oid, $iri));
2 daniel-mar 416
                        }
417
                }
418
        }
12 daniel-mar 419
 
20 daniel-mar 420
        public function one_up() {
421
                return self::parse(self::ns().':'.oid_up($this->oid));
12 daniel-mar 422
        }
423
 
424
        public function distance($to) {
425
                if (!is_object($to)) $to = OIDplusObject::parse($to);
28 daniel-mar 426
                if (!($to instanceof $this)) return false;
12 daniel-mar 427
                return oid_distance($to->oid, $this->oid);
428
        }
192 daniel-mar 429
 
193 daniel-mar 430
        public function getAltIds() {
431
                if ($this->isRoot()) return array();
432
                $ids = parent::getAltIds();
433
                if ($uuid = oid_to_uuid($this->oid)) {
360 daniel-mar 434
                        $ids[] = new OIDplusAltId('guid', $uuid, _L('GUID representation of this OID'));
193 daniel-mar 435
                }
360 daniel-mar 436
                $ids[] = new OIDplusAltId('guid', gen_uuid_md5_namebased(UUID_NAMEBASED_NS_OID, $this->oid), _L('Name based version 3 / MD5 UUID with namespace %1','UUID_NAMEBASED_NS_OID'));
437
                $ids[] = new OIDplusAltId('guid', gen_uuid_sha1_namebased(UUID_NAMEBASED_NS_OID, $this->oid), _L('Name based version 5 / SHA1 UUID with namespace %1','UUID_NAMEBASED_NS_OID'));
193 daniel-mar 438
                return $ids;
192 daniel-mar 439
        }
360 daniel-mar 440
}