Subversion Repositories oidplus

Rev

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