|
@@ -22,10 +22,12 @@
|
|
|
<div class="field">
|
|
|
<label>Server Name (Domain)</label>
|
|
|
<input type="text" id="certdomain" placeholder="example.com / blog.example.com">
|
|
|
+ <small><i class="exclamation circle yellow icon"></i> Match the server name with your CN/DNS entry in certificate for faster resolve time</small>
|
|
|
</div>
|
|
|
<div class="field">
|
|
|
<label>Public Key (.pem)</label>
|
|
|
<input type="file" id="pubkeySelector" onchange="handleFileSelect(event, 'pub')">
|
|
|
+ <small>or .crt files in order systems</small>
|
|
|
</div>
|
|
|
<div class="field">
|
|
|
<label>Private Key (.key)</label>
|
|
@@ -64,6 +66,7 @@
|
|
|
<tr><th>Domain</th>
|
|
|
<th>Last Update</th>
|
|
|
<th>Expire At</th>
|
|
|
+ <th class="no-sort">Renew</th>
|
|
|
<th class="no-sort">Remove</th>
|
|
|
</tr></thead>
|
|
|
<tbody id="certifiedDomainList">
|
|
@@ -142,6 +145,110 @@
|
|
|
|
|
|
$("#defaultCA").dropdown();
|
|
|
|
|
|
+
|
|
|
+ //Renew certificate by button press
|
|
|
+ function renewCertificate(domain, btn=undefined){
|
|
|
+ let defaultCA = $("#defaultCA").dropdown("get value");
|
|
|
+ if (defaultCA.trim() == ""){
|
|
|
+ defaultCA = "Let's Encrypt";
|
|
|
+ }
|
|
|
+ //Get a new cert using ACME
|
|
|
+ msgbox("Requesting certificate via " + defaultCA +"...");
|
|
|
+
|
|
|
+ //Request ACME for certificate
|
|
|
+ if (btn != undefined){
|
|
|
+ $(btn).addClass('disabled');
|
|
|
+ $(btn).html(`<i class="ui loading spinner icon"></i>`);
|
|
|
+ }
|
|
|
+ obtainCertificate(domain, defaultCA.trim(), function(succ){
|
|
|
+ if (btn != undefined){
|
|
|
+ $(btn).removeClass('disabled');
|
|
|
+ if (succ){
|
|
|
+ $(btn).html(`<i class="ui green check icon"></i>`);
|
|
|
+ }else{
|
|
|
+ $(btn).html(`<i class="ui red times icon"></i>`);
|
|
|
+ }
|
|
|
+
|
|
|
+ setTimeout(function(){
|
|
|
+ initManagedDomainCertificateList();
|
|
|
+ }, 3000);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ Obtain Certificate via ACME
|
|
|
+ */
|
|
|
+
|
|
|
+ // Obtain certificate from API, only support one domain
|
|
|
+ function obtainCertificate(domains, usingCa = "Let's Encrypt", callback=undefined) {
|
|
|
+ //Load the ACME email from server side
|
|
|
+ let acmeEmail = "";
|
|
|
+ $.get("/api/acme/autoRenew/email", function(data){
|
|
|
+ if (data != "" && data != undefined && data != null){
|
|
|
+ acmeEmail = data;
|
|
|
+ }
|
|
|
+
|
|
|
+ let filename = "";
|
|
|
+ let email = acmeEmail;
|
|
|
+ if (acmeEmail == ""){
|
|
|
+ msgbox("Unable to obtain certificate: ACME email not set", false, 8000);
|
|
|
+ if (callback != undefined){
|
|
|
+ callback(false);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (filename.trim() == "" && !domains.includes(",")){
|
|
|
+ //Zoraxy filename are the matching name for domains.
|
|
|
+ //Use the same as domains
|
|
|
+ filename = domains;
|
|
|
+ }else if (filename != "" && !domains.includes(",")){
|
|
|
+ //Invalid settings. Force the filename to be same as domain
|
|
|
+ //if there are only 1 domain
|
|
|
+ filename = domains;
|
|
|
+ }else{
|
|
|
+ msgbox("Filename cannot be empty for certs containing multiple domains.")
|
|
|
+ if (callback != undefined){
|
|
|
+ callback(false);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ $.ajax({
|
|
|
+ url: "/api/acme/obtainCert",
|
|
|
+ method: "GET",
|
|
|
+ data: {
|
|
|
+ domains: domains,
|
|
|
+ filename: filename,
|
|
|
+ email: email,
|
|
|
+ ca: usingCa,
|
|
|
+ },
|
|
|
+ success: function(response) {
|
|
|
+ if (response.error) {
|
|
|
+ console.log("Error:", response.error);
|
|
|
+ // Show error message
|
|
|
+ msgbox(response.error, false, 12000);
|
|
|
+ if (callback != undefined){
|
|
|
+ callback(false);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.log("Certificate installed successfully");
|
|
|
+ // Show success message
|
|
|
+ msgbox("Certificate installed successfully");
|
|
|
+
|
|
|
+ if (callback != undefined){
|
|
|
+ callback(false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ error: function(error) {
|
|
|
+ console.log("Failed to install certificate:", error);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
//Delete the certificate by its domain
|
|
|
function deleteCertificate(domain){
|
|
|
if (confirm("Confirm delete certificate for " + domain + " ?")){
|
|
@@ -166,6 +273,12 @@
|
|
|
//Initialize the current default CA options
|
|
|
$.get("/api/acme/autoRenew/email", function(data){
|
|
|
$("#prefACMEEmail").val(data);
|
|
|
+ if (data.trim() == ""){
|
|
|
+ //acme email is not yet set
|
|
|
+ $(".renewButton").addClass('disabled');
|
|
|
+ }else{
|
|
|
+ $(".renewButton").removeClass('disabled');
|
|
|
+ }
|
|
|
});
|
|
|
|
|
|
$.get("/api/acme/autoRenew/ca", function(data){
|
|
@@ -205,6 +318,9 @@
|
|
|
success: function(data){
|
|
|
if (data.error != undefined){
|
|
|
msgbox(data.error, false);
|
|
|
+ }else{
|
|
|
+ //Update the renew button states
|
|
|
+ $(".renewButton").removeClass('disabled');
|
|
|
}
|
|
|
}
|
|
|
});
|
|
@@ -241,6 +357,7 @@
|
|
|
<td>${entry.Domain}</td>
|
|
|
<td>${entry.LastModifiedDate}</td>
|
|
|
<td class="${isExpired?"expired":"valid"} certdate">${entry.ExpireDate} (${!isExpired?entry.RemainingDays+" days left":"Expired"})</td>
|
|
|
+ <td><button title="Renew Certificate" class="ui mini basic icon button renewButton" onclick="renewCertificate('${entry.Domain}', this);"><i class="ui green refresh icon"></i></button></td>
|
|
|
<td><button title="Delete key-pair" class="ui mini basic red icon button" onclick="deleteCertificate('${entry.Domain}');"><i class="ui red trash icon"></i></button></td>
|
|
|
</tr>`);
|
|
|
});
|