Subversion Repositories oidplus

Rev

Rev 360 | Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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.  
  24. originHeaders();
  25.  
  26. // Step 0: Get request parameter
  27.  
  28. if (php_sapi_name() == 'cli') {
  29.         if ($_SERVER['argc'] != 2) {
  30.                 echo _L('Syntax').': '.$_SERVER['argv'][0].' <query>'."\n";
  31.                 exit(2);
  32.         }
  33.         $query = $_SERVER['argv'][1];
  34. } else {
  35.         if (!isset($_REQUEST['query'])) {
  36.                 http_response_code(400);
  37.                 die('<h1>'._L('Error').'</h1><p>'._L('Argument "%1" is missing','query').'<p>');
  38.         }
  39.         $query = $_REQUEST['query'];
  40. }
  41.  
  42. $authTokens = explode('$', $query);
  43. $query = array_shift($authTokens);
  44.  
  45. $authToken = trim(OIDplus::config()->getValue('whois_auth_token'));
  46. if (empty($authToken)) $authToken = false;
  47.  
  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
  72.         $res = OIDplus::db()->query("select * from ###objects where id = ?", array($obj->nodeId()));
  73.         if ($res->num_rows() > 0) {
  74.                 $found = true;
  75.                 $distance = 0;
  76.         } else {
  77.                 $found = false;
  78.                 $objParent = OIDplusObject::parse($query)->getParent();
  79.                 if ($objParent) {
  80.                         $res = OIDplus::db()->query("select * from ###objects where id = ?", array($objParent->nodeId()));
  81.                         $distance = $objParent->distance($query);
  82.                         assert($res->num_rows() > 0);
  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"; // DO NOT TRANSLATE!
  94.                 $out[] = "distance: $distance"; // DO NOT TRANSLATE
  95.                 $continue = true;
  96.         } else {
  97.                 $out[] = "result: Not found"; // DO NOT TRANSLATE!
  98.                 $continue = false;
  99.         }
  100. } else {
  101.         $out[] = "result: Found"; // DO NOT TRANSLATE!
  102.         $continue = true;
  103. }
  104.  
  105. if ($continue) {
  106.         $out[] = "";
  107.         $out[] = "object: $query"; // DO NOT TRANSLATE!
  108.         if ($obj->isConfidential() && !$show_confidential) {
  109.                 $out[] = "status: Information unavailable"; // DO NOT TRANSLATE!
  110.                 $out[] = "attribute: confidential"; // DO NOT TRANSLATE!
  111.         } else {
  112.                 $out[] = "status: Information available"; // DO NOT TRANSLATE!
  113.  
  114.                 $row = $res->fetch_object();
  115.                 assert($row);
  116.                 $obj = OIDplusObject::parse($row->id);
  117.  
  118.                 $out[] = 'name: ' . $row->title; // DO NOT TRANSLATE!
  119.  
  120.                 $cont = $row->description;
  121.                 $cont = preg_replace('@<a[^>]+href\s*=\s*["\']([^\'"]+)["\'][^>]*>(.+)<\s*/\s*a\s*>@ismU', '\2 (\1)', $cont);
  122.                 $cont = preg_replace('@<br.*>@', "\n", $cont);
  123.                 $cont = preg_replace('@\\n+@', "\n", $cont);
  124.                 $out[] = 'description: ' . trim(html_entity_decode(strip_tags($cont))); // DO NOT TRANSLATE!
  125.  
  126.                 if (substr($query,0,4) === 'oid:') {
  127.                         $out[] = 'asn1-notation: ' . $obj->getAsn1Notation(false); // DO NOT TRANSLATE!
  128.                         $out[] = 'iri-notation: ' . $obj->getIriNotation(false); // DO NOT TRANSLATE!
  129.  
  130.                         $res2 = OIDplus::db()->query("select * from ###asn1id where oid = ?", array($row->id));
  131.                         while ($row2 = $res2->fetch_object()) {
  132.                                 $out[] = 'identifier: ' . $row2->name; // DO NOT TRANSLATE!
  133.                         }
  134.  
  135.                         $res2 = OIDplus::db()->query("select * from ###asn1id where standardized = ? and oid = ?", array(true, $row->id));
  136.                         while ($row2 = $res2->fetch_object()) {
  137.                                 $out[] = 'standardized-id: ' . $row2->name; // DO NOT TRANSLATE!
  138.                         }
  139.  
  140.                         $res2 = OIDplus::db()->query("select * from ###iri where oid = ?", array($row->id));
  141.                         while ($row2 = $res2->fetch_object()) {
  142.                                 $out[] = 'unicode-label: ' . $row2->name; // DO NOT TRANSLATE!
  143.                         }
  144.  
  145.                         $res2 = OIDplus::db()->query("select * from ###iri where longarc = ? and oid = ?", array(true, $row->id));
  146.                         while ($row2 = $res2->fetch_object()) {
  147.                                 $out[] = 'long-arc: ' . $row2->name; // DO NOT TRANSLATE!
  148.                         }
  149.                 }
  150.  
  151.                 // TODO: Field "attribute: confidential" if OID is hidden
  152.  
  153.                 foreach (OIDplus::getPagePlugins() as $plugin) {
  154.                         if ($plugin->implementsFeature('1.3.6.1.4.1.37476.2.5.2.3.4')) {
  155.                                 $plugin->whoisObjectAttributes($row->id, $out);
  156.                         }
  157.                 }
  158.  
  159.                 if (!empty($row->parent) && (!is_root($row->parent))) {
  160.                         $out[] = 'parent: ' . $row->parent . show_asn1_appendix($row->parent); // DO NOT TRANSLATE!
  161.                 }
  162.  
  163.                 $res2 = OIDplus::db()->query("select * from ###objects where parent = ? order by ".OIDplus::db()->natOrder('id'), array($row->id));
  164.                 if ($res2->num_rows() == 0) {
  165.                         // $out[] = 'subordinate: (none)';
  166.                 }
  167.                 while ($row2 = $res2->fetch_object()) {
  168.                         $out[] = 'subordinate: ' . $row2->id . show_asn1_appendix($row2->id); // DO NOT TRANSLATE!
  169.                 }
  170.  
  171.                 $out[] = 'created: ' . $row->created; // DO NOT TRANSLATE!
  172.                 $out[] = 'updated: ' . $row->updated; // DO NOT TRANSLATE!
  173.  
  174.                 $out[] = '';
  175.  
  176.                 $res2 = OIDplus::db()->query("select * from ###ra where email = ?", array($row->ra_email));
  177.                 if ($row2 = $res2->fetch_object()) {
  178.                         $out[] = 'ra: '.(!empty($row2->ra_name) ? $row2->ra_name : (!empty($row2->email) ? $row2->email : _L('Unknown'))); // DO NOT TRANSLATE!
  179.                         $out[] = 'ra-status: Information available'; // DO NOT TRANSLATE!
  180.  
  181.                         $tmp = array();
  182.                         if (!empty($row2->office)) $tmp[] = $row2->office;
  183.                         if (!empty($row2->organization)) $tmp[] = $row2->organization;
  184.                         $tmp = implode(', ', $tmp);
  185.  
  186.                         $out[] = 'ra-contact-name: ' . $row2->personal_name.(!empty($tmp) ? " ($tmp)" : ''); // DO NOT TRANSLATE!
  187.                         if ($row2->privacy && !$show_confidential) {
  188.                                 if (!empty($row2->street) || !empty($row2->zip_town) || !empty($row2->country)) {
  189.                                         $out[] = 'ra-address: '._L('(redacted)'); // DO NOT TRANSLATE!
  190.                                 }
  191.                                 $out[] = 'ra-phone: ' . (!empty($row2->phone) ? _L('(redacted)') : ''); // DO NOT TRANSLATE!
  192.                                 $out[] = 'ra-mobile: ' . (!empty($row2->mobile) ? _L('(redacted)') : ''); // DO NOT TRANSLATE!
  193.                                 $out[] = 'ra-fax: ' . (!empty($row2->fax) ? _L('(redacted)') : ''); // DO NOT TRANSLATE!
  194.                         } else {
  195.                                 if (!empty($row2->street))   $out[] = 'ra-address: ' . $row2->street; // DO NOT TRANSLATE!
  196.                                 if (!empty($row2->zip_town)) $out[] = 'ra-address: ' . $row2->zip_town; // DO NOT TRANSLATE!
  197.                                 if (!empty($row2->country))  $out[] = 'ra-address: ' . $row2->country; // DO NOT TRANSLATE!
  198.                                 $out[] = 'ra-phone: ' . $row2->phone; // DO NOT TRANSLATE!
  199.                                 $out[] = 'ra-mobile: ' . $row2->mobile; // DO NOT TRANSLATE!
  200.                                 $out[] = 'ra-fax: ' . $row2->fax; // DO NOT TRANSLATE!
  201.                         }
  202.                         $out[] = 'ra-email: ' . $row->ra_email; // DO NOT TRANSLATE!
  203.                         foreach (OIDplus::getPagePlugins() as $plugin) {
  204.                                 if ($plugin->implementsFeature('1.3.6.1.4.1.37476.2.5.2.3.4')) {
  205.                                         $plugin->whoisRaAttributes($row->ra_email, $out);
  206.                                 }
  207.                         }
  208.                         $out[] = 'ra-created: ' . $row2->registered; // DO NOT TRANSLATE!
  209.                         $out[] = 'ra-updated: ' . $row2->updated; // DO NOT TRANSLATE!
  210.                 } else {
  211.                         $out[] = 'ra: '.(!empty($row->ra_email) ? $row->ra_email : _L('Unknown')); // DO NOT TRANSLATE!
  212.                         foreach (OIDplus::getPagePlugins() as $plugin) {
  213.                                 if ($plugin->implementsFeature('1.3.6.1.4.1.37476.2.5.2.3.4')) {
  214.                                         $plugin->whoisRaAttributes($row->ra_email, $out);
  215.                                 }
  216.                         }
  217.                         $out[] = "ra-status: Information unavailable"; // DO NOT TRANSLATE!
  218.                 }
  219.         }
  220. }
  221.  
  222. // Step 2: Format output
  223.  
  224. ob_start();
  225.  
  226. $format = isset($_REQUEST['format']) ? $_REQUEST['format'] : 'txt';
  227.  
  228. if ($format == 'txt') {
  229.         header('Content-Type:text/plain; charset=UTF-8');
  230.  
  231.         $longest_key = 0;
  232.         foreach ($out as $line) {
  233.                 $longest_key = max($longest_key, strlen(trim(explode(':',$line,2)[0])));
  234.         }
  235.  
  236.         //echo '% ' . str_repeat('*', OIDplus::config()->getValue('webwhois_output_format_max_line_length', 80)-2)."\n";
  237.  
  238.         foreach ($out as $line) {
  239.                 if (trim($line) == '') {
  240.                         echo "\n";
  241.                         continue;
  242.                 }
  243.  
  244.                 $ary = explode(':', $line, 2);
  245.  
  246.                 $key = trim($ary[0]);
  247.  
  248.                 $value = isset($ary[1]) ? trim($ary[1]) : '';
  249.                 $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));
  250.                 $value = str_replace("\n", "\n$key:".str_repeat(' ', $longest_key-strlen($key)) . str_repeat(' ', OIDplus::config()->getValue('webwhois_output_format_spacer', 2)), $value);
  251.  
  252.                 if (!empty($value)) {
  253.                         echo $key.':' . str_repeat(' ', $longest_key-strlen($key)) . str_repeat(' ', OIDplus::config()->getValue('webwhois_output_format_spacer', 2)) . $value . "\n";
  254.                 }
  255.         }
  256.  
  257.         //echo '% ' . str_repeat('*', OIDplus::config()->getValue('webwhois_output_format_max_line_length', 80)-2)."\n";
  258.  
  259.         $cont = ob_get_contents();
  260.         ob_end_clean();
  261.  
  262.         echo $cont;
  263.  
  264.         if (OIDplus::getPkiStatus(true)) {
  265.                 $signature = '';
  266.                 if (@openssl_sign($cont, $signature, OIDplus::config()->getValue('oidplus_private_key'))) {
  267.                         $signature = base64_encode($signature);
  268.                         $signature = mb_wordwrap($signature, OIDplus::config()->getValue('webwhois_output_format_max_line_length', 80) - strlen('% '), "\n", true);
  269.                         $signature = "% -----BEGIN RSA SIGNATURE-----\n".
  270.                                      preg_replace('/^/m', '% ', $signature)."\n".
  271.                                      "% -----END RSA SIGNATURE-----\n";
  272.                         echo $signature;
  273.                 }
  274.         }
  275. }
  276.  
  277. if ($format == 'json') {
  278.         $ary = array();
  279.  
  280.         $current_section = array();
  281.         $ary[] = &$current_section;
  282.  
  283.         foreach ($out as $line) {
  284.                 if ($line == '') {
  285.                         unset($current_section);
  286.                         $current_section = array();
  287.                         $ary[] = &$current_section;
  288.                 } else {
  289.                         list($key,$val) = explode(':', $line, 2);
  290.                         $val = trim($val);
  291.                         if (!empty($val)) {
  292.                                 if (!isset($current_section[$key])) {
  293.                                         $current_section[$key] = $val;
  294.                                 } elseif (is_array($current_section[$key])) {
  295.                                         $current_section[$key][] = $val;
  296.                                 } else {
  297.                                         $current_section[$key] = array($current_section[$key], $val);
  298.                                 }
  299.                         }
  300.                 }
  301.         }
  302.         $ary = array(
  303.                 // https://code.visualstudio.com/docs/languages/json#_mapping-in-the-json
  304.                 // Note that this syntax is VS Code-specific and not part of the JSON Schema specification.
  305.                 //'$schema' => 'https://oidplus.viathinksoft.com/oidplus/plugins/publicPages/100_whois/whois/json_schema.json',
  306.                 '$schema' => OIDplus::getSystemUrl().'plugins/publicPages/100_whois/whois/json_schema.json',
  307.  
  308.                 // 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)
  309.                 'whois' => $ary
  310.         );
  311.  
  312.         if (OIDplus::getPkiStatus(true)) {
  313.                 $cont = json_encode($ary);
  314.                 $signature = '';
  315.                 if (@openssl_sign($cont, $signature, OIDplus::config()->getValue('oidplus_private_key'))) {
  316.                         $signature = base64_encode($signature);
  317.                         $ary['signature'] = array('content' => $cont, 'signature' => $signature);
  318.                 }
  319.         }
  320.  
  321.         // Good JSON schema validator here: https://www.jsonschemavalidator.net
  322.         header('Content-Type:application/json; charset=UTF-8');
  323.         echo json_encode($ary);
  324. }
  325.  
  326. if ($format == 'xml') {
  327.         $xml = '<whois><section>';
  328.         foreach ($out as $line) {
  329.                 if ($line == '') {
  330.                         $xml .= '</section><section>';
  331.                 } else {
  332.                         list($key,$val) = explode(':', $line, 2);
  333.                         $val = trim($val);
  334.                         if (!empty($val)) {
  335.                                 $xml .= "<$key>".htmlspecialchars($val)."</$key>";
  336.                         }
  337.                 }
  338.         }
  339.         $xml .= '</section></whois>';
  340.  
  341.         $xml = preg_replace('@<section><(.+)>(.+)</section>@ismU', '<\\1Section><\\1>\\2</\\1Section>', $xml);
  342.  
  343.         if (OIDplus::getPkiStatus(true)) {
  344.                 $cont = $xml;
  345.                 $signature = '';
  346.                 if (@openssl_sign($cont, $signature, OIDplus::config()->getValue('oidplus_private_key'))) {
  347.                         $signature = base64_encode($signature);
  348.                         $xml .= "<signature><content>".htmlspecialchars($cont)."</content><signature>".htmlspecialchars($signature)."</signature></signature>";
  349.                 }
  350.         }
  351.  
  352.         // Good XSD validator here: https://www.liquid-technologies.com/online-xsd-validator
  353.         header('Content-Type:application/xml; charset=UTF-8');
  354.         echo '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>';
  355.         echo '<root xmlns="urn:oid:1.3.6.1.4.1.37476.2.5.2.5.1.1"';
  356.         echo '      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"';
  357.         //echo '      xsi:schemaLocation="urn:oid:1.3.6.1.4.1.37476.2.5.2.5.1.1 https://oidplus.viathinksoft.com/oidplus/plugins/publicPages/100_whois/whois/xml_schema.xsd">';
  358.         echo '      xsi:schemaLocation="urn:oid:1.3.6.1.4.1.37476.2.5.2.5.1.1 '.OIDplus::getSystemUrl().'plugins/publicPages/100_whois/whois/xml_schema.xsd">';
  359.         echo $xml;
  360.         echo '</root>';
  361. }
  362.  
  363. # ---
  364.  
  365. function show_asn1_appendix($id) {
  366.         if (substr($id,0,4) === 'oid:') {
  367.                 $appendix_asn1ids = array();
  368.                 $res3 = OIDplus::db()->query("select * from ###asn1id where oid = ?", array($id));
  369.                 while ($row3 = $res3->fetch_object()) {
  370.                         $appendix_asn1ids[] = $row3->name;
  371.                 }
  372.  
  373.                 $appendix = implode(', ', $appendix_asn1ids);
  374.                 if (!empty($appendix)) $appendix = " ($appendix)";
  375.         } else {
  376.                 $appendix = '';
  377.         }
  378.         return $appendix;
  379. }
  380.  
  381. function is_root($id) {
  382.         return empty(explode(':',$id,2)[1]);
  383. }