mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-06-03 06:07:20 +02:00
Added Custom Name Server Option
This commit is contained in:
parent
4a4483e09d
commit
e6b2d458f7
@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"github.com/go-acme/lego/v4/certcrypto"
|
"github.com/go-acme/lego/v4/certcrypto"
|
||||||
"github.com/go-acme/lego/v4/certificate"
|
"github.com/go-acme/lego/v4/certificate"
|
||||||
|
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||||
"github.com/go-acme/lego/v4/challenge/http01"
|
"github.com/go-acme/lego/v4/challenge/http01"
|
||||||
"github.com/go-acme/lego/v4/lego"
|
"github.com/go-acme/lego/v4/lego"
|
||||||
"github.com/go-acme/lego/v4/registration"
|
"github.com/go-acme/lego/v4/registration"
|
||||||
@ -30,11 +31,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type CertificateInfoJSON struct {
|
type CertificateInfoJSON struct {
|
||||||
AcmeName string `json:"acme_name"` //ACME provider name
|
AcmeName string `json:"acme_name"` //ACME provider name
|
||||||
AcmeUrl string `json:"acme_url"` //Custom ACME URL (if any)
|
AcmeUrl string `json:"acme_url"` //Custom ACME URL (if any)
|
||||||
SkipTLS bool `json:"skip_tls"` //Skip TLS verification of upstream
|
SkipTLS bool `json:"skip_tls"` //Skip TLS verification of upstream
|
||||||
UseDNS bool `json:"dns"` //Use DNS challenge
|
UseDNS bool `json:"dns"` //Use DNS challenge
|
||||||
PropTimeout int `json:"prop_time"` //Propagation timeout
|
PropTimeout int `json:"prop_time"` //Propagation timeout
|
||||||
|
DNSServers []string `json:"dnsServers"` // DNS servers
|
||||||
}
|
}
|
||||||
|
|
||||||
// ACMEUser represents a user in the ACME system.
|
// ACMEUser represents a user in the ACME system.
|
||||||
@ -94,7 +96,7 @@ func (a *ACMEHandler) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ObtainCert obtains a certificate for the specified domains.
|
// ObtainCert obtains a certificate for the specified domains.
|
||||||
func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email string, caName string, caUrl string, skipTLS bool, useDNS bool, propagationTimeout int) (bool, error) {
|
func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email string, caName string, caUrl string, skipTLS bool, useDNS bool, propagationTimeout int, dnsServers []string) (bool, error) {
|
||||||
a.Logf("Obtaining certificate for: "+strings.Join(domains, ", "), nil)
|
a.Logf("Obtaining certificate for: "+strings.Join(domains, ", "), nil)
|
||||||
|
|
||||||
// generate private key
|
// generate private key
|
||||||
@ -114,7 +116,6 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email
|
|||||||
config := lego.NewConfig(&adminUser)
|
config := lego.NewConfig(&adminUser)
|
||||||
|
|
||||||
// skip TLS verify if need
|
// skip TLS verify if need
|
||||||
// Ref: https://github.com/go-acme/lego/blob/6af2c756ac73a9cb401621afca722d0f4112b1b8/lego/client_config.go#L74
|
|
||||||
if skipTLS {
|
if skipTLS {
|
||||||
a.Logf("Ignoring TLS/SSL Verification Error for ACME Server", nil)
|
a.Logf("Ignoring TLS/SSL Verification Error for ACME Server", nil)
|
||||||
config.HTTPClient.Transport = &http.Transport{
|
config.HTTPClient.Transport = &http.Transport{
|
||||||
@ -150,7 +151,6 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email
|
|||||||
config.CADirURL = caLinkOverwrite
|
config.CADirURL = caLinkOverwrite
|
||||||
a.Logf("Using "+caLinkOverwrite+" for CA Directory URL", nil)
|
a.Logf("Using "+caLinkOverwrite+" for CA Directory URL", nil)
|
||||||
} else {
|
} else {
|
||||||
// (caName == "" || caUrl == "") will use default acme
|
|
||||||
config.CADirURL = a.DefaultAcmeServer
|
config.CADirURL = a.DefaultAcmeServer
|
||||||
a.Logf("Using Default ACME "+a.DefaultAcmeServer+" for CA Directory URL", nil)
|
a.Logf("Using Default ACME "+a.DefaultAcmeServer+" for CA Directory URL", nil)
|
||||||
}
|
}
|
||||||
@ -168,11 +168,11 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email
|
|||||||
if useDNS {
|
if useDNS {
|
||||||
if !a.Database.TableExists("acme") {
|
if !a.Database.TableExists("acme") {
|
||||||
a.Database.NewTable("acme")
|
a.Database.NewTable("acme")
|
||||||
return false, errors.New("DNS Provider and DNS Credenital configuration required for ACME Provider (Error -1)")
|
return false, errors.New("DNS Provider and DNS Credential configuration required for ACME Provider (Error -1)")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !a.Database.KeyExists("acme", certificateName+"_dns_provider") || !a.Database.KeyExists("acme", certificateName+"_dns_credentials") {
|
if !a.Database.KeyExists("acme", certificateName+"_dns_provider") || !a.Database.KeyExists("acme", certificateName+"_dns_credentials") {
|
||||||
return false, errors.New("DNS Provider and DNS Credenital configuration required for ACME Provider (Error -2)")
|
return false, errors.New("DNS Provider and DNS Credential configuration required for ACME Provider (Error -2)")
|
||||||
}
|
}
|
||||||
|
|
||||||
var dnsCredentials string
|
var dnsCredentials string
|
||||||
@ -195,7 +195,11 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = client.Challenge.SetDNS01Provider(provider)
|
if len(dnsServers) > 0 {
|
||||||
|
err = client.Challenge.SetDNS01Provider(provider, dns01.AddRecursiveNameservers(dnsServers))
|
||||||
|
} else {
|
||||||
|
err = client.Challenge.SetDNS01Provider(provider)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.Logf("Failed to resolve DNS01 Provider", err)
|
a.Logf("Failed to resolve DNS01 Provider", err)
|
||||||
return false, err
|
return false, err
|
||||||
@ -209,19 +213,9 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New users will need to register
|
// New users will need to register
|
||||||
/*
|
|
||||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
var reg *registration.Resource
|
var reg *registration.Resource
|
||||||
// New users will need to register
|
|
||||||
if client.GetExternalAccountRequired() {
|
if client.GetExternalAccountRequired() {
|
||||||
a.Logf("External Account Required for this ACME Provider", nil)
|
a.Logf("External Account Required for this ACME Provider", nil)
|
||||||
// IF KID and HmacEncoded is overidden
|
|
||||||
|
|
||||||
if !a.Database.TableExists("acme") {
|
if !a.Database.TableExists("acme") {
|
||||||
a.Database.NewTable("acme")
|
a.Database.NewTable("acme")
|
||||||
return false, errors.New("kid and HmacEncoded configuration required for ACME Provider (Error -1)")
|
return false, errors.New("kid and HmacEncoded configuration required for ACME Provider (Error -1)")
|
||||||
@ -257,7 +251,6 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email
|
|||||||
a.Logf("Register with external account binder failed", err)
|
a.Logf("Register with external account binder failed", err)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
//return false, errors.New("External Account Required for this ACME Provider.")
|
|
||||||
} else {
|
} else {
|
||||||
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
reg, err = client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -298,6 +291,7 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email
|
|||||||
SkipTLS: skipTLS,
|
SkipTLS: skipTLS,
|
||||||
UseDNS: useDNS,
|
UseDNS: useDNS,
|
||||||
PropTimeout: propagationTimeout,
|
PropTimeout: propagationTimeout,
|
||||||
|
DNSServers: dnsServers,
|
||||||
}
|
}
|
||||||
|
|
||||||
certInfoBytes, err := json.Marshal(certInfo)
|
certInfoBytes, err := json.Marshal(certInfo)
|
||||||
@ -479,12 +473,22 @@ func (a *ACMEHandler) HandleRenewCertificate(w http.ResponseWriter, r *http.Requ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extract DNS servers from the request
|
||||||
|
var dnsServers []string
|
||||||
|
dnsServersPara, err := utils.PostPara(r, "dnsServers")
|
||||||
|
if err == nil && dnsServersPara != "" {
|
||||||
|
dnsServers = strings.Split(dnsServersPara, ",")
|
||||||
|
for i := range dnsServers {
|
||||||
|
dnsServers[i] = strings.TrimSpace(dnsServers[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Clean spaces in front or behind each domain
|
//Clean spaces in front or behind each domain
|
||||||
cleanedDomains := []string{}
|
cleanedDomains := []string{}
|
||||||
for _, domain := range domains {
|
for _, domain := range domains {
|
||||||
cleanedDomains = append(cleanedDomains, strings.TrimSpace(domain))
|
cleanedDomains = append(cleanedDomains, strings.TrimSpace(domain))
|
||||||
}
|
}
|
||||||
result, err := a.ObtainCert(cleanedDomains, filename, email, ca, caUrl, skipTLS, dns, propagationTimeout)
|
result, err := a.ObtainCert(cleanedDomains, filename, email, ca, caUrl, skipTLS, dns, propagationTimeout, dnsServers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.SendErrorResponse(w, jsonEscape(err.Error()))
|
utils.SendErrorResponse(w, jsonEscape(err.Error()))
|
||||||
return
|
return
|
||||||
|
@ -354,7 +354,6 @@ func (a *AutoRenewer) CheckAndRenewCertificates() ([]string, error) {
|
|||||||
return a.renewExpiredDomains(expiredCertList)
|
return a.renewExpiredDomains(expiredCertList)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the auto renewer
|
|
||||||
func (a *AutoRenewer) Close() {
|
func (a *AutoRenewer) Close() {
|
||||||
if a.TickerstopChan != nil {
|
if a.TickerstopChan != nil {
|
||||||
a.TickerstopChan <- true
|
a.TickerstopChan <- true
|
||||||
@ -384,13 +383,19 @@ func (a *AutoRenewer) renewExpiredDomains(certs []*ExpiredCerts) ([]string, erro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//For upgrading config from older version of Zoraxy which don't have timeout
|
// For upgrading config from older version of Zoraxy which don't have timeout
|
||||||
if certInfo.PropTimeout == 0 {
|
if certInfo.PropTimeout == 0 {
|
||||||
//Set default timeout
|
// Set default timeout
|
||||||
certInfo.PropTimeout = 300
|
certInfo.PropTimeout = 300
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = a.AcmeHandler.ObtainCert(expiredCert.Domains, certName, a.RenewerConfig.Email, certInfo.AcmeName, certInfo.AcmeUrl, certInfo.SkipTLS, certInfo.UseDNS, certInfo.PropTimeout)
|
// Extract DNS servers from the certificate info if available
|
||||||
|
var dnsServers []string
|
||||||
|
if certInfo.DNSServers != nil {
|
||||||
|
dnsServers = certInfo.DNSServers
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = a.AcmeHandler.ObtainCert(expiredCert.Domains, certName, a.RenewerConfig.Email, certInfo.AcmeName, certInfo.AcmeUrl, certInfo.SkipTLS, certInfo.UseDNS, certInfo.PropTimeout, dnsServers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.Logf("Renew "+fileName+"("+strings.Join(expiredCert.Domains, ",")+") failed", err)
|
a.Logf("Renew "+fileName+"("+strings.Join(expiredCert.Domains, ",")+") failed", err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -25,8 +25,6 @@
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<link rel="stylesheet" href="../darktheme.css">
|
|
||||||
<script src="../script/darktheme.js"></script>
|
|
||||||
<br>
|
<br>
|
||||||
<div class="ui container">
|
<div class="ui container">
|
||||||
<div class="ui header">
|
<div class="ui header">
|
||||||
@ -52,7 +50,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<small>If you don't want to share your private email address, you can also fill in an email address that point to a mailbox not exists on your domain.</small>
|
<small>If you don't want to share your private email address, you can also fill in an email address that point to a mailbox not exists on your domain.</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui basic segment advanceoptions">
|
<div class="ui basic segment" style="background-color: #f7f7f7; border-radius: 1em;">
|
||||||
<div class="ui accordion advanceSettings">
|
<div class="ui accordion advanceSettings">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<i class="dropdown icon"></i>
|
<i class="dropdown icon"></i>
|
||||||
@ -137,6 +135,13 @@
|
|||||||
<!-- Auto populate moved to acmedns module and initDNSProviderList() -->
|
<!-- Auto populate moved to acmedns module and initDNSProviderList() -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="ui form">
|
||||||
|
<div class="field">
|
||||||
|
<label>Domain Name Server (optional)</label>
|
||||||
|
<input id="dnsInput" type="text" placeholder="ns.example.com" onkeyup="handlePostInputAutomation();">
|
||||||
|
<small>If you have more than one DNS server, enter them separated by commas (e.g. ns1.example.com,ns2.example.com)
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field dnsChallengeOnly" style="display:none;">
|
<div class="field dnsChallengeOnly" style="display:none;">
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
@ -439,15 +444,11 @@
|
|||||||
let optionalFieldsHTML = "";
|
let optionalFieldsHTML = "";
|
||||||
for (const [key, datatype] of Object.entries(data)) {
|
for (const [key, datatype] of Object.entries(data)) {
|
||||||
if (datatype == "int"){
|
if (datatype == "int"){
|
||||||
let defaultValue = 10;
|
$("#dnsProviderAPIFields").append(`<div class="ui fluid labeled dnsConfigField input" key="${key}" style="margin-top: 0.2em;">
|
||||||
if (key == "HTTPTimeout"){
|
|
||||||
defaultValue = 300;
|
|
||||||
}
|
|
||||||
$("#dnsProviderAPIFields").append(`<div class="ui fluid labeled dnsConfigField input typeint" key="${key}" style="margin-top: 0.2em;">
|
|
||||||
<div class="ui basic blue label" style="font-weight: 300;">
|
<div class="ui basic blue label" style="font-weight: 300;">
|
||||||
${key}
|
${key}
|
||||||
</div>
|
</div>
|
||||||
<input type="number" value="${defaultValue}">
|
<input type="number" value="300">
|
||||||
</div>`);
|
</div>`);
|
||||||
}else if (datatype == "bool"){
|
}else if (datatype == "bool"){
|
||||||
booleanFieldsHTML += (`<div class="ui checkbox dnsConfigField" key="${key}" style="margin-top: 1em !important; padding-left: 0.4em;">
|
booleanFieldsHTML += (`<div class="ui checkbox dnsConfigField" key="${key}" style="margin-top: 1em !important; padding-left: 0.4em;">
|
||||||
@ -606,12 +607,8 @@
|
|||||||
//Boolean option
|
//Boolean option
|
||||||
let checked = $(this).find("input")[0].checked;
|
let checked = $(this).find("input")[0].checked;
|
||||||
dnsCredentials[thisKey] = checked;
|
dnsCredentials[thisKey] = checked;
|
||||||
}else if ($(this).hasClass("typeint")){
|
|
||||||
//Int options
|
|
||||||
let value = $(this).find("input").val();
|
|
||||||
dnsCredentials[thisKey] = parseInt(value);
|
|
||||||
}else{
|
}else{
|
||||||
//String options
|
//String or int options
|
||||||
let value = $(this).find("input").val().trim();
|
let value = $(this).find("input").val().trim();
|
||||||
dnsCredentials[thisKey] = value;
|
dnsCredentials[thisKey] = value;
|
||||||
}
|
}
|
||||||
@ -725,8 +722,7 @@
|
|||||||
if (callback != undefined){callback(false);}
|
if (callback != undefined){callback(false);}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var ca = $("#ca").dropdown("get value");
|
var ca = $("#ca").dropdown("get value");
|
||||||
var caURL = "";
|
var caURL = "";
|
||||||
if (ca == "Custom ACME Server") {
|
if (ca == "Custom ACME Server") {
|
||||||
@ -734,9 +730,9 @@
|
|||||||
caURL = $("#caURL").val();
|
caURL = $("#caURL").val();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var dns = $("#useDnsChallenge")[0].checked;
|
var dns = $("#useDnsChallenge")[0].checked;
|
||||||
var skipTLSValue = $("#skipTLSCheckbox")[0].checked;
|
var skipTLSValue = $("#skipTLSCheckbox")[0].checked;
|
||||||
|
var dnsServers = $("#dnsInput").val(); // New line: Read DNS servers from input field
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "/api/acme/obtainCert",
|
url: "/api/acme/obtainCert",
|
||||||
@ -749,22 +745,18 @@
|
|||||||
caURL: caURL,
|
caURL: caURL,
|
||||||
skipTLS: skipTLSValue,
|
skipTLS: skipTLSValue,
|
||||||
dns: dns,
|
dns: dns,
|
||||||
|
dnsServers: dnsServers // New line: Include DNS servers in the request
|
||||||
},
|
},
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
$("#obtainButton").removeClass("loading").removeClass("disabled");
|
$("#obtainButton").removeClass("loading").removeClass("disabled");
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
console.log("Error:", response.error);
|
console.log("Error:", response.error);
|
||||||
// Show error message
|
|
||||||
parent.msgbox(response.error, false, 12000);
|
parent.msgbox(response.error, false, 12000);
|
||||||
if (callback != undefined){callback(false);}
|
if (callback != undefined){callback(false);}
|
||||||
} else {
|
} else {
|
||||||
console.log("Certificate renewed successfully");
|
console.log("Certificate renewed successfully");
|
||||||
// Show success message
|
|
||||||
parent.msgbox("Certificate renewed successfully");
|
parent.msgbox("Certificate renewed successfully");
|
||||||
|
|
||||||
// Renew the parent certificate list
|
|
||||||
parent.initManagedDomainCertificateList();
|
parent.initManagedDomainCertificateList();
|
||||||
|
|
||||||
if (callback != undefined){callback(true);}
|
if (callback != undefined){callback(true);}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user