Subversion Repositories oidplus

Rev

Rev 4 | Go to most recent revision | Blame | Compare with Previous | 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. class OIDplusGui {
  21.  
  22.         private static $crudCounter = 0;
  23.  
  24.         protected static function objDescription($html) {
  25.                 // We allow HTML, but no hacking
  26.                 // TODO: disallow more html tags https://www.experts-exchange.com/questions/22664900/Extensive-list-of-all-dangerous-HTML-tags-and-attributes-anti-XSS.html
  27.                 $forbidden_tags = array('script');
  28.                 $html = str_ireplace('<script', '<xxx', $html);
  29.                 $html = str_ireplace('</script>', '</xxx>', $html);
  30.                 return $html;
  31.         }
  32.  
  33.         protected static function showRAInfo($email) {
  34.                 $out = '';
  35.  
  36.                 $res = OIDplus::db()->query("select * from ".OIDPLUS_TABLENAME_PREFIX."ra where email = '".OIDplus::db()->real_escape_string($email)."'");
  37.                 if (OIDplus::db()->num_rows($res) === 0) {
  38.                         $out = '<p>The RA <a href="mailto:'.htmlentities($email).'">'.htmlentities($email).'</a> is not registered in the database.</p>';
  39.  
  40.                 } else {
  41.                         $row = OIDplus::db()->fetch_array($res);
  42.                         $out = '<b>'.htmlentities($row['ra_name']).'</b><br>';
  43.                         $out .= 'E-Mail: <a href="mailto:'.htmlentities($email).'">'.htmlentities($email).'</a><br>';
  44.                         if (trim($row['personal_name']) !== '') $out .= htmlentities($row['personal_name']).'<br>';
  45.                         if (trim($row['organization']) !== '') $out .= htmlentities($row['organization']).'<br>';
  46.                         if (trim($row['office']) !== '') $out .= htmlentities($row['office']).'<br>';
  47.                         if ($row['privacy']) {
  48.                                 // TODO: meldung nur anzeigen, wenn benutzer überhaupt straße, adresse etc hat
  49.                                 // TODO: aber der admin soll es sehen, und der user selbst (mit anmerkung, dass es privat ist)
  50.                                 $out .= '<p>The RA does not want to publish their personal information.</p>';
  51.                         } else {
  52.                                 if (trim($row['street']) !== '') $out .= htmlentities($row['street']).'<br>';
  53.                                 if (trim($row['zip_town']) !== '') $out .= htmlentities($row['zip_town']).'<br>';
  54.                                 if (trim($row['country']) !== '') $out .= htmlentities($row['country']).'<br>';
  55.                                 $out .= '<br>';
  56.                                 if (trim($row['phone']) !== '') $out .= htmlentities($row['phone']).'<br>';
  57.                                 if (trim($row['fax']) !== '') $out .= htmlentities($row['fax']).'<br>';
  58.                                 if (trim($row['mobile']) !== '') $out .= htmlentities($row['mobile']).'<br>';
  59.                                 $out .= '<br>';
  60.                         }
  61.                 }
  62.  
  63.                 return $out;
  64.         }
  65.  
  66.         protected static function showCrud($parent='oid:') {
  67.                 $items_total = 0;
  68.                 $items_hidden = 0;
  69.  
  70.                 $objParent = OIDplusObject::parse($parent);
  71.  
  72.                 $output = '';
  73.                 if (!$objParent->userHasWriteRights()) {
  74.                         // TODO: wir sollten eigentlich bei noscript die buttons und edits ausblenden
  75.                         $output .= '<noscript><b>Please enable JavaScript to edit the subsequent OIDs.</b></noscript>';
  76.                 }
  77.                 $output .= '<div class="container box"><div id="suboid_table" class="table-responsive">';
  78.                 $output .= '<table class="table table-bordered table-striped">';
  79.                 $output .= '    <tr>';
  80.                 $output .= '         <th>ID'.(($objParent::ns() == 'gs1') ? ' (without check digit)' : '').'</th>';
  81.                 if ($objParent::ns() == 'oid') $output .= '          <th>ASN.1 IDs (comma sep.)</th>';
  82.                 if ($objParent::ns() == 'oid') $output .= '          <th>IRI IDs (comma sep.)</th>';
  83.                 $output .= '         <th>RA</th>';
  84.                 if ($objParent->userHasWriteRights()) {
  85.                         $output .= '         <th>Hide</th>';
  86.                         $output .= '         <th>Update</th>';
  87.                         $output .= '         <th>Delete</th>';
  88.                 }
  89.                 $output .= '         <th>Created</th>';
  90.                 $output .= '         <th>Updated</th>';
  91.                 $output .= '    </tr>';
  92.  
  93.                 $result = OIDplus::db()->query("select o.*, r.ra_name from ".OIDPLUS_TABLENAME_PREFIX."objects o left join ".OIDPLUS_TABLENAME_PREFIX."ra r on r.email = o.ra_email where parent = '".OIDplus::db()->real_escape_string($parent)."' order by ".OIDplus::db()->natOrder('id'));
  94.                 while ($row = OIDplus::db()->fetch_object($result)) {
  95.                         $obj = OIDplusObject::parse($row->id);
  96.  
  97.                         $items_total++;
  98.                         if (!$obj->userHasReadRights()) {
  99.                                 $items_hidden++;
  100.                                 continue;
  101.                         }
  102.  
  103.                         $show_id = $obj->crudShowId($objParent);
  104.  
  105.                         $asn1ids = array();
  106.                         $res2 = OIDplus::db()->query("select name from ".OIDPLUS_TABLENAME_PREFIX."asn1id where oid = '".OIDplus::db()->real_escape_string($row->id)."' order by lfd");
  107.                         while ($row2 = OIDplus::db()->fetch_array($res2)) {
  108.                                 $asn1ids[] = $row2['name'];
  109.                         }
  110.                         $asn1ids = implode(', ', $asn1ids);
  111.  
  112.                         $iris = array();
  113.                         $res2 = OIDplus::db()->query("select name from ".OIDPLUS_TABLENAME_PREFIX."iri where oid = '".OIDplus::db()->real_escape_string($row->id)."' order by lfd");
  114.                         while ($row2 = OIDplus::db()->fetch_array($res2)) {
  115.                                 $iris[] = $row2['name'];
  116.                         }
  117.                         $iris = implode(', ', $iris);
  118.  
  119.                         $output .= '<tr>';
  120. // TODO: if no scripts are allowed, we cannot open this link using openAndSelectNode()
  121.                         $output .= '     <td><a href="javascript:openAndSelectNode('.js_escape($row->id).', '.js_escape($parent).')">'.htmlentities($show_id).'</a></td>';
  122.                         if ($objParent->userHasWriteRights()) {
  123.                                 if ($obj::ns() == 'oid') $output .= '     <td><input type="text" id="asn1ids_'.$row->id.'" value="'.$asn1ids.'"></td>';
  124.                                 if ($obj::ns() == 'oid') $output .= '     <td><input type="text" id="iris_'.$row->id.'" value="'.$iris.'"></td>';
  125.                                 $output .= '     <td><input type="text" id="ra_email_'.$row->id.'" value="'.$row->ra_email.'"></td>';
  126.                                 $output .= '     <td><input type="checkbox" id="hide_'.$row->id.'" '.($row->confidential ? 'checked' : '').'></td>';
  127.                                 $output .= '     <td><button type="button" name="update_'.$row->id.'" id="update_'.$row->id.'" class="btn btn-success btn-xs update" onclick="javascript:crudActionUpdate('.js_escape($row->id).', '.js_escape($parent).')">Update</button></td>';
  128.                                 $output .= '     <td><button type="button" name="delete_'.$row->id.'" id="delete_'.$row->id.'" class="btn btn-danger btn-xs delete" onclick="javascript:crudActionDelete('.js_escape($row->id).', '.js_escape($parent).')">Delete</button></td>';
  129.                                 $output .= '     <td>'.oiddb_formatdate($row->created).'</td>';
  130.                                 $output .= '     <td>'.oiddb_formatdate($row->updated).'</td>';
  131.                         } else {
  132.                                 if ($asn1ids == '') $asn1ids = '<i>(none)</i>';
  133.                                 if ($iris == '') $iris = '<i>(none)</i>';
  134.                                 if ($obj::ns() == 'oid') $output .= '     <td><a href="javascript:openAndSelectNode('.js_escape($row->id).', '.js_escape($parent).')">'.$asn1ids.'</a></td>';
  135.                                 if ($obj::ns() == 'oid') $output .= '     <td>'.$iris.'</td>';
  136. // TODO: if no scripts are allowed, we cannot open the rainfo: pages using openOidInPanel()
  137.                                 $output .= '     <td><a href="javascript:openOidInPanel('.js_escape('oidplus:rainfo$'.str_replace('@', "'+'@'+'", $row->ra_email)).', true)">'.htmlentities(empty($row->ra_name) ? str_replace('@','&',$row->ra_email) : $row->ra_name).'</a></td>';
  138.                                 $output .= '     <td>'.oiddb_formatdate($row->created).'</td>';
  139.                                 $output .= '     <td>'.oiddb_formatdate($row->updated).'</td>';
  140.                         }
  141.                         $output .= '</tr>';
  142.                 }
  143.  
  144.                 $result = OIDplus::db()->query("select * from ".OIDPLUS_TABLENAME_PREFIX."objects where id = '".OIDplus::db()->real_escape_string($parent)."'");
  145.                 $parent_ra_email = OIDplus::db()->num_rows($result) > 0 ? OIDplus::db()->fetch_object($result)->ra_email : '';
  146.  
  147.                 if ($objParent->userHasWriteRights()) {
  148.                         $output .= '<tr>';
  149.                         $prefix = is_null($objParent) ? '' : $objParent->crudInsertPrefix();
  150.                         if ($objParent::ns() == 'oid') {
  151.                                 $output .= '     <td>'.$prefix.' <input type="text" id="id" value="" style="width:100%;min-width:50px"></td>'; // TODO: idee classname vergeben, z.B. "OID" und dann mit einem oid-spezifischen css die breite einstellbar machen, somit hat das plugin mehr kontrolle über das aussehen und die mindestbreiten
  152.                         } else {
  153.                                 $output .= '     <td>'.$prefix.' <input type="text" id="id" value=""></td>';
  154.                         }
  155.                         if ($objParent::ns() == 'oid') $output .= '     <td><input type="text" id="asn1ids" value=""></td>';
  156.                         if ($objParent::ns() == 'oid') $output .= '     <td><input type="text" id="iris" value=""></td>';
  157.                         $output .= '     <td><input type="text" id="ra_email" value="'.htmlentities($parent_ra_email).'"></td>';
  158.                         $output .= '     <td><input type="checkbox" id="hide"></td>';
  159.                         $output .= '     <td><button type="button" name="insert" id="insert" class="btn btn-success btn-xs update" onclick="javascript:crudActionInsert('.js_escape($parent).')">Insert</button></td>';
  160.                         $output .= '     <td></td>';
  161.                         $output .= '     <td></td>';
  162.                         $output .= '     <td></td>';
  163.                         $output .= '</tr>';
  164.                 } else {
  165.                         if ($items_total-$items_hidden == 0) {
  166.                                 $cols = ($objParent::ns() == 'oid') ? 7 : 5;
  167.                                 $output .= '<tr><td colspan="'.$cols.'">No items available</td></tr>';
  168.                         }
  169.                 }
  170.  
  171.                 $output .= '</table>';
  172.                 $output .= '</div></div>';
  173.  
  174.                 if ($items_hidden == 1) {
  175.                         $output .= '<p>'.$items_hidden.' item is hidden. Please <a href="?goto=oidplus:login">log in</a> to see it.</p>';
  176.                 } else if ($items_hidden > 1) {
  177.                         $output .= '<p>'.$items_hidden.' items are hidden. Please <a href="?goto=oidplus:login">log in</a> to see them.</p>';
  178.                 }
  179.  
  180.                 return $output;
  181.         }
  182.  
  183.         public static $exclude_tinymce_plugins = array('fullpage', 'bbcode');
  184.  
  185.         protected static function showMCE($name, $content) {
  186.                 $mce_plugins = array();
  187.                 foreach (glob(__DIR__ . '/../3p/tinymce/plugins/*') as $m) { // */
  188.                         $mce_plugins[] = basename($m);
  189.                 }
  190.  
  191.                 foreach (self::$exclude_tinymce_plugins as $exclude) {
  192.                         $index = array_search($exclude, $mce_plugins);
  193.                         if ($index !== false) unset($mce_plugins[$index]);
  194.                 }
  195.  
  196.                 $out = "<script>
  197.                                 tinymce.remove('#".$name."');
  198.                                 tinymce.init({
  199.                                         selector: '#".$name."',
  200.                                         plugins: '".implode(' ', $mce_plugins)."'
  201.                                 });
  202.                         </script>";
  203.  
  204.                 $out .= '<textarea name="'.htmlentities($name).'" id="'.htmlentities($name).'" rows="10">'.trim($content).'</textarea><br>';
  205.  
  206.                 return $out;
  207.         }
  208.  
  209.         public static function getInvitationText($email) {
  210.                 $res = OIDplus::db()->query("select * from ".OIDPLUS_TABLENAME_PREFIX."ra where email = '".OIDplus::db()->real_escape_string($email)."'");
  211.                 if (OIDplus::db()->num_rows($res) > 0) {
  212.                         throw new Exception("This RA is already registered and does not need to be invited.");
  213.                 }
  214.  
  215.                 if (!OIDplus::authUtils()::isAdminLoggedIn()) {
  216.                         // Check if the RA may invite the user (i.e. the they are the parent of an OID of that person)
  217.                         $ok = false;
  218.                         $res = OIDplus::db()->query("select parent from ".OIDPLUS_TABLENAME_PREFIX."objects where ra_email = '".OIDplus::db()->real_escape_string($email)."'");
  219.                         while ($row = OIDplus::db()->fetch_array($res)) {
  220.                                 $objParent = OIDplusObject::parse($row['parent']);
  221.                                 if (is_null($objParent)) throw new Exception("Type of ".$row['parent']." unknown");
  222.                                 if ($objParent->userHasWriteRights()) {
  223.                                         $ok = true;
  224.                                 }
  225.                         }
  226.                         if (!$ok) {
  227.                                 throw new Exception('You may not invite this RA. Maybe you need to log in again.');
  228.                         }
  229.                 }
  230.  
  231.                 $list_of_oids = array();
  232.                 $res = OIDplus::db()->query("select id from ".OIDPLUS_TABLENAME_PREFIX."objects where ra_email = '".OIDplus::db()->real_escape_string($email)."'");
  233.                 while ($row = OIDplus::db()->fetch_array($res)) {
  234.                         $list_of_oids[] = $row['id'];
  235.                 }
  236.  
  237.                 $message = file_get_contents(__DIR__ . '/../invite_msg.tpl');
  238.  
  239.                 // Resolve stuff
  240.                 $message = str_replace('{{SYSTEM_URL}}', OIDplus::system_url(), $message);
  241.                 $message = str_replace('{{OID_LIST}}', implode("\n", $list_of_oids), $message);
  242.                 $message = str_replace('{{ADMIN_EMAIL}}', OIDPLUS_ADMIN_EMAIL, $message);
  243.                 $message = str_replace('{{PARTY}}', OIDplus::authUtils()::isAdminLoggedIn() ? 'the system administrator' : 'a superior Registration Authority', $message);
  244.  
  245.                 // {{ACTIVATE_URL}} will be resolved in action.php
  246.  
  247.                 return $message;
  248.         }
  249.  
  250.         public static function getForgotPasswordText($email) {
  251.                 $res = OIDplus::db()->query("select * from ".OIDPLUS_TABLENAME_PREFIX."ra where email = '".OIDplus::db()->real_escape_string($email)."'");
  252.                 if (OIDplus::db()->num_rows($res) == 0) {
  253.                         throw new Exception("This RA does not exist.");
  254.                 }
  255.  
  256.                 $message = file_get_contents(__DIR__ . '/../forgot_password.tpl');
  257.  
  258.                 // Resolve stuff
  259.                 $message = str_replace('{{SYSTEM_URL}}', OIDplus::system_url(), $message);
  260.                 $message = str_replace('{{ADMIN_EMAIL}}', OIDPLUS_ADMIN_EMAIL, $message);
  261.  
  262.                 // {{ACTIVATE_URL}} will be resolved in action.php
  263.  
  264.                 return $message;
  265.         }
  266.  
  267.         public static function generateContentPage($id) {
  268.                 $out = array();
  269.  
  270.                 $handled = false;
  271.                 $out['title'] = '';
  272.                 $out['text'] = '';
  273.  
  274.                 // === System ===
  275.  
  276.                 if ($id === 'oidplus:system') {
  277.                         $handled = true;
  278.  
  279.                         $out['title'] = 'Object Database of ' . $_SERVER['SERVER_NAME'];
  280.                         $out['text'] = file_get_contents('welcome.html');
  281.                         return $out;
  282.  
  283.                 // === Generic stuff ===
  284.  
  285.                 } else if (explode('$',$id)[0] == 'oidplus:rainfo') {
  286.                         $handled = true;
  287.  
  288.                         $ra_email = explode('$',$id)[1];
  289.  
  290.                         $out['title'] = 'Registration Authority Information'; // TODO: email addresse reinschreiben? aber wie vor anti spam schützen?
  291.  
  292.                         if (empty($ra_email)) {
  293.                                 $out['text'] = '<p>Following object roots have an undefined Registration Authority:</p>';
  294.                         } else {
  295.                                 $out['text'] = self::showRAInfo($ra_email);
  296.                         }
  297.  
  298.                         foreach (OIDplusObject::getRaRoots($ra_email) as $loc_root) {
  299.                                 $icon = file_exists('plugins/objectTypes/'.$loc_root::ns().'/img/treeicon_link.png') ? 'plugins/objectTypes/'.$loc_root::ns().'/img/treeicon_link.png' : 'img/link.png';
  300.                                 $out['text'] .= '<p><a href="?goto='.$loc_root->nodeId().'"><img src="'.$icon.'"> Jump to RA root '.$loc_root->objectTypeTitleShort().' '.$loc_root->crudShowId(OIDplusObject::parse($loc_root::root())).'</a></p>';
  301.                         }
  302.  
  303.  
  304.                         if (OIDplus::authUtils()::isAdminLoggedIn()) {
  305.                                 $out['text'] .= '<p><a href="javascript:deleteRa('.js_escape($ra_email).',null)">Delete this RA</a></p>';
  306.                         }
  307.  
  308.                 // === Forgot password ===
  309.  
  310.                 } else if (explode('$',$id)[0] == 'oidplus:forgot_password') {
  311.                         $handled = true;
  312.  
  313.                         $out['title'] = 'Forgot password';
  314.  
  315.                         try {
  316.                                 $out['text'] .= '<p>Please enter the email address of your account, and information about the password reset will be sent to you.</p>
  317.                                   <form id="forgotPasswordForm" onsubmit="return forgotPasswordFormOnSubmit();">
  318.                                     E-Mail: <input type="text" id="email" value=""/><br><br>'.
  319.                                  (RECAPTCHA_ENABLED ? '<script> grecaptcha.render(document.getElementById("g-recaptcha"), { "sitekey" : "'.RECAPTCHA_PUBLIC.'" }); </script>'.
  320.                                                    '<div id="g-recaptcha" class="g-recaptcha" data-sitekey="'.RECAPTCHA_PUBLIC.'"></div>' : '').
  321.                                 ' <br>
  322.                                     <input type="submit" value="Send recovery information">
  323.                                   </form>';
  324.  
  325.                         } catch (Exception $e) {
  326.  
  327.                                 $out['text'] = "Error: ".$e->getMessage();
  328.  
  329.                         }
  330.                 } else if (explode('$',$id)[0] == 'oidplus:reset_password') {
  331.                         $handled = true;
  332.  
  333.                         $email = explode('$',$id)[1];
  334.                         $timestamp = explode('$',$id)[2];
  335.                         $auth = explode('$',$id)[3];
  336.  
  337.                         $out['title'] = 'Reset password';
  338.  
  339.                         if (!OIDplus::authUtils()::validateAuthKey('reset_password;'.$email.';'.$timestamp, $auth)) {
  340.                                 $out['text'] = 'Invalid authorization. Is the URL OK?';
  341.                         } else {
  342.                                 $out['text'] = '<p>E-Mail-Adress: <b>'.$email.'</b></p>
  343.  
  344.                                   <form id="resetPasswordForm" onsubmit="return resetPasswordFormOnSubmit();">
  345.                                     <input type="hidden" id="email" value="'.htmlentities($email).'"/>
  346.                                     <input type="hidden" id="timestamp" value="'.htmlentities($timestamp).'"/>
  347.                                     <input type="hidden" id="auth" value="'.htmlentities($auth).'"/>
  348.                                     New password: <input type="password" id="password1" value=""/><br><br>
  349.                                     Again: <input type="password" id="password2" value=""/><br><br>
  350.                                     <input type="submit" value="Change password">
  351.                                   </form>';
  352.                         }
  353.  
  354.  
  355.                 // === Invite ===
  356.  
  357.                 } else if (explode('$',$id)[0] == 'oidplus:invite_ra') {
  358.                         $handled = true;
  359.  
  360.                         $email = explode('$',$id)[1];
  361.                         $origin = explode('$',$id)[2];
  362.  
  363.                         $out['title'] = 'Invite a Registration Authority';
  364.  
  365.                         try {
  366.                                 $cont = self::getInvitationText($email);
  367.  
  368.                                 $out['text'] .= '<p>You have chosen to invite <b>'.$email.'</b> as an Registration Authority. If you click "Send", the following email will be sent to '.$email.':</p><p><i>'.nl2br(htmlentities($cont)).'</i></p>
  369.                                   <form id="inviteForm" onsubmit="return inviteFormOnSubmit();">
  370.                                     <input type="hidden" id="email" value="'.htmlentities($email).'"/>
  371.                                     <input type="hidden" id="origin" value="'.htmlentities($origin).'"/>'.
  372.                                  (RECAPTCHA_ENABLED ? '<script> grecaptcha.render(document.getElementById("g-recaptcha"), { "sitekey" : "'.RECAPTCHA_PUBLIC.'" }); </script>'.
  373.                                                    '<div id="g-recaptcha" class="g-recaptcha" data-sitekey="'.RECAPTCHA_PUBLIC.'"></div>' : '').
  374.                                 ' <br>
  375.                                     <input type="submit" value="Send invitation">
  376.                                   </form>';
  377.  
  378.                         } catch (Exception $e) {
  379.  
  380.                                 $out['text'] = "Error: ".$e->getMessage();
  381.  
  382.                         }
  383.                 } else if (explode('$',$id)[0] == 'oidplus:activate_ra') {
  384.                         $handled = true;
  385.  
  386.                         $email = explode('$',$id)[1];
  387.                         $timestamp = explode('$',$id)[2];
  388.                         $auth = explode('$',$id)[3];
  389.  
  390.                         $out['title'] = 'Register as Registration Authority';
  391.  
  392.                         $res = OIDplus::db()->query("select * from ".OIDPLUS_TABLENAME_PREFIX."ra where email = '".OIDplus::db()->real_escape_string($email)."'");
  393.                         if (OIDplus::db()->num_rows($res) > 0) {
  394.                                 $out['text'] = 'This RA is already registered and does not need to be invited.';
  395.                         } else {
  396.                                 if (!OIDplus::authUtils()::validateAuthKey('activate_ra;'.$email.';'.$timestamp, $auth)) {
  397.                                         $out['text'] = 'Invalid authorization. Is the URL OK?';
  398.                                 } else {
  399.                                         // TODO: like in the FreeOID plugin, we could ask here at least for a name for the RA
  400.                                         $out['text'] = '<p>E-Mail-Adress: <b>'.$email.'</b></p>
  401.  
  402.                                           <form id="activateRaForm" onsubmit="return activateRaFormOnSubmit();">
  403.                                             <input type="hidden" id="email" value="'.htmlentities($email).'"/>
  404.                                             <input type="hidden" id="timestamp" value="'.htmlentities($timestamp).'"/>
  405.                                             <input type="hidden" id="auth" value="'.htmlentities($auth).'"/>
  406.                                             New password: <input type="password" id="password1" value=""/><br><br>
  407.                                             Again: <input type="password" id="password2" value=""/><br><br>
  408.                                             <input type="submit" value="Register">
  409.                                           </form>';
  410.                                 }
  411.                         }
  412.  
  413.                 // === Login ===
  414.  
  415.                 } else if ($id === 'oidplus:login') {
  416.                         $handled = true;
  417.                         $out['title'] = 'Login';
  418.  
  419.                         $out['text'] = 'Here you can login and register as RA.';
  420.  
  421.                         $out['text'] .= '<script>function raLoginOnSubmit() {';
  422.                         $out['text'] .= '       raLogin(document.getElementById("raLoginEMail").value, document.getElementById("raLoginPassword").value);';
  423.                         $out['text'] .= '       return false;';
  424.                         $out['text'] .= '}</script>';
  425.  
  426.                         $out['text'] .= (RECAPTCHA_ENABLED ? '<script> grecaptcha.render(document.getElementById("g-recaptcha"), { "sitekey" : "'.RECAPTCHA_PUBLIC.'" }); </script>'.
  427.                                                           '<div id="g-recaptcha" class="g-recaptcha" data-sitekey="'.RECAPTCHA_PUBLIC.'"></div>' : '');
  428.  
  429.                         $out['text'] .= '<h2>Login as RA</h2>';
  430.                         $out['text'] .= '<form action="action.php" method="POST" onsubmit="return raLoginOnSubmit(this);">';
  431.                         $out['text'] .= '<input type="hidden" name="action" value="ra_login">';
  432.                         $out['text'] .= 'E-Mail: <input type="text" name="email" value="" id="raLoginEMail"><br>';
  433.                         $out['text'] .= 'Password: <input type="password" name="password" value="" id="raLoginPassword"><br>';
  434.                         $out['text'] .= '<input type="submit" value="Login">';
  435.                         $out['text'] .= '</form>';
  436.                         $out['text'] .= '<p><a href="?goto=oidplus:forgot_password">Forgot password?</a><br>';
  437.                         $out['text'] .= '<abbr title="To receive login data, the superior RA needs to send you an invitation. After creating or updating your OID, the system will ask them if they want to send you an invitation. If they accept, you will receive an email with an activation link.">How to register?</abbr></p>';
  438.  
  439.                         $out['text'] .= '<script>function adminLoginOnSubmit() {';
  440.                         $out['text'] .= '       adminLogin(document.getElementById("adminLoginPassword").value);';
  441.                         $out['text'] .= '       return false;';
  442.                         $out['text'] .= '}</script>';
  443.  
  444.                         if (OIDplus::authUtils()::isAdminLoggedIn()) {
  445.                                 $out['text'] .= '<h2>Admin login</h2>';
  446.                                 $out['text'] .= '<p>You are logged in as administrator.</p>';
  447.                                 $out['text'] .= '<a href="javascript:adminLogout();">Logout</a>';
  448.                         } else {
  449.                                 $out['text'] .= '<h2>Login as admin</h2>';
  450.                                 $out['text'] .= '<form action="action.php" method="POST" onsubmit="return adminLoginOnSubmit(this);">';
  451.                                 $out['text'] .= '<input type="hidden" name="action" value="admin_login">';
  452.                                 $out['text'] .= 'Password: <input type="password" name="password" value="" id="adminLoginPassword"><br>';
  453.                                 $out['text'] .= '<input type="submit" value="Login">';
  454.                                 $out['text'] .= '</form>';
  455.                                 $out['text'] .= '<p><abbr title="Delete the file includes/config.inc.php and reload the page to start Setup again">Forgot password?</abbr></p>';
  456.                         }
  457.                 }
  458.  
  459.                 // === Plugins ===
  460.  
  461.                 $ary = glob(__DIR__ . '/../../plugins/publicPages/'.'*'.'/gui.inc.php');
  462.                 sort($ary);
  463.                 foreach ($ary as $a) include $a;
  464.  
  465.                 $ary = glob(__DIR__ . '/../../plugins/adminPages/'.'*'.'/gui.inc.php');
  466.                 sort($ary);
  467.                 foreach ($ary as $a) include $a;
  468.  
  469.                 $ary = glob(__DIR__ . '/../../plugins/raPages/'.'*'.'/gui.inc.php');
  470.                 sort($ary);
  471.                 foreach ($ary as $a) include $a;
  472.  
  473.                 // === Everything else (objects) ===
  474.  
  475.                 if (!$handled) {
  476.                         $obj = OIDplusObject::parse($id);
  477.  
  478.                         if ((!is_null($obj)) && (!$obj->userHasReadRights())) {
  479.                                 $out['title'] = 'Access denied';
  480.                                 $out['text'] = '<p>Please <a href="?goto=oidplus:login">log in</a> to receive information about this object.</p>';
  481.                                 return $out;
  482.                         }
  483.  
  484.                         $res = OIDplus::db()->query("select * from ".OIDPLUS_TABLENAME_PREFIX."objects where id = '".OIDplus::db()->real_escape_string($id)."'");
  485.                         $row = OIDplus::db()->fetch_array($res);
  486.  
  487.                         if (empty($row['title'])) {
  488.                                 $out['title'] = is_null($obj) ? $id : $obj->defaultTitle();
  489.                         } else {
  490.                                 $out['title'] = $row['title'];
  491.                         }
  492.  
  493.                         if (isset($row['description'])) {
  494.                                 $desc = empty($row['description']) ? '<p><i>No description for this object available</i></p>' : OIDplusGui::objDescription($row['description']);
  495.                                 if ($obj->userHasWriteRights()) {
  496.                                         $rand = ++self::$crudCounter;
  497.                                         $desc = '<noscript><p><b>You need to enable JavaScript to edit title or description of this object.</b></p>'.$desc.'</noscript>';
  498.                                         $desc .= '<div class="container box" style="display:none" id="descbox_'.$rand.'">';
  499.                                         $desc .= 'Title: <input type="text" name="title" id="titleedit" value="'.htmlentities($row['title']).'"><br><br>Description:<br>';
  500.                                         $desc .= self::showMCE('description', $row['description']);
  501.                                         $desc .= '<button type="button" name="update_desc" id="update_desc" class="btn btn-success btn-xs update" onclick="javascript:updateDesc()">Update description</button>';
  502.                                         $desc .= '</div>';
  503.                                         $desc .= '<script>document.getElementById("descbox_'.$rand.'").style.display = "block";</script>';
  504.                                 }
  505.                         } else {
  506.                                 $desc = '';
  507.                         }
  508.  
  509.                         $matches_any_registered_type = false;
  510.                         foreach (OIDplusObject::$registeredObjectTypes as $ot) {
  511.                                 if ($obj = $ot::parse($id)) {
  512.                                         $matches_any_registered_type = true;
  513.                                         if ((OIDplus::db()->num_rows($res) == 0) && !$obj->isRoot()){
  514.                                                 http_response_code(404);
  515.                                                 $out['title'] = 'Object not found';
  516.                                                 $out['text'] = 'The object <code>'.htmlentities($id).'</code> was not found in this database.';
  517.                                                 return $out;
  518.                                         } else {
  519.                                                 $obj->getContentPage($out['title'], $out['text']);
  520.                                         }
  521.                                 }
  522.                         }
  523.                         if (!$matches_any_registered_type) {
  524.                                 http_response_code(404);
  525.                                 $out['title'] = 'Object not found';
  526.                                 $out['text'] = 'The object <code>'.htmlentities($id).'</code> was not found in this database.';
  527.                                 return $out;
  528.                         }
  529.  
  530.                         if (strpos($out['text'], '%%DESC%%') !== false)
  531.                                 $out['text'] = str_replace('%%DESC%%',    $desc,                              $out['text']);
  532.                         if (strpos($out['text'], '%%CRUD%%') !== false)
  533.                                 $out['text'] = str_replace('%%CRUD%%',    self::showCrud($id),                $out['text']);
  534.                         if (strpos($out['text'], '%%RA_INFO%%') !== false)
  535.                                 $out['text'] = str_replace('%%RA_INFO%%', self::showRaInfo($row['ra_email']), $out['text']);
  536.                 }
  537.  
  538.                 return $out;
  539.         }
  540.  
  541. }
  542.