admin_diagnostics.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. "use strict";
  2. var dnsCheck = false;
  3. var timeCheck = false;
  4. var domainCheck = false;
  5. var httpsCheck = false;
  6. // ================================
  7. // Date & Time Check
  8. const d = new Date();
  9. const year = d.getUTCFullYear();
  10. const month = String(d.getUTCMonth()+1).padStart(2, "0");
  11. const day = String(d.getUTCDate()).padStart(2, "0");
  12. const hour = String(d.getUTCHours()).padStart(2, "0");
  13. const minute = String(d.getUTCMinutes()).padStart(2, "0");
  14. const seconds = String(d.getUTCSeconds()).padStart(2, "0");
  15. const browserUTC = `${year}-${month}-${day} ${hour}:${minute}:${seconds} UTC`;
  16. // ================================
  17. // Check if the output is a valid IP
  18. const isValidIp = value => (/^(?:(?:^|\.)(?:2(?:5[0-5]|[0-4]\d)|1?\d?\d)){4}$/.test(value) ? true : false);
  19. function checkVersions(platform, installed, latest, commit=null) {
  20. if (installed === "-" || latest === "-") {
  21. document.getElementById(`${platform}-failed`).classList.remove("d-none");
  22. return;
  23. }
  24. // Only check basic versions, no commit revisions
  25. if (commit === null || installed.indexOf("-") === -1) {
  26. if (installed !== latest) {
  27. document.getElementById(`${platform}-warning`).classList.remove("d-none");
  28. } else {
  29. document.getElementById(`${platform}-success`).classList.remove("d-none");
  30. }
  31. } else {
  32. // Check if this is a branched version.
  33. const branchRegex = /(?:\s)\((.*?)\)/;
  34. const branchMatch = installed.match(branchRegex);
  35. if (branchMatch !== null) {
  36. document.getElementById(`${platform}-branch`).classList.remove("d-none");
  37. }
  38. // This will remove branch info and check if there is a commit hash
  39. const installedRegex = /(\d+\.\d+\.\d+)-(\w+)/;
  40. const instMatch = installed.match(installedRegex);
  41. // It could be that a new tagged version has the same commit hash.
  42. // In this case the version is the same but only the number is different
  43. if (instMatch !== null) {
  44. if (instMatch[2] === commit) {
  45. // The commit hashes are the same, so latest version is installed
  46. document.getElementById(`${platform}-success`).classList.remove("d-none");
  47. return;
  48. }
  49. }
  50. if (installed === latest) {
  51. document.getElementById(`${platform}-success`).classList.remove("d-none");
  52. } else {
  53. document.getElementById(`${platform}-warning`).classList.remove("d-none");
  54. }
  55. }
  56. }
  57. // ================================
  58. // Generate support string to be pasted on github or the forum
  59. async function generateSupportString(dj) {
  60. event.preventDefault();
  61. event.stopPropagation();
  62. let supportString = "### Your environment (Generated via diagnostics page)\n";
  63. supportString += `* Vaultwarden version: v${dj.current_release}\n`;
  64. supportString += `* Web-vault version: v${dj.web_vault_version}\n`;
  65. supportString += `* OS/Arch: ${dj.host_os}/${dj.host_arch}\n`;
  66. supportString += `* Running within Docker: ${dj.running_within_docker} (Base: ${dj.docker_base_image})\n`;
  67. supportString += "* Environment settings overridden: ";
  68. if (dj.overrides != "") {
  69. supportString += "true\n";
  70. } else {
  71. supportString += "false\n";
  72. }
  73. supportString += `* Uses a reverse proxy: ${dj.ip_header_exists}\n`;
  74. if (dj.ip_header_exists) {
  75. supportString += `* IP Header check: ${dj.ip_header_match} (${dj.ip_header_name})\n`;
  76. }
  77. supportString += `* Internet access: ${dj.has_http_access}\n`;
  78. supportString += `* Internet access via a proxy: ${dj.uses_proxy}\n`;
  79. supportString += `* DNS Check: ${dnsCheck}\n`;
  80. supportString += `* Time Check: ${timeCheck}\n`;
  81. supportString += `* Domain Configuration Check: ${domainCheck}\n`;
  82. supportString += `* HTTPS Check: ${httpsCheck}\n`;
  83. supportString += `* Database type: ${dj.db_type}\n`;
  84. supportString += `* Database version: ${dj.db_version}\n`;
  85. supportString += "* Clients used: \n";
  86. supportString += "* Reverse proxy and version: \n";
  87. supportString += "* Other relevant information: \n";
  88. const jsonResponse = await fetch(`${BASE_URL}/admin/diagnostics/config`, {
  89. "headers": { "Accept": "application/json" }
  90. });
  91. if (!jsonResponse.ok) {
  92. alert("Generation failed: " + jsonResponse.statusText);
  93. throw new Error(jsonResponse);
  94. }
  95. const configJson = await jsonResponse.json();
  96. supportString += "\n### Config (Generated via diagnostics page)\n<details><summary>Show Running Config</summary>\n";
  97. supportString += `\n**Environment settings which are overridden:** ${dj.overrides}\n`;
  98. supportString += "\n\n```json\n" + JSON.stringify(configJson, undefined, 2) + "\n```\n</details>\n";
  99. document.getElementById("support-string").innerText = supportString;
  100. document.getElementById("support-string").classList.remove("d-none");
  101. document.getElementById("copy-support").classList.remove("d-none");
  102. }
  103. function copyToClipboard() {
  104. event.preventDefault();
  105. event.stopPropagation();
  106. const supportStr = document.getElementById("support-string").innerText;
  107. const tmpCopyEl = document.createElement("textarea");
  108. tmpCopyEl.setAttribute("id", "copy-support-string");
  109. tmpCopyEl.setAttribute("readonly", "");
  110. tmpCopyEl.value = supportStr;
  111. tmpCopyEl.style.position = "absolute";
  112. tmpCopyEl.style.left = "-9999px";
  113. document.body.appendChild(tmpCopyEl);
  114. tmpCopyEl.select();
  115. document.execCommand("copy");
  116. tmpCopyEl.remove();
  117. new BSN.Toast("#toastClipboardCopy").show();
  118. }
  119. function checkTimeDrift(browserUTC, serverUTC) {
  120. const timeDrift = (
  121. Date.parse(serverUTC.replace(" ", "T").replace(" UTC", "")) -
  122. Date.parse(browserUTC.replace(" ", "T").replace(" UTC", ""))
  123. ) / 1000;
  124. if (timeDrift > 20 || timeDrift < -20) {
  125. document.getElementById("time-warning").classList.remove("d-none");
  126. } else {
  127. document.getElementById("time-success").classList.remove("d-none");
  128. timeCheck = true;
  129. }
  130. }
  131. function checkDomain(browserURL, serverURL) {
  132. if (serverURL == browserURL) {
  133. document.getElementById("domain-success").classList.remove("d-none");
  134. domainCheck = true;
  135. } else {
  136. document.getElementById("domain-warning").classList.remove("d-none");
  137. }
  138. // Check for HTTPS at domain-server-string
  139. if (serverURL.startsWith("https://") ) {
  140. document.getElementById("https-success").classList.remove("d-none");
  141. httpsCheck = true;
  142. } else {
  143. document.getElementById("https-warning").classList.remove("d-none");
  144. }
  145. }
  146. function initVersionCheck(dj) {
  147. const serverInstalled = dj.current_release;
  148. const serverLatest = dj.latest_release;
  149. const serverLatestCommit = dj.latest_commit;
  150. if (serverInstalled.indexOf("-") !== -1 && serverLatest !== "-" && serverLatestCommit !== "-") {
  151. document.getElementById("server-latest-commit").classList.remove("d-none");
  152. }
  153. checkVersions("server", serverInstalled, serverLatest, serverLatestCommit);
  154. if (!dj.running_within_docker) {
  155. const webInstalled = dj.web_vault_version;
  156. const webLatest = dj.latest_web_build;
  157. checkVersions("web", webInstalled, webLatest);
  158. }
  159. }
  160. function checkDns(dns_resolved) {
  161. if (isValidIp(dns_resolved)) {
  162. document.getElementById("dns-success").classList.remove("d-none");
  163. dnsCheck = true;
  164. } else {
  165. document.getElementById("dns-warning").classList.remove("d-none");
  166. }
  167. }
  168. function init(dj) {
  169. // Time check
  170. document.getElementById("time-browser-string").innerText = browserUTC;
  171. checkTimeDrift(browserUTC, dj.server_time);
  172. // Domain check
  173. const browserURL = location.href.toLowerCase();
  174. document.getElementById("domain-browser-string").innerText = browserURL;
  175. checkDomain(browserURL, dj.admin_url.toLowerCase());
  176. // Version check
  177. initVersionCheck(dj);
  178. // DNS Check
  179. checkDns(dj.dns_resolved);
  180. }
  181. // onLoad events
  182. document.addEventListener("DOMContentLoaded", (/*event*/) => {
  183. const diag_json = JSON.parse(document.getElementById("diagnostics_json").innerText);
  184. init(diag_json);
  185. document.getElementById("gen-support").addEventListener("click", () => {
  186. generateSupportString(diag_json);
  187. });
  188. document.getElementById("copy-support").addEventListener("click", copyToClipboard);
  189. });