vdir.html 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  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?selfsignchk=true",
  183. data: {url: targetDomain},
  184. success: function(data){
  185. if (data.error != undefined){
  186. }else if (data.protocol == "https"){
  187. $("#vdReqTls").parent().checkbox("set checked");
  188. if (data.selfsign){
  189. $("#vdSkipTLSValidation").parent().checkbox("set checked");
  190. }else{
  191. $("#vdSkipTLSValidation").parent().checkbox("set unchecked");
  192. }
  193. }else if (data.protocol == "http"){
  194. $("#vdReqTls").parent().checkbox("set unchecked");
  195. }
  196. }
  197. });
  198. }
  199. }
  200. function reloadVdirList(){
  201. $("#vdirList").find(".editBtn").removeClass("disabled");
  202. if ($("#useRootProxyRouterForVdir")[0].checked){
  203. loadVdirList("root");
  204. return;
  205. }
  206. let endpoint = $("#vdirBaseRoutingRule").val().trim();
  207. if (endpoint != ""){
  208. loadVdirList(endpoint);
  209. }
  210. }
  211. //Create a virtual directory routing rule and attach to this endpoint
  212. function addVdirToHost(){
  213. var matchingPath = $("#virtualDirectoryPath").val().trim();
  214. var targetDomain = $("#virtualDirectoryDomain").val().trim();
  215. var reqTLS = $("#vdReqTls")[0].checked;
  216. var skipTLSValidation = $("#vdSkipTLSValidation")[0].checked;
  217. //Validate the input data
  218. if (matchingPath == ""){
  219. $("#virtualDirectoryPath").parent().addClass('error');
  220. return;
  221. }else{
  222. $("#virtualDirectoryPath").parent().removeClass('error');
  223. }
  224. if (targetDomain == ""){
  225. $("#virtualDirectoryDomain").parent().addClass('error');
  226. return;
  227. }else{
  228. $("#virtualDirectoryDomain").parent().removeClass('error');
  229. }
  230. //Check if we are editing host
  231. let epType = "host";
  232. let endpoint = "root";
  233. if ($("#useRootProxyRouterForVdir")[0].checked){
  234. //Editing root virtual directory
  235. epType = "root";
  236. }else{
  237. //Editing hosts virtual directory
  238. endpoint = $("#vdirBaseRoutingRule").val().trim();
  239. }
  240. //Create a virtual directory endpoint
  241. $.cjax({
  242. url: "/api/proxy/vdir/add",
  243. method: "POST",
  244. data: {
  245. "type": epType,
  246. "endpoint": endpoint,
  247. "path": matchingPath,
  248. "domain":targetDomain,
  249. "reqTLS":reqTLS,
  250. "skipValid":skipTLSValidation,
  251. },
  252. success: function(data){
  253. if (data.error != undefined){
  254. msgbox(data.error, false);
  255. }else{
  256. msgbox("New Virtual Directory rule added");
  257. reloadVdirList();
  258. resetVdirForm();
  259. }
  260. },
  261. error: function(){
  262. msgbox("Add Virtual Directory failed due to unknown reasons", false);
  263. }
  264. })
  265. }
  266. //Reset the vdir form
  267. function resetVdirForm(){
  268. $("#virtualDirectoryPath").val("");
  269. $("#virtualDirectoryDomain").val("");
  270. $("#vdReqTls").parent().checkbox("set unchecked");
  271. $("#vdSkipTLSValidation").parent().checkbox("set unchecked");
  272. }
  273. //Remove Vdir
  274. function deleteVdir(matchingPath, endpoint){
  275. var epType = "host";
  276. var path = $("#vdirBaseRoutingRule").val().trim();
  277. if (endpoint.trim() == "root"){
  278. epType = "root";
  279. path = "";
  280. }
  281. $.cjax({
  282. url: "/api/proxy/vdir/del",
  283. method: "POST",
  284. data: {
  285. "type":epType,
  286. "vdir": matchingPath,
  287. "path": path
  288. },
  289. success: function(data){
  290. if (data.error != undefined){
  291. msgbox(data.error, false);
  292. }else{
  293. msgbox("Virtual Directory rule removed", true);
  294. reloadVdirList();
  295. }
  296. }
  297. })
  298. }
  299. function editVdir(matchingPath, ept){
  300. let targetDOM = $(".vdirEntry[vdirid='" + matchingPath.hexEncode() + "']");
  301. $("#vdirList").find(".editBtn").addClass("disabled");
  302. let payload = $(targetDOM).attr("payload").hexDecode();
  303. payload = JSON.parse(payload);
  304. console.log(payload);
  305. $(targetDOM).find("td[editable='true']").each(function(){
  306. let datatype = $(this).attr("datatype");
  307. let column = $(this);
  308. if (datatype == "domain"){
  309. let domain = payload.Domain;
  310. //Target require TLS for proxying
  311. let tls = payload.RequireTLS;
  312. if (tls){
  313. tls = "checked";
  314. }else{
  315. tls = "";
  316. }
  317. //Require TLS validation
  318. let skipTLSValidation = payload.SkipCertValidations;
  319. let checkstate = "";
  320. if (skipTLSValidation){
  321. checkstate = "checked";
  322. }
  323. input = `
  324. <div class="ui mini fluid input">
  325. <input type="text" class="Domain" value="${domain}">
  326. </div>
  327. <div class="ui checkbox" style="margin-top: 0.4em;">
  328. <input type="checkbox" class="RequireTLS" ${tls}>
  329. <label>Require TLS<br>
  330. <small>Proxy target require HTTPS connection</small></label>
  331. </div><br>
  332. <div class="ui checkbox" style="margin-top: 0.4em;">
  333. <input type="checkbox" class="SkipCertValidations" ${checkstate}>
  334. <label>Skip Verification<br>
  335. <small>Check this if proxy target is using self signed certificates</small></label>
  336. </div>
  337. `;
  338. column.empty().append(input);
  339. }else if (datatype == 'action'){
  340. column.empty().append(`
  341. <button title="Save" onclick="saveVdirInlineEdit('${payload.MatchingPath.hexEncode()}');" class="ui basic small icon circular button inlineEditActionBtn"><i class="ui green save icon"></i></button>
  342. <button title="Cancel" onclick="exitVdirInlineEdit();" class="ui basic small icon circular button inlineEditActionBtn"><i class="ui remove icon"></i></button>
  343. `);
  344. }
  345. });
  346. }
  347. function saveVdirInlineEdit(mathingPath){
  348. mathingPath = mathingPath.hexDecode();
  349. var epType = "host";
  350. var path = $("#vdirBaseRoutingRule").val().trim();
  351. if ($("#useRootProxyRouterForVdir")[0].checked){
  352. epType = "root";
  353. path = "";
  354. }
  355. //Load new setting from inline editor
  356. let newDomain = $("#vdirList").find(".Domain").val();
  357. let requireTLS = $("#vdirList").find(".RequireTLS")[0].checked;
  358. let skipValidation = $("#vdirList").find(".SkipCertValidations")[0].checked;
  359. //console.log(mathingPath, newDomain, requireTLS, skipValidation);
  360. $.cjax({
  361. url: "/api/proxy/vdir/edit",
  362. method: "POST",
  363. data: {
  364. "type": epType,
  365. "vdir": mathingPath,
  366. "domain":newDomain,
  367. "path":path,
  368. "reqTLS":requireTLS,
  369. "skipValid": skipValidation
  370. },
  371. success: function(data){
  372. if (data.error != undefined){
  373. msgbox(data.error, false);
  374. }else{
  375. msgbox("Virtual Directory rule updated", true);
  376. exitVdirInlineEdit();
  377. }
  378. },
  379. error: function(){
  380. msgbox("unknown error occured", false)
  381. }
  382. })
  383. }
  384. function exitVdirInlineEdit(){
  385. reloadVdirList();
  386. }
  387. //Bind on tab switch events
  388. tabSwitchEventBind["vdir"] = function(){
  389. initVdirList();
  390. }
  391. initVdirList();
  392. </script>