utils.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. <div class="standardContainer">
  2. <div class="ui basic segment">
  3. <h2>Utilities</h2>
  4. <p>You might find these tools or information helpful when setting up your gateway server</p>
  5. </div>
  6. <div class="ui divider"></div>
  7. <div class="selfauthOnly">
  8. <h3>Account Management</h3>
  9. <p>Functions to help management the current account</p>
  10. <div class="ui basic segment">
  11. <h5><i class="chevron down icon"></i> Change Password</h5>
  12. <div class="ui form">
  13. <div class="field">
  14. <label>Current Password</label>
  15. <input type="password" name="oldPassword" placeholder="Current Password">
  16. </div>
  17. <div class="field">
  18. <label>New Password</label>
  19. <input type="password" name="newPassword" placeholder="New Password">
  20. </div>
  21. <div class="field">
  22. <label>Confirm New Password</label>
  23. <input type="password" name="confirmNewPassword" placeholder="Confirm New Password">
  24. </div>
  25. <button class="ui basic button" onclick="changePassword()"><i class="ui teal key icon"></i> Change Password</button>
  26. </div>
  27. <div id="passwordChangeSuccMsg" class="ui green message" style="display:none;">
  28. <i class="ui circle checkmark green icon "></i> Password Updated
  29. </div>
  30. </div>
  31. <div class="ui divider"></div>
  32. <h3>Forget Password Email</h3>
  33. <p>The following SMTP settings help you to reset your password in case you have lost your management account.</p>
  34. <form id="email-form" class="ui form">
  35. <div class="field">
  36. <div class="fields">
  37. <div class="twelve wide field">
  38. <label>SMTP Provider Hostname</label>
  39. <input type="text" name="hostname" placeholder="E.g. mail.gandi.net">
  40. </div>
  41. <div class="four wide field">
  42. <label>Port</label>
  43. <input type="number" name="port" placeholder="E.g. 587" value="587">
  44. </div>
  45. </div>
  46. </div>
  47. <div class="field">
  48. <label>Sender Domain</label>
  49. <input type="text" name="domain" min="1" max="65534" placeholder="E.g. arozos.com">
  50. </div>
  51. <div class="field">
  52. <label>Sender Address</label>
  53. <input type="text" name="senderAddr" placeholder="E.g. [email protected]">
  54. </div>
  55. <div class="field">
  56. <div class="two fields">
  57. <div class="field">
  58. <label>Sender Username</label>
  59. <input type="text" name="username" placeholder="Username of the email account">
  60. </div>
  61. <div class="field">
  62. <label>Sender Password</label>
  63. <input type="password" name="password" placeholder="Password of the email account">
  64. <small>Leave empty to use the old password</small>
  65. </div>
  66. </div>
  67. </div>
  68. <div class="ui divider"></div>
  69. <p> Email for sending account reset link</p>
  70. <div class="field">
  71. <label>Admin Address</label>
  72. <input type="text" name="recvAddr" placeholder="E.g. [email protected]">
  73. </div>
  74. <button class="ui basic button" type="submit"><i class="blue save icon"></i> Set SMTP Configs</button>
  75. <button class="ui basic button" onclick="event.preventDefault(); sendTestEmail(this);"><i class="teal mail icon"></i> Send Test Email</button>
  76. </form>
  77. </div>
  78. <h3> IP Address to CIDR</h3>
  79. <p>No experience with CIDR notations? Here are some tools you can use to make setting up easier.</p>
  80. <div class="ui basic segment">
  81. <h5><i class="chevron down icon"></i> IP Range to CIDR Conversion</h5>
  82. <div class="ui message">
  83. <i class="info circle icon"></i> Note that the CIDR generated here covers additional IP address before or after the given range. If you need more details settings, please use CIDR with a smaller range and add additional IPs for detail range adjustment.
  84. </div>
  85. <div class="ui input">
  86. <input type="text" placeholder="Start IP" id="startIpInput">
  87. </div>
  88. <div class="ui input">
  89. <input type="text" placeholder="End IP" id="endIpInput">
  90. </div>
  91. <br>
  92. <button style="margin-top: 0.6em;" class="ui basic button" onclick="convertToCIDR()">Convert</button>
  93. <p>Results: <div id="cidrOutput">N/A</div></p>
  94. </div>
  95. <div class="ui basic segment">
  96. <h5><i class="chevron down icon"></i> CIDR to IP Range Conversion</h5>
  97. <div class="ui action input">
  98. <input type="text" placeholder="CIDR" id="cidrInput">
  99. <button class="ui basic button" onclick="convertToIPRange()">Convert</button>
  100. </div>
  101. <p>Results: <div id="ipRangeOutput">N/A</div></p>
  102. </div>
  103. </div>
  104. <script>
  105. /*
  106. Account Password utilities
  107. */
  108. $.get("/api/auth/userCount", function(data){
  109. if (data == 0){
  110. //Using external auth manager. Hide options
  111. $(".selfauthOnly").hide();
  112. }
  113. })
  114. function changePassword() {
  115. const oldPassword = document.getElementsByName('oldPassword')[0].value;
  116. const newPassword = document.getElementsByName('newPassword')[0].value;
  117. const confirmNewPassword = document.getElementsByName('confirmNewPassword')[0].value;
  118. $.ajax({
  119. type: "POST",
  120. url: "/api/auth/changePassword",
  121. data: {
  122. oldPassword: oldPassword,
  123. newPassword: newPassword,
  124. confirmPassword: confirmNewPassword,
  125. },
  126. success: function (data) {
  127. if (data.error != undefined){
  128. alert(data.error);
  129. }else{
  130. $("#passwordChangeSuccMsg").stop().finish().slideDown("fast").delay(3000).slideUp("fast");
  131. $('[name="oldPassword"]').val('');
  132. $('[name="newPassword"]').val('');
  133. $('[name="confirmNewPassword"]').val('');
  134. }
  135. },
  136. error: function (xhr, status, error) {
  137. alert("Error changing password: " + error);
  138. },
  139. });
  140. }
  141. /*
  142. SMTP Settings
  143. */
  144. //Bind events to the form
  145. $('#email-form').submit(function(e) {
  146. e.preventDefault();
  147. var data = {
  148. hostname: $('input[name=hostname]').val(),
  149. domain: $('input[name=domain]').val(),
  150. port: parseInt($('input[name=port]').val()),
  151. username: $('input[name=username]').val(),
  152. password: $('input[name=password]').val(),
  153. senderAddr: $('input[name=senderAddr]').val(),
  154. adminAddr: $('input[name=recvAddr]').val()
  155. };
  156. var inputValid = validateSMTPInputs();
  157. if (!inputValid){
  158. msgbox("SMTP input not valid", false, 5000);
  159. return;
  160. }
  161. $.ajax({
  162. type: "POST",
  163. url: "/api/tools/smtp/set",
  164. data: data,
  165. success: function(data) {
  166. if (data.error != undefined){
  167. msgbox(data.error, false, 5000);
  168. }else{
  169. msgbox("SMTP Account Updated")
  170. }
  171. },
  172. error: function(xhr, status, error) {
  173. msgbox(xhr.responseText, false, 5000);
  174. }
  175. });
  176. });
  177. function initSMTPSettings(){
  178. $.get("/api/tools/smtp/get", function(data){
  179. $('#email-form input[name=hostname]').val(data.Hostname);
  180. $('#email-form input[name=domain]').val(data.Domain);
  181. $('#email-form input[name=port]').val(data.Port);
  182. $('#email-form input[name=username]').val(data.Username);
  183. $('#email-form input[name=senderAddr]').val(data.SenderAddr);
  184. });
  185. $.get("/api/tools/smtp/admin", function(data){
  186. $('#email-form input[name=recvAddr]').val(data);
  187. });
  188. }
  189. initSMTPSettings();
  190. function sendTestEmail(btn){
  191. $(btn).addClass("loading").addClass("disabled");
  192. $.get("/api/tools/smtp/test", function(data){
  193. if (data.error !== undefined){
  194. msgbox(data.error, false, 5000);
  195. }else{
  196. msgbox("Test Email Sent")
  197. }
  198. $(btn).removeClass("loading").removeClass("disabled");
  199. })
  200. }
  201. function validateSMTPInputs() {
  202. let isValid = true;
  203. const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; // email regex pattern
  204. const domainRegex = /^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i; // domain/subdomain regex pattern
  205. const form = $('#email-form');
  206. // validate hostname
  207. const hostname = form.find('input[name="hostname"]').val().trim();
  208. if (!domainRegex.test(hostname)) {
  209. form.find('input[name="hostname"]').parent().addClass('error');
  210. isValid = false;
  211. } else {
  212. form.find('input[name="hostname"]').parent().removeClass('error');
  213. }
  214. // validate domain
  215. const domain = form.find('input[name="domain"]').val().trim();
  216. if (!domainRegex.test(domain)) {
  217. form.find('input[name="domain"]').parent().addClass('error');
  218. isValid = false;
  219. } else {
  220. form.find('input[name="domain"]').parent().removeClass('error');
  221. }
  222. // validate username
  223. const username = form.find('input[name="username"]').val().trim();
  224. if (username === '') {
  225. form.find('input[name="username"]').parent().addClass('error');
  226. isValid = false;
  227. } else {
  228. form.find('input[name="username"]').parent().removeClass('error');
  229. }
  230. // validate password
  231. const password = form.find('input[name="password"]').val().trim();
  232. if (password === '') {
  233. form.find('input[name="password"]').parent().addClass('error');
  234. isValid = false;
  235. } else {
  236. form.find('input[name="password"]').parent().removeClass('error');
  237. }
  238. // validate sender address
  239. const senderAddr = form.find('input[name="senderAddr"]').val().trim();
  240. if (!emailRegex.test(senderAddr)) {
  241. form.find('input[name="senderAddr"]').parent().addClass('error');
  242. isValid = false;
  243. } else {
  244. form.find('input[name="senderAddr"]').parent().removeClass('error');
  245. }
  246. // validate receiver address
  247. const recvAddr = form.find('input[name="recvAddr"]').val().trim();
  248. if (!emailRegex.test(recvAddr)) {
  249. form.find('input[name="recvAddr"]').parent().addClass('error');
  250. isValid = false;
  251. } else {
  252. form.find('input[name="recvAddr"]').parent().removeClass('error');
  253. }
  254. return isValid;
  255. }
  256. /*
  257. IP Address Utilities
  258. */
  259. //events handler
  260. function convertToCIDR() {
  261. const startIp = document.getElementById('startIpInput').value.trim();
  262. const endIp = document.getElementById('endIpInput').value.trim();
  263. const cidrOutput = document.getElementById('cidrOutput');
  264. const cidr = ipRangeToCIDR(startIp, endIp);
  265. const ipRange = cidrToRange(cidr);
  266. cidrOutput.innerHTML = `CIDR: ${cidr} <br> (Cover range: ${ipRange[0]} to ${ipRange[1]})`;
  267. }
  268. // CIDR to IP Range Conversion
  269. function convertToIPRange() {
  270. const cidr = document.getElementById('cidrInput').value.trim();
  271. const ipRangeOutput = document.getElementById('ipRangeOutput');
  272. const ipRange = cidrToRange(cidr);
  273. ipRangeOutput.innerHTML = `Start IP: ${ipRange[0]}<br>End IP: ${ipRange[1]}`;
  274. }
  275. //Ip conversion function
  276. function cidrToRange(cidr) {
  277. var range = [2];
  278. cidr = cidr.split('/');
  279. var cidr_1 = parseInt(cidr[1])
  280. range[0] = long2ip((ip2long(cidr[0])) & ((-1 << (32 - cidr_1))));
  281. start = ip2long(range[0])
  282. range[1] = long2ip( start + Math.pow(2, (32 - cidr_1)) - 1);
  283. return range;
  284. }
  285. function ipRangeToCIDR(ipStart, ipEnd) {
  286. var start = ip2long(ipStart);
  287. var end = ip2long(ipEnd);
  288. var cidr = 32;
  289. while (start != end) {
  290. start >>= 1;
  291. end >>= 1;
  292. cidr--;
  293. }
  294. return ipStart + '/' + cidr;
  295. }
  296. function ip2long (argIP) {
  297. // discuss at: https://locutus.io/php/ip2long/
  298. // original by: Waldo Malqui Silva (https://waldo.malqui.info)
  299. // improved by: Victor
  300. // revised by: fearphage (https://my.opera.com/fearphage/)
  301. // revised by: Theriault (https://github.com/Theriault)
  302. // estarget: es2015
  303. // example 1: ip2long('192.0.34.166')
  304. // returns 1: 3221234342
  305. // example 2: ip2long('0.0xABCDEF')
  306. // returns 2: 11259375
  307. // example 3: ip2long('255.255.255.256')
  308. // returns 3: false
  309. let i = 0
  310. // PHP allows decimal, octal, and hexadecimal IP components.
  311. // PHP allows between 1 (e.g. 127) to 4 (e.g 127.0.0.1) components.
  312. const pattern = new RegExp([
  313. '^([1-9]\\d*|0[0-7]*|0x[\\da-f]+)',
  314. '(?:\\.([1-9]\\d*|0[0-7]*|0x[\\da-f]+))?',
  315. '(?:\\.([1-9]\\d*|0[0-7]*|0x[\\da-f]+))?',
  316. '(?:\\.([1-9]\\d*|0[0-7]*|0x[\\da-f]+))?$'
  317. ].join(''), 'i')
  318. argIP = argIP.match(pattern) // Verify argIP format.
  319. if (!argIP) {
  320. // Invalid format.
  321. return false
  322. }
  323. // Reuse argIP variable for component counter.
  324. argIP[0] = 0
  325. for (i = 1; i < 5; i += 1) {
  326. argIP[0] += !!((argIP[i] || '').length)
  327. argIP[i] = parseInt(argIP[i]) || 0
  328. }
  329. // Continue to use argIP for overflow values.
  330. // PHP does not allow any component to overflow.
  331. argIP.push(256, 256, 256, 256)
  332. // Recalculate overflow of last component supplied to make up for missing components.
  333. argIP[4 + argIP[0]] *= Math.pow(256, 4 - argIP[0])
  334. if (argIP[1] >= argIP[5] ||
  335. argIP[2] >= argIP[6] ||
  336. argIP[3] >= argIP[7] ||
  337. argIP[4] >= argIP[8]) {
  338. return false
  339. }
  340. return argIP[1] * (argIP[0] === 1 || 16777216) +
  341. argIP[2] * (argIP[0] <= 2 || 65536) +
  342. argIP[3] * (argIP[0] <= 3 || 256) +
  343. argIP[4] * 1
  344. }
  345. function long2ip (ip) {
  346. // discuss at: https://locutus.io/php/long2ip/
  347. // original by: Waldo Malqui Silva (https://fayr.us/waldo/)
  348. // example 1: long2ip( 3221234342 )
  349. // returns 1: '192.0.34.166'
  350. if (!isFinite(ip)) {
  351. return false
  352. }
  353. return [ip >>> 24 & 0xFF, ip >>> 16 & 0xFF, ip >>> 8 & 0xFF, ip & 0xFF].join('.')
  354. }
  355. </script>