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