1
0

httprp.html 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. <div class="standardContainer">
  2. <div class="ui basic segment">
  3. <h2>HTTP Proxy</h2>
  4. <p>Proxy HTTP server with HTTP or HTTPS for multiple hosts. If you are only proxying for one host / domain, use Default Site instead.</p>
  5. </div>
  6. <style>
  7. #httpProxyList .ui.toggle.checkbox input:checked ~ label::before{
  8. background-color: #00ca52 !important;
  9. }
  10. .subdEntry td:not(.ignoremw){
  11. min-width: 200px;
  12. }
  13. </style>
  14. <div style="width: 100%; overflow-x: auto; margin-bottom: 1em; min-height: 300px;">
  15. <table class="ui celled sortable unstackable compact table">
  16. <thead>
  17. <tr>
  18. <th>Host</th>
  19. <th>Destination</th>
  20. <th>Virtual Directory</th>
  21. <th style="max-width: 300px;">Advanced Settings</th>
  22. <th class="no-sort" style="min-width:150px;">Actions</th>
  23. </tr>
  24. </thead>
  25. <tbody id="httpProxyList">
  26. </tbody>
  27. </table>
  28. </div>
  29. <button class="ui icon right floated basic button" onclick="listProxyEndpoints();"><i class="green refresh icon"></i> Refresh</button>
  30. <br><br>
  31. </div>
  32. <script>
  33. /* List all proxy endpoints */
  34. function listProxyEndpoints(){
  35. $.get("/api/proxy/list?type=host", function(data){
  36. $("#httpProxyList").html(``);
  37. if (data.error !== undefined){
  38. $("#httpProxyList").append(`<tr>
  39. <td data-label="" colspan="5"><i class="remove icon"></i> ${data.error}</td>
  40. </tr>`);
  41. }else if (data.length == 0){
  42. $("#httpProxyList").append(`<tr>
  43. <td data-label="" colspan="5"><i class="green check circle icon"></i> No HTTP Proxy Record</td>
  44. </tr>`);
  45. }else{
  46. //Sort by RootOrMatchingDomain field
  47. data.sort((a,b) => (a.RootOrMatchingDomain > b.RootOrMatchingDomain) ? 1 : ((b.RootOrMatchingDomain > a.RootOrMatchingDomain) ? -1 : 0))
  48. data.forEach(subd => {
  49. let subdData = encodeURIComponent(JSON.stringify(subd));
  50. //Build the upstream list
  51. let upstreams = "";
  52. if (subd.ActiveOrigins.length == 0){
  53. //Invalid config
  54. upstreams = `<i class="ui yellow exclamation triangle icon"></i> No Active Upstream Origin<br>`;
  55. }else{
  56. subd.ActiveOrigins.forEach(upstream => {
  57. console.log(upstream);
  58. //Check if the upstreams require TLS connections
  59. let tlsIcon = "";
  60. if (upstream.RequireTLS){
  61. tlsIcon = `<i class="green lock icon" title="TLS Mode"></i>`;
  62. if (upstream.SkipCertValidations){
  63. tlsIcon = `<i class="yellow lock icon" title="TLS/SSL mode without verification"></i>`
  64. }
  65. }
  66. let upstreamLink = `${upstream.RequireTLS?"https://":"http://"}${upstream.OriginIpOrDomain}`;
  67. upstreams += `<a href="${upstreamLink}" target="_blank">${upstream.OriginIpOrDomain} ${tlsIcon}</a><br>`;
  68. })
  69. }
  70. let inboundTlsIcon = "";
  71. if ($("#tls").checkbox("is checked")){
  72. inboundTlsIcon = `<i class="green lock icon" title="TLS Mode"></i>`;
  73. if (subd.BypassGlobalTLS){
  74. inboundTlsIcon = `<i class="grey lock icon" title="TLS Bypass Enabled"></i>`;
  75. }
  76. }else{
  77. inboundTlsIcon = `<i class="yellow lock open icon" title="Plain Text Mode"></i>`;
  78. }
  79. //Build the virtual directory list
  80. var vdList = `<div class="ui list">`;
  81. subd.VirtualDirectories.forEach(vdir => {
  82. vdList += `<div class="item">${vdir.MatchingPath} <i class="green angle double right icon"></i> ${vdir.Domain}</div>`;
  83. });
  84. vdList += `</div>`;
  85. if (subd.VirtualDirectories.length == 0){
  86. vdList = `<small style="opacity: 0.3; pointer-events: none; user-select: none;">No Virtual Directory</small>`;
  87. }
  88. let enableChecked = "checked";
  89. if (subd.Disabled){
  90. enableChecked = "";
  91. }
  92. let aliasDomains = ``;
  93. if (subd.MatchingDomainAlias != undefined && subd.MatchingDomainAlias.length > 0){
  94. aliasDomains = `<small class="aliasDomains" eptuuid="${subd.RootOrMatchingDomain}" style="color: #636363;">Alias: `;
  95. subd.MatchingDomainAlias.forEach(alias => {
  96. aliasDomains += `<a href="//${alias}" target="_blank">${alias}</a>, `;
  97. });
  98. aliasDomains = aliasDomains.substr(0, aliasDomains.length - 2); //Remove the last tailing seperator
  99. aliasDomains += `</small><br>`;
  100. }
  101. $("#httpProxyList").append(`<tr eptuuid="${subd.RootOrMatchingDomain}" payload="${subdData}" class="subdEntry">
  102. <td data-label="" editable="true" datatype="inbound">
  103. <a href="//${subd.RootOrMatchingDomain}" target="_blank">${subd.RootOrMatchingDomain}</a> ${inboundTlsIcon}<br>
  104. ${aliasDomains}
  105. <small class="accessRuleNameUnderHost" ruleid="${subd.AccessFilterUUID}"></small>
  106. </td>
  107. <td data-label="" editable="true" datatype="domain">
  108. <div class="upstreamList">
  109. ${upstreams}
  110. </div>
  111. </td>
  112. <td data-label="" editable="true" datatype="vdir">${vdList}</td>
  113. <td data-label="" editable="true" datatype="advanced" style="width: 350px;">
  114. ${subd.AuthenticationProvider.AuthMethod == 0x1?`<i class="ui green check icon"></i> Basic Auth`:``}
  115. ${subd.AuthenticationProvider.AuthMethod == 0x1 && subd.RequireRateLimit?"<br>":""}
  116. ${subd.AuthenticationProvider.RequireRateLimit?`<i class="ui green check icon"></i> Rate Limit @ ${subd.RateLimit} req/s`:``}
  117. ${!subd.AuthenticationProvider.AuthMethod == 0x1 && !subd.RequireRateLimit?`<small style="opacity: 0.3; pointer-events: none; user-select: none;">No Special Settings</small>`:""}
  118. </td>
  119. <td class="center aligned ignoremw" editable="true" datatype="action" data-label="">
  120. <div class="ui toggle tiny fitted checkbox" style="margin-bottom: -0.5em; margin-right: 0.4em;" title="Enable / Disable Rule">
  121. <input type="checkbox" class="enableToggle" name="active" ${enableChecked} eptuuid="${subd.RootOrMatchingDomain}" onchange="handleProxyRuleToggle(this);">
  122. <label></label>
  123. </div>
  124. <button title="Edit Proxy Rule" class="ui circular mini basic icon button editBtn inlineEditActionBtn" onclick='editEndpoint("${(subd.RootOrMatchingDomain).hexEncode()}")'><i class="edit icon"></i></button>
  125. <button title="Remove Proxy Rule" class="ui circular mini red basic icon button inlineEditActionBtn" onclick='deleteEndpoint("${(subd.RootOrMatchingDomain).hexEncode()}")'><i class="trash icon"></i></button>
  126. </td>
  127. </tr>`);
  128. });
  129. }
  130. resolveAccessRuleNameOnHostRPlist();
  131. });
  132. }
  133. //Perform realtime alias update without refreshing the whole page
  134. function updateAliasListForEndpoint(endpointName, newAliasDomainList){
  135. let targetEle = $(`.aliasDomains[eptuuid='${endpointName}']`);
  136. console.log(targetEle);
  137. if (targetEle.length == 0){
  138. return;
  139. }
  140. let aliasDomains = ``;
  141. if (newAliasDomainList != undefined && newAliasDomainList.length > 0){
  142. aliasDomains = `Alias: `;
  143. newAliasDomainList.forEach(alias => {
  144. aliasDomains += `<a href="//${alias}" target="_blank">${alias}</a>, `;
  145. });
  146. aliasDomains = aliasDomains.substr(0, aliasDomains.length - 2); //Remove the last tailing seperator
  147. $(targetEle).html(aliasDomains);
  148. $(targetEle).show();
  149. }else{
  150. $(targetEle).hide();
  151. }
  152. }
  153. //Resolve & Update all rule names on host PR list
  154. function resolveAccessRuleNameOnHostRPlist(){
  155. //Resolve the access filters
  156. $.get("/api/access/list", function(data){
  157. console.log(data);
  158. if (data.error == undefined){
  159. //Build a map base on the data
  160. let accessRuleMap = {};
  161. for (var i = 0; i < data.length; i++){
  162. accessRuleMap[data[i].ID] = data[i];
  163. }
  164. $(".accessRuleNameUnderHost").each(function(){
  165. let thisAccessRuleID = $(this).attr("ruleid");
  166. if (thisAccessRuleID== ""){
  167. thisAccessRuleID = "default"
  168. }
  169. if (thisAccessRuleID == "default"){
  170. //No need to label default access rules
  171. $(this).html("");
  172. return;
  173. }
  174. let rule = accessRuleMap[thisAccessRuleID];
  175. let icon = `<i class="ui grey filter icon"></i>`;
  176. if (rule.ID == "default"){
  177. icon = `<i class="ui yellow star icon"></i>`;
  178. }else if (rule.BlacklistEnabled && !rule.WhitelistEnabled){
  179. //This is a blacklist filter
  180. icon = `<i class="ui red filter icon"></i>`;
  181. }else if (rule.WhitelistEnabled && !rule.BlacklistEnabled){
  182. //This is a whitelist filter
  183. icon = `<i class="ui green filter icon"></i>`;
  184. }else if (rule.WhitelistEnabled && rule.BlacklistEnabled){
  185. //Whitelist and blacklist filter
  186. icon = `<i class="ui yellow filter icon"></i>`;
  187. }
  188. if (rule != undefined){
  189. $(this).html(`${icon} ${rule.Name}`);
  190. }
  191. });
  192. }
  193. })
  194. }
  195. //Update the access rule name on given epuuid, call by hostAccessEditor.html
  196. function updateAccessRuleNameUnderHost(epuuid, newruleUID){
  197. $(`tr[eptuuid='${epuuid}'].subdEntry`).find(".accessRuleNameUnderHost").attr("ruleid", newruleUID);
  198. resolveAccessRuleNameOnHostRPlist();
  199. }
  200. /*
  201. Inline editor for httprp.html
  202. */
  203. function editEndpoint(uuid) {
  204. uuid = uuid.hexDecode();
  205. var row = $('tr[eptuuid="' + uuid + '"]');
  206. var columns = row.find('td[data-label]');
  207. var payload = $(row).attr("payload");
  208. payload = JSON.parse(decodeURIComponent(payload));
  209. console.log(payload);
  210. columns.each(function(index) {
  211. var column = $(this);
  212. var oldValue = column.text().trim();
  213. if ($(this).attr("editable") == "false"){
  214. //This col do not allow edit. Skip
  215. return;
  216. }
  217. // Create an input element based on the column content
  218. var input;
  219. var datatype = $(this).attr("datatype");
  220. if (datatype == "domain"){
  221. let useStickySessionChecked = "";
  222. if (payload.UseStickySession){
  223. useStickySessionChecked = "checked";
  224. }
  225. input = `<button class="ui basic compact tiny button" style="margin-left: 0.4em; margin-top: 1em;" onclick="editUpstreams('${uuid}');"><i class="grey server icon"></i> Edit Upstreams</button>
  226. <div class="ui divider"></div>
  227. <div class="ui checkbox" style="margin-top: 0.4em;">
  228. <input type="checkbox" class="UseStickySession" ${useStickySessionChecked}>
  229. <label>Use Sticky Session<br>
  230. <small>Enable stick session on load balancing</small></label>
  231. </div>
  232. `;
  233. column.append(input);
  234. $(column).find(".upstreamList").addClass("editing");
  235. }else if (datatype == "vdir"){
  236. //Append a quick access button for vdir page
  237. column.append(`<button class="ui basic tiny button" style="margin-left: 0.4em; margin-top: 0.4em;" onclick="quickEditVdir('${uuid}');">
  238. <i class="ui yellow folder icon"></i> Edit Virtual Directories
  239. </button>`);
  240. }else if (datatype == "advanced"){
  241. let requireBasicAuth = payload.AuthenticationProvider.AuthMethod == 0x1;
  242. let basicAuthCheckstate = "";
  243. if (requireBasicAuth){
  244. basicAuthCheckstate = "checked";
  245. }
  246. let skipWebSocketOriginCheck = payload.SkipWebSocketOriginCheck;
  247. let wsCheckstate = "";
  248. if (skipWebSocketOriginCheck){
  249. wsCheckstate = "checked";
  250. }
  251. let requireRateLimit = payload.RequireRateLimit;
  252. let rateLimitCheckState = "";
  253. if (requireRateLimit){
  254. rateLimitCheckState = "checked";
  255. }
  256. let rateLimit = payload.RateLimit;
  257. if (rateLimit == 0){
  258. //This value is not set. Make it default to 100
  259. rateLimit = 100;
  260. }
  261. let rateLimitDisableState = "";
  262. if (!payload.RequireRateLimit){
  263. rateLimitDisableState = "disabled";
  264. }
  265. column.empty().append(`<div class="ui checkbox" style="margin-top: 0.4em;">
  266. <input type="checkbox" class="RequireBasicAuth" ${basicAuthCheckstate}>
  267. <label>Require Basic Auth</label>
  268. </div>
  269. <br>
  270. <button class="ui basic compact tiny button" style="margin-left: 0.4em; margin-top: 0.4em;" onclick="editBasicAuthCredentials('${uuid}');"><i class="ui blue user circle icon"></i> Edit Credentials</button>
  271. <br>
  272. <button class="ui basic compact tiny button" style="margin-left: 0.4em; margin-top: 0.4em;" onclick="editCustomHeaders('${uuid}');"><i class="heading icon"></i> Custom Headers</button>
  273. <div class="ui basic advance segment" style="padding: 0.4em !important; border-radius: 0.4em;">
  274. <div class="ui endpointAdvanceConfig accordion" style="padding-right: 0.6em;">
  275. <div class="title">
  276. <i class="dropdown icon"></i>
  277. Security Options
  278. </div>
  279. <div class="content">
  280. <div class="ui checkbox" style="margin-top: 0.4em;">
  281. <input type="checkbox" onchange="handleToggleRateLimitInput();" class="RequireRateLimit" ${rateLimitCheckState}>
  282. <label>Require Rate Limit<br>
  283. <small>Check this to enable rate limit on this inbound hostname</small></label>
  284. </div><br>
  285. <div class="ui mini right labeled fluid input ${rateLimitDisableState}" style="margin-top: 0.4em;">
  286. <input type="number" class="RateLimit" value="${rateLimit}" min="1" >
  287. <label class="ui basic label">
  288. req / sec / IP
  289. </label>
  290. </div>
  291. </div>
  292. </div>
  293. <div>
  294. `);
  295. } else if (datatype == "ratelimit"){
  296. column.empty().append(`
  297. <div class="ui checkbox" style="margin-top: 0.4em;">
  298. <input type="checkbox" class="RequireRateLimit" ${checkstate}>
  299. <label>Require Rate Limit</label>
  300. </div>
  301. <div class="ui mini fluid input">
  302. <input type="number" class="RateLimit" value="${rateLimit}" placeholder="100" min="1" max="1000" >
  303. </div>
  304. `);
  305. }else if (datatype == 'action'){
  306. column.empty().append(`
  307. <button title="Save" onclick="saveProxyInlineEdit('${uuid.hexEncode()}');" class="ui basic small icon circular button inlineEditActionBtn"><i class="ui green save icon"></i></button>
  308. <button title="Cancel" onclick="exitProxyInlineEdit();" class="ui basic small icon circular button inlineEditActionBtn"><i class="ui remove icon"></i></button>
  309. `);
  310. }else if (datatype == "inbound"){
  311. let originalContent = $(column).html();
  312. //Check if this host is covered within one of the certificates. If not, show the icon
  313. let enableQuickRequestButton = true;
  314. let domains = [payload.RootOrMatchingDomain]; //Domain for getting certificate if needed
  315. for (var i = 0; i < payload.MatchingDomainAlias.length; i++){
  316. let thisAliasName = payload.MatchingDomainAlias[i];
  317. domains.push(thisAliasName);
  318. }
  319. //Check if the domain or alias contains wildcard, if yes, disabled the get certificate button
  320. if (payload.RootOrMatchingDomain.indexOf("*") > -1){
  321. enableQuickRequestButton = false;
  322. }
  323. if (payload.MatchingDomainAlias != undefined){
  324. for (var i = 0; i < payload.MatchingDomainAlias.length; i++){
  325. if (payload.MatchingDomainAlias[i].indexOf("*") > -1){
  326. enableQuickRequestButton = false;
  327. break;
  328. }
  329. }
  330. }
  331. //encode the domain to DOM
  332. let certificateDomains = encodeURIComponent(JSON.stringify(domains));
  333. column.empty().append(`${originalContent}
  334. <div class="ui divider"></div>
  335. <div class="ui checkbox" style="margin-top: 0.4em;">
  336. <input type="checkbox" class="BypassGlobalTLS" ${payload.BypassGlobalTLS?"checked":""}>
  337. <label>Allow plain HTTP access<br>
  338. <small>Allow inbound connections without TLS/SSL</small></label>
  339. </div><br>
  340. <button class="ui basic compact tiny button" style="margin-left: 0.4em; margin-top: 0.4em;" onclick="editAliasHostnames('${uuid}');"><i class=" blue at icon"></i> Alias</button>
  341. <button class="ui basic compact tiny button" style="margin-left: 0.4em; margin-top: 0.4em;" onclick="editAccessRule('${uuid}');"><i class="ui filter icon"></i> Access Rule</button>
  342. <button class="ui basic compact tiny ${enableQuickRequestButton?"":"disabled"} button" style="margin-left: 0.4em; margin-top: 0.4em;" onclick="requestCertificateForExistingHost('${uuid}', '${certificateDomains}', this);"><i class="green lock icon"></i> Get Certificate</button>
  343. `);
  344. $(".hostAccessRuleSelector").dropdown();
  345. }else{
  346. //Unknown field. Leave it untouched
  347. }
  348. });
  349. $(".endpointAdvanceConfig").accordion();
  350. $("#httpProxyList").find(".editBtn").addClass("disabled");
  351. }
  352. //handleToggleRateLimitInput will get trigger if the "require rate limit" checkbox
  353. // is changed and toggle the disable state of the rate limit input field
  354. function handleToggleRateLimitInput(){
  355. let isRateLimitEnabled = $("#httpProxyList input.RequireRateLimit")[0].checked;
  356. if (isRateLimitEnabled){
  357. $("#httpProxyList input.RateLimit").parent().removeClass("disabled");
  358. }else{
  359. $("#httpProxyList input.RateLimit").parent().addClass("disabled");
  360. }
  361. }
  362. function exitProxyInlineEdit(){
  363. listProxyEndpoints();
  364. $("#httpProxyList").find(".editBtn").removeClass("disabled");
  365. }
  366. function saveProxyInlineEdit(uuid){
  367. uuid = uuid.hexDecode();
  368. var row = $('tr[eptuuid="' + uuid + '"]');
  369. if (row.length == 0){
  370. return;
  371. }
  372. var epttype = "host";
  373. let useStickySession = $(row).find(".UseStickySession")[0].checked;
  374. let requireBasicAuth = $(row).find(".RequireBasicAuth")[0].checked;
  375. let requireRateLimit = $(row).find(".RequireRateLimit")[0].checked;
  376. let rateLimit = $(row).find(".RateLimit").val();
  377. let bypassGlobalTLS = $(row).find(".BypassGlobalTLS")[0].checked;
  378. $.cjax({
  379. url: "/api/proxy/edit",
  380. method: "POST",
  381. data: {
  382. "type": epttype,
  383. "rootname": uuid,
  384. "ss":useStickySession,
  385. "bpgtls": bypassGlobalTLS,
  386. "bauth" :requireBasicAuth,
  387. "rate" :requireRateLimit,
  388. "ratenum" :rateLimit,
  389. },
  390. success: function(data){
  391. if (data.error !== undefined){
  392. msgbox(data.error, false, 6000);
  393. }else{
  394. msgbox("Proxy endpoint updated");
  395. listProxyEndpoints();
  396. }
  397. }
  398. })
  399. }
  400. //Generic functions for delete rp endpoints
  401. function deleteEndpoint(epoint){
  402. epoint = decodeURIComponent(epoint).hexDecode();
  403. if (confirm("Confirm remove proxy for :" + epoint + "?")){
  404. $.cjax({
  405. url: "/api/proxy/del",
  406. method: "POST",
  407. data: {ep: epoint},
  408. success: function(data){
  409. if (data.error == undefined){
  410. listProxyEndpoints();
  411. msgbox("Proxy Rule Deleted", true);
  412. reloadUptimeList();
  413. }else{
  414. msgbox(data.error, false);
  415. }
  416. }
  417. })
  418. }
  419. }
  420. /* button events */
  421. function editBasicAuthCredentials(uuid){
  422. let payload = encodeURIComponent(JSON.stringify({
  423. ept: "host",
  424. ep: uuid
  425. }));
  426. showSideWrapper("snippet/basicAuthEditor.html?t=" + Date.now() + "#" + payload);
  427. }
  428. function editAccessRule(uuid){
  429. let payload = encodeURIComponent(JSON.stringify({
  430. ept: "host",
  431. ep: uuid
  432. }));
  433. showSideWrapper("snippet/hostAccessEditor.html?t=" + Date.now() + "#" + payload);
  434. }
  435. function editAliasHostnames(uuid){
  436. let payload = encodeURIComponent(JSON.stringify({
  437. ept: "host",
  438. ep: uuid
  439. }));
  440. showSideWrapper("snippet/aliasEditor.html?t=" + Date.now() + "#" + payload);
  441. }
  442. function quickEditVdir(uuid){
  443. openTabById("vdir");
  444. $("#vdirBaseRoutingRule").parent().dropdown("set selected", uuid);
  445. }
  446. //Open the custom header editor
  447. function editCustomHeaders(uuid){
  448. let payload = encodeURIComponent(JSON.stringify({
  449. ept: "host",
  450. ep: uuid
  451. }));
  452. showSideWrapper("snippet/customHeaders.html?t=" + Date.now() + "#" + payload);
  453. }
  454. //Open the load balance option
  455. function editUpstreams(uuid){
  456. let payload = encodeURIComponent(JSON.stringify({
  457. ept: "host",
  458. ep: uuid
  459. }));
  460. showSideWrapper("snippet/upstreams.html?t=" + Date.now() + "#" + payload);
  461. }
  462. function handleProxyRuleToggle(object){
  463. let endpointUUID = $(object).attr("eptuuid");
  464. let isChecked = object.checked;
  465. $.cjax({
  466. url: "/api/proxy/toggle",
  467. data: {
  468. "ep": endpointUUID,
  469. "enable": isChecked
  470. },
  471. success: function(data){
  472. if (data.error != undefined){
  473. msgbox(data.error, false);
  474. }else{
  475. if (isChecked){
  476. msgbox("Proxy Rule Enabled");
  477. }else{
  478. msgbox("Proxy Rule Disabled");
  479. }
  480. }
  481. }
  482. })
  483. }
  484. /*
  485. Certificate Shortcut
  486. */
  487. function requestCertificateForExistingHost(hostUUID, RootAndAliasDomains, btn=undefined){
  488. RootAndAliasDomains = JSON.parse(decodeURIComponent(RootAndAliasDomains))
  489. let renewDomainKey = RootAndAliasDomains.join(",");
  490. let preferedACMEEmail = $("#prefACMEEmail").val();
  491. if (preferedACMEEmail == ""){
  492. msgbox("Preferred email for ACME registration not set", false);
  493. return;
  494. }
  495. let defaultCA = $("#defaultCA").dropdown("get value");
  496. if (defaultCA == ""){
  497. defaultCA = "Let's Encrypt";
  498. }
  499. //Check if the root or the alias domain contain wildcard character, if yes, return error
  500. for (var i = 0; i < RootAndAliasDomains.length; i++){
  501. if (RootAndAliasDomains[i].indexOf("*") != -1){
  502. msgbox("Wildcard domain can only be setup via ACME tool", false);
  503. return;
  504. }
  505. }
  506. //Renew the certificate
  507. renewCertificate(renewDomainKey, false, btn);
  508. }
  509. //Bind on tab switch events
  510. tabSwitchEventBind["httprp"] = function(){
  511. listProxyEndpoints();
  512. }
  513. </script>