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 | } |