Added default Ca features

+ Added default CA feature
+ Fixed RWD issue in TLS cert table
+ Optimized ACME UI in the TLS page
This commit is contained in:
Toby Chui 2023-09-25 20:54:50 +08:00
parent fd6ba56143
commit bda47fc36b
9 changed files with 124 additions and 18 deletions

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -114,3 +115,23 @@ func AcmeCheckAndHandleRenewCertificate(w http.ResponseWriter, r *http.Request)
} }
} }
} }
// HandleACMEPreferredCA return the user preferred / default CA for new subdomain auto creation
func HandleACMEPreferredCA(w http.ResponseWriter, r *http.Request) {
ca, err := utils.PostPara(r, "set")
if err != nil {
//Return the current ca to user
prefCA := "Let's Encrypt"
sysdb.Read("acmepref", "prefca", &prefCA)
js, _ := json.Marshal(prefCA)
utils.SendJSONResponse(w, string(js))
} else {
//Check if the CA is supported
acme.IsSupportedCA(ca)
//Set the new config
sysdb.Write("acmepref", "prefca", ca)
log.Println("Updating prefered ACME CA to " + ca)
utils.SendOK(w)
}
}

View File

@ -162,6 +162,7 @@ func initAPIs() {
authRouter.HandleFunc("/api/acme/listExpiredDomains", acmeHandler.HandleGetExpiredDomains) authRouter.HandleFunc("/api/acme/listExpiredDomains", acmeHandler.HandleGetExpiredDomains)
authRouter.HandleFunc("/api/acme/obtainCert", AcmeCheckAndHandleRenewCertificate) authRouter.HandleFunc("/api/acme/obtainCert", AcmeCheckAndHandleRenewCertificate)
authRouter.HandleFunc("/api/acme/autoRenew/enable", acmeAutoRenewer.HandleAutoRenewEnable) authRouter.HandleFunc("/api/acme/autoRenew/enable", acmeAutoRenewer.HandleAutoRenewEnable)
authRouter.HandleFunc("/api/acme/autoRenew/ca", HandleACMEPreferredCA)
authRouter.HandleFunc("/api/acme/autoRenew/email", acmeAutoRenewer.HandleACMEEmail) authRouter.HandleFunc("/api/acme/autoRenew/email", acmeAutoRenewer.HandleACMEEmail)
authRouter.HandleFunc("/api/acme/autoRenew/setDomains", acmeAutoRenewer.HandleSetAutoRenewDomains) authRouter.HandleFunc("/api/acme/autoRenew/setDomains", acmeAutoRenewer.HandleSetAutoRenewDomains)
authRouter.HandleFunc("/api/acme/autoRenew/listDomains", acmeAutoRenewer.HandleLoadAutoRenewDomains) authRouter.HandleFunc("/api/acme/autoRenew/listDomains", acmeAutoRenewer.HandleLoadAutoRenewDomains)

View File

@ -361,8 +361,8 @@ func IsPortInUse(port int) bool {
} }
// Load cert information from json file
func loadCertInfoJSON(filename string) (*CertificateInfoJSON, error) { func loadCertInfoJSON(filename string) (*CertificateInfoJSON, error) {
certInfoBytes, err := os.ReadFile(filename) certInfoBytes, err := os.ReadFile(filename)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -49,3 +49,8 @@ func loadCAApiServerFromName(caName string) (string, error) {
return val, nil return val, nil
} }
func IsSupportedCA(caName string) bool {
_, err := loadCAApiServerFromName(caName)
return err == nil
}

View File

@ -204,6 +204,8 @@ func startupSequence() {
Obtaining certificates from ACME Server Obtaining certificates from ACME Server
*/ */
//Create a table just to store acme related preferences
sysdb.NewTable("acmepref")
acmeHandler = initACME() acmeHandler = initACME()
acmeAutoRenewer, err = acme.NewAutoRenewer("./conf/acme_conf.json", "./conf/certs/", int64(*acmeAutoRenewInterval), acmeHandler) acmeAutoRenewer, err = acme.NewAutoRenewer("./conf/acme_conf.json", "./conf/certs/", int64(*acmeAutoRenewInterval), acmeHandler)
if err != nil { if err != nil {

View File

@ -65,17 +65,20 @@
</div> </div>
<br> <br>
<div> <div>
<table class="ui sortable unstackable celled table"> <div style="width: 100%; overflow-x: auto; margin-bottom: 1em;">
<thead> <table class="ui sortable unstackable celled table">
<tr><th>Domain</th> <thead>
<th>Last Update</th> <tr><th>Domain</th>
<th>Expire At</th> <th>Last Update</th>
<th class="no-sort">Remove</th> <th>Expire At</th>
</tr></thead> <th class="no-sort">Remove</th>
<tbody id="certifiedDomainList"> </tr></thead>
<tbody id="certifiedDomainList">
</tbody>
</table>
</div>
</tbody>
</table>
<button class="ui basic button" onclick="initManagedDomainCertificateList();"><i class="green refresh icon"></i> Refresh List</button> <button class="ui basic button" onclick="initManagedDomainCertificateList();"><i class="green refresh icon"></i> Refresh List</button>
</div> </div>
<div class="ui message"> <div class="ui message">
@ -90,6 +93,7 @@
<p>The default CA to use when create a new subdomain proxy endpoint with TLS certificate</p> <p>The default CA to use when create a new subdomain proxy endpoint with TLS certificate</p>
<div class="ui fluid form"> <div class="ui fluid form">
<div class="field"> <div class="field">
<label>Preferred CA</label>
<div class="ui selection dropdown" id="defaultCA"> <div class="ui selection dropdown" id="defaultCA">
<input type="hidden" name="defaultCA"> <input type="hidden" name="defaultCA">
<i class="dropdown icon"></i> <i class="dropdown icon"></i>
@ -101,10 +105,22 @@
</div> </div>
</div> </div>
</div> </div>
<div class="field">
<label>ACME Email</label>
<input id="prefACMEEmail" type="text" placeholder="ACME Email">
</div>
<button class="ui basic icon button" onclick="saveDefaultCA();"><i class="ui blue save icon"></i> Save Settings</button> <button class="ui basic icon button" onclick="saveDefaultCA();"><i class="ui blue save icon"></i> Save Settings</button>
</div><br> </div><br>
<h5>Certificate Renew / Generation (ACME) Settings</h5> <h5>Certificate Renew / Generation (ACME) Settings</h5>
<div class="ui basic segment">
<h4 class="ui header" id="acmeAutoRenewer">
<i class="red circle icon"></i>
<div class="content">
<span id="acmeAutoRenewerStatus">Disabled</span>
<div class="sub header">Auto-Renewer Status</div>
</div>
</h4>
</div>
<p>This tool provide you a graphical interface to setup auto certificate renew on your (sub)domains. You can also manually generate a certificate if one of your domain do not have certificate.</p> <p>This tool provide you a graphical interface to setup auto certificate renew on your (sub)domains. You can also manually generate a certificate if one of your domain do not have certificate.</p>
<button class="ui basic button" onclick="openACMEManager();"><i class="yellow external icon"></i> Open ACME Tool</button> <button class="ui basic button" onclick="openACMEManager();"><i class="yellow external icon"></i> Open ACME Tool</button>
</div> </div>
@ -134,9 +150,60 @@
} }
function initAcmeStatus(){
//Initialize the current default CA options
$.get("/api/acme/autoRenew/email", function(data){
$("#prefACMEEmail").val(data);
});
$.get("/api/acme/autoRenew/ca", function(data){
$("#defaultCA").dropdown("set value", data);
});
$.get("/api/acme/autoRenew/enable", function(data){
setACMEEnableStates(data);
})
}
//Set the status of the acme enable icon
function setACMEEnableStates(enabled){
$("#acmeAutoRenewerStatus").text(enabled?"Enabled":"Disabled");
$("#acmeAutoRenewer").find("i").attr("class", enabled?"green circle icon":"red circle icon");
}
initAcmeStatus();
function saveDefaultCA(){ function saveDefaultCA(){
//TODO: Add an endpoint to handle default CA set and load let newDefaultEmail = $("#prefACMEEmail").val().trim();
alert("WIP"); let newDefaultCA = $("#defaultCA").dropdown("get value");
if (newDefaultEmail == ""){
msgbox("Invalid acme email given", false);
return;
}
$.ajax({
url: "/api/acme/autoRenew/email",
method: "POST",
data: {"set": newDefaultEmail},
success: function(data){
if (data.error != undefined){
msgbox(data.error, false);
}
}
});
$.ajax({
url: "/api/acme/autoRenew/ca",
data: {"set": newDefaultCA},
method: "POST",
success: function(data){
if (data.error != undefined){
msgbox(data.error, false);
}
}
});
msgbox("Settings updated");
} }
//List the stored certificates //List the stored certificates

View File

@ -184,10 +184,15 @@
if (type == "subd" && $("#tls").checkbox("is checked")){ if (type == "subd" && $("#tls").checkbox("is checked")){
confirmBox("Request new SSL Cert for this subdomain?", function(choice){ confirmBox("Request new SSL Cert for this subdomain?", function(choice){
if (choice == true){ if (choice == true){
//Load the prefer CA from TLS page
let defaultCA = $("#defaultCA").dropdown("get value");
if (defaultCA.trim() == ""){
defaultCA = "Let's Encrypt";
}
//Get a new cert using ACME //Get a new cert using ACME
msgbox("Requesting certificate via Let's Encrypt..."); msgbox("Requesting certificate via " + defaultCA +"...");
console.log("Trying to get a new certificate via ACME"); console.log("Trying to get a new certificate via ACME");
obtainCertificate(rootname); obtainCertificate(rootname, defaultCA.trim());
}else{ }else{
msgbox("Proxy Endpoint Added"); msgbox("Proxy Endpoint Added");
} }

View File

@ -9,7 +9,7 @@
<i class="green circle icon"></i> <i class="green circle icon"></i>
<div class="content"> <div class="content">
<span class="webserv_status">Running</span> <span class="webserv_status">Running</span>
<div class="sub header">Listening on :<span class="webserv_port">8081</span></div> <div class="sub header">Listen port :<span class="webserv_port">8081</span></div>
</div> </div>
</h4> </h4>
</div> </div>

View File

@ -218,6 +218,11 @@
$("#enableToggleSucc").stop().finish().fadeIn("fast").delay(3000).fadeOut("fast"); $("#enableToggleSucc").stop().finish().fadeIn("fast").delay(3000).fadeOut("fast");
} }
}); });
if (parent && parent.setACMEEnableStates){
parent.setACMEEnableStates(enabled);
}
} }
//Render the domains table that exists in this zoraxy host //Render the domains table that exists in this zoraxy host