vdir.html 18 KB

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