httprp.html 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  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. let enableUptimeMonitor = "";
  233. //Note the config file store the uptime monitor as disable, so we need to reverse the logic
  234. if (!payload.DisableUptimeMonitor){
  235. enableUptimeMonitor = "checked";
  236. }
  237. 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>
  238. <div class="ui divider"></div>
  239. <div class="ui checkbox" style="margin-top: 0.4em;">
  240. <input type="checkbox" class="UseStickySession" ${useStickySessionChecked}>
  241. <label>Use Sticky Session<br>
  242. <small>Enable stick session on load balancing</small></label>
  243. </div>
  244. <div class="ui checkbox" style="margin-top: 0.4em;">
  245. <input type="checkbox" class="EnableUptimeMonitor" ${enableUptimeMonitor}>
  246. <label>Monitor Uptime<br>
  247. <small>Enable active uptime monitor</small></label>
  248. </div>
  249. `;
  250. column.append(input);
  251. $(column).find(".upstreamList").addClass("editing");
  252. }else if (datatype == "vdir"){
  253. //Append a quick access button for vdir page
  254. column.append(`<button class="ui basic tiny button" style="margin-left: 0.4em; margin-top: 0.4em;" onclick="quickEditVdir('${uuid}');">
  255. <i class="ui yellow folder icon"></i> Edit Virtual Directories
  256. </button>`);
  257. }else if (datatype == "advanced"){
  258. let authProvider = payload.AuthenticationProvider.AuthMethod;
  259. let skipWebSocketOriginCheck = payload.SkipWebSocketOriginCheck;
  260. let wsCheckstate = "";
  261. if (skipWebSocketOriginCheck){
  262. wsCheckstate = "checked";
  263. }
  264. let requireRateLimit = payload.RequireRateLimit;
  265. let rateLimitCheckState = "";
  266. if (requireRateLimit){
  267. rateLimitCheckState = "checked";
  268. }
  269. let rateLimit = payload.RateLimit;
  270. if (rateLimit == 0){
  271. //This value is not set. Make it default to 100
  272. rateLimit = 100;
  273. }
  274. let rateLimitDisableState = "";
  275. if (!payload.RequireRateLimit){
  276. rateLimitDisableState = "disabled";
  277. }
  278. column.empty().append(`
  279. <div class="grouped fields authProviderPicker">
  280. <label><b>Authentication Provider</b></label>
  281. <div class="field">
  282. <div class="ui radio checkbox">
  283. <input type="radio" value="0" name="authProviderType" ${authProvider==0x0?"checked":""}>
  284. <label>None (Anyone can access)</label>
  285. </div>
  286. </div>
  287. <div class="field">
  288. <div class="ui radio checkbox">
  289. <input type="radio" value="1" name="authProviderType" ${authProvider==0x1?"checked":""}>
  290. <label>Basic Auth</label>
  291. </div>
  292. </div>
  293. <div class="field">
  294. <div class="ui radio checkbox">
  295. <input type="radio" value="2" name="authProviderType" ${authProvider==0x2?"checked":""}>
  296. <label>Authelia</label>
  297. </div>
  298. </div>
  299. </div>
  300. <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>
  301. <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>
  302. <div class="ui basic advance segment" style="padding: 0.4em !important; border-radius: 0.4em;">
  303. <div class="ui endpointAdvanceConfig accordion" style="padding-right: 0.6em;">
  304. <div class="title">
  305. <i class="dropdown icon"></i>
  306. Security Options
  307. </div>
  308. <div class="content">
  309. <div class="ui checkbox" style="margin-top: 0.4em;">
  310. <input type="checkbox" onchange="handleToggleRateLimitInput();" class="RequireRateLimit" ${rateLimitCheckState}>
  311. <label>Require Rate Limit<br>
  312. <small>Check this to enable rate limit on this inbound hostname</small></label>
  313. </div><br>
  314. <div class="ui mini right labeled fluid input ${rateLimitDisableState}" style="margin-top: 0.4em;">
  315. <input type="number" class="RateLimit" value="${rateLimit}" min="1" >
  316. <label class="ui basic label">
  317. req / sec / IP
  318. </label>
  319. </div>
  320. </div>
  321. </div>
  322. <div>
  323. `);
  324. $('.authProviderPicker .ui.checkbox').checkbox();
  325. } else if (datatype == "ratelimit"){
  326. column.empty().append(`
  327. <div class="ui checkbox" style="margin-top: 0.4em;">
  328. <input type="checkbox" class="RequireRateLimit" ${checkstate}>
  329. <label>Require Rate Limit</label>
  330. </div>
  331. <div class="ui mini fluid input">
  332. <input type="number" class="RateLimit" value="${rateLimit}" placeholder="100" min="1" max="1000" >
  333. </div>
  334. `);
  335. }else if (datatype == 'action'){
  336. column.empty().append(`
  337. <button title="Save" onclick="saveProxyInlineEdit('${uuid.hexEncode()}');" class="ui basic small icon circular button inlineEditActionBtn"><i class="ui green save icon"></i></button>
  338. <button title="Cancel" onclick="exitProxyInlineEdit();" class="ui basic small icon circular button inlineEditActionBtn"><i class="ui remove icon"></i></button>
  339. `);
  340. }else if (datatype == "inbound"){
  341. let originalContent = $(column).html();
  342. //Check if this host is covered within one of the certificates. If not, show the icon
  343. let enableQuickRequestButton = true;
  344. let domains = [payload.RootOrMatchingDomain]; //Domain for getting certificate if needed
  345. for (var i = 0; i < payload.MatchingDomainAlias.length; i++){
  346. let thisAliasName = payload.MatchingDomainAlias[i];
  347. domains.push(thisAliasName);
  348. }
  349. //Check if the domain or alias contains wildcard, if yes, disabled the get certificate button
  350. if (payload.RootOrMatchingDomain.indexOf("*") > -1){
  351. enableQuickRequestButton = false;
  352. }
  353. if (payload.MatchingDomainAlias != undefined){
  354. for (var i = 0; i < payload.MatchingDomainAlias.length; i++){
  355. if (payload.MatchingDomainAlias[i].indexOf("*") > -1){
  356. enableQuickRequestButton = false;
  357. break;
  358. }
  359. }
  360. }
  361. //encode the domain to DOM
  362. let certificateDomains = encodeURIComponent(JSON.stringify(domains));
  363. column.empty().append(`${originalContent}
  364. <div class="ui divider"></div>
  365. <div class="ui checkbox" style="margin-top: 0.4em;">
  366. <input type="checkbox" class="BypassGlobalTLS" ${payload.BypassGlobalTLS?"checked":""}>
  367. <label>Allow plain HTTP access<br>
  368. <small>Allow inbound connections without TLS/SSL</small></label>
  369. </div><br>
  370. <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>
  371. <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>
  372. <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>
  373. `);
  374. $(".hostAccessRuleSelector").dropdown();
  375. }else{
  376. //Unknown field. Leave it untouched
  377. }
  378. });
  379. $(".endpointAdvanceConfig").accordion();
  380. $("#httpProxyList").find(".editBtn").addClass("disabled");
  381. }
  382. //handleToggleRateLimitInput will get trigger if the "require rate limit" checkbox
  383. // is changed and toggle the disable state of the rate limit input field
  384. function handleToggleRateLimitInput(){
  385. let isRateLimitEnabled = $("#httpProxyList input.RequireRateLimit")[0].checked;
  386. if (isRateLimitEnabled){
  387. $("#httpProxyList input.RateLimit").parent().removeClass("disabled");
  388. }else{
  389. $("#httpProxyList input.RateLimit").parent().addClass("disabled");
  390. }
  391. }
  392. function exitProxyInlineEdit(){
  393. listProxyEndpoints();
  394. $("#httpProxyList").find(".editBtn").removeClass("disabled");
  395. }
  396. function saveProxyInlineEdit(uuid){
  397. uuid = uuid.hexDecode();
  398. var row = $('tr[eptuuid="' + uuid + '"]');
  399. if (row.length == 0){
  400. return;
  401. }
  402. var epttype = "host";
  403. let useStickySession = $(row).find(".UseStickySession")[0].checked;
  404. let DisableUptimeMonitor = !$(row).find(".EnableUptimeMonitor")[0].checked;
  405. let authProviderType = $(row).find(".authProviderPicker input[type='radio']:checked").val();
  406. let requireRateLimit = $(row).find(".RequireRateLimit")[0].checked;
  407. let rateLimit = $(row).find(".RateLimit").val();
  408. let bypassGlobalTLS = $(row).find(".BypassGlobalTLS")[0].checked;
  409. $.cjax({
  410. url: "/api/proxy/edit",
  411. method: "POST",
  412. data: {
  413. "type": epttype,
  414. "rootname": uuid,
  415. "ss":useStickySession,
  416. "dutm": DisableUptimeMonitor,
  417. "bpgtls": bypassGlobalTLS,
  418. "authprovider" :authProviderType,
  419. "rate" :requireRateLimit,
  420. "ratenum" :rateLimit,
  421. },
  422. success: function(data){
  423. if (data.error !== undefined){
  424. msgbox(data.error, false, 6000);
  425. }else{
  426. msgbox("Proxy endpoint updated");
  427. listProxyEndpoints();
  428. }
  429. }
  430. })
  431. }
  432. //Generic functions for delete rp endpoints
  433. function deleteEndpoint(epoint){
  434. epoint = decodeURIComponent(epoint).hexDecode();
  435. if (confirm("Confirm remove proxy for :" + epoint + "?")){
  436. $.cjax({
  437. url: "/api/proxy/del",
  438. method: "POST",
  439. data: {ep: epoint},
  440. success: function(data){
  441. if (data.error == undefined){
  442. listProxyEndpoints();
  443. msgbox("Proxy Rule Deleted", true);
  444. reloadUptimeList();
  445. }else{
  446. msgbox(data.error, false);
  447. }
  448. }
  449. })
  450. }
  451. }
  452. /* button events */
  453. function editBasicAuthCredentials(uuid){
  454. let payload = encodeURIComponent(JSON.stringify({
  455. ept: "host",
  456. ep: uuid
  457. }));
  458. showSideWrapper("snippet/basicAuthEditor.html?t=" + Date.now() + "#" + payload);
  459. }
  460. function editAccessRule(uuid){
  461. let payload = encodeURIComponent(JSON.stringify({
  462. ept: "host",
  463. ep: uuid
  464. }));
  465. showSideWrapper("snippet/hostAccessEditor.html?t=" + Date.now() + "#" + payload);
  466. }
  467. function editAliasHostnames(uuid){
  468. let payload = encodeURIComponent(JSON.stringify({
  469. ept: "host",
  470. ep: uuid
  471. }));
  472. showSideWrapper("snippet/aliasEditor.html?t=" + Date.now() + "#" + payload);
  473. }
  474. function quickEditVdir(uuid){
  475. openTabById("vdir");
  476. $("#vdirBaseRoutingRule").parent().dropdown("set selected", uuid);
  477. }
  478. //Open the custom header editor
  479. function editCustomHeaders(uuid){
  480. let payload = encodeURIComponent(JSON.stringify({
  481. ept: "host",
  482. ep: uuid
  483. }));
  484. showSideWrapper("snippet/customHeaders.html?t=" + Date.now() + "#" + payload);
  485. }
  486. //Open the load balance option
  487. function editUpstreams(uuid){
  488. let payload = encodeURIComponent(JSON.stringify({
  489. ept: "host",
  490. ep: uuid
  491. }));
  492. showSideWrapper("snippet/upstreams.html?t=" + Date.now() + "#" + payload);
  493. }
  494. function handleProxyRuleToggle(object){
  495. let endpointUUID = $(object).attr("eptuuid");
  496. let isChecked = object.checked;
  497. $.cjax({
  498. url: "/api/proxy/toggle",
  499. data: {
  500. "ep": endpointUUID,
  501. "enable": isChecked
  502. },
  503. success: function(data){
  504. if (data.error != undefined){
  505. msgbox(data.error, false);
  506. }else{
  507. if (isChecked){
  508. msgbox("Proxy Rule Enabled");
  509. }else{
  510. msgbox("Proxy Rule Disabled");
  511. }
  512. }
  513. }
  514. })
  515. }
  516. /*
  517. Certificate Shortcut
  518. */
  519. function requestCertificateForExistingHost(hostUUID, RootAndAliasDomains, btn=undefined){
  520. RootAndAliasDomains = JSON.parse(decodeURIComponent(RootAndAliasDomains))
  521. let renewDomainKey = RootAndAliasDomains.join(",");
  522. let preferedACMEEmail = $("#prefACMEEmail").val();
  523. if (preferedACMEEmail == ""){
  524. msgbox("Preferred email for ACME registration not set", false);
  525. return;
  526. }
  527. let defaultCA = $("#defaultCA").dropdown("get value");
  528. if (defaultCA == ""){
  529. defaultCA = "Let's Encrypt";
  530. }
  531. //Check if the root or the alias domain contain wildcard character, if yes, return error
  532. for (var i = 0; i < RootAndAliasDomains.length; i++){
  533. if (RootAndAliasDomains[i].indexOf("*") != -1){
  534. msgbox("Wildcard domain can only be setup via ACME tool", false);
  535. return;
  536. }
  537. }
  538. //Renew the certificate
  539. renewCertificate(renewDomainKey, false, btn);
  540. }
  541. //Bind on tab switch events
  542. tabSwitchEventBind["httprp"] = function(){
  543. listProxyEndpoints();
  544. }
  545. </script>