Subversion Repositories oidplus

Rev

Rev 224 | 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. if (!defined('IN_OIDPLUS')) die();
  21.  
  22. require_once __DIR__ . '/WeidOidConverter.class.php';
  23.  
  24. class OIDplusObjectTypePluginOid extends OIDplusObjectTypePlugin {
  25.  
  26.         public static function getPluginInformation() {
  27.                 $out = array();
  28.                 $out['name'] = 'Object Identifier (OID)';
  29.                 $out['author'] = 'ViaThinkSoft';
  30.                 $out['version'] = null;
  31.                 $out['descriptionHTML'] = null;
  32.                 return $out;
  33.         }
  34.  
  35.         public static function getObjectTypeClassName() {
  36.                 return 'OIDplusOid';
  37.         }
  38.  
  39. }
  40.  
  41. class OIDplusOid extends OIDplusObject {
  42.         private $oid;
  43.  
  44.         public function __construct($oid) {
  45.                 $bak_oid = $oid;
  46.  
  47.                 $oid = sanitizeOID($oid, 'auto');
  48.                 if ($oid === false) {
  49.                         throw new Exception("Invalid OID '$bak_oid'");
  50.                 }
  51.  
  52.                 if (($oid != '') && (!oid_valid_dotnotation($oid, false, true, 0))) {
  53.                         // avoid OIDs like 3.0
  54.                         throw new Exception("Invalid OID '$bak_oid'");
  55.                 }
  56.  
  57.                 $this->oid = $oid;
  58.         }
  59.  
  60.         public static function parse($node_id) {
  61.                 @list($namespace, $oid) = explode(':', $node_id, 2);
  62.                 if ($namespace !== 'oid') return false;
  63.                 return new self($oid);
  64.         }
  65.  
  66.         public static function objectTypeTitle() {
  67.                 return "Object Identifier (OID)";
  68.         }
  69.  
  70.         public static function objectTypeTitleShort() {
  71.                 return "OID";
  72.         }
  73.  
  74.         public static function ns() {
  75.                 return 'oid';
  76.         }
  77.  
  78.         public static function root() {
  79.                 return 'oid:';
  80.         }
  81.  
  82.         public function isRoot() {
  83.                 return $this->oid == '';
  84.         }
  85.  
  86.         public function nodeId() {
  87.                 return 'oid:'.$this->oid;
  88.         }
  89.  
  90.         public function addString($str) {
  91.                 if (!$this->isRoot()) {
  92.                         if (strpos($str,'.') !== false) throw new Exception("Please only submit one arc (not an absolute OID or multiple arcs).");
  93.                 }
  94.  
  95.                 return $this->appendArcs($str)->nodeId();
  96.         }
  97.  
  98.         public function crudShowId(OIDplusObject $parent) {
  99.                 return $this->deltaDotNotation($parent);
  100.         }
  101.  
  102.         public function crudInsertPrefix() {
  103.                 return '';
  104.         }
  105.  
  106.         public function jsTreeNodeName(OIDplusObject $parent = null) {
  107.                 if ($parent == null) return $this->objectTypeTitle();
  108.                 return $this->viewGetArcAsn1s($parent);
  109.         }
  110.  
  111.         public function defaultTitle() {
  112.                 return 'OID ' . $this->oid;
  113.         }
  114.  
  115.         public function isLeafNode() {
  116.                 return false;
  117.         }
  118.  
  119.         public function getContentPage(&$title, &$content, &$icon) {
  120.                 $icon = file_exists(__DIR__.'/icon_big.png') ? 'plugins/objectTypes/'.basename(__DIR__).'/icon_big.png' : '';
  121.  
  122.                 if ($this->isRoot()) {
  123.                         $title = OIDplusOid::objectTypeTitle();
  124.  
  125.                         $res = OIDplus::db()->query("select id from ".OIDPLUS_TABLENAME_PREFIX."objects where parent = ?", array(self::root()));
  126.                         if (OIDplus::db()->num_rows($res) > 0) {
  127.                                 $content = 'Please select an OID in the tree view at the left to show its contents.';
  128.                         } else {
  129.                                 $content = 'Currently, no OID is registered in the system.';
  130.                         }
  131.  
  132.                         if (!$this->isLeafNode()) {
  133.                                 if (OIDplus::authUtils()::isAdminLoggedIn()) {
  134.                                         $content .= '<h2>Manage your root OIDs</h2>';
  135.                                 } else {
  136.                                         $content .= '<h2>Root OIDs</h2>';
  137.                                 }
  138.                                 $content .= '%%CRUD%%';
  139.                         }
  140.                 } else {
  141.                         $title = $this->getTitle();
  142.  
  143.                         $content = "<h2>Technical information</h2>".$this->oidInformation().
  144.                                    "<h2>Description</h2>%%DESC%%".
  145.                                    "<h2>Registration Authority</h2>%%RA_INFO%%";
  146.  
  147.                         if (!$this->isLeafNode()) {
  148.                                 if ($this->userHasWriteRights()) {
  149.                                         $content .= '<h2>Create or change subsequent objects</h2>';
  150.                                 } else {
  151.                                         $content .= '<h2>Subsequent objects</h2>';
  152.                                 }
  153.                                 $content .= '%%CRUD%%';
  154.                         }
  155.                 }
  156.         }
  157.  
  158.         # ---
  159.  
  160.         public function isWeid($allow_root) {
  161.                 $weid = WeidOidConverter::oid2weid($this->getDotNotation());
  162.                 if (!$allow_root && ($weid === 'weid:4')) return false;
  163.                 return $weid !== false;
  164.         }
  165.  
  166.         public function weidArc() {
  167.                 $weid = WeidOidConverter::oid2weid($this->getDotNotation());
  168.                 if ($weid === false) return false;
  169.                 list($ns,$weid) = explode(':', $weid, 2);
  170.                 $x = explode('-', $weid);
  171.                 if (count($x) < 2) return ''; // WEID root arc. Has no name
  172.                 return $x[count($x)-2];
  173.         }
  174.  
  175.         public function getWeidNotation($withAbbr=true) {
  176.                 $weid = WeidOidConverter::oid2weid($this->getDotNotation());
  177.                 if ($withAbbr) {
  178.                         list($ns,$weid) = explode(':', $weid);
  179.                         $weid_arcs = explode('-', $weid);
  180.                         foreach ($weid_arcs as $i => &$weid) {
  181.                                 if ($i == count($weid_arcs)-1) {
  182.                                         $weid = '<abbr title="weLuhn check digit">'.$weid.'</abbr>';
  183.                                 } else {
  184.                                         $oid_arcs = explode('.',$this->oid);
  185.                                         $weid_num = $oid_arcs[(count($oid_arcs)-1)-(count($weid_arcs)-1)+($i+1)];
  186.                                         if ($weid_num != $weid) {
  187.                                                 $weid = '<abbr title="Numeric value: '.$weid_num.'">'.$weid.'</abbr>';
  188.                                         }
  189.                                 }
  190.                         }
  191.                         $weid = '<abbr title="Root arc: 1.3.6.1.4.1.37553.8">' . $ns . '</abbr>:' . implode('-',$weid_arcs);
  192.                 }
  193.                 return $weid;
  194.         }
  195.  
  196.         private function oidInformation() {
  197.                 $out = array();
  198.                 $out[] = "Dot notation: <code>" . $this->getDotNotation() . "</code>";
  199.                 $out[] = "ASN.1 notation: <code>{ " . $this->getAsn1Notation() . " }</code>";
  200.                 $out[] = "OID-IRI notation: <code>" . $this->getIriNotation() . "</code>";
  201.                 if ($this->isWeid(true)) {
  202.                         $out[] = "WEID notation: <code>" . $this->getWeidNotation() . "</code>";
  203.                 }
  204.                 return '<p>'.implode('<br>',$out).'</p>';
  205.         }
  206.  
  207.         public function __clone() {
  208.                 return new self($this->oid);
  209.         }
  210.  
  211.         public function appendArcs(String $arcs) {
  212.                 $out = clone $this;
  213.  
  214.                 if ($out->isRoot()) {
  215.                         $out->oid .= $arcs;
  216.                 } else {
  217.                         $out->oid .= '.' . $arcs;
  218.                 }
  219.  
  220.                 $bak_oid = $out->oid;
  221.                 $out->oid = sanitizeOID($out->oid);
  222.                 if ($out->oid === false) throw new Exception("$bak_oid is not a valid OID!");
  223.  
  224.                 return $out;
  225.         }
  226.  
  227.         public function deltaDotNotation(OIDplusOid $parent) {
  228.                 if (!$parent->isRoot()) {
  229.                         if (substr($this->oid, 0, strlen($parent->oid)+1) == $parent->oid.'.') {
  230.                                 return substr($this->oid, strlen($parent->oid)+1);
  231.                         } else {
  232.                                 return false;
  233.                         }
  234.                 } else {
  235.                         return $this->oid;
  236.                 }
  237.         }
  238.  
  239.         public function viewGetArcAsn1s(OIDplusOid $parent=null, $separator = ' | ') {
  240.                 $asn_ids = array();
  241.  
  242.                 if (is_null($parent)) $parent = OIDplusOid::parse('oid:');
  243.  
  244.                 $part = $this->deltaDotNotation($parent);
  245.  
  246.                 if (strpos($part, '.') === false) {
  247.                         $res2 = OIDplus::db()->query("select name from ".OIDPLUS_TABLENAME_PREFIX."asn1id where oid = ? order by lfd", array("oid:".$this->oid));
  248.                         while ($row2 = OIDplus::db()->fetch_array($res2)) {
  249.                                 $asn_ids[] = $row2['name'].'('.$part.')';
  250.                         }
  251.                 }
  252.  
  253.                 if (count($asn_ids) == 0) $asn_ids = array($part);
  254.                 return implode($asn_ids, $separator);
  255.         }
  256.  
  257.         public function getAsn1Notation($withAbbr=true) {
  258.                 $asn1_notation = '';
  259.                 $arcs = explode('.', $this->oid);
  260.  
  261.                 foreach ($arcs as $arc) {
  262.                         $res = OIDplus::db()->query("select name, standardized from ".OIDPLUS_TABLENAME_PREFIX."asn1id where oid = ? order by lfd", array('oid:'.implode('.',$arcs)));
  263.  
  264.                         $names = array();
  265.                         while ($row = OIDplus::db()->fetch_array($res)) {
  266.                                 $names[] = $row['name']."(".end($arcs).")";
  267.                                 if ($row['standardized']) {
  268.                                         $names[] = $row['name'];
  269.                                 }
  270.                         }
  271.  
  272.                         $numeric = array_pop($arcs);
  273.                         if (count($names) > 1) {
  274.                                 $first_name = array_shift($names);
  275.                                 $abbr = 'Other identifiers:&#10;      '.implode('&#10;      ',$names);
  276.                                 if ($withAbbr) {
  277.                                         $asn1_notation = '<abbr title="'.$abbr.'">'.$first_name.'</abbr> '.$asn1_notation;
  278.                                 } else {
  279.                                         $asn1_notation = $first_name.' '.$asn1_notation;
  280.                                 }
  281.                         } else if (count($names) == 1) {
  282.                                 $asn1_notation = array_shift($names).' '.$asn1_notation;
  283.                         } else {
  284.                                 $asn1_notation = $numeric.' '.$asn1_notation;
  285.                         }
  286.                 }
  287.  
  288.                 return $asn1_notation;
  289.         }
  290.  
  291.         public function getIriNotation($withAbbr=true) {
  292.                 $iri_notation = '';
  293.                 $arcs = explode('.', $this->oid);
  294.  
  295.                 foreach ($arcs as $arc) {
  296.                         $res = OIDplus::db()->query("select name, longarc from ".OIDPLUS_TABLENAME_PREFIX."iri where oid = ? order by lfd", array('oid:'.implode('.',$arcs)));
  297.  
  298.                         $is_longarc = false;
  299.                         $names = array();
  300.                         while ($row = OIDplus::db()->fetch_array($res)) {
  301.                                 $is_longarc = $row['longarc'];
  302.                                 $names[] = $row['name'];
  303.  
  304.                                 if ($is_longarc) {
  305.                                         $names[] = 'Joint-ISO-ITU-T/'.$row['name']; // Long arcs can only be inside root OID 2
  306.                                 }
  307.                         }
  308.  
  309.                         $names[] = array_pop($arcs);
  310.                         if (count($names) > 2) {
  311.                                 $first_name = array_shift($names);
  312.                                 $numeric = array_pop($names);
  313.                                 $abbr = 'Other identifiers:&#10;      '.implode('&#10;      ',$names).'&#10;Numeric value: '.$numeric;
  314.                                 $iri_notation = $withAbbr ? '<abbr title="'.$abbr.'">'.$first_name.'</abbr>/'.$iri_notation : $first_name.'/'.$iri_notation;
  315.                         } else if (count($names) > 1) {
  316.                                 $first_name = array_shift($names);
  317.                                 $abbr = 'Numeric value: '.array_shift($names);
  318.                                 $iri_notation = $withAbbr ? '<abbr title="'.$abbr.'">'.$first_name.'</abbr>/'.$iri_notation : $first_name.'/'.$iri_notation;
  319.                         } else if (count($names) == 1) {
  320.                                 $iri_notation = array_shift($names) . '/' . $iri_notation;
  321.                         }
  322.  
  323.                         if ($is_longarc) break; // we don't write /ITU-T/ at the beginning, when /ITU-T/xxx is a long arc
  324.                 }
  325.                 $iri_notation = '/' . substr($iri_notation, 0, strlen($iri_notation)-1);
  326.  
  327.                 return $iri_notation;
  328.         }
  329.  
  330.         public function getDotNotation() {
  331.                 return $this->oid;
  332.         }
  333.  
  334.         public function isWellKnown() {
  335.                 $res = OIDplus::db()->query("select oid from ".OIDPLUS_TABLENAME_PREFIX."asn1id where oid = ? and well_known = 1", array("oid:".$this->oid));
  336.                 if (OIDplus::db()->num_rows($res) > 0) return true;
  337.  
  338.                 $res = OIDplus::db()->query("select oid from ".OIDPLUS_TABLENAME_PREFIX."iri where oid = ? and well_known = 1", array("oid:".$this->oid));
  339.                 if (OIDplus::db()->num_rows($res) > 0) return true;
  340.  
  341.                 return false;
  342.         }
  343.  
  344.         public function replaceAsn1Ids($demandedASN1s=array(), $simulate=false) {
  345.                 if ($this->isWellKnown()) {
  346.                         throw new Exception("OID ".$this->oid." is a 'well-known' OID. Its identifiers cannot be changed.");
  347.                 }
  348.  
  349.                 // First do a few checks
  350.                 foreach ($demandedASN1s as &$asn1) {
  351.                         $asn1 = trim($asn1);
  352.  
  353.                         // Validate identifier
  354.                         if (!oid_id_is_valid($asn1)) throw new Exception("'$asn1' is not a valid ASN.1 identifier!");
  355.  
  356.                         // Check if the (real) parent has any conflict
  357.                         // Unlike IRI identifiers, ASN.1 identifiers may be used multiple times (not recommended), except if one of them is standardized
  358.                         $res = OIDplus::db()->query("select oid from ".OIDPLUS_TABLENAME_PREFIX."asn1id where name = ? and standardized = 1", array($asn1));
  359.                         while ($row = OIDplus::db()->fetch_array($res)) {
  360.                                 $check_oid = OIDplusOid::parse($row['oid'])->oid;
  361.                                 if ((oid_up($check_oid) === oid_up($this->oid)) && // same parent
  362.                                    ($check_oid !== $this->oid))                    // different OID
  363.                                 {
  364.                                         throw new Exception("ASN.1 identifier '$asn1' is a standardized identifier belonging to OID ($check_oid)");
  365.                                 }
  366.                         }
  367.                 }
  368.  
  369.                 // Now do the real replacement
  370.                 if (!$simulate) {
  371.                         OIDplus::db()->query("delete from ".OIDPLUS_TABLENAME_PREFIX."asn1id where oid = ?", array("oid:".$this->oid));
  372.                         foreach ($demandedASN1s as &$asn1) {
  373.                                 if (!OIDplus::db()->query("insert into ".OIDPLUS_TABLENAME_PREFIX."asn1id (oid, name) values (?, ?)", array("oid:".$this->oid, $asn1))) {
  374.                                         throw new Exception("Insertion of ASN.1 ID $asn1 to OID ".$this->oid." failed!");
  375.                                 }
  376.                         }
  377.                 }
  378.         }
  379.  
  380.         public function replaceIris($demandedIris=array(), $simulate=false) {
  381.                 if ($this->isWellKnown()) {
  382.                         throw new Exception("OID ".$this->oid." is a 'well-known' OID. Its identifiers cannot be changed.");
  383.                 }
  384.  
  385.                 // First do a few checks
  386.                 foreach ($demandedIris as &$iri) {
  387.                         $iri = trim($iri);
  388.  
  389.                         // Validate identifier
  390.                         if (!iri_arc_valid($iri, false)) throw new Exception("'$iri' is not a valid IRI!");
  391.  
  392.                         // Check if the (real) parent has any conflict
  393.                         $res = OIDplus::db()->query("select oid from ".OIDPLUS_TABLENAME_PREFIX."iri where name = ?", array($iri));
  394.                         while ($row = OIDplus::db()->fetch_array($res)) {
  395.                                 $check_oid = OIDplusOid::parse($row['oid'])->oid;
  396.                                 if ((oid_up($check_oid) === oid_up($this->oid)) && // same parent
  397.                                    ($check_oid !== $this->oid))                    // different OID
  398.                                 {
  399.                                         throw new Exception("IRI '$iri' is already used by another OID ($check_oid)");
  400.                                 }
  401.                         }
  402.                 }
  403.  
  404.                 // Now do the real replacement
  405.                 if (!$simulate) {
  406.                         OIDplus::db()->query("delete from ".OIDPLUS_TABLENAME_PREFIX."iri where oid = ?", array("oid:".$this->oid));
  407.                         foreach ($demandedIris as &$iri) {
  408.                                 if (!OIDplus::db()->query("insert into ".OIDPLUS_TABLENAME_PREFIX."iri (oid, name) values (?, ?)", array("oid:".$this->oid, $iri))) {
  409.                                         throw new Exception("Insertion of IRI $iri to OID ".$this->oid." failed!");
  410.                                 }
  411.                         }
  412.                 }
  413.         }
  414.  
  415.         public function one_up() {
  416.                 return self::parse(self::ns().':'.oid_up($this->oid));
  417.         }
  418.  
  419.         public function distance($to) {
  420.                 if (!is_object($to)) $to = OIDplusObject::parse($to);
  421.                 if (!($to instanceof $this)) return false;
  422.                 return oid_distance($to->oid, $this->oid);
  423.         }
  424.  
  425.         public function getAltIds() {
  426.                 if ($this->isRoot()) return array();
  427.                 $ids = parent::getAltIds();
  428.                 if ($uuid = oid_to_uuid($this->oid)) {
  429.                         $ids[] = array('guid', $uuid, 'GUID representation of this OID');
  430.                 }
  431.                 $ids[] = array('guid', gen_uuid_md5_namebased(UUID_NAMEBASED_NS_OID, $this->oid), 'Namebased version 3 / MD5 UUID with namespace UUID_NAMEBASED_NS_OID');
  432.                 $ids[] = array('guid', gen_uuid_sha1_namebased(UUID_NAMEBASED_NS_OID, $this->oid), 'Namebased version 5 / SHA1 UUID with namespace UUID_NAMEBASED_NS_OID');
  433.                 return $ids;
  434.         }
  435. }
  436.