httprp.html 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  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 grey key icon"></i> Basic Auth`:``}
  115. ${subd.AuthenticationProvider.AuthMethod == 0x2?`<i class="ui blue key icon"></i> Authelia`:``}
  116. ${subd.AuthenticationProvider.AuthMethod == 0x3?`<i class="ui yellow key icon"></i> Oauth2`:``}
  117. ${subd.AuthenticationProvider.AuthMethod != 0x0 && subd.RequireRateLimit?"<br>":""}
  118. ${subd.RequireRateLimit?`<i class="ui green check icon"></i> Rate Limit @ ${subd.RateLimit} req/s`:``}
  119. ${subd.AuthenticationProvider.AuthMethod == 0x0 && !subd.RequireRateLimit?`<small style="opacity: 0.3; pointer-events: none; user-select: none;">No Special Settings</small>`:""}
  120. </td>
  121. <td class="center aligned ignoremw" editable="true" datatype="action" data-label="">
  122. <div class="ui toggle tiny fitted checkbox" style="margin-bottom: -0.5em; margin-right: 0.4em;" title="Enable / Disable Rule">
  123. <input type="checkbox" class="enableToggle" name="active" ${enableChecked} eptuuid="${subd.RootOrMatchingDomain}" onchange="handleProxyRuleToggle(this);">
  124. <label></label>
  125. </div>
  126. <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>
  127. <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>
  128. </td>
  129. </tr>`);
  130. });
  131. }
  132. resolveAccessRuleNameOnHostRPlist();
  133. });
  134. }
  135. //Perform realtime alias update without refreshing the whole page
  136. function updateAliasListForEndpoint(endpointName, newAliasDomainList){
  137. let targetEle = $(`.aliasDomains[eptuuid='${endpointName}']`);
  138. console.log(targetEle);
  139. if (targetEle.length == 0){
  140. return;
  141. }
  142. let aliasDomains = ``;
  143. if (newAliasDomainList != undefined && newAliasDomainList.length > 0){
  144. aliasDomains = `Alias: `;
  145. newAliasDomainList.forEach(alias => {
  146. aliasDomains += `<a href="//${alias}" target="_blank">${alias}</a>, `;
  147. });
  148. aliasDomains = aliasDomains.substr(0, aliasDomains.length - 2); //Remove the last tailing seperator
  149. $(targetEle).html(aliasDomains);
  150. $(targetEle).show();
  151. }else{
  152. $(targetEle).hide();
  153. }
  154. }
  155. //Resolve & Update all rule names on host PR list
  156. function resolveAccessRuleNameOnHostRPlist(){
  157. //Resolve the access filters
  158. $.get("/api/access/list", function(data){
  159. console.log(data);
  160. if (data.error == undefined){
  161. //Build a map base on the data
  162. let accessRuleMap = {};
  163. for (var i = 0; i < data.length; i++){
  164. accessRuleMap[data[i].ID] = data[i];
  165. }
  166. $(".accessRuleNameUnderHost").each(function(){
  167. let thisAccessRuleID = $(this).attr("ruleid");
  168. if (thisAccessRuleID== ""){
  169. thisAccessRuleID = "default"
  170. }
  171. if (thisAccessRuleID == "default"){
  172. //No need to label default access rules
  173. $(this).html("");
  174. return;
  175. }
  176. let rule = accessRuleMap[thisAccessRuleID];
  177. if (rule == undefined){
  178. //Missing config or config too old
  179. $(this).html(`<i class="ui red exclamation triangle icon"></i> <b style="color: #db2828;">Access Rule Error</b>`);
  180. return;
  181. }
  182. let icon = `<i class="ui grey filter icon"></i>`;
  183. if (rule.ID == "default"){
  184. icon = `<i class="ui yellow star icon"></i>`;
  185. }else if (rule.BlacklistEnabled && !rule.WhitelistEnabled){
  186. //This is a blacklist filter
  187. icon = `<i class="ui red filter icon"></i>`;
  188. }else if (rule.WhitelistEnabled && !rule.BlacklistEnabled){
  189. //This is a whitelist filter
  190. icon = `<i class="ui green filter icon"></i>`;
  191. }else if (rule.WhitelistEnabled && rule.BlacklistEnabled){
  192. //Whitelist and blacklist filter
  193. icon = `<i class="ui yellow filter icon"></i>`;
  194. }
  195. if (rule != undefined){
  196. $(this).html(`${icon} ${rule.Name}`);
  197. }
  198. });
  199. }
  200. })
  201. }
  202. //Update the access rule name on given epuuid, call by hostAccessEditor.html
  203. function updateAccessRuleNameUnderHost(epuuid, newruleUID){
  204. $(`tr[eptuuid='${epuuid}'].subdEntry`).find(".accessRuleNameUnderHost").attr("ruleid", newruleUID);
  205. resolveAccessRuleNameOnHostRPlist();
  206. }
  207. /*
  208. Inline editor for httprp.html
  209. */
  210. function editEndpoint(uuid) {
  211. uuid = uuid.hexDecode();
  212. var row = $('tr[eptuuid="' + uuid + '"]');
  213. var columns = row.find('td[data-label]');
  214. var payload = $(row).attr("payload");
  215. payload = JSON.parse(decodeURIComponent(payload));
  216. console.log(payload);
  217. columns.each(function(index) {
  218. var column = $(this);
  219. var oldValue = column.text().trim();
  220. if ($(this).attr("editable") == "false"){
  221. //This col do not allow edit. Skip
  222. return;
  223. }
  224. // Create an input element based on the column content
  225. var input;
  226. var datatype = $(this).attr("datatype");
  227. if (datatype == "domain"){
  228. let useStickySessionChecked = "";
  229. if (payload.UseStickySession){
  230. useStickySessionChecked = "checked";
  231. }
  232. 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>
  233. <div class="ui divider"></div>
  234. <div class="ui checkbox" style="margin-top: 0.4em;">
  235. <input type="checkbox" class="UseStickySession" ${useStickySessionChecked}>
  236. <label>Use Sticky Session<br>
  237. <small>Enable stick session on load balancing</small></label>
  238. </div>
  239. `;
  240. column.append(input);
  241. $(column).find(".upstreamList").addClass("editing");
  242. }else if (datatype == "vdir"){
  243. //Append a quick access button for vdir page
  244. column.append(`<button class="ui basic tiny button" style="margin-left: 0.4em; margin-top: 0.4em;" onclick="quickEditVdir('${uuid}');">
  245. <i class="ui yellow folder icon"></i> Edit Virtual Directories
  246. </button>`);
  247. }else if (datatype == "advanced"){
  248. let authProvider = payload.AuthenticationProvider.AuthMethod;
  249. let skipWebSocketOriginCheck = payload.SkipWebSocketOriginCheck;
  250. let wsCheckstate = "";
  251. if (skipWebSocketOriginCheck){
  252. wsCheckstate = "checked";
  253. }
  254. let requireRateLimit = payload.RequireRateLimit;
  255. let rateLimitCheckState = "";
  256. if (requireRateLimit){
  257. rateLimitCheckState = "checked";
  258. }
  259. let rateLimit = payload.RateLimit;
  260. if (rateLimit == 0){
  261. //This value is not set. Make it default to 100
  262. rateLimit = 100;
  263. }
  264. let rateLimitDisableState = "";
  265. if (!payload.RequireRateLimit){
  266. rateLimitDisableState = "disabled";
  267. }
  268. column.empty().append(`
  269. <div class="grouped fields authProviderPicker">
  270. <label><b>Authentication Provider</b></label>
  271. <div class="field">
  272. <div class="ui radio checkbox">
  273. <input type="radio" value="0" name="authProviderType" ${authProvider==0x0?"checked":""}>
  274. <label>None (Anyone can access)</label>
  275. </div>
  276. </div>
  277. <div class="field">
  278. <div class="ui radio checkbox">
  279. <input type="radio" value="1" name="authProviderType" ${authProvider==0x1?"checked":""}>
  280. <label>Basic Auth</label>
  281. </div>
  282. </div>
  283. <div class="field">
  284. <div class="ui radio checkbox">
  285. <input type="radio" value="2" name="authProviderType" ${authProvider==0x2?"checked":""}>
  286. <label>Authelia</label>
  287. </div>
  288. </div>
  289. </div>
  290. <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>
  291. <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>
  292. <div class="ui basic advance segment" style="padding: 0.4em !important; border-radius: 0.4em;">
  293. <div class="ui endpointAdvanceConfig accordion" style="padding-right: 0.6em;">
  294. <div class="title">
  295. <i class="dropdown icon"></i>
  296. Security Options
  297. </div>
  298. <div class="content">
  299. <div class="ui checkbox" style="margin-top: 0.4em;">
  300. <input type="checkbox" onchange="handleToggleRateLimitInput();" class="RequireRateLimit" ${rateLimitCheckState}>
  301. <label>Require Rate Limit<br>
  302. <small>Check this to enable rate limit on this inbound hostname</small></label>
  303. </div><br>
  304. <div class="ui mini right labeled fluid input ${rateLimitDisableState}" style="margin-top: 0.4em;">
  305. <input type="number" class="RateLimit" value="${rateLimit}" min="1" >
  306. <label class="ui basic label">
  307. req / sec / IP
  308. </label>
  309. </div>
  310. </div>
  311. </div>
  312. <div>
  313. `);
  314. $('.authProviderPicker .ui.checkbox').checkbox();
  315. } else if (datatype == "ratelimit"){
  316. column.empty().append(`
  317. <div class="ui checkbox" style="margin-top: 0.4em;">
  318. <input type="checkbox" class="RequireRateLimit" ${checkstate}>
  319. <label>Require Rate Limit</label>
  320. </div>
  321. <div class="ui mini fluid input">
  322. <input type="number" class="RateLimit" value="${rateLimit}" placeholder="100" min="1" max="1000" >
  323. </div>
  324. `);
  325. }else if (datatype == 'action'){
  326. column.empty().append(`
  327. <button title="Save" onclick="saveProxyInlineEdit('${uuid.hexEncode()}');" class="ui basic small icon circular button inlineEditActionBtn"><i class="ui green save icon"></i></button>
  328. <button title="Cancel" onclick="exitProxyInlineEdit();" class="ui basic small icon circular button inlineEditActionBtn"><i class="ui remove icon"></i></button>
  329. `);
  330. }else if (datatype == "inbound"){
  331. let originalContent = $(column).html();
  332. //Check if this host is covered within one of the certificates. If not, show the icon
  333. let enableQuickRequestButton = true;
  334. let domains = [payload.RootOrMatchingDomain]; //Domain for getting certificate if needed
  335. for (var i = 0; i < payload.MatchingDomainAlias.length; i++){
  336. let thisAliasName = payload.MatchingDomainAlias[i];
  337. domains.push(thisAliasName);
  338. }
  339. //Check if the domain or alias contains wildcard, if yes, disabled the get certificate button
  340. if (payload.RootOrMatchingDomain.indexOf("*") > -1){
  341. enableQuickRequestButton = false;
  342. }
  343. if (payload.MatchingDomainAlias != undefined){
  344. for (var i = 0; i < payload.MatchingDomainAlias.length; i++){
  345. if (payload.MatchingDomainAlias[i].indexOf("*") > -1){
  346. enableQuickRequestButton = false;
  347. break;
  348. }
  349. }
  350. }
  351. //encode the domain to DOM
  352. let certificateDomains = encodeURIComponent(JSON.stringify(domains));
  353. column.empty().append(`${originalContent}
  354. <div class="ui divider"></div>
  355. <div class="ui checkbox" style="margin-top: 0.4em;">
  356. <input type="checkbox" class="BypassGlobalTLS" ${payload.BypassGlobalTLS?"checked":""}>
  357. <label>Allow plain HTTP access<br>
  358. <small>Allow inbound connections without TLS/SSL</small></label>
  359. </div><br>
  360. <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>
  361. <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>
  362. <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>
  363. `);
  364. $(".hostAccessRuleSelector").dropdown();
  365. }else{
  366. //Unknown field. Leave it untouched
  367. }
  368. });
  369. $(".endpointAdvanceConfig").accordion();
  370. $("#httpProxyList").find(".editBtn").addClass("disabled");
  371. }
  372. //handleToggleRateLimitInput will get trigger if the "require rate limit" checkbox
  373. // is changed and toggle the disable state of the rate limit input field
  374. function handleToggleRateLimitInput(){
  375. let isRateLimitEnabled = $("#httpProxyList input.RequireRateLimit")[0].checked;
  376. if (isRateLimitEnabled){
  377. $("#httpProxyList input.RateLimit").parent().removeClass("disabled");
  378. }else{
  379. $("#httpProxyList input.RateLimit").parent().addClass("disabled");
  380. }
  381. }
  382. function exitProxyInlineEdit(){
  383. listProxyEndpoints();
  384. $("#httpProxyList").find(".editBtn").removeClass("disabled");
  385. }
  386. function saveProxyInlineEdit(uuid){
  387. uuid = uuid.hexDecode();
  388. var row = $('tr[eptuuid="' + uuid + '"]');
  389. if (row.length == 0){
  390. return;
  391. }
  392. var epttype = "host";
  393. let useStickySession = $(row).find(".UseStickySession")[0].checked;
  394. let authProviderType = $(row).find(".authProviderPicker input[type='radio']:checked").val();
  395. let requireRateLimit = $(row).find(".RequireRateLimit")[0].checked;
  396. let rateLimit = $(row).find(".RateLimit").val();
  397. let bypassGlobalTLS = $(row).find(".BypassGlobalTLS")[0].checked;
  398. $.cjax({
  399. url: "/api/proxy/edit",
  400. method: "POST",
  401. data: {
  402. "type": epttype,
  403. "rootname": uuid,
  404. "ss":useStickySession,
  405. "bpgtls": bypassGlobalTLS,
  406. "authprovider" :authProviderType,
  407. "rate" :requireRateLimit,
  408. "ratenum" :rateLimit,
  409. },
  410. success: function(data){
  411. if (data.error !== undefined){
  412. msgbox(data.error, false, 6000);
  413. }else{
  414. msgbox("Proxy endpoint updated");
  415. listProxyEndpoints();
  416. }
  417. }
  418. })
  419. }
  420. //Generic functions for delete rp endpoints
  421. function deleteEndpoint(epoint){
  422. epoint = decodeURIComponent(epoint).hexDecode();
  423. if (confirm("Confirm remove proxy for :" + epoint + "?")){
  424. $.cjax({
  425. url: "/api/proxy/del",
  426. method: "POST",
  427. data: {ep: epoint},
  428. success: function(data){
  429. if (data.error == undefined){
  430. listProxyEndpoints();
  431. msgbox("Proxy Rule Deleted", true);
  432. reloadUptimeList();
  433. }else{
  434. msgbox(data.error, false);
  435. }
  436. }
  437. })
  438. }
  439. }
  440. /* button events */
  441. function editBasicAuthCredentials(uuid){
  442. let payload = encodeURIComponent(JSON.stringify({
  443. ept: "host",
  444. ep: uuid
  445. }));
  446. showSideWrapper("snippet/basicAuthEditor.html?t=" + Date.now() + "#" + payload);
  447. }
  448. function editAccessRule(uuid){
  449. let payload = encodeURIComponent(JSON.stringify({
  450. ept: "host",
  451. ep: uuid
  452. }));
  453. showSideWrapper("snippet/hostAccessEditor.html?t=" + Date.now() + "#" + payload);
  454. }
  455. function editAliasHostnames(uuid){
  456. let payload = encodeURIComponent(JSON.stringify({
  457. ept: "host",
  458. ep: uuid
  459. }));
  460. showSideWrapper("snippet/aliasEditor.html?t=" + Date.now() + "#" + payload);
  461. }
  462. function quickEditVdir(uuid){
  463. openTabById("vdir");
  464. $("#vdirBaseRoutingRule").parent().dropdown("set selected", uuid);
  465. }
  466. //Open the custom header editor
  467. function editCustomHeaders(uuid){
  468. let payload = encodeURIComponent(JSON.stringify({
  469. ept: "host",
  470. ep: uuid
  471. }));
  472. showSideWrapper("snippet/customHeaders.html?t=" + Date.now() + "#" + payload);
  473. }
  474. //Open the load balance option
  475. function editUpstreams(uuid){
  476. let payload = encodeURIComponent(JSON.stringify({
  477. ept: "host",
  478. ep: uuid
  479. }));
  480. showSideWrapper("snippet/upstreams.html?t=" + Date.now() + "#" + payload);
  481. }
  482. function handleProxyRuleToggle(object){
  483. let endpointUUID = $(object).attr("eptuuid");
  484. let isChecked = object.checked;
  485. $.cjax({
  486. url: "/api/proxy/toggle",
  487. data: {
  488. "ep": endpointUUID,
  489. "enable": isChecked
  490. },
  491. success: function(data){
  492. if (data.error != undefined){
  493. msgbox(data.error, false);
  494. }else{
  495. if (isChecked){
  496. msgbox("Proxy Rule Enabled");
  497. }else{
  498. msgbox("Proxy Rule Disabled");
  499. }
  500. }
  501. }
  502. })
  503. }
  504. /*
  505. Certificate Shortcut
  506. */
  507. function requestCertificateForExistingHost(hostUUID, RootAndAliasDomains, btn=undefined){
  508. RootAndAliasDomains = JSON.parse(decodeURIComponent(RootAndAliasDomains))
  509. let renewDomainKey = RootAndAliasDomains.join(",");
  510. let preferedACMEEmail = $("#prefACMEEmail").val();
  511. if (preferedACMEEmail == ""){
  512. msgbox("Preferred email for ACME registration not set", false);
  513. return;
  514. }
  515. let defaultCA = $("#defaultCA").dropdown("get value");
  516. if (defaultCA == ""){
  517. defaultCA = "Let's Encrypt";
  518. }
  519. //Check if the root or the alias domain contain wildcard character, if yes, return error
  520. for (var i = 0; i < RootAndAliasDomains.length; i++){
  521. if (RootAndAliasDomains[i].indexOf("*") != -1){
  522. msgbox("Wildcard domain can only be setup via ACME tool", false);
  523. return;
  524. }
  525. }
  526. //Renew the certificate
  527. renewCertificate(renewDomainKey, false, btn);
  528. }
  529. //Bind on tab switch events
  530. tabSwitchEventBind["httprp"] = function(){
  531. listProxyEndpoints();
  532. }
  533. </script>