vdir.html 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. <div class="standardContainer">
  2. <div class="ui basic segment">
  3. <h2>Virtual Directory</h2>
  4. <p>A virtual directory is a consolidated view of multiple directories that provides a unified entry point for users to access disparate sources.</p>
  5. </div>
  6. <div id="currentVirtualDirectoryAttachingHost" class="ui basic segment">
  7. Select a host / routing rule to start editing Virtual Directory
  8. </div>
  9. <div class="ui stackable grid">
  10. <div class="six wide column">
  11. <h4>Select a Target Host / Site</h4>
  12. <p>Attach Virtual Directory routing rule to root proxy router</p>
  13. <div class="ui checkbox">
  14. <input type="checkbox" id="useRootProxyRouterForVdir" onchange="handleVdirAttachTargetChange(this);">
  15. <label>Root Proxy Router<br>
  16. <small>Only applicable when Default Site is set to "Reverse Proxy" mode</small></label>
  17. </div>
  18. <div class="ui horizontal divider">OR</div>
  19. <p>Create Virtual Directory routing in existing host / routing rule entries</p>
  20. <div class="ui fluid search selection dropdown">
  21. <input type="hidden" id="vdirBaseRoutingRule" name="vdirBaseRoutingRule" onchange="handleVdirAttachTargetChange();">
  22. <i class="dropdown icon"></i>
  23. <div class="default text">Select a host to edit</div>
  24. <div class="menu" id="hostDomainList">
  25. </div>
  26. </div>
  27. </div>
  28. <div class="ten wide column">
  29. <h4>Edit Virtual Directory Routing Rules</h4>
  30. <p>The following are the list of Virtual Directories currently handled by the host router above</p>
  31. <div style="width: 100%; overflow-x: auto; margin-bottom: 1em;">
  32. <table class="ui celled sortable unstackable compact table">
  33. <thead>
  34. <tr>
  35. <th>Virtual Directory</th>
  36. <th>Destination</th>
  37. <th class="no-sort" style="min-width: 7.2em;">Actions</th>
  38. </tr>
  39. </thead>
  40. <tbody id="vdirList">
  41. <tr>
  42. <td data-label="" colspan="3">No Selected Host</td>
  43. </tr>
  44. </tbody>
  45. </table>
  46. </div>
  47. <button class="ui icon right floated basic button" onclick="reloadVdirList();"><i class="green refresh icon"></i> Refresh</button>
  48. <br><br>
  49. <div class="ui divider"></div>
  50. <div id="newVDSection" class="disabled section">
  51. <h4>New Virtual Directory Rule</h4>
  52. <form class="ui form">
  53. <div class="field">
  54. <label>Matching Path Prefix</label>
  55. <input type="text" id="virtualDirectoryPath" placeholder="/mysite/">
  56. <small>Path that follows your select host / domain, e.g. <code>/mysite/</code> as path prefix will forward all request that matches <code>mydomain.com/mysite/*</code></small>
  57. </div>
  58. <div class="field">
  59. <label>Target IP Address or Domain Name with port</label>
  60. <input type="text" id="virtualDirectoryDomain" onchange="updateVDTargetTLSState();">
  61. <small>E.g. 192.168.0.101:8000 or example.com</small>
  62. </div>
  63. <div class="field">
  64. <div class="ui checkbox">
  65. <input type="checkbox" id="vdReqTls">
  66. <label>Proxy Target require TLS Connection <br><small>(i.e. Your proxy target starts with https://)</small></label>
  67. </div>
  68. </div>
  69. <!-- Advance configs -->
  70. <div class="ui basic segment advanceoptions">
  71. <div id="advanceProxyRules" class="ui fluid accordion">
  72. <div class="title">
  73. <i class="dropdown icon"></i>
  74. Advance Settings
  75. </div>
  76. <div class="content">
  77. <p></p>
  78. <div class="field">
  79. <div class="ui checkbox">
  80. <input type="checkbox" id="vdSkipTLSValidation">
  81. <label>Ignore TLS/SSL Verification Error<br><small>For targets that is using self-signed, expired certificate (Not Recommended)</small></label>
  82. </div>
  83. </div>
  84. </div>
  85. </div>
  86. </div>
  87. <button class="ui basic button" onclick="addVdirToHost(); event.preventDefault();"><i class="green add icon"></i> Create Virtual Directory</button>
  88. </form>
  89. </div>
  90. </div>
  91. </div>
  92. <br><br>
  93. </div>
  94. <script>
  95. //Virtual directories functions
  96. //Initialize the list of hosts that can be used to attach vdirs config
  97. function initVdirList(){
  98. //Load the hosts into the dropdown
  99. $("#hostDomainList").html("");
  100. $.get("/api/proxy/list?type=host", function(data){
  101. if (data.error != undefined){
  102. msgbox(data.error, false);
  103. }else{
  104. if (data.length == 0){
  105. //No hosts found
  106. }else{
  107. data.forEach(proxyEndpoint => {
  108. let domain = proxyEndpoint.RootOrMatchingDomain;
  109. $("#hostDomainList").append(`<div class="item" data-value="${domain}">${domain}</div>`);
  110. });
  111. //Update the dropdown events
  112. $("#vdirBaseRoutingRule").parent().dropdown();
  113. }
  114. }
  115. });
  116. }
  117. function handleVdirAttachTargetChange(targetCheckbox=undefined){
  118. if (targetCheckbox != undefined && targetCheckbox.checked){
  119. $("#vdirBaseRoutingRule").parent().addClass("disabled");
  120. //Load the vdir list for root
  121. loadVdirList("root");
  122. $("#newVDSection").removeClass("disabled");
  123. }else{
  124. $("#vdirBaseRoutingRule").parent().removeClass("disabled");
  125. let selectedEndpointRule = $("#vdirBaseRoutingRule").val();
  126. if (selectedEndpointRule != ""){
  127. loadVdirList(selectedEndpointRule);
  128. $("#newVDSection").removeClass("disabled");
  129. }else{
  130. $("#newVDSection").addClass("disabled");
  131. }
  132. }
  133. }
  134. //List the Vdir of the given endpoint, use "root" for root router
  135. function loadVdirList(endpoint){
  136. $("#currentVirtualDirectoryAttachingHost").html(`Editing Host: ${endpoint}`);
  137. let reqURL = "/api/proxy/vdir/list?type=host&ep=" + endpoint;
  138. if (endpoint == "root"){
  139. //Load root endpoint vdir list
  140. reqURL = "/api/proxy/vdir/list?type=root";
  141. }
  142. $.get(reqURL, function(data){
  143. if (data.error != undefined){
  144. msgbox(data.error, false);
  145. }else{
  146. $("#vdirList").html("");
  147. if (data.length == 0){
  148. //No virtual directory for this host
  149. $("#vdirList").append(`<tr>
  150. <td data-label="" colspan="3"><i class="green check circle icon"></i> No Virtual Directory Routing Rule</td>
  151. </tr>`);
  152. }else{
  153. //List the vdirs
  154. console.log(data);
  155. data.forEach(vdir => {
  156. var tlsIcon = "";
  157. if (vdir.RequireTLS){
  158. tlsIcon = `<i class="green lock icon" title="TLS Mode"></i>`;
  159. if (vdir.SkipCertValidations){
  160. tlsIcon = `<i class="yellow lock icon" title="TLS/SSL mode without verification"></i>`
  161. }
  162. }
  163. let payload = JSON.stringify(vdir).hexEncode();
  164. $("#vdirList").append(`<tr vdirid="${vdir.MatchingPath.hexEncode()}" class="vdirEntry" payload="${payload}">
  165. <td data-label="" editable="false" >${vdir.MatchingPath}</td>
  166. <td data-label="" editable="true" datatype="domain">${vdir.Domain} ${tlsIcon}</td>
  167. <td class="center aligned" editable="true" datatype="action" data-label="">
  168. <button class="ui circular mini basic icon button editBtn" onclick='editVdir("${vdir.MatchingPath}", "${endpoint}")'><i class="edit icon"></i></button>
  169. <button class="ui circular mini red basic icon button" onclick='deleteVdir("${vdir.MatchingPath}", "${endpoint}")'><i class="trash icon"></i></button>
  170. </td>
  171. </tr>`);
  172. })
  173. }
  174. }
  175. });
  176. }
  177. //Check if the entered domain require TLS
  178. function updateVDTargetTLSState(){
  179. var targetDomain = $("#virtualDirectoryDomain").val().trim();
  180. if (targetDomain != ""){
  181. $.cjax({
  182. url: "/api/proxy/tlscheck",
  183. data: {url: targetDomain},
  184. success: function(data){
  185. if (data.error != undefined){
  186. }else if (data == "https"){
  187. $("#vdReqTls").parent().checkbox("set checked");
  188. }else if (data == "http"){
  189. $("#vdReqTls").parent().checkbox("set unchecked");
  190. }
  191. }
  192. });
  193. }
  194. }
  195. function reloadVdirList(){
  196. $("#vdirList").find(".editBtn").removeClass("disabled");
  197. if ($("#useRootProxyRouterForVdir")[0].checked){
  198. loadVdirList("root");
  199. return;
  200. }
  201. let endpoint = $("#vdirBaseRoutingRule").val().trim();
  202. if (endpoint != ""){
  203. loadVdirList(endpoint);
  204. }
  205. }
  206. //Create a virtual directory routing rule and attach to this endpoint
  207. function addVdirToHost(){
  208. var matchingPath = $("#virtualDirectoryPath").val().trim();
  209. var targetDomain = $("#virtualDirectoryDomain").val().trim();
  210. var reqTLS = $("#vdReqTls")[0].checked;
  211. var skipTLSValidation = $("#vdSkipTLSValidation")[0].checked;
  212. //Validate the input data
  213. if (matchingPath == ""){
  214. $("#virtualDirectoryPath").parent().addClass('error');
  215. return;
  216. }else{
  217. $("#virtualDirectoryPath").parent().removeClass('error');
  218. }
  219. if (targetDomain == ""){
  220. $("#virtualDirectoryDomain").parent().addClass('error');
  221. return;
  222. }else{
  223. $("#virtualDirectoryDomain").parent().removeClass('error');
  224. }
  225. //Check if we are editing host
  226. let epType = "host";
  227. let endpoint = "root";
  228. if ($("#useRootProxyRouterForVdir")[0].checked){
  229. //Editing root virtual directory
  230. epType = "root";
  231. }else{
  232. //Editing hosts virtual directory
  233. endpoint = $("#vdirBaseRoutingRule").val().trim();
  234. }
  235. //Create a virtual directory endpoint
  236. $.cjax({
  237. url: "/api/proxy/vdir/add",
  238. method: "POST",
  239. data: {
  240. "type": epType,
  241. "endpoint": endpoint,
  242. "path": matchingPath,
  243. "domain":targetDomain,
  244. "reqTLS":reqTLS,
  245. "skipValid":skipTLSValidation,
  246. },
  247. success: function(data){
  248. if (data.error != undefined){
  249. msgbox(data.error, false);
  250. }else{
  251. msgbox("New Virtual Directory rule added");
  252. reloadVdirList();
  253. resetVdirForm();
  254. }
  255. },
  256. error: function(){
  257. msgbox("Add Virtual Directory failed due to unknown reasons", false);
  258. }
  259. })
  260. }
  261. //Reset the vdir form
  262. function resetVdirForm(){
  263. $("#virtualDirectoryPath").val("");
  264. $("#virtualDirectoryDomain").val("");
  265. $("#vdReqTls").parent().checkbox("set unchecked");
  266. $("#vdSkipTLSValidation").parent().checkbox("set unchecked");
  267. }
  268. //Remove Vdir
  269. function deleteVdir(matchingPath, endpoint){
  270. var epType = "host";
  271. var path = $("#vdirBaseRoutingRule").val().trim();
  272. if (endpoint.trim() == "root"){
  273. epType = "root";
  274. path = "";
  275. }
  276. $.cjax({
  277. url: "/api/proxy/vdir/del",
  278. method: "POST",
  279. data: {
  280. "type":epType,
  281. "vdir": matchingPath,
  282. "path": path
  283. },
  284. success: function(data){
  285. if (data.error != undefined){
  286. msgbox(data.error, false);
  287. }else{
  288. msgbox("Virtual Directory rule removed", true);
  289. reloadVdirList();
  290. }
  291. }
  292. })
  293. }
  294. function editVdir(matchingPath, ept){
  295. let targetDOM = $(".vdirEntry[vdirid='" + matchingPath.hexEncode() + "']");
  296. $("#vdirList").find(".editBtn").addClass("disabled");
  297. let payload = $(targetDOM).attr("payload").hexDecode();
  298. payload = JSON.parse(payload);
  299. console.log(payload);
  300. $(targetDOM).find("td[editable='true']").each(function(){
  301. let datatype = $(this).attr("datatype");
  302. let column = $(this);
  303. if (datatype == "domain"){
  304. let domain = payload.Domain;
  305. //Target require TLS for proxying
  306. let tls = payload.RequireTLS;
  307. if (tls){
  308. tls = "checked";
  309. }else{
  310. tls = "";
  311. }
  312. //Require TLS validation
  313. let skipTLSValidation = payload.SkipCertValidations;
  314. let checkstate = "";
  315. if (skipTLSValidation){
  316. checkstate = "checked";
  317. }
  318. input = `
  319. <div class="ui mini fluid input">
  320. <input type="text" class="Domain" value="${domain}">
  321. </div>
  322. <div class="ui checkbox" style="margin-top: 0.4em;">
  323. <input type="checkbox" class="RequireTLS" ${tls}>
  324. <label>Require TLS<br>
  325. <small>Proxy target require HTTPS connection</small></label>
  326. </div><br>
  327. <div class="ui checkbox" style="margin-top: 0.4em;">
  328. <input type="checkbox" class="SkipCertValidations" ${checkstate}>
  329. <label>Skip Verification<br>
  330. <small>Check this if proxy target is using self signed certificates</small></label>
  331. </div>
  332. `;
  333. column.empty().append(input);
  334. }else if (datatype == 'action'){
  335. column.empty().append(`
  336. <button title="Save" onclick="saveVdirInlineEdit('${payload.MatchingPath.hexEncode()}');" class="ui basic small icon circular button inlineEditActionBtn"><i class="ui green save icon"></i></button>
  337. <button title="Cancel" onclick="exitVdirInlineEdit();" class="ui basic small icon circular button inlineEditActionBtn"><i class="ui remove icon"></i></button>
  338. `);
  339. }
  340. });
  341. }
  342. function saveVdirInlineEdit(mathingPath){
  343. mathingPath = mathingPath.hexDecode();
  344. var epType = "host";
  345. var path = $("#vdirBaseRoutingRule").val().trim();
  346. if ($("#useRootProxyRouterForVdir")[0].checked){
  347. epType = "root";
  348. path = "";
  349. }
  350. //Load new setting from inline editor
  351. let newDomain = $("#vdirList").find(".Domain").val();
  352. let requireTLS = $("#vdirList").find(".RequireTLS")[0].checked;
  353. let skipValidation = $("#vdirList").find(".SkipCertValidations")[0].checked;
  354. //console.log(mathingPath, newDomain, requireTLS, skipValidation);
  355. $.cjax({
  356. url: "/api/proxy/vdir/edit",
  357. method: "POST",
  358. data: {
  359. "type": epType,
  360. "vdir": mathingPath,
  361. "domain":newDomain,
  362. "path":path,
  363. "reqTLS":requireTLS,
  364. "skipValid": skipValidation
  365. },
  366. success: function(data){
  367. if (data.error != undefined){
  368. msgbox(data.error, false);
  369. }else{
  370. msgbox("Virtual Directory rule updated", true);
  371. exitVdirInlineEdit();
  372. }
  373. },
  374. error: function(){
  375. msgbox("unknown error occured", false)
  376. }
  377. })
  378. }
  379. function exitVdirInlineEdit(){
  380. reloadVdirList();
  381. }
  382. //Bind on tab switch events
  383. tabSwitchEventBind["vdir"] = function(){
  384. initVdirList();
  385. }
  386. initVdirList();
  387. </script>