Subversion Repositories oidplus

Rev

Rev 1207 | View as "text/javascript" | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.  * OIDplus 2.0
  3.  * Copyright 2019 - 2021 Daniel Marschall, ViaThinkSoft
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17.  
  18. // DEFAULT_LANGUAGE will be set by setup.js.php
  19. // language_messages will be set by setup.js.php
  20. // language_tblprefix will be set by setup.js.php
  21.  
  22. // TODO: Put these settings in a "setup configuration file" (hardcoded)
  23. min_password_length = 10; // see also plugins/viathinksoft/publicPages/092_forgot_password_admin/script.js
  24. password_salt_length = 10;
  25. bcrypt_rounds = 10;
  26.  
  27. function adminGeneratePassword(password) {
  28.         var salt = generateRandomString(password_salt_length);
  29.         return salt+'$'+hexToBase64(sha3_512(salt+password));
  30. }
  31.  
  32. var bCryptWorker = null;
  33. var g_prevBcryptPw = null;
  34. var g_last_admPwdHash = null;
  35. var g_last_pwComment = null;
  36.  
  37. function rebuild() {
  38.         var pw = $("#admin_password")[0].value;
  39.  
  40.         if (pw != g_prevBcryptPw) {
  41.                 // sync call to calculate SHA3
  42.                 var admPwdHash = adminGeneratePassword(pw);
  43.                 var pwComment = 'salted, base64 encoded SHA3-512 hash';
  44.                 doRebuild(admPwdHash, pwComment);
  45.  
  46.                 // "async" call to calculate bcrypt (via web-worker)
  47.                 if (bCryptWorker != null) {
  48.                         g_prevBcryptPw = null;
  49.                         bCryptWorker.terminate();
  50.                 }
  51.                 bCryptWorker = new Worker('../bcrypt_worker.js');
  52.                 bCryptWorker.postMessage([pw, bcrypt_rounds]);
  53.                 bCryptWorker.onmessage = function (event) {
  54.                         var admPwdHash = event.data;
  55.                         var pwComment = 'bcrypt encoded hash';
  56.                         doRebuild(admPwdHash, pwComment);
  57.                         g_prevBcryptPw = pw;
  58.                 };
  59.         } else {
  60.                 doRebuild(g_last_admPwdHash, g_last_pwComment);
  61.         }
  62. }
  63.  
  64. function doRebuild(admPwdHash, pwComment) {
  65.         g_last_admPwdHash = admPwdHash;
  66.         g_last_pwComment = pwComment;
  67.  
  68.         var error = false;
  69.  
  70.         if ($("#config")[0] == null) return;
  71.  
  72.         // Check 1: Has the password the correct length?
  73.         if ($("#admin_password")[0].value.length < min_password_length)
  74.         {
  75.                 $("#password_warn")[0].innerHTML = '<font color="red">'+_L('Password must be at least %1 characters long',min_password_length)+'</font>';
  76.                 $("#config")[0].innerHTML = '<b>&lt?php</b><br><br><i>// ERROR: Password must be at least '+min_password_length+' characters long</i>'; // do not translate
  77.                 error = true;
  78.         } else {
  79.                 $("#password_warn")[0].innerHTML = '';
  80.         }
  81.  
  82.         // Check 2: Do the passwords match?
  83.         if ($("#admin_password")[0].value != $("#admin_password2")[0].value) {
  84.                 $("#password_warn2")[0].innerHTML = '<font color="red">'+_L('The passwords do not match!')+'</font>';
  85.                 error = true;
  86.         } else {
  87.                 $("#password_warn2")[0].innerHTML = '';
  88.         }
  89.  
  90.         // Check 3: Ask the database or captcha plugins for verification of their data
  91.         for (var i = 0; i < rebuild_callbacks.length; i++) {
  92.                 var f = rebuild_callbacks[i];
  93.                 if (!f()) {
  94.                         error = true;
  95.                 }
  96.         }
  97.  
  98.         // Continue
  99.         if (!error)
  100.         {
  101.                 var e = $("#db_plugin")[0];
  102.                 var strDatabasePlugin = e.options[e.selectedIndex].value;
  103.                 var e = $("#captcha_plugin")[0];
  104.                 var strCaptchaPlugin = e.options[e.selectedIndex].value;
  105.  
  106.                 $("#config")[0].innerHTML = '<b>&lt?php</b><br><br>' +
  107.                         '<i>// To renew this file, please run setup/ in your browser.</i><br>' + // do not translate
  108.                         '<i>// If you don\'t want to run setup again, you can also change most of the settings directly in this file.</i><br>' + // do not translate
  109.                         '<i>// List of possible values: doc/config_values.md</i><br>' + // do not translate
  110.                         '<br>' +
  111.                         'use ViaThinkSoft\\OIDplus\\OIDplus;<br>' +
  112.                         '<br>' +
  113.                         'OIDplus::baseConfig()->setValue(\'CONFIG_VERSION\',    2.1);<br>' +
  114.                         '<br>' +
  115.                         // Passwords are Base64 encoded to avoid that passwords can be read upon first sight,
  116.                         // e.g. if collegues are looking over your shoulder while you accidently open (and quickly close) userdata/baseconfig/config.inc.php
  117.                         'OIDplus::baseConfig()->setValue(\'ADMIN_PASSWORD\',    ' + jsString(admPwdHash) + '); // '+pwComment+'<br>' +
  118.                         '<br>' +
  119.                         'OIDplus::baseConfig()->setValue(\'DATABASE_PLUGIN\',   ' + jsString(strDatabasePlugin) + ');<br>';
  120.                 for (var i = 0; i < rebuild_config_callbacks.length; i++) {
  121.                         var f = rebuild_config_callbacks[i];
  122.                         var cont = f();
  123.                         if (cont) {
  124.                                 $("#config")[0].innerHTML = $("#config")[0].innerHTML + cont;
  125.                         }
  126.                 }
  127.                 $("#config")[0].innerHTML = $("#config")[0].innerHTML +
  128.                         //'<br>' +
  129.                         'OIDplus::baseConfig()->setValue(\'TABLENAME_PREFIX\',  ' + jsString($("#tablename_prefix")[0].value) + ');<br>' +
  130.                         '<br>' +
  131.                         'OIDplus::baseConfig()->setValue(\'SERVER_SECRET\',     ' + jsString(generateRandomString(32)) + ');<br>' +
  132.                         '<br>' +
  133.                         'OIDplus::baseConfig()->setValue(\'CAPTCHA_PLUGIN\',    ' + jsString(strCaptchaPlugin) + ');<br>';
  134.                 for (var i = 0; i < captcha_rebuild_config_callbacks.length; i++) {
  135.                         var f = captcha_rebuild_config_callbacks[i];
  136.                         var cont = f();
  137.                         if (cont) {
  138.                                 $("#config")[0].innerHTML = $("#config")[0].innerHTML + cont;
  139.                         }
  140.                 }
  141.  
  142.                 $("#config")[0].innerHTML = $("#config")[0].innerHTML +
  143.                         '<br>' +
  144.                         'OIDplus::baseConfig()->setValue(\'ENFORCE_SSL\',       ' + $("#enforce_ssl")[0].value + ');<br>';
  145.  
  146.                 if ($("#canonical_url")[0].value.trim() != '') {
  147.                         $("#config")[0].innerHTML = $("#config")[0].innerHTML +
  148.                                 '<br>' +
  149.                                 'OIDplus::baseConfig()->setValue(\'CANONICAL_SYSTEM_URL\', ' + jsString($("#canonical_url")[0].value.trim()) + ');<br>';
  150.                 }
  151.  
  152.                 $("#config")[0].innerHTML = $("#config")[0].innerHTML.replaceAll(' ', '&nbsp;');
  153.         }
  154.  
  155.         // In case something is not good, do not allow the user to continue with the other configuration steps:
  156.         if (error) {
  157.                 $("#step2")[0].style.display = "None";
  158.                 $("#step3")[0].style.display = "None";
  159.                 $("#step4")[0].style.display = "None";
  160.                 $("#footer_warn")[0].innerHTML = '<font color="red">'+_L('Please correct the errors above (in red) before continuing.')+'</font>';
  161.         } else {
  162.                 $("#step2")[0].style.display = "Block";
  163.                 $("#step3")[0].style.display = "Block";
  164.                 $("#step4")[0].style.display = "Block";
  165.                 $("#footer_warn")[0].innerHTML = '';
  166.         }
  167. }
  168.  
  169. function checkAccess(dir) {
  170.         if (!dir.toLowerCase().startsWith('https:') && !dir.toLowerCase().startsWith('http:')) {
  171.                 var url = '../' + dir;
  172.                 var visibleUrl = RemoveLastDirectoryPartOf(window.location.href) + '/' + dir; // xhr.responseURL not available in IE
  173.         } else {
  174.                 var url = dir;
  175.                 var visibleUrl = dir; // xhr.responseURL not available in IE
  176.         }
  177.  
  178.         var xhr = new XMLHttpRequest();
  179.         xhr.onreadystatechange = function() {
  180.                 if (xhr.readyState === 4) {
  181.                         if (xhr.status === 200) {
  182.                                 $("#systemCheckCaption")[0].style.display = 'block';
  183.                                 // TODO: At my Ubuntu VM, after fixing an issue with Apache2, the messages still appeared. I had to click the links and press F5 for each one
  184.                                 //       THERE MUST BE NO CACHE!!!
  185.                                 $("#dirAccessWarning")[0].innerHTML = $("#dirAccessWarning")[0].innerHTML + _L('Attention: The following directory is world-readable: %1 ! You need to configure your web server to restrict access to this directory! (For Apache see <i>.htaccess</i>, for Microsoft IIS see <i>web.config</i>, for Nginx see <i>nginx.conf</i>).','<a target="_blank" href="'+url+'">'+visibleUrl+'</a>') + '<br>';
  186.                         }
  187.                 }
  188.         };
  189.  
  190.         xhr.open('GET', url);
  191.         xhr.send();
  192. }
  193.  
  194. function dbplugin_changed() {
  195.         var e = $("#db_plugin")[0];
  196.         var strDatabasePlugin = e.options[e.selectedIndex].value;
  197.  
  198.         for (var i = 0; i < plugin_combobox_change_callbacks.length; i++) {
  199.                 var f = plugin_combobox_change_callbacks[i];
  200.                 f(strDatabasePlugin);
  201.         }
  202.  
  203.         rebuild();
  204. }
  205.  
  206. function captchaplugin_changed() {
  207.         var e = $("#captcha_plugin")[0];
  208.         var strCaptchaPlugin = e.options[e.selectedIndex].value;
  209.  
  210.         for (var i = 0; i < captcha_plugin_combobox_change_callbacks.length; i++) {
  211.                 var f = captcha_plugin_combobox_change_callbacks[i];
  212.                 f(strCaptchaPlugin);
  213.         }
  214.  
  215.         rebuild();
  216. }
  217.  
  218. function performAccessCheck() {
  219.         $("#dirAccessWarning")[0].innerHTML = "";
  220.         checkAccess("userdata/index.html");
  221.         checkAccess("res/ATTENTION.TXT");
  222.         checkAccess("dev/index.html");
  223.         checkAccess("includes/index.html");
  224.         checkAccess("setup/includes/index.html");
  225.         //checkAccess("plugins/viathinksoft/publicPages/100_whois/whois/cli/index.html");
  226.  
  227.         if (window.location.href.toLowerCase().startsWith('https://')) {
  228.                 $("#enforce_ssl").val('OIDplus::ENFORCE_SSL_YES'); // enforce SSL (because we are already SSL)
  229.         } else {
  230.                 // Do a SSL detection now.
  231.                 // This is important because on XAMPP the SSL cert is invalid (self signed) and the user might
  232.                 // be very confused if the PHP detection (OIDplus::ENFORCE_SSL_AUTO) notices the open 443 port and redirects the user to a
  233.                 // big warning page of the browser!
  234.                 var xhr = new XMLHttpRequest();
  235.                 xhr.onreadystatechange = function() {
  236.                         if (xhr.readyState === 4) {
  237.                                 if (xhr.status === 200) {
  238.                                         $("#enforce_ssl").val('OIDplus::ENFORCE_SSL_YES'); // enforce SSL (we checked that it loads correctly)
  239.                                 } else {
  240.                                         console.log("JS SSL detection result: "+xhr.status);
  241.                                         $("#enforce_ssl").val('OIDplus::ENFORCE_SSL_NO'); // disable SSL (because it failed, e.g. because of invalid cert or closed port)
  242.                                         setCookie('SSL_CHECK', 0, 0/*Until browser closes*/, oidplus_webpath_relative); // we must revert the SSL_CHECK=1 the PHP script did set (see explanation in OIDplus.class.php:isSslAvailable)
  243.                                 }
  244.                         }
  245.                 };
  246.                 var https_url = window.location.href.replace(/^http:/i, "https:");
  247.                 xhr.open('GET', https_url);
  248.                 xhr.send();
  249.         }
  250. }
  251.  
  252. function setupOnLoad() {
  253.         rebuild();
  254.         dbplugin_changed();
  255.         captchaplugin_changed();
  256.         performAccessCheck();
  257. }
  258.  
  259. $(document).ready(setupOnLoad);
  260.