mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-08-14 08:59:19 +02:00
Restructure TLS options
- Moved certification related functions into tlscert module - Added specific host TLS behavior logic - Added support for disabling SNI and manually overwrite preferred certificate to serve - Fixed SSO requestHeaders null bug
This commit is contained in:
@@ -339,11 +339,15 @@
|
||||
<div class="rpconfig_content" rpcfg="ssl">
|
||||
<div class="ui segment">
|
||||
<p>The table below shows which certificate will be served by Zoraxy when a client request the following hostnames.</p>
|
||||
<table class="ui celled small compact table Tls_resolve_list">
|
||||
<div class="ui blue message sni_grey_out_info" style="margin-bottom: 1em; display:none;">
|
||||
<i class="info circle icon"></i>
|
||||
Certificate dropdowns are greyed out because SNI is enabled
|
||||
</div>
|
||||
<table class="ui celled small compact table sortable Tls_resolve_list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Hostname</th>
|
||||
<th>Resolve to Certificate</th>
|
||||
<th class="no-sort">Resolve to Certificate</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -359,18 +363,20 @@
|
||||
<div class="ui checkbox" style="margin-top: 0.4em;">
|
||||
<input type="checkbox" class="Tls_EnableLegacyCertificateMatching">
|
||||
<label>Enable Legacy Certificate Matching<br>
|
||||
<small>Use legacy filename / hostname matching for loading certificates</small>
|
||||
<small>Use filename for hostname matching, faster but less accurate</small>
|
||||
</label>
|
||||
</div>
|
||||
<div class="ui checkbox" style="margin-top: 0.4em;">
|
||||
<div class="ui disabled checkbox" style="margin-top: 0.4em;">
|
||||
<input type="checkbox" class="Tls_EnableAutoHTTPS">
|
||||
<label>Enable Auto HTTPS<br>
|
||||
<label>Enable Auto HTTPS (WIP)<br>
|
||||
<small>Automatically request a certificate for the domain</small>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<div class="ui divider"></div>
|
||||
<button class="ui basic small button getCertificateBtn" style="margin-left: 0.4em; margin-top: 0.4em;"><i class="green lock icon"></i> Get Certificate</button>
|
||||
<button class="ui basic small button getSelfSignCertBtn" style="margin-left: 0.4em; margin-top: 0.4em;"><i class="yellow lock icon"></i> Generate Self-Signed Certificate</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Custom Headers -->
|
||||
@@ -747,7 +753,7 @@
|
||||
let newTlsOption = {
|
||||
"DisableSNI": !enableSNI,
|
||||
"DisableLegacyCertificateMatching": !enableLegacyCertificateMatching,
|
||||
"EnableAutoHTTPS": enableAutoHTTPS
|
||||
"EnableAutoHTTPS": enableAutoHTTPS,
|
||||
}
|
||||
$.cjax({
|
||||
url: "/api/proxy/setTlsConfig",
|
||||
@@ -769,6 +775,9 @@
|
||||
|
||||
function updateTlsResolveList(uuid){
|
||||
let editor = $("#httprpEditModalWrapper");
|
||||
editor.find(".certificateDropdown .ui.dropdown").off("change");
|
||||
editor.find(".certificateDropdown .ui.dropdown").remove();
|
||||
|
||||
//Update the TLS resolve list
|
||||
$.ajax({
|
||||
url: "/api/cert/resolve?domain=" + uuid,
|
||||
@@ -785,17 +794,60 @@
|
||||
resolveList.append(`
|
||||
<tr>
|
||||
<td>${primaryDomain}</td>
|
||||
<td>${certMap[primaryDomain] || "Fallback Certificate"}</td>
|
||||
<td class="certificateDropdown" domain="${primaryDomain}">${certMap[primaryDomain] || "Fallback Certificate"}</td>
|
||||
</tr>
|
||||
`);
|
||||
aliasDomains.forEach(alias => {
|
||||
resolveList.append(`
|
||||
<tr>
|
||||
<td>${alias}</td>
|
||||
<td>${certMap[alias] || "Fallback Certificate"}</td>
|
||||
<td class="certificateDropdown" domain="${alias}">${certMap[alias] || "Fallback Certificate"}</td>
|
||||
</tr>
|
||||
`);
|
||||
});
|
||||
|
||||
//Generate the certificate dropdown
|
||||
generateCertificateDropdown(function(dropdown) {
|
||||
let SNIEnabled = editor.find(".Tls_EnableSNI")[0].checked;
|
||||
editor.find(".certificateDropdown").html(dropdown);
|
||||
editor.find(".certificateDropdown").each(function() {
|
||||
let dropdownDomain = $(this).attr("domain");
|
||||
let selectedCertname = certMap[dropdownDomain];
|
||||
if (selectedCertname) {
|
||||
$(this).find(".ui.dropdown").dropdown("set selected", selectedCertname);
|
||||
}
|
||||
});
|
||||
|
||||
editor.find(".certificateDropdown .ui.dropdown").dropdown({
|
||||
onChange: function(value, text, $selectedItem) {
|
||||
console.log("Selected certificate for domain:", $(this).parent().attr("domain"), "Value:", value);
|
||||
let domain = $(this).parent().attr("domain");
|
||||
let newCertificateName = value;
|
||||
$.cjax({
|
||||
url: "/api/cert/setPreferredCertificate",
|
||||
method: "POST",
|
||||
data: {
|
||||
"domain": domain,
|
||||
"certname": newCertificateName
|
||||
},
|
||||
success: function(data) {
|
||||
if (data.error !== undefined) {
|
||||
msgbox(data.error, false, 3000);
|
||||
} else {
|
||||
msgbox("Preferred Certificate updated");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (SNIEnabled) {
|
||||
editor.find(".certificateDropdown .ui.dropdown").addClass("disabled");
|
||||
editor.find(".sni_grey_out_info").show();
|
||||
}else{
|
||||
editor.find(".sni_grey_out_info").hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -946,6 +998,29 @@
|
||||
renewCertificate(renewDomainKey, false, btn);
|
||||
}
|
||||
|
||||
function generateSelfSignedCertificate(uuid, domains, btn=undefined){
|
||||
let payload = JSON.stringify(domains);
|
||||
$.cjax({
|
||||
url: "/api/cert/selfsign",
|
||||
data: {
|
||||
"cn": uuid,
|
||||
"domains": payload
|
||||
},
|
||||
success: function(data){
|
||||
if (data.error == undefined){
|
||||
msgbox("Self-Signed Certificate Generated", true);
|
||||
resyncProxyEditorConfig();
|
||||
if (typeof(initManagedDomainCertificateList) != undefined){
|
||||
//Re-init the managed domain certificate list
|
||||
initManagedDomainCertificateList();
|
||||
}
|
||||
}else{
|
||||
msgbox(data.error, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* Tags & Search */
|
||||
function handleSearchInput(event){
|
||||
if (event.key == "Escape"){
|
||||
@@ -1074,6 +1149,28 @@
|
||||
return subd;
|
||||
}
|
||||
|
||||
// Generate a certificate dropdown for the HTTP Proxy Rule Editor
|
||||
// so user can pick which certificate they want to use for the current editing hostname
|
||||
function generateCertificateDropdown(callback){
|
||||
$.ajax({
|
||||
url: "/api/cert/list",
|
||||
method: "GET",
|
||||
success: function(data) {
|
||||
let dropdown = $('<div class="ui fluid selection dropdown"></div>');
|
||||
let menu = $('<div class="menu"></div>');
|
||||
data.forEach(cert => {
|
||||
menu.append(`<div class="item" data-value="${cert}">${cert}</div>`);
|
||||
});
|
||||
// Add a hidden input to store the selected certificate
|
||||
dropdown.append('<input type="hidden" name="certificate">');
|
||||
dropdown.append('<i class="dropdown icon"></i>');
|
||||
dropdown.append('<div class="default text">Fallback Certificate</div>');
|
||||
dropdown.append(menu);
|
||||
callback(dropdown);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//Initialize the http proxy rule editor
|
||||
function initHttpProxyRuleEditorModal(rulepayload){
|
||||
let subd = JSON.parse(JSON.stringify(rulepayload));
|
||||
@@ -1175,39 +1272,6 @@
|
||||
|
||||
});
|
||||
editor.find(".downstream_alias_hostname").html(aliasHTML);
|
||||
|
||||
//TODO: Move this to SSL TLS section
|
||||
let enableQuickRequestButton = true;
|
||||
let domains = [subd.RootOrMatchingDomain]; //Domain for getting certificate if needed
|
||||
for (var i = 0; i < subd.MatchingDomainAlias.length; i++){
|
||||
let thisAliasName = subd.MatchingDomainAlias[i];
|
||||
domains.push(thisAliasName);
|
||||
}
|
||||
|
||||
//Check if the domain or alias contains wildcard, if yes, disabled the get certificate button
|
||||
if (subd.RootOrMatchingDomain.indexOf("*") > -1){
|
||||
enableQuickRequestButton = false;
|
||||
}
|
||||
|
||||
if (subd.MatchingDomainAlias != undefined){
|
||||
for (var i = 0; i < subd.MatchingDomainAlias.length; i++){
|
||||
if (subd.MatchingDomainAlias[i].indexOf("*") > -1){
|
||||
enableQuickRequestButton = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let certificateDomains = encodeURIComponent(JSON.stringify(domains));
|
||||
if (enableQuickRequestButton){
|
||||
editor.find(".getCertificateBtn").removeClass("disabled");
|
||||
}else{
|
||||
editor.find(".getCertificateBtn").addClass("disabled");
|
||||
}
|
||||
|
||||
editor.find(".getCertificateBtn").off("click").on("click", function(){
|
||||
requestCertificateForExistingHost(uuid, certificateDomains, this);
|
||||
});
|
||||
|
||||
/* ------------ Upstreams ------------ */
|
||||
editor.find(".upstream_list").html(renderUpstreamList(subd));
|
||||
@@ -1237,6 +1301,8 @@
|
||||
editor.find(".vdir_list").html(renderVirtualDirectoryList(subd));
|
||||
editor.find(".editVdirBtn").off("click").on("click", function(){
|
||||
quickEditVdir(uuid);
|
||||
//Temporary restore scroll
|
||||
$("body").css("overflow", "auto");
|
||||
});
|
||||
|
||||
/* ------------ Alias ------------ */
|
||||
@@ -1336,6 +1402,7 @@
|
||||
/* ------------ TLS ------------ */
|
||||
updateTlsResolveList(uuid);
|
||||
editor.find(".Tls_EnableSNI").prop("checked", !subd.TlsOptions.DisableSNI);
|
||||
|
||||
editor.find(".Tls_EnableLegacyCertificateMatching").prop("checked", !subd.TlsOptions.DisableLegacyCertificateMatching);
|
||||
editor.find(".Tls_EnableAutoHTTPS").prop("checked", !!subd.TlsOptions.EnableAutoHTTPS);
|
||||
|
||||
@@ -1349,6 +1416,45 @@
|
||||
saveTlsConfigs(uuid);
|
||||
});
|
||||
|
||||
/* Quick access to get certificate for the current host */
|
||||
let enableQuickRequestButton = true;
|
||||
let domains = [subd.RootOrMatchingDomain]; //Domain for getting certificate if needed
|
||||
for (var i = 0; i < subd.MatchingDomainAlias.length; i++){
|
||||
let thisAliasName = subd.MatchingDomainAlias[i];
|
||||
domains.push(thisAliasName);
|
||||
}
|
||||
|
||||
//Check if the domain or alias contains wildcard, if yes, disabled the get certificate button
|
||||
if (subd.RootOrMatchingDomain.indexOf("*") > -1){
|
||||
enableQuickRequestButton = false;
|
||||
}
|
||||
|
||||
if (subd.MatchingDomainAlias != undefined){
|
||||
for (var i = 0; i < subd.MatchingDomainAlias.length; i++){
|
||||
if (subd.MatchingDomainAlias[i].indexOf("*") > -1){
|
||||
enableQuickRequestButton = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (enableQuickRequestButton){
|
||||
editor.find(".getCertificateBtn").removeClass("disabled");
|
||||
}else{
|
||||
editor.find(".getCertificateBtn").addClass("disabled");
|
||||
}
|
||||
|
||||
editor.find(".getCertificateBtn").off("click").on("click", function(){
|
||||
let certificateDomains = encodeURIComponent(JSON.stringify(domains));
|
||||
requestCertificateForExistingHost(uuid, certificateDomains, this);
|
||||
});
|
||||
|
||||
// Bind event to self-signed certificate button
|
||||
editor.find(".getSelfSignCertBtn").off("click").on("click", function() {
|
||||
generateSelfSignedCertificate(uuid, domains, this);
|
||||
});
|
||||
|
||||
|
||||
|
||||
/* ------------ Tags ------------ */
|
||||
(()=>{
|
||||
let payload = encodeURIComponent(JSON.stringify({
|
||||
@@ -1411,7 +1517,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Page Initialization Functions
|
||||
*/
|
||||
@@ -1436,7 +1541,9 @@
|
||||
// there is a chance where the user has modified the Vdir
|
||||
// we need to get the latest setting from server side and
|
||||
// render it again
|
||||
updateVdirInProxyEditor();
|
||||
resyncProxyEditorConfig();
|
||||
window.scrollTo(0, 0);
|
||||
$("body").css("overflow", "hidden");
|
||||
} else {
|
||||
listProxyEndpoints();
|
||||
//Reset the tag filter
|
||||
|
@@ -151,11 +151,31 @@
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
$('#forwardAuthAddress').val(data.address);
|
||||
$('#forwardAuthResponseHeaders').val(data.responseHeaders.join(","));
|
||||
$('#forwardAuthResponseClientHeaders').val(data.responseClientHeaders.join(","));
|
||||
$('#forwardAuthRequestHeaders').val(data.requestHeaders.join(","));
|
||||
$('#forwardAuthRequestIncludedCookies').val(data.requestIncludedCookies.join(","));
|
||||
$('#forwardAuthRequestExcludedCookies').val(data.requestExcludedCookies.join(","));
|
||||
if (data.responseHeaders != null) {
|
||||
$('#forwardAuthResponseHeaders').val(data.responseHeaders.join(","));
|
||||
} else {
|
||||
$('#forwardAuthResponseHeaders').val("");
|
||||
}
|
||||
if (data.responseClientHeaders != null) {
|
||||
$('#forwardAuthResponseClientHeaders').val(data.responseClientHeaders.join(","));
|
||||
} else {
|
||||
$('#forwardAuthResponseClientHeaders').val("");
|
||||
}
|
||||
if (data.requestHeaders != null) {
|
||||
$('#forwardAuthRequestHeaders').val(data.requestHeaders.join(","));
|
||||
} else {
|
||||
$('#forwardAuthRequestHeaders').val("");
|
||||
}
|
||||
if (data.requestIncludedCookies != null) {
|
||||
$('#forwardAuthRequestIncludedCookies').val(data.requestIncludedCookies.join(","));
|
||||
} else {
|
||||
$('#forwardAuthRequestIncludedCookies').val("");
|
||||
}
|
||||
if (data.requestExcludedCookies != null) {
|
||||
$('#forwardAuthRequestExcludedCookies').val(data.requestExcludedCookies.join(","));
|
||||
} else {
|
||||
$('#forwardAuthRequestExcludedCookies').val("");
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
console.error('Error fetching SSO settings:', textStatus, errorThrown);
|
||||
|
Reference in New Issue
Block a user