Rev 331 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
101 | daniel-mar | 1 | <?php |
2 | |||
3 | /* |
||
4 | * OIDplus 2.0 |
||
5 | * Copyright 2019 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 | |||
20 | require_once __DIR__ . '/../../../../includes/oidplus.inc.php'; |
||
21 | |||
22 | OIDplus::init(true); |
||
23 | |||
180 | daniel-mar | 24 | originHeaders(); |
101 | daniel-mar | 25 | |
26 | // Step 0: Get request parameter |
||
27 | |||
28 | if (php_sapi_name() == 'cli') { |
||
29 | if ($argc != 2) { |
||
30 | echo "Syntax: $argv[0] <query>\n"; |
||
31 | exit(2); |
||
32 | } |
||
33 | $query = $argv[1]; |
||
34 | } else { |
||
35 | if (!isset($_REQUEST['query'])) { |
||
36 | http_response_code(400); |
||
240 | daniel-mar | 37 | die("<h1>Error</h1><p>Argument 'query' is missing<p>"); |
101 | daniel-mar | 38 | } |
39 | $query = $_REQUEST['query']; |
||
40 | } |
||
41 | |||
42 | $authTokens = explode('$', $query); |
||
43 | $query = array_shift($authTokens); |
||
104 | daniel-mar | 44 | |
45 | $authToken = trim(OIDplus::config()->getValue('whois_auth_token')); |
||
46 | if (empty($authToken)) $authToken = false; |
||
47 | |||
101 | daniel-mar | 48 | $show_confidential = $authToken && in_array($authToken, $authTokens); |
49 | |||
50 | $query = str_replace('oid:.', 'oid:', $query); // allow leading dot |
||
51 | |||
52 | // Step 1: Collect data |
||
53 | |||
54 | $out = array(); |
||
55 | |||
56 | $out[] = "query: $query"; |
||
57 | |||
58 | $distance = null; |
||
59 | $found = null; |
||
60 | |||
61 | try { |
||
62 | $obj = OIDplusObject::findFitting($query); |
||
63 | 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 |
||
64 | } catch (Exception $e) { |
||
65 | $obj = null; |
||
66 | } |
||
67 | |||
68 | if (!$obj) { |
||
69 | $found = false; |
||
70 | } else { |
||
71 | $query = $obj->nodeId(); // this may sanitize/canonize identifiers |
||
261 | daniel-mar | 72 | $res = OIDplus::db()->query("select * from ###objects where id = ?", array($obj->nodeId())); |
236 | daniel-mar | 73 | if ($res->num_rows() > 0) { |
101 | daniel-mar | 74 | $found = true; |
75 | $distance = 0; |
||
76 | } else { |
||
77 | $found = false; |
||
78 | $objParent = OIDplusObject::parse($query)->getParent(); |
||
79 | if ($objParent) { |
||
261 | daniel-mar | 80 | $res = OIDplus::db()->query("select * from ###objects where id = ?", array($objParent->nodeId())); |
101 | daniel-mar | 81 | $distance = $objParent->distance($query); |
236 | daniel-mar | 82 | assert($res->num_rows() > 0); |
101 | daniel-mar | 83 | |
84 | $query = $objParent->nodeId(); |
||
85 | $obj = $objParent; |
||
86 | } |
||
87 | } |
||
88 | } |
||
89 | |||
90 | $continue = null; |
||
91 | if (!$found) { |
||
92 | if (!is_null($distance)) { |
||
93 | $out[] = "result: Not found; superior object found"; |
||
94 | $out[] = "distance: $distance"; |
||
95 | $continue = true; |
||
96 | } else { |
||
97 | $out[] = "result: Not found"; |
||
98 | $continue = false; |
||
99 | } |
||
100 | } else { |
||
101 | $out[] = "result: Found"; |
||
102 | $continue = true; |
||
103 | } |
||
104 | |||
105 | if ($continue) { |
||
106 | $out[] = ""; |
||
107 | $out[] = "object: $query"; |
||
108 | if ($obj->isConfidential() && !$show_confidential) { |
||
109 | $out[] = "status: Confidential"; |
||
110 | } else { |
||
125 | daniel-mar | 111 | $out[] = "status: Information available"; |
101 | daniel-mar | 112 | |
262 | daniel-mar | 113 | $row = $res->fetch_object(); |
114 | assert($row); |
||
101 | daniel-mar | 115 | $obj = OIDplusObject::parse($row->id); |
116 | |||
117 | if (!empty($row->parent) && (!is_root($row->parent))) { |
||
118 | $out[] = 'parent: ' . $row->parent . show_asn1_appendix($row->parent); |
||
119 | } |
||
120 | $out[] = 'name: ' . $row->title; |
||
121 | |||
122 | $cont = $row->description; |
||
123 | $cont = preg_replace('@<a[^>]+href\s*=\s*["\']([^\'"]+)["\'][^>]*>(.+)<\s*/\s*a\s*>@ismU', '\2 (\1)', $cont); |
||
332 | daniel-mar | 124 | $cont = preg_replace('@<br.*>@', "\n", $cont); |
125 | $cont = preg_replace('@\\n+@', "\n", $cont); |
||
101 | daniel-mar | 126 | $out[] = 'description: ' . trim(html_entity_decode(strip_tags($cont))); |
127 | |||
128 | if (substr($query,0,4) === 'oid:') { |
||
261 | daniel-mar | 129 | $res2 = OIDplus::db()->query("select * from ###asn1id where oid = ?", array($row->id)); |
236 | daniel-mar | 130 | while ($row2 = $res2->fetch_object()) { |
101 | daniel-mar | 131 | $out[] = 'identifier: ' . $row2->name; |
132 | } |
||
133 | |||
261 | daniel-mar | 134 | $res2 = OIDplus::db()->query("select * from ###asn1id where standardized = ? and oid = ?", array(true, $row->id)); |
236 | daniel-mar | 135 | while ($row2 = $res2->fetch_object()) { |
101 | daniel-mar | 136 | $out[] = 'standardized-id: ' . $row2->name; |
137 | } |
||
138 | |||
261 | daniel-mar | 139 | $res2 = OIDplus::db()->query("select * from ###iri where oid = ?", array($row->id)); |
236 | daniel-mar | 140 | while ($row2 = $res2->fetch_object()) { |
101 | daniel-mar | 141 | $out[] = 'unicode-label: ' . $row2->name; |
142 | } |
||
143 | |||
261 | daniel-mar | 144 | $res2 = OIDplus::db()->query("select * from ###iri where longarc = ? and oid = ?", array(true, $row->id)); |
236 | daniel-mar | 145 | while ($row2 = $res2->fetch_object()) { |
101 | daniel-mar | 146 | $out[] = 'long-arc: ' . $row2->name; |
147 | } |
||
148 | } |
||
322 | daniel-mar | 149 | foreach (OIDplus::getPagePlugins() as $plugin) { |
150 | if ($plugin->implementsFeature('1.3.6.1.4.1.37476.2.5.2.3.4')) { |
||
151 | $plugin->whoisObjectAttributes($row->id, $out); |
||
152 | } |
||
153 | } |
||
101 | daniel-mar | 154 | $out[] = 'created: ' . $row->created; |
155 | $out[] = 'updated: ' . $row->updated; |
||
156 | |||
261 | daniel-mar | 157 | $res2 = OIDplus::db()->query("select * from ###objects where parent = ? order by ".OIDplus::db()->natOrder('id'), array($row->id)); |
236 | daniel-mar | 158 | if ($res2->num_rows() == 0) { |
101 | daniel-mar | 159 | // $out[] = 'subordinate: (none)'; |
160 | } |
||
236 | daniel-mar | 161 | while ($row2 = $res2->fetch_object()) { |
101 | daniel-mar | 162 | $out[] = 'subordinate: ' . $row2->id . show_asn1_appendix($row2->id); |
163 | } |
||
164 | |||
165 | $out[] = ''; |
||
166 | |||
261 | daniel-mar | 167 | $res2 = OIDplus::db()->query("select * from ###ra where email = ?", array($row->ra_email)); |
236 | daniel-mar | 168 | if ($row2 = $res2->fetch_object()) { |
101 | daniel-mar | 169 | $out[] = 'ra: '.(!empty($row2->ra_name) ? $row2->ra_name : $row2->email); |
125 | daniel-mar | 170 | $out[] = 'ra-status: Information available'; |
101 | daniel-mar | 171 | $out[] = 'ra-name: ' . $row2->ra_name; |
172 | $out[] = 'ra-email: ' . $row->ra_email; |
||
332 | daniel-mar | 173 | $out[] = 'ra-personal-name: ' . $row2->personal_name; // Note: This is currently not in the RFC |
101 | daniel-mar | 174 | $out[] = 'ra-organization: ' . $row2->organization; |
332 | daniel-mar | 175 | $out[] = 'ra-office: ' . $row2->office; // Note: This is currently not in the RFC |
101 | daniel-mar | 176 | if ($row2->privacy && !$show_confidential) { |
332 | daniel-mar | 177 | // TODO: Follow new RFC draft and only return only "ra-address" |
101 | daniel-mar | 178 | $out[] = 'ra-street: ' . (!empty($row2->street) ? '(redacted)' : ''); |
179 | $out[] = 'ra-town: ' . (!empty($row2->zip_town) ? '(redacted)' : ''); |
||
180 | $out[] = 'ra-country: ' . (!empty($row2->country) ? '(redacted)' : ''); |
||
181 | $out[] = 'ra-phone: ' . (!empty($row2->phone) ? '(redacted)' : ''); |
||
182 | $out[] = 'ra-mobile: ' . (!empty($row2->mobile) ? '(redacted)' : ''); |
||
183 | $out[] = 'ra-fax: ' . (!empty($row2->fax) ? '(redacted)' : ''); |
||
184 | } else { |
||
332 | daniel-mar | 185 | // TODO: Follow new RFC draft and only return only "ra-address" |
101 | daniel-mar | 186 | $out[] = 'ra-street: ' . $row2->street; |
330 | daniel-mar | 187 | $out[] = 'ra-town: ' . $row2->zip_town; |
101 | daniel-mar | 188 | $out[] = 'ra-country: ' . $row2->country; |
189 | $out[] = 'ra-phone: ' . $row2->phone; |
||
190 | $out[] = 'ra-mobile: ' . $row2->mobile; |
||
191 | $out[] = 'ra-fax: ' . $row2->fax; |
||
192 | } |
||
322 | daniel-mar | 193 | foreach (OIDplus::getPagePlugins() as $plugin) { |
194 | if ($plugin->implementsFeature('1.3.6.1.4.1.37476.2.5.2.3.4')) { |
||
195 | $plugin->whoisRaAttributes($row->ra_email, $out); |
||
196 | } |
||
197 | } |
||
101 | daniel-mar | 198 | $out[] = 'ra-created: ' . $row2->registered; |
199 | $out[] = 'ra-updated: ' . $row2->updated; |
||
200 | } else { |
||
201 | $out[] = 'ra: '.$row->ra_email; |
||
322 | daniel-mar | 202 | foreach (OIDplus::getPagePlugins() as $plugin) { |
203 | if ($plugin->implementsFeature('1.3.6.1.4.1.37476.2.5.2.3.4')) { |
||
204 | $plugin->whoisRaAttributes($row->ra_email, $out); |
||
205 | } |
||
206 | } |
||
125 | daniel-mar | 207 | $out[] = "ra-status: Information unavailable"; |
101 | daniel-mar | 208 | } |
209 | } |
||
210 | } |
||
211 | |||
212 | // Step 2: Format output |
||
213 | |||
214 | ob_start(); |
||
215 | |||
201 | daniel-mar | 216 | $format = isset($_REQUEST['format']) ? $_REQUEST['format'] : 'txt'; |
101 | daniel-mar | 217 | |
201 | daniel-mar | 218 | if ($format == 'txt') { |
219 | header('Content-Type:text/plain; charset=UTF-8'); |
||
101 | daniel-mar | 220 | |
201 | daniel-mar | 221 | $longest_key = 0; |
222 | foreach ($out as $line) { |
||
223 | $longest_key = max($longest_key, strlen(trim(explode(':',$line,2)[0]))); |
||
101 | daniel-mar | 224 | } |
225 | |||
332 | daniel-mar | 226 | //echo '% ' . str_repeat('*', OIDplus::config()->getValue('webwhois_output_format_max_line_length', 80)-2)."\n"; |
101 | daniel-mar | 227 | |
201 | daniel-mar | 228 | foreach ($out as $line) { |
229 | if (trim($line) == '') { |
||
230 | echo "\n"; |
||
231 | continue; |
||
232 | } |
||
101 | daniel-mar | 233 | |
201 | daniel-mar | 234 | $ary = explode(':', $line, 2); |
101 | daniel-mar | 235 | |
201 | daniel-mar | 236 | $key = trim($ary[0]); |
237 | |||
322 | daniel-mar | 238 | $value = isset($ary[1]) ? trim($ary[1]) : ''; |
261 | daniel-mar | 239 | $value = wordwrap($value, OIDplus::config()->getValue('webwhois_output_format_max_line_length', 80) - $longest_key - strlen(':') - OIDplus::config()->getValue('webwhois_output_format_spacer', 2)); |
240 | $value = str_replace("\n", "\n$key:".str_repeat(' ', $longest_key-strlen($key)) . str_repeat(' ', OIDplus::config()->getValue('webwhois_output_format_spacer', 2)), $value); |
||
201 | daniel-mar | 241 | |
261 | daniel-mar | 242 | echo $key.':' . str_repeat(' ', $longest_key-strlen($key)) . str_repeat(' ', OIDplus::config()->getValue('webwhois_output_format_spacer', 2)) . (!empty($value) ? $value : '.') . "\n"; |
201 | daniel-mar | 243 | } |
244 | |||
332 | daniel-mar | 245 | //echo '% ' . str_repeat('*', OIDplus::config()->getValue('webwhois_output_format_max_line_length', 80)-2)."\n"; |
201 | daniel-mar | 246 | |
247 | $cont = ob_get_contents(); |
||
248 | ob_end_clean(); |
||
249 | |||
250 | echo $cont; |
||
251 | |||
227 | daniel-mar | 252 | if (OIDplus::getPkiStatus(true)) { |
201 | daniel-mar | 253 | $signature = ''; |
239 | daniel-mar | 254 | if (@openssl_sign($cont, $signature, OIDplus::config()->getValue('oidplus_private_key'))) { |
201 | daniel-mar | 255 | $signature = base64_encode($signature); |
332 | daniel-mar | 256 | $signature = wordwrap($signature, 78, "\n", true); |
257 | $signature = "% -----BEGIN RSA SIGNATURE-----\n". |
||
258 | preg_replace('/^/m', '% ', $signature)."\n". |
||
259 | "% -----END RSA SIGNATURE-----\n"; |
||
201 | daniel-mar | 260 | echo $signature; |
261 | } |
||
262 | } |
||
101 | daniel-mar | 263 | } |
264 | |||
201 | daniel-mar | 265 | if ($format == 'json') { |
266 | $ary = array(); |
||
101 | daniel-mar | 267 | |
201 | daniel-mar | 268 | $current_section = array(); |
269 | $ary[] = &$current_section; |
||
101 | daniel-mar | 270 | |
201 | daniel-mar | 271 | foreach ($out as $line) { |
272 | if ($line == '') { |
||
273 | unset($current_section); |
||
274 | $current_section = array(); |
||
275 | $ary[] = &$current_section; |
||
276 | } else { |
||
277 | list($key,$val) = explode(':', $line, 2); |
||
278 | $val = trim($val); |
||
279 | if (!isset($current_section[$key])) { |
||
280 | $current_section[$key] = $val; |
||
281 | } elseif (is_array($current_section[$key])) { |
||
282 | $current_section[$key][] = $val; |
||
283 | } else { |
||
284 | $current_section[$key] = array($current_section[$key], $val); |
||
285 | } |
||
286 | } |
||
287 | } |
||
331 | daniel-mar | 288 | $ary = array( |
289 | // https://code.visualstudio.com/docs/languages/json#_mapping-in-the-json |
||
290 | // Note that this syntax is VS Code-specific and not part of the JSON Schema specification. |
||
291 | //'$schema' => 'https://oidplus.viathinksoft.com/oidplus/plugins/publicPages/100_whois/whois/json_schema.json', |
||
292 | '$schema' => OIDplus::getSystemUrl().'plugins/publicPages/100_whois/whois/json_schema.json', |
||
101 | daniel-mar | 293 | |
331 | daniel-mar | 294 | // 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) |
295 | 'whois' => $ary |
||
296 | ); |
||
297 | |||
227 | daniel-mar | 298 | if (OIDplus::getPkiStatus(true)) { |
201 | daniel-mar | 299 | $cont = json_encode($ary); |
300 | $signature = ''; |
||
239 | daniel-mar | 301 | if (@openssl_sign($cont, $signature, OIDplus::config()->getValue('oidplus_private_key'))) { |
201 | daniel-mar | 302 | $signature = base64_encode($signature); |
303 | $ary['signature'] = array('content' => $cont, 'signature' => $signature); |
||
304 | } |
||
305 | } |
||
306 | header('Content-Type:application/json; charset=UTF-8'); |
||
307 | echo json_encode($ary); |
||
308 | } |
||
101 | daniel-mar | 309 | |
201 | daniel-mar | 310 | if ($format == 'xml') { |
311 | $xml = '<whois><section>'; |
||
312 | foreach ($out as $line) { |
||
313 | if ($line == '') { |
||
314 | $xml .= '</section><section>'; |
||
315 | } else { |
||
316 | list($key,$val) = explode(':', $line, 2); |
||
317 | $val = trim($val); |
||
318 | $xml .= "<$key>".htmlspecialchars($val)."</$key>"; |
||
319 | } |
||
320 | } |
||
321 | $xml .= '</section></whois>'; |
||
101 | daniel-mar | 322 | |
227 | daniel-mar | 323 | if (OIDplus::getPkiStatus(true)) { |
201 | daniel-mar | 324 | $cont = $xml; |
325 | $signature = ''; |
||
239 | daniel-mar | 326 | if (@openssl_sign($cont, $signature, OIDplus::config()->getValue('oidplus_private_key'))) { |
201 | daniel-mar | 327 | $signature = base64_encode($signature); |
328 | $xml .= "<signature><content>".htmlspecialchars($cont)."</content><signature>".htmlspecialchars($signature)."</signature></signature>"; |
||
329 | } |
||
101 | daniel-mar | 330 | } |
201 | daniel-mar | 331 | |
332 | header('Content-Type:application/xml; charset=UTF-8'); |
||
333 | echo '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>'; |
||
330 | daniel-mar | 334 | echo '<root xmlns="https://oidplus.viathinksoft.com"'; |
335 | echo ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'; |
||
331 | daniel-mar | 336 | //echo ' xsi:schemaLocation="https://oidplus.viathinksoft.com/oidplus/plugins/publicPages/100_whois/whois/xml_schema.xsd">'; |
337 | echo ' xsi:schemaLocation="'.OIDplus::getSystemUrl().'plugins/publicPages/100_whois/whois/xml_schema.xsd">'; |
||
330 | daniel-mar | 338 | echo $xml; |
339 | echo '</root>'; |
||
101 | daniel-mar | 340 | } |
341 | |||
342 | # --- |
||
343 | |||
344 | function show_asn1_appendix($id) { |
||
345 | if (substr($id,0,4) === 'oid:') { |
||
346 | $appendix_asn1ids = array(); |
||
261 | daniel-mar | 347 | $res3 = OIDplus::db()->query("select * from ###asn1id where oid = ?", array($id)); |
236 | daniel-mar | 348 | while ($row3 = $res3->fetch_object()) { |
101 | daniel-mar | 349 | $appendix_asn1ids[] = $row3->name; |
350 | } |
||
351 | |||
352 | $appendix = implode(', ', $appendix_asn1ids); |
||
353 | if (!empty($appendix)) $appendix = " ($appendix)"; |
||
354 | } else { |
||
355 | $appendix = ''; |
||
356 | } |
||
357 | return $appendix; |
||
358 | } |
||
359 | |||
360 | function is_root($id) { |
||
361 | return empty(explode(':',$id,2)[1]); |
||
362 | } |