<!DOCTYPE html> <html> <head> <!-- Notes: This should be open in its original path--> <link rel="stylesheet" href="../script/semantic/semantic.min.css"> <script src="../script/jquery-3.6.0.min.js"></script> <script src="../script/semantic/semantic.min.js"></script> <style> .ui.tabular.menu .item.narrowpadding{ padding: 0.6em !important; margin: 0.15em !important; } </style> </head> <body> <br> <div class="ui container"> <div class="ui header"> <div class="content"> Custom Headers <div class="sub header" id="epname"></div> </div> </div> <div class="ui divider"></div> <div class="ui small pointing secondary menu"> <a class="item active narrowpadding" data-tab="customheaders">Custom Headers</a> <a class="item narrowpadding" data-tab="security">Security Headers</a> </div> <div class="ui tab basic segment active" data-tab="customheaders"> <table class="ui very basic compacted unstackable celled table"> <thead> <tr> <th>Key</th> <th>Value</th> <th>Remove</th> </tr></thead> <tbody id="headerTable"> <tr> <td colspan="3"><i class="ui green circle check icon"></i> No Additonal Header</td> </tr> </tbody> </table> <p> <i class="angle double right blue icon"></i> Sent additional custom headers to origin server <br> <i class="angle double left orange icon"></i> Inject custom headers into origin server responses </p> <div class="ui divider"></div> <h4>Edit Custom Header</h4> <p>Add or remove custom header(s) over this proxy target</p> <div class="scrolling content ui form"> <div class="five small fields credentialEntry"> <div class="field" align="center"> <button id="toOriginButton" style="margin-top: 0.6em;" title="Downstream to Upstream" class="ui circular basic active button">Zoraxy <i class="angle double right blue icon" style="margin-right: 0.4em;"></i> Origin</button> <button id="toClientButton" style="margin-top: 0.6em;" title="Upstream to Downstream" class="ui circular basic button">Client <i class="angle double left orange icon" style="margin-left: 0.4em;"></i> Zoraxy</button> </div> <div class="field" align="center"> <button id="headerModeAdd" style="margin-top: 0.6em;" class="ui circular basic active button"><i class="ui green circle add icon"></i> Add Header</button> <button id="headerModeRemove" style="margin-top: 0.6em;" class="ui circular basic button"><i class="ui red circle times icon"></i> Remove Header</button> </div> <div class="field"> <label>Header Key</label> <input id="headerName" type="text" placeholder="X-Custom-Header" autocomplete="off"> <small>The header key is <b>NOT</b> case sensitive</small> </div> <div class="field"> <label>Header Value</label> <input id="headerValue" type="text" placeholder="value1,value2,value3" autocomplete="off"> </div> <div class="field" > <button class="ui basic button" onclick="addCustomHeader();"><i class="green add icon"></i> Add Header Rewrite Rule</button> </div> <div class="ui divider"></div> </div> </div> </div> <div class="ui tab basic segment" data-tab="security"> <h4>HTTP Strict Transport Security</h4> <p>Force future attempts to access this site to only use HTTPS</p> <div class="ui toggle checkbox"> <input type="checkbox" id="enableHSTS" name="enableHSTS"> <label>Enable HSTS<br> <small>HSTS header will be automatically ignored if the site is accessed using HTTP</small></label> </div> <div class="ui divider"></div> <h4>Permission Policy</h4> <p>Explicitly declare what functionality can and cannot be used on this website. </p> <div class="ui toggle checkbox" style="margin-top: 0.6em;"> <input type="checkbox" name="enableHSTS"> <label>Enable Permission Policy<br> <small>Enable Permission-Policy header with all allowed state.</small></label> </div> <div id="permissionPolicyEditTable"> </div> <br><br> <button class="ui basic button"><i class="green save icon"></i> Save</button> </div> <div class="field" > <button class="ui basic button" style="float: right;" onclick="closeThisWrapper();">Close</button> </div> </div> <br><br><br><br> <script> $('.menu .item').tab(); let editingEndpoint = {}; if (window.location.hash.length > 1){ let payloadHash = window.location.hash.substr(1); try{ payloadHash = JSON.parse(decodeURIComponent(payloadHash)); $("#epname").text(payloadHash.ep); editingEndpoint = payloadHash; }catch(ex){ console.log("Unable to load endpoint data from hash") } } function closeThisWrapper(){ parent.hideSideWrapper(true); } //Bind events to header mod mode $("#headerModeAdd").on("click", function(){ $("#headerModeAdd").addClass("active"); $("#headerModeRemove").removeClass("active"); $("#headerValue").parent().show(); }); $("#headerModeRemove").on("click", function(){ $("#headerModeAdd").removeClass("active"); $("#headerModeRemove").addClass("active"); $("#headerValue").parent().hide(); $("#headerValue").val(""); }); //Bind events to header directions option $("#toOriginButton").on("click", function(){ $("#toOriginButton").addClass("active"); $("#toClientButton").removeClass("active"); }); $("#toClientButton").on("click", function(){ $("#toOriginButton").removeClass("active"); $("#toClientButton").addClass("active"); }); //Return "add" or "remove" depending on mode user selected function getHeaderEditMode(){ if ($("#headerModeAdd").hasClass("active")){ return "add"; } return "remove"; } //Return "toOrigin" or "toClient" function getHeaderDirection(){ if ($("#toOriginButton").hasClass("active")){ return "toOrigin"; } return "toClient"; } //$("#debug").text(JSON.stringify(editingEndpoint)); function addCustomHeader(){ let name = $("#headerName").val().trim(); let value = $("#headerValue").val().trim(); if (name == ""){ $("#headerName").parent().addClass("error"); return }else{ $("#headerName").parent().removeClass("error"); } if (getHeaderEditMode() == "add"){ if (value == ""){ $("#headerValue").parent().addClass("error"); return }else{ $("#headerValue").parent().removeClass("error"); } } $.ajax({ url: "/api/proxy/header/add", data: { "type": getHeaderEditMode(), "domain": editingEndpoint.ep, "direction":getHeaderDirection(), "name": name, "value": value }, success: function(data){ if (data.error != undefined){ if (parent != undefined && parent.msgbox != undefined){ parent.msgbox(data.error,false); }else{ alert(data.error); } }else{ listCustomHeaders(); if (parent != undefined && parent.msgbox != undefined){ parent.msgbox("Custom header added",true); } //Clear the form $("#headerName").val(""); $("#headerValue").val(""); } } }); } function deleteCustomHeader(name){ $.ajax({ url: "/api/proxy/header/remove", data: { //"type": editingEndpoint.ept, "domain": editingEndpoint.ep, "name": name, }, success: function(data){ listCustomHeaders(); if (parent != undefined && parent.msgbox != undefined){ parent.msgbox("Custom header removed",true); } } }); } function listCustomHeaders(){ $("#headerTable").html(`<tr><td colspan="3"><i class="ui loading spinner icon"></i> Loading</td></tr>`); $.ajax({ url: "/api/proxy/header/list", data: { "type": editingEndpoint.ept, "domain": editingEndpoint.ep, }, success: function(data){ if (data.error != undefined){ alert(data.error); }else{ $("#headerTable").html(""); data.forEach(header => { let editModeIcon = header.IsRemove?`<i class="ui red times circle icon"></i>`:`<i class="ui green add circle icon"></i>`; let direction = (header.Direction==0)?`<i class="angle double right blue icon"></i>`:`<i class="angle double left orange icon"></i>`; let valueField = header.Value; if (header.IsRemove){ valueField = "<small style='color: grey;'>(Field Removed)</small>"; } $("#headerTable").append(` <tr> <td>${direction} ${header.Key}</td> <td>${editModeIcon} ${valueField}</td> <td><button class="ui basic circular mini red icon button" onclick="deleteCustomHeader('${header.Key}');"><i class="ui trash icon"></i></button></td> </tr> `); }); if (data.length == 0){ $("#headerTable").html(`<tr> <td colspan="3"><i class="ui green circle check icon"></i> No Additonal Header</td> </tr>`); } } }, }); } listCustomHeaders(); /* Bind events to toggles */ $.get("/api/proxy/header/handleHSTS?domain=" + editingEndpoint.ep, function(data){ if (data == 0){ //HSTS disabled $("#enableHSTS").parent().checkbox("set unchecked"); }else{ //HSTS enabled $("#enableHSTS").parent().checkbox("set checked"); } $("#enableHSTS").on("change", function(){ let HSTSEnabled = $("#enableHSTS")[0].checked; $.ajax({ url: "/api/proxy/header/handleHSTS", method: "POST", data: { "domain": editingEndpoint.ep, "maxage": 31536000 }, success: function(data){ if (data.error != undefined){ parent.msgbox(data.error, false); }else{ parent.msgbox(`HSTS ${HSTSEnabled?"Enabled":"Disabled"}`); } } }) }); }); /* List permission policy header from server */ </script> </body> </html>