Subversion Repositories oidplus

Rev

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

Rev Author Line No. Line
919 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
1086 daniel-mar 5
 * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
919 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
 
1050 daniel-mar 20
namespace ViaThinkSoft\OIDplus;
919 daniel-mar 21
 
1086 daniel-mar 22
// phpcs:disable PSR1.Files.SideEffects
23
\defined('INSIDE_OIDPLUS') or die;
24
// phpcs:enable PSR1.Files.SideEffects
25
 
919 daniel-mar 26
class OIDplusAid extends OIDplusObject {
27
        private $aid;
28
 
29
        public function __construct($aid) {
30
                // TODO: syntax checks
31
                $this->aid = $aid;
32
        }
33
 
34
        public static function parse($node_id) {
35
                @list($namespace, $aid) = explode(':', $node_id, 2);
36
                if ($namespace !== self::ns()) return false;
37
                return new self($aid);
38
        }
39
 
40
        public static function objectTypeTitle() {
959 daniel-mar 41
                return _L('Application Identifier (ISO/IEC 7816)');
919 daniel-mar 42
        }
43
 
44
        public static function objectTypeTitleShort() {
45
                return _L('AID');
46
        }
47
 
48
        public static function ns() {
49
                return 'aid';
50
        }
51
 
52
        public static function root() {
53
                return self::ns().':';
54
        }
55
 
56
        public function isRoot() {
57
                return $this->aid == '';
58
        }
59
 
60
        public function nodeId($with_ns=true) {
61
                return $with_ns ? self::root().$this->aid : $this->aid;
62
        }
63
 
64
        public function addString($str) {
65
                $m = array();
922 daniel-mar 66
 
67
                $str = str_replace(' ','',$str);
931 daniel-mar 68
                $str = str_replace(':','',$str);
922 daniel-mar 69
 
919 daniel-mar 70
                if (!preg_match('@^[0-9a-fA-F]+$@', $str, $m)) {
71
                        throw new OIDplusException(_L('AID part needs to be hexadecimal'));
72
                }
73
 
925 daniel-mar 74
                if (strlen($this->nodeId(false).$str) > 32) {
924 daniel-mar 75
                        throw new OIDplusException(_L('An AID has a maximum length of 16 bytes'));
919 daniel-mar 76
                }
77
 
930 daniel-mar 78
                // removed, because for D2 76 00 01 86 F... it makes sense to have your root (which is inside a foreign RID) being your OIDplus root
79
                /*
925 daniel-mar 80
                $pre   = $this->nodeId(false);
81
                $add   = strtoupper($str);
82
                $after = $pre.$add;
83
                $rid = '?';
84
                $pix = '?';
85
                $p = aid_split_rid_pix($after, $rid, $pix);
86
                if ($p > 1) { // Why $p>1? For "F", there is no RID. We allow that somebody include "F" in the first node
87
                        if ((strlen($pre)<$p) && (strlen($after)>$p)) {
88
                                $rid = substr($rid,strlen($pre));
89
                                throw new OIDplusException(_L('This node would mix RID (registry ID) and PIX (application specific). Please split it into two nodes "%1" and "%2".',$rid,$pix));
90
                        }
91
                }
930 daniel-mar 92
                */
925 daniel-mar 93
 
94
                return $this->nodeId(true).strtoupper($str);
919 daniel-mar 95
        }
96
 
97
        public function crudShowId(OIDplusObject $parent) {
98
                return $this->chunkedNotation(false);
99
        }
100
 
101
        public function crudInsertPrefix() {
102
                return $this->isRoot() ? '' : $this->chunkedNotation(false);
103
        }
104
 
105
        public function jsTreeNodeName(OIDplusObject $parent = null) {
106
                if ($parent == null) return $this->objectTypeTitle();
107
                return substr($this->nodeId(), strlen($parent->nodeId()));
108
        }
109
 
110
        public function defaultTitle() {
111
                return $this->aid;
112
        }
113
 
114
        public function isLeafNode() {
962 daniel-mar 115
                // We don't know when an AID is "leaf", because an AID can have an arbitary length <= 16 Bytes.
116
                // But if it is 16 bytes long (32 nibbles), then we are 100% certain that it is a leaf node.
117
                return (strlen($this->nodeId(false)) == 32);
919 daniel-mar 118
        }
119
 
120
        public function getContentPage(&$title, &$content, &$icon) {
121
                $icon = file_exists(__DIR__.'/img/main_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon.png' : '';
122
 
123
                if ($this->isRoot()) {
124
                        $title = OIDplusAid::objectTypeTitle();
125
 
126
                        $res = OIDplus::db()->query("select * from ###objects where parent = ?", array(self::root()));
127
                        if ($res->any()) {
962 daniel-mar 128
                                $content  = '<p>'._L('Please select an item in the tree view at the left to show its contents.').'</p>';
919 daniel-mar 129
                        } else {
962 daniel-mar 130
                                $content  = '<p>'._L('Currently, no Application Identifiers are registered in the system.').'</p>';
919 daniel-mar 131
                        }
132
 
133
                        if (!$this->isLeafNode()) {
134
                                if (OIDplus::authUtils()->isAdminLoggedIn()) {
135
                                        $content .= '<h2>'._L('Manage root objects').'</h2>';
136
                                } else {
137
                                        $content .= '<h2>'._L('Available objects').'</h2>';
138
                                }
139
                                $content .= '%%CRUD%%';
140
                        }
141
                } else {
142
                        $title = $this->getTitle();
143
 
144
                        $chunked = $this->chunkedNotation(true);
145
                        $content = '<h2>'.$chunked.'</h2>';
922 daniel-mar 146
 
924 daniel-mar 147
                        $tmp = decode_aid($this->aid,true);
148
                        $tmp = htmlentities($tmp);
149
                        $tmp = str_replace(' ','&nbsp;',$tmp);
150
                        $tmp = nl2br($tmp);
932 daniel-mar 151
                        $tmp = preg_replace('@(warning|invalid|error|illegal(&nbsp;usage){0,1})@i', '<span class="errortext">\\1</span>', $tmp);
152
                        $tmp = preg_replace('@(\\\\\\d{3})@i', '<span class="specialhexchar">\\1</span>', $tmp);
924 daniel-mar 153
 
922 daniel-mar 154
                        $content .= '<h2>'._L('Decoding').'</h2>';
155
                        $content .= '<table border="0">';
924 daniel-mar 156
                        $content .= '<code>'.$tmp.'</code>';
922 daniel-mar 157
                        $content .= '</table>';
158
 
924 daniel-mar 159
                        $content .= '<h2>'._L('Description').'</h2>%%DESC%%';
919 daniel-mar 160
                        if ($this->userHasWriteRights()) {
928 daniel-mar 161
                                $content .= '<h2>'._L('Create or change subordinate objects').'</h2>';
919 daniel-mar 162
                        } else {
928 daniel-mar 163
                                $content .= '<h2>'._L('Subordinate objects').'</h2>';
919 daniel-mar 164
                        }
165
                        $content .= '%%CRUD%%';
166
                }
167
        }
168
 
169
        # ---
170
 
171
        public function chunkedNotation($withAbbr=true) {
172
                $curid = self::root().$this->aid;
173
 
977 daniel-mar 174
                $obj = OIDplusObject::findFitting($curid);
175
                if (!$obj) return $this->aid;
919 daniel-mar 176
 
177
                $hints = array();
178
                $lengths = array(strlen($curid));
977 daniel-mar 179
                while ($obj = OIDplusObject::findFitting($curid)) {
180
                        $objParent = $obj->getParent();
181
                        if (!$objParent) break;
182
                        $curid = $objParent->nodeId();
183
                        $hints[] = $obj->getTitle();
919 daniel-mar 184
                        $lengths[] = strlen($curid);
185
                }
186
 
187
                array_shift($lengths);
188
                $chunks = array();
189
 
190
                $full = self::root().$this->aid;
191
                foreach ($lengths as $len) {
192
                        $chunks[] = substr($full, $len);
193
                        $full = substr($full, 0, $len);
194
                }
195
 
196
                $hints = array_reverse($hints);
197
                $chunks = array_reverse($chunks);
198
 
199
                $full = array();
200
                foreach ($chunks as $c) {
934 daniel-mar 201
                        $hint = array_shift($hints);
202
                        $full[] = $withAbbr && ($hint !== '') ? '<abbr title="'.htmlentities($hint).'">'.$c.'</abbr>' : $c;
919 daniel-mar 203
                }
204
                return implode(' ', $full);
205
        }
206
 
207
        public function one_up() {
208
                return OIDplusObject::parse($this->ns().':'.substr($this->aid,0,strlen($this->aid)-1));
209
        }
210
 
211
        public function distance($to) {
212
                if (!is_object($to)) $to = OIDplusObject::parse($to);
213
                if (!($to instanceof $this)) return false;
214
 
215
                $a = $to->aid;
216
                $b = $this->aid;
217
 
218
                $ary = $a;
219
                $bry = $b;
220
 
221
                $min_len = min(strlen($ary), strlen($bry));
222
 
223
                for ($i=0; $i<$min_len; $i++) {
224
                        if ($ary[$i] != $bry[$i]) return false;
225
                }
226
 
227
                return strlen($ary) - strlen($bry);
228
        }
229
 
930 daniel-mar 230
        public function getAltIds() {
231
                if ($this->isRoot()) return array();
232
                $ids = parent::getAltIds();
233
 
945 daniel-mar 234
                $aid = $this->nodeId(false);
235
                $aid = strtoupper($aid);
236
 
1077 daniel-mar 237
                // ViaThinkSoft proprietary AIDs
238
 
239
                // (VTS B1) Members
240
                if ($aid == 'D276000186B1') {
241
                        $oid = '1.3.6.1.4.1.37476.1';
242
                        $ids[] = new OIDplusAltId('oid', $oid, _L('Object Identifier (OID)'));
243
                }
244
 
245
                if (preg_match('@^D276000186B1(....)$@', $aid, $m)) {
246
                        $oid = '1.3.6.1.4.1.37476.1.'.ltrim($m[1],'0');
247
                        $ids[] = new OIDplusAltId('oid', $oid, _L('Object Identifier (OID)'));
248
                }
249
 
250
                // (VTS B2) Products
251
                if ($aid == 'D276000186B2') {
252
                        $oid = '1.3.6.1.4.1.37476.2';
253
                        $ids[] = new OIDplusAltId('oid', $oid, _L('Object Identifier (OID)'));
254
                }
255
 
256
                if (preg_match('@^D276000186B2(....)$@', $aid, $m)) {
257
                        $oid = '1.3.6.1.4.1.37476.2.'.ltrim($m[1],'0');
258
                        $ids[] = new OIDplusAltId('oid', $oid, _L('Object Identifier (OID)'));
259
                }
260
 
1078 daniel-mar 261
                // (VTS B2 00 05) OIDplus Information Objects AID
262
                // Attention: D276000186B20005 does NOT represent 1.3.6.1.4.1.37476.30.9
263
                //            because the mapping to OIDplus systems only applies for 00......-7F...... (31 bit hash)
264
 
265
                if (preg_match('@^D276000186B20005([0-7].......)$@', $aid, $m)) {
266
                        $oid = '1.3.6.1.4.1.37476.30.9.'.hexdec($m[1]);
267
                        $ids[] = new OIDplusAltId('oid', $oid, _L('Object Identifier (OID)'));
268
                }
269
 
270
                if (preg_match('@^D276000186B20005([0-7].......)([0-7].......)$@', $aid, $m)) {
271
                        $oid = '1.3.6.1.4.1.37476.30.9.'.hexdec($m[1]).'.'.hexdec($m[2]);
272
                        $ids[] = new OIDplusAltId('oid', $oid, _L('Object Identifier (OID)'));
273
                }
274
 
1079 daniel-mar 275
                // ViaThinkSoft "Example" AID
276
 
277
                if ($aid == 'D276000186E0') {
278
                        // Note that the OID object type plugin also maps children of 2.999 to AID,
279
                        // using a hash. But since this is not unique and cannot be reverted,
280
                        // we cannot have an reverse lookup/map.
281
                        $ids[] = new OIDplusAltId('oid', '2.999', _L('Object Identifier (OID)'), ' ('._L('Optional PIX allowed, without prefix').')');
282
                }
283
 
930 daniel-mar 284
                // ViaThinkSoft "Foreign" AIDs
285
 
945 daniel-mar 286
                // (VTS F0) IANA PEN + PIX
287
                // Resolve only if there is no PIX
288
                if (str_starts_with($aid,'D276000186F0')) {
289
                        $rest = substr($aid,strlen('D276000186F0'));
290
                        $p = strpos($rest,'F');
291
                        if ($p !== false) {
292
                                $pen = substr($rest,0,$p);
293
                                $pix = substr($rest,$p+1);
294
                        } else {
295
                                $pen = $rest;
296
                                $pix = '';
297
                        }
298
                        if (($pix === '') && preg_match('/^[0-9]+$/',$pen,$m)) {
299
                                $oid = '1.3.6.1.4.1.'.$pen;
300
                                $ids[] = new OIDplusAltId('oid', $oid, _L('Object Identifier (OID)'));
961 daniel-mar 301
                                $ids[] = new OIDplusAltId('iana-pen', $pen, _L('IANA Private Enterprise Number (PEN)'));
945 daniel-mar 302
                        }
303
                }
304
 
305
                // (VTS F1) ViaThinkSoft FreeOID + PIX
306
                // Resolve only if there is no PIX
307
                if (str_starts_with($aid,'D276000186F1')) {
308
                        $rest = substr($aid,strlen('D276000186F1'));
309
                        $p = strpos($rest,'F');
310
                        if ($p !== false) {
311
                                $number = substr($rest,0,$p);
312
                                $pix = substr($rest,$p+1);
313
                        } else {
314
                                $number = $rest;
315
                                $pix = '';
316
                        }
317
                        if (($pix === '') && preg_match('/^[0-9]+$/',$number,$m)) {
318
                                $oid = '1.3.6.1.4.1.37476.9000.'.$number;
319
                                $ids[] = new OIDplusAltId('oid', $oid, _L('Object Identifier (OID)'));
320
                        }
321
                }
322
 
323
                // (VTS F2) MAC address + PIX
324
                // Resolve only if there is no PIX
325
                if (str_starts_with($aid,'D276000186F2')) {
326
                        $rest = substr($aid,strlen('D276000186F2'));
327
                        if (strlen($rest) == 12) {
328
                                $mac = $rest;
329
                                $ids[] = new OIDplusAltId('mac', $mac, _L('MAC address'));
330
                        }
331
                }
332
 
333
                // (VTS F3) USB-IF VendorID + PIX
334
                // Resolve only if there is no PIX
335
                if (str_starts_with($aid,'D276000186F3')) {
336
                        $rest = substr($aid,strlen('D276000186F3'));
337
                        if (strlen($rest) == 4) {
338
                                $vid = $rest;
339
                                $ids[] = new OIDplusAltId('usb-vendor-id', $vid, _L('USB-IF (usb.org) VendorID'));
340
                        }
341
                }
342
 
343
                // (VTS F4) D-U-N-S number + PIX
344
                // Resolve only if there is no PIX
345
                if (str_starts_with($aid,'D276000186F4')) {
346
                        $rest = substr($aid,strlen('D276000186F4'));
347
                        $p = strpos($rest,'F');
348
                        if ($p !== false) {
349
                                $duns = substr($rest,0,$p);
350
                                $pix = substr($rest,$p+1);
351
                        } else {
352
                                $duns = $rest;
353
                                $pix = '';
354
                        }
355
                        if (($pix === '') && preg_match('/^[0-9]+$/',$duns,$m)) {
356
                                $ids[] = new OIDplusAltId('duns', $duns, _L('Data Universal Numbering System (D-U-N-S)'));
357
                        }
358
                }
359
 
360
                // (VTS F5) GS1 number + PIX
361
                // Resolve only if there is no PIX
362
                if (str_starts_with($aid,'D276000186F5')) {
363
                        $rest = substr($aid,strlen('D276000186F5'));
364
                        $p = strpos($rest,'F');
365
                        if ($p !== false) {
366
                                $gs1 = substr($rest,0,$p);
367
                                $pix = substr($rest,$p+1);
368
                        } else {
369
                                $gs1 = $rest;
370
                                $pix = '';
371
                        }
372
                        if (($pix === '') && preg_match('/^[0-9]+$/',$gs1,$m)) {
373
                                $ids[] = new OIDplusAltId('gs1', $gs1, _L('GS1 Based IDs (GLN/GTIN/SSCC/...)'), ' ('._L('without check-digit').')');
374
                        }
375
                }
376
 
377
                // (VTS F6) OID<->AID, no PIX
930 daniel-mar 378
                if (str_starts_with($aid,'D276000186F6')) {
379
                        $der = substr($aid,strlen('D276000186F6'));
380
                        $len = strlen($der);
381
                        if ($len%2 == 0) {
382
                                $len /= 2;
383
                                $len = str_pad("$len", 2, '0', STR_PAD_LEFT);
384
                                $type = '06'; // absolute OID
385
                                $der = "$type $len $der";
1050 daniel-mar 386
                                $oid = \OidDerConverter::derToOID(\OidDerConverter::hexStrToArray($der));
930 daniel-mar 387
                                if ($oid) {
388
                                        $oid = ltrim($oid,'.');
389
                                        $ids[] = new OIDplusAltId('oid', $oid, _L('Object Identifier (OID)'));
390
                                }
391
                        }
392
                }
393
 
933 daniel-mar 394
                // The case E8... (Standard OID 1.0) doesn't need to be addressed here, because it is already shown in the AID decoder (and it is ambiguous since DER and PIX are mixed)
945 daniel-mar 395
                // TODO: If it has no pix, then resolve it !!! but how do we know if there is a PIX or a part ID ?
933 daniel-mar 396
 
930 daniel-mar 397
                return $ids;
398
        }
399
 
919 daniel-mar 400
        public function getDirectoryName() {
401
                if ($this->isRoot()) return $this->ns();
402
                return $this->ns().'_'.$this->nodeId(false); // safe, because there are only AIDs
403
        }
404
 
405
        public static function treeIconFilename($mode) {
406
                return 'img/'.$mode.'_icon16.png';
407
        }
408
}