Subversion Repositories oidplus

Rev

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

Rev Author Line No. Line
635 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
758 daniel-mar 5
 * Copyright 2019 - 2022 Daniel Marschall, ViaThinkSoft
635 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
 
20
require_once __DIR__ . '/../../../../../includes/oidplus.inc.php';
21
 
868 daniel-mar 22
define('XML_URN', 'urn:ietf:id:viathinksoft-oidip-03');
867 daniel-mar 23
define('XML_URN_URL', OIDplus::webpath(__DIR__,OIDplus::PATH_ABSOLUTE).'xml_schema.xsd');
24
define('JSON_SCHEMA', OIDplus::webpath(__DIR__,OIDplus::PATH_ABSOLUTE).'json_schema.json');
762 daniel-mar 25
 
635 daniel-mar 26
OIDplus::init(true);
27
set_exception_handler(array('OIDplusGui', 'html_exception_handler'));
28
 
29
if (OIDplus::baseConfig()->getValue('DISABLE_PLUGIN_OIDplusPagePublicWhois', false)) {
30
        throw new OIDplusException(_L('This plugin was disabled by the system administrator!'));
31
}
32
 
33
originHeaders();
34
 
35
// Step 0: Get request parameter
36
 
37
if (PHP_SAPI == 'cli') {
38
        if ($_SERVER['argc'] != 2) {
39
                echo _L('Syntax').': '.$_SERVER['argv'][0].' <query>'."\n";
40
                exit(2);
41
        }
42
        $query = $_SERVER['argv'][1];
43
} else {
44
        if (!isset($_REQUEST['query'])) {
45
                http_response_code(400);
46
                die('<h1>'._L('Error').'</h1><p>'._L('Argument "%1" is missing','query').'<p>');
47
        }
48
        $query = $_REQUEST['query'];
49
}
50
 
51
// Split input into query, authTokens and serverCommands
52
$tokens = explode('$', $query);
53
$query = array_shift($tokens);
54
$authTokens[] = array();
55
$serverCommands = array();
56
foreach ($tokens as $token) {
57
        if (strpos($token,'=') !== false) {
58
                $tmp = explode('=',$token,2);
59
                $serverCommands[strtolower($tmp[0])] = $tmp[1];
60
        } else {
61
                $authTokens[] = $token;
62
        }
63
}
64
 
65
$query = str_replace('oid:.', 'oid:', $query); // allow leading dot
66
 
765 daniel-mar 67
if (isset($_REQUEST['format'])) {
68
        $format = $_REQUEST['format'];
69
} else if (isset($serverCommands['format'])) {
70
        $format = $serverCommands['format'];
71
} else {
72
        $format = 'text'; // default
73
}
74
 
75
$unimplemented_format = ($format != 'text') && ($format != 'json') && ($format != 'xml');
76
if ($unimplemented_format) {
77
        $format = 'text';
78
}
79
 
635 daniel-mar 80
// Step 1: Collect data
81
 
82
$out = array();
83
 
84
$out[] = "query: $query";
85
 
775 daniel-mar 86
$query = OIDplus::prefilterQuery($query, false);
773 daniel-mar 87
 
765 daniel-mar 88
if ($unimplemented_format) {
89
        $out[] = 'result: Service error';
90
        $out[] = 'message: Format is not implemented';
91
} else {
635 daniel-mar 92
 
765 daniel-mar 93
        $distance = null;
94
        $found = null;
635 daniel-mar 95
 
765 daniel-mar 96
        try {
97
                $obj = OIDplusObject::findFitting($query);
98
                if (!$obj) $obj = OIDplusObject::parse($query); // in case we didn't find anything fitting, we take it as it is and later use getParent() to find something else
99
                $query = $obj->nodeId();
100
        } catch (Exception $e) {
101
                $obj = null;
102
        }
635 daniel-mar 103
 
765 daniel-mar 104
        $only_wellknown_ids_found = false;
635 daniel-mar 105
        $continue = false;
106
 
765 daniel-mar 107
        if (!$obj) {
108
                $out[] = "result: Not found"; // DO NOT TRANSLATE!
109
                $continue = false;
110
                $res = null;
111
        } else {
112
                $obj = null;
113
                $distance = 0;
635 daniel-mar 114
 
765 daniel-mar 115
                $init_query = $query;
635 daniel-mar 116
                while (true) {
765 daniel-mar 117
                        $res = OIDplus::db()->query("select * from ###objects where id = ?", array($query));
790 daniel-mar 118
                        if ($res->any()) {
635 daniel-mar 119
                                $obj = OIDplusObject::parse($query);
120
                                if ($distance > 0) {
121
                                        $out[] = "result: Not found; superior object found"; // DO NOT TRANSLATE!
122
                                        $out[] = "distance: $distance"; // DO NOT TRANSLATE
123
                                } else {
124
                                        $out[] = "result: Found"; // DO NOT TRANSLATE!
125
                                }
126
                                $continue = true;
127
                                break;
128
                        }
129
 
765 daniel-mar 130
                        if (substr($query,0,4) === 'oid:') {
131
                                $query_prev = $query;
132
                                $query = 'oid:'.oid_up(explode(':',$query,2)[1]);
133
                                if ($query == $query_prev) break;
134
                                $distance++;
135
                        } else {
136
                                // getParent() will find the parent which DOES exist in the DB.
137
                                // It does not need to be the direct parent (like ->one_up() does)
138
                                $obj = OIDplusObject::parse($query)->getParent(); // For objects, we assume that they are parents of each other
139
                                if ($obj) {
140
                                        $res = OIDplus::db()->query("select * from ###objects where id = ?", array($obj->nodeId()));
141
                                        $distance = $obj->distance($query);
790 daniel-mar 142
                                        assert($res->any());
635 daniel-mar 143
 
765 daniel-mar 144
                                        $query = $obj->nodeId();
145
                                }
635 daniel-mar 146
 
765 daniel-mar 147
                                if ($distance > 0) {
148
                                        $out[] = "result: Not found; superior object found"; // DO NOT TRANSLATE!
149
                                        $out[] = "distance: $distance"; // DO NOT TRANSLATE
150
                                }
151
                                $continue = true;
152
 
153
                                break;
154
                        }
635 daniel-mar 155
                }
156
 
765 daniel-mar 157
                if ((substr($query,0,4) === 'oid:') && (!$obj)) {
158
                        $query = $init_query;
159
                        $distance = 0;
160
                        while (true) {
161
                                $res = OIDplus::db()->query("select * from ###asn1id where oid = ? union select * from ###iri where oid = ?", array($query, $query));
790 daniel-mar 162
                                if ($res->any()) {
765 daniel-mar 163
                                        $obj = OIDplusObject::parse($query);
164
                                        $res = null;
165
                                        if ($distance > 0) {
166
                                                $out[] = "result: Not found; superior object found"; // DO NOT TRANSLATE!
167
                                                $out[] = "distance: $distance"; // DO NOT TRANSLATE
168
                                        } else {
169
                                                $out[] = "result: Found"; // DO NOT TRANSLATE!
170
                                        }
171
                                        $only_wellknown_ids_found = true; // Information partially available
172
                                        $continue = true;
173
                                        break;
174
                                }
175
                                $query_prev = $query;
176
                                $query = 'oid:'.oid_up(explode(':',$query,2)[1]);
177
                                if ($query == $query_prev) break;
178
                                $distance++;
179
                        }
180
                }
635 daniel-mar 181
 
765 daniel-mar 182
                if (!$obj) {
183
                        $out[] = "result: Not found"; // DO NOT TRANSLATE!
184
                        $continue = false;
635 daniel-mar 185
                }
186
 
765 daniel-mar 187
                $found = $distance == 0;
188
        }
635 daniel-mar 189
 
765 daniel-mar 190
        if ($continue) {
191
                $out[] = "";
192
                $out[] = "object: $query"; // DO NOT TRANSLATE!
193
                if (!allowObjectView($obj, $authTokens)) {
194
                        $out[] = "status: Information unavailable"; // DO NOT TRANSLATE!
195
                        $out[] = "attribute: confidential"; // DO NOT TRANSLATE!
196
                } else {
197
                        if ($only_wellknown_ids_found) {
198
                                $out[] = "status: Information partially available"; // DO NOT TRANSLATE!
199
                        } else {
200
                                $out[] = "status: Information available"; // DO NOT TRANSLATE!
635 daniel-mar 201
                        }
202
 
765 daniel-mar 203
                        $row = $res ? $res->fetch_object() : null;
635 daniel-mar 204
 
765 daniel-mar 205
                        if (!is_null($row)) {
206
                                $out[] = 'name: ' . $row->title; // DO NOT TRANSLATE!
635 daniel-mar 207
 
765 daniel-mar 208
                                $cont = $row->description;
209
                                $cont = preg_replace('@<a[^>]+href\s*=\s*["\']([^\'"]+)["\'][^>]*>(.+)<\s*/\s*a\s*>@ismU', '\2 (\1)', $cont);
210
                                $cont = preg_replace('@<br.*>@', "\n", $cont);
211
                                $cont = preg_replace('@\\n+@', "\n", $cont);
212
                                $out[] = 'description: ' . trim(html_entity_decode(strip_tags($cont))); // DO NOT TRANSLATE!
635 daniel-mar 213
                        }
214
 
765 daniel-mar 215
                        if (substr($query,0,4) === 'oid:') {
216
                                $out[] = 'asn1-notation: ' . $obj->getAsn1Notation(false); // DO NOT TRANSLATE!
217
                                $out[] = 'iri-notation: ' . $obj->getIriNotation(false); // DO NOT TRANSLATE!
635 daniel-mar 218
 
765 daniel-mar 219
                                $res2 = OIDplus::db()->query("select * from ###asn1id where oid = ?", array($obj->nodeId()));
220
                                while ($row2 = $res2->fetch_object()) {
221
                                        $out[] = 'identifier: ' . $row2->name; // DO NOT TRANSLATE!
222
                                }
730 daniel-mar 223
 
765 daniel-mar 224
                                $res2 = OIDplus::db()->query("select * from ###asn1id where standardized = ? and oid = ?", array(true, $obj->nodeId()));
225
                                while ($row2 = $res2->fetch_object()) {
226
                                        $out[] = 'standardized-id: ' . $row2->name; // DO NOT TRANSLATE!
227
                                }
635 daniel-mar 228
 
765 daniel-mar 229
                                $res2 = OIDplus::db()->query("select * from ###iri where oid = ?", array($obj->nodeId()));
230
                                while ($row2 = $res2->fetch_object()) {
231
                                        $out[] = 'unicode-label: ' . $row2->name; // DO NOT TRANSLATE!
232
                                }
635 daniel-mar 233
 
765 daniel-mar 234
                                $res2 = OIDplus::db()->query("select * from ###iri where longarc = ? and oid = ?", array(true, $obj->nodeId()));
235
                                while ($row2 = $res2->fetch_object()) {
236
                                        $out[] = 'long-arc: ' . $row2->name; // DO NOT TRANSLATE!
237
                                }
635 daniel-mar 238
                        }
239
 
765 daniel-mar 240
                        if ($obj->isConfidential()) { // yes, we use isConfidential() instead of allowObjectView()!
241
                                $out[] = 'attribute: confidential'; // DO NOT TRANSLATE!
635 daniel-mar 242
                        }
243
 
765 daniel-mar 244
                        if ($obj->implementsFeature('1.3.6.1.4.1.37476.2.5.2.3.4')) {
245
                                // Also ask $obj for extra attributes:
246
                                // This way we could add various additional information, e.g. IPv4/6 range analysis, interpretation of GUID, etc. (TODO)
247
                                $obj->whoisObjectAttributes($obj->nodeId(), $out);
248
                        }
635 daniel-mar 249
 
765 daniel-mar 250
                        foreach (OIDplus::getPagePlugins() as $plugin) {
251
                                if ($plugin->implementsFeature('1.3.6.1.4.1.37476.2.5.2.3.4')) {
252
                                        $plugin->whoisObjectAttributes($obj->nodeId(), $out);
253
                                }
254
                        }
635 daniel-mar 255
 
765 daniel-mar 256
                        if (substr($query,0,4) === 'oid:') {
257
                                $sParent = 'oid:'.oid_up(explode(':',$query,2)[1]);
635 daniel-mar 258
 
765 daniel-mar 259
                                $objTest = OIDplusObject::parse($sParent);
260
                                if (allowObjectView($objTest, $authTokens)) {
261
                                        $out[] = 'parent: ' . $sParent . show_asn1_appendix($sParent); // DO NOT TRANSLATE!
262
                                } else {
263
                                        $out[] = 'parent: ' . $sParent; // DO NOT TRANSLATE!
264
                                }
265
                        } else if (!is_null($row) && !empty($row->parent) && (!is_root($row->parent))) {
266
                                $sParent = $row->parent;
267
                                $out[] = 'parent: ' . $row->parent; // DO NOT TRANSLATE!
268
                        }
635 daniel-mar 269
 
765 daniel-mar 270
                        $res2 = OIDplus::db()->query("select * from ###objects where parent = ? order by ".OIDplus::db()->natOrder('id'), array($obj->nodeId()));
271
                        while ($row2 = $res2->fetch_object()) {
272
                                $objTest = OIDplusObject::parse($row2->id);
273
                                if (allowObjectView($objTest, $authTokens)) {
274
                                        $out[] = 'subordinate: ' . $row2->id . show_asn1_appendix($row2->id); // DO NOT TRANSLATE!
275
                                } else {
276
                                        $out[] = 'subordinate: ' . $row2->id; // DO NOT TRANSLATE!
635 daniel-mar 277
                                }
278
                        }
730 daniel-mar 279
 
765 daniel-mar 280
                        if (!is_null($row)) {
281
                                if ($row->created) $out[] = 'created: ' . date('Y-m-d H:i:s', strtotime($row->created)); // DO NOT TRANSLATE!
282
                                if ($row->updated) $out[] = 'updated: ' . date('Y-m-d H:i:s', strtotime($row->updated)); // DO NOT TRANSLATE!
730 daniel-mar 283
                        }
284
 
765 daniel-mar 285
                        $out[] = '';
286
 
287
                        $res2 = OIDplus::db()->query("select * from ###ra where email = ?", array(is_null($row) ? '' : $row->ra_email));
288
                        if ($row2 = $res2->fetch_object()) {
289
                                $out[] = 'ra: '.(!empty($row2->ra_name) ? $row2->ra_name : (!empty($row2->email) ? $row2->email : _L('Unknown'))); // DO NOT TRANSLATE!
290
                                $out[] = 'ra-status: Information available'; // DO NOT TRANSLATE!
291
 
292
                                $tmp = array();
293
                                if (!empty($row2->office)) $tmp[] = $row2->office;
294
                                if (!empty($row2->organization)) $tmp[] = $row2->organization;
295
                                $tmp = implode(', ', $tmp);
296
 
297
                                $out[] = 'ra-contact-name: ' . $row2->personal_name.(!empty($tmp) ? " ($tmp)" : ''); // DO NOT TRANSLATE!
298
                                if (!allowRAView($row2, $authTokens)) {
299
                                        if (!empty($row2->street) || !empty($row2->zip_town) || !empty($row2->country)) {
300
                                                $out[] = 'ra-address: '._L('(redacted)'); // DO NOT TRANSLATE!
301
                                        }
302
                                        $out[] = 'ra-phone: ' . (!empty($row2->phone) ? _L('(redacted)') : ''); // DO NOT TRANSLATE!
303
                                        $out[] = 'ra-mobile: ' . (!empty($row2->mobile) ? _L('(redacted)') : ''); // DO NOT TRANSLATE!
304
                                        $out[] = 'ra-fax: ' . (!empty($row2->fax) ? _L('(redacted)') : ''); // DO NOT TRANSLATE!
305
                                } else {
306
                                        if (!empty($row2->street))   $out[] = 'ra-address: ' . $row2->street; // DO NOT TRANSLATE!
307
                                        if (!empty($row2->zip_town)) $out[] = 'ra-address: ' . $row2->zip_town; // DO NOT TRANSLATE!
308
                                        if (!empty($row2->country))  $out[] = 'ra-address: ' . $row2->country; // DO NOT TRANSLATE!
309
                                        $out[] = 'ra-phone: ' . $row2->phone; // DO NOT TRANSLATE!
310
                                        $out[] = 'ra-mobile: ' . $row2->mobile; // DO NOT TRANSLATE!
311
                                        $out[] = 'ra-fax: ' . $row2->fax; // DO NOT TRANSLATE!
635 daniel-mar 312
                                }
765 daniel-mar 313
                                $out[] = 'ra-email: ' . $row->ra_email; // DO NOT TRANSLATE!
635 daniel-mar 314
 
765 daniel-mar 315
                                $ra = new OIDplusRA($row->ra_email);
316
                                if ($ra->implementsFeature('1.3.6.1.4.1.37476.2.5.2.3.4')) {
317
                                        $ra->whoisRaAttributes($row->ra_email, $out); /** @phpstan-ignore-line */
318
                                }
635 daniel-mar 319
 
320
                                foreach (OIDplus::getPagePlugins() as $plugin) {
321
                                        if ($plugin->implementsFeature('1.3.6.1.4.1.37476.2.5.2.3.4')) {
322
                                                $plugin->whoisRaAttributes($row->ra_email, $out);
323
                                        }
324
                                }
765 daniel-mar 325
 
326
                                if ($row2->privacy) { // yes, we use row2->privacy() instead of allowRAView()!
327
                                        $out[] = 'ra-attribute: confidential'; // DO NOT TRANSLATE!
328
                                }
329
 
330
                                if ($row2->registered) $out[] = 'ra-created: ' . date('Y-m-d H:i:s', strtotime($row2->registered)); // DO NOT TRANSLATE!
331
                                if ($row2->updated)    $out[] = 'ra-updated: ' . date('Y-m-d H:i:s', strtotime($row2->updated)); // DO NOT TRANSLATE!
332
                        } else {
333
                                $out[] = 'ra: '.(!is_null($row) && !empty($row->ra_email) ? $row->ra_email : _L('Unknown')); // DO NOT TRANSLATE!
334
                                if (!is_null($row)) {
335
                                        foreach (OIDplus::getPagePlugins() as $plugin) {
336
                                                if ($plugin->implementsFeature('1.3.6.1.4.1.37476.2.5.2.3.4')) {
337
                                                        $plugin->whoisRaAttributes($row->ra_email, $out);
338
                                                }
339
                                        }
340
                                }
341
                                $out[] = "ra-status: Information unavailable"; // DO NOT TRANSLATE!
635 daniel-mar 342
                        }
343
                }
344
        }
345
}
346
 
347
// Step 2: Format output
348
 
765 daniel-mar 349
if ($format == 'text') {
635 daniel-mar 350
        header('Content-Type:text/plain; charset=UTF-8');
351
 
352
        $longest_key = 0;
353
        foreach ($out as $line) {
354
                $longest_key = max($longest_key, strlen(trim(explode(':',$line,2)[0])));
355
        }
356
 
357
        ob_start();
358
 
359
        //echo '% ' . str_repeat('*', OIDplus::config()->getValue('webwhois_output_format_max_line_length', 80)-2)."\r\n";
360
 
361
        foreach ($out as $line) {
362
                if (trim($line) == '') {
363
                        echo "\r\n";
364
                        continue;
365
                }
366
 
367
                $ary = explode(':', $line, 2);
368
 
369
                $key = trim($ary[0]);
370
 
371
                $value = isset($ary[1]) ? trim($ary[1]) : '';
674 daniel-mar 372
 
373
                // Normalize line-breaks to \r\n, otherwise mb_wordwrap won't work correctly
374
                $value = str_replace("\r\n", "\n", $value);
375
                $value = str_replace("\r", "\n", $value);
376
                $value = str_replace("\n", "\r\n", $value);
377
 
635 daniel-mar 378
                $value = mb_wordwrap($value, OIDplus::config()->getValue('webwhois_output_format_max_line_length', 80) - $longest_key - strlen(':') - OIDplus::config()->getValue('webwhois_output_format_spacer', 2), "\r\n");
379
                $value = str_replace("\r\n", "\r\n$key:".str_repeat(' ', $longest_key-strlen($key)) . str_repeat(' ', OIDplus::config()->getValue('webwhois_output_format_spacer', 2)), $value);
380
 
381
                if (!empty($value)) {
382
                        echo $key.':' . str_repeat(' ', $longest_key-strlen($key)) . str_repeat(' ', OIDplus::config()->getValue('webwhois_output_format_spacer', 2)) . $value . "\r\n";
383
                }
384
        }
385
 
386
        //echo '% ' . str_repeat('*', OIDplus::config()->getValue('webwhois_output_format_max_line_length', 80)-2)."\r\n";
387
 
388
        $cont = ob_get_contents();
389
        ob_end_clean();
390
 
391
        echo $cont;
392
 
393
        if (OIDplus::getPkiStatus()) {
394
                $signature = '';
830 daniel-mar 395
                if (@openssl_sign($cont, $signature, OIDplus::getSystemPrivateKey())) {
635 daniel-mar 396
                        $signature = base64_encode($signature);
397
                        $signature = mb_wordwrap($signature, OIDplus::config()->getValue('webwhois_output_format_max_line_length', 80) - strlen('% '), "\r\n", true);
398
                        $signature = "% -----BEGIN RSA SIGNATURE-----\r\n".
399
                                     preg_replace('/^/m', '% ', $signature)."\r\n".
400
                                     "% -----END RSA SIGNATURE-----\r\n";
401
                        echo $signature;
402
                }
403
        }
404
}
405
 
406
if ($format == 'json') {
407
        $ary = array();
408
 
409
        $current_section = array();
410
        $ary[] = &$current_section;
411
 
412
        foreach ($out as $line) {
413
                if ($line == '') {
414
                        unset($current_section);
415
                        $current_section = array();
416
                        $ary[] = &$current_section;
417
                } else {
418
                        list($key,$val) = explode(':', $line, 2);
419
                        $val = trim($val);
420
                        if (!empty($val)) {
421
                                if (!isset($current_section[$key])) {
422
                                        $current_section[$key] = $val;
423
                                } elseif (is_array($current_section[$key])) {
424
                                        $current_section[$key][] = $val;
425
                                } else {
426
                                        $current_section[$key] = array($current_section[$key], $val);
427
                                }
428
                        }
429
                }
430
        }
431
        $ary = array(
432
                // https://code.visualstudio.com/docs/languages/json#_mapping-in-the-json
433
                // Note that this syntax is VS Code-specific and not part of the JSON Schema specification.
434
                //'$schema' => 'https://oidplus.viathinksoft.com/oidplus/plugins/publicPages/100_whois/whois/json_schema.json',
867 daniel-mar 435
                '$schema' => JSON_SCHEMA,
635 daniel-mar 436
 
437
                // we need this NAMED root, otherwise PHP will name the sections "0", "1", "2" if the array is not sequencial (e.g. because "signature" is added)
758 daniel-mar 438
                'oidip' => $ary
635 daniel-mar 439
        );
440
 
868 daniel-mar 441
        $json = json_encode($ary);
442
 
635 daniel-mar 443
        if (OIDplus::getPkiStatus()) {
868 daniel-mar 444
                require_once __DIR__.'/json/security.inc.php';
445
                $json = oidplus_json_sign($json, OIDplus::getSystemPrivateKey(), OIDplus::getSystemPublicKey());
635 daniel-mar 446
        }
447
 
448
        // Good JSON schema validator here: https://www.jsonschemavalidator.net
449
        header('Content-Type:application/json; charset=UTF-8');
868 daniel-mar 450
        echo $json;
635 daniel-mar 451
}
452
 
453
if ($format == 'xml') {
758 daniel-mar 454
        $xml = '<oidip><section>';
635 daniel-mar 455
        foreach ($out as $line) {
456
                if ($line == '') {
457
                        $xml .= '</section><section>';
458
                } else {
459
                        list($key,$val) = explode(':', $line, 2);
460
                        $val = trim($val);
461
                        if (!empty($val)) {
462
                                $xml .= "<$key>".htmlspecialchars($val)."</$key>";
463
                        }
464
                }
465
        }
758 daniel-mar 466
        $xml .= '</section></oidip>';
635 daniel-mar 467
 
468
        $xml = preg_replace('@<section><(.+)>(.+)</section>@ismU', '<\\1Section><\\1>\\2</\\1Section>', $xml);
469
 
868 daniel-mar 470
        // Good XSD validator here: https://www.liquid-technologies.com/online-xsd-validator
471
        $xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>'.
472
               '<root xmlns="'.XML_URN.'"'.
473
               '      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'.
474
               '      xsi:schemaLocation="'.XML_URN.' '.XML_URN_URL.'">'.
475
               $xml.
476
               '</root>';
477
 
635 daniel-mar 478
        if (OIDplus::getPkiStatus()) {
868 daniel-mar 479
                require_once __DIR__.'/xml/security.inc.php';
480
                $xml = oidplus_xml_sign($xml, OIDplus::getSystemPrivateKey(), OIDplus::getSystemPublicKey());
635 daniel-mar 481
        }
482
 
483
        header('Content-Type:application/xml; charset=UTF-8');
484
        echo $xml;
485
}
486
 
487
# ---
488
 
489
function show_asn1_appendix($id) {
490
        if (substr($id,0,4) === 'oid:') {
491
                $appendix_asn1ids = array();
492
                $res3 = OIDplus::db()->query("select * from ###asn1id where oid = ?", array($id));
493
                while ($row3 = $res3->fetch_object()) {
494
                        $appendix_asn1ids[] = $row3->name;
495
                }
496
 
497
                $appendix = implode(', ', $appendix_asn1ids);
498
                if (!empty($appendix)) $appendix = " ($appendix)";
499
        } else {
500
                $appendix = '';
501
        }
502
        return $appendix;
503
}
504
 
505
function is_root($id) {
506
        return empty(explode(':',$id,2)[1]);
507
}
508
 
509
function authTokenAccepted($content, $authTokens) {
510
        foreach ($authTokens as $token) {
511
                if (OIDplusPagePublicWhois::genWhoisAuthToken($content) == $token) return true;
512
        }
513
        return false;
514
}
515
 
516
function allowObjectView($obj, $authTokens) {
517
        // Master auth token
518
        $authToken = trim(OIDplus::config()->getValue('whois_auth_token'));
519
        if (empty($authToken)) $authToken = false;
520
        if ($authToken && in_array($authToken, $authTokens)) return true;
521
 
522
        // Per-OID auth tokens
523
        $curid = $obj->nodeId();
790 daniel-mar 524
        while (($res = OIDplus::db()->query("select parent, confidential from ###objects where id = ?", array($curid)))->any()) {
635 daniel-mar 525
                $row = $res->fetch_array();
526
                // Example: You have an auth Token for 2.999.1.2.3
527
                // This allows you to view 2.999.1.2.3 and all of its children,
528
                // as long as they are not confidential (then you need their auth token).
529
                // 2, 2.999, 2.999.1 and 2.999.1.2 are visible,
530
                // (because their existence is now obvious).
531
                if ($row['confidential'] && !authTokenAccepted($curid, $authTokens)) return false;
532
                $curid = $row['parent'];
533
        }
534
 
535
        // Allow
536
        return true;
537
}
538
 
539
function allowRAView($row, $authTokens) {
540
        // Master auth token
541
        $authToken = trim(OIDplus::config()->getValue('whois_auth_token'));
542
        if (empty($authToken)) $authToken = false;
543
        if ($authToken && in_array($authToken, $authTokens)) return true;
544
 
545
        // Per-RA auth tokens
546
        if ($row->privacy && !authTokenAccepted('ra:'.$row->ra_name, $authTokens)) return false;
547
 
548
        // Allow
549
        return true;
550
}