Skip to content

Commit

Permalink
Merge pull request #66 from tobychui/2.6.7
Browse files Browse the repository at this point in the history
v2.6.7 Update
  • Loading branch information
tobychui authored Sep 26, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents 83f574e + bda47fc commit d4bb841
Showing 48 changed files with 8,036 additions and 55 deletions.
3 changes: 2 additions & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
@@ -19,7 +19,8 @@ clean:

$(PLATFORMS):
@echo "Building $(os)/$(arch)"
GOROOT_FINAL=Git/ GOOS=$(os) GOARCH=$(arch) GOARM=6 go build -o './dist/zoraxy_$(os)_$(arch)' -ldflags "-s -w" -trimpath
GOROOT_FINAL=Git/ GOOS=$(os) GOARCH=$(arch) $(if $(filter linux/arm,$(os)/$(arch)),GOARM=6,) go build -o './dist/zoraxy_$(os)_$(arch)' -ldflags "-s -w" -trimpath
# GOROOT_FINAL=Git/ GOOS=$(os) GOARCH=$(arch) GOARM=6 go build -o './dist/zoraxy_$(os)_$(arch)' -ldflags "-s -w" -trimpath


fixwindows:
27 changes: 24 additions & 3 deletions src/acme.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package main

import (
"encoding/json"
"fmt"
"io/ioutil"
"io"
"log"
"math/rand"
"net/http"
@@ -38,7 +39,7 @@ func initACME() *acme.ACMEHandler {
port = getRandomPort(30000)
}

return acme.NewACME("https://acme-staging-v02.api.letsencrypt.org/directory", strconv.Itoa(port))
return acme.NewACME("https://acme-v02.api.letsencrypt.org/directory", strconv.Itoa(port))
}

// create the special routing rule for ACME
@@ -65,7 +66,7 @@ func acmeRegisterSpecialRoutingRule() {
return
}

resBody, err := ioutil.ReadAll(res.Body)
resBody, err := io.ReadAll(res.Body)
defer res.Body.Close()
if err != nil {
fmt.Printf("error reading: %s\n", err)
@@ -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)
}

}
19 changes: 19 additions & 0 deletions src/api.go
Original file line number Diff line number Diff line change
@@ -162,13 +162,32 @@ func initAPIs() {
authRouter.HandleFunc("/api/acme/listExpiredDomains", acmeHandler.HandleGetExpiredDomains)
authRouter.HandleFunc("/api/acme/obtainCert", AcmeCheckAndHandleRenewCertificate)
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/setDomains", acmeAutoRenewer.HandleSetAutoRenewDomains)
authRouter.HandleFunc("/api/acme/autoRenew/listDomains", acmeAutoRenewer.HandleLoadAutoRenewDomains)
authRouter.HandleFunc("/api/acme/autoRenew/renewPolicy", acmeAutoRenewer.HandleRenewPolicy)
authRouter.HandleFunc("/api/acme/autoRenew/renewNow", acmeAutoRenewer.HandleRenewNow)
authRouter.HandleFunc("/api/acme/wizard", acmewizard.HandleGuidedStepCheck) //ACME Wizard

//Static Web Server
authRouter.HandleFunc("/api/webserv/status", staticWebServer.HandleGetStatus)
authRouter.HandleFunc("/api/webserv/start", staticWebServer.HandleStartServer)
authRouter.HandleFunc("/api/webserv/stop", staticWebServer.HandleStopServer)
authRouter.HandleFunc("/api/webserv/setPort", staticWebServer.HandlePortChange)
authRouter.HandleFunc("/api/webserv/setDirList", staticWebServer.SetEnableDirectoryListing)
if *allowWebFileManager {
//Web Directory Manager file operation functions
authRouter.HandleFunc("/api/fs/list", staticWebServer.FileManager.HandleList)
authRouter.HandleFunc("/api/fs/upload", staticWebServer.FileManager.HandleUpload)
authRouter.HandleFunc("/api/fs/download", staticWebServer.FileManager.HandleDownload)
authRouter.HandleFunc("/api/fs/newFolder", staticWebServer.FileManager.HandleNewFolder)
authRouter.HandleFunc("/api/fs/copy", staticWebServer.FileManager.HandleFileCopy)
authRouter.HandleFunc("/api/fs/move", staticWebServer.FileManager.HandleFileMove)
authRouter.HandleFunc("/api/fs/properties", staticWebServer.FileManager.HandleFileProperties)
authRouter.HandleFunc("/api/fs/del", staticWebServer.FileManager.HandleFileDelete)
}

//Others
http.HandleFunc("/api/info/x", HandleZoraxyInfo)
authRouter.HandleFunc("/api/info/geoip", HandleGeoIpLookup)
7 changes: 6 additions & 1 deletion src/main.go
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@ import (
"imuslab.com/zoraxy/mod/tlscert"
"imuslab.com/zoraxy/mod/uptime"
"imuslab.com/zoraxy/mod/utils"
"imuslab.com/zoraxy/mod/webserv"
)

// General flags
@@ -41,9 +42,12 @@ var ztAuthToken = flag.String("ztauth", "", "ZeroTier authtoken for the local no
var ztAPIPort = flag.Int("ztport", 9993, "ZeroTier controller API port")
var acmeAutoRenewInterval = flag.Int("autorenew", 86400, "ACME auto TLS/SSL certificate renew check interval (seconds)")
var enableHighSpeedGeoIPLookup = flag.Bool("fastgeoip", false, "Enable high speed geoip lookup, require 1GB extra memory (Not recommend for low end devices)")
var staticWebServerRoot = flag.String("webroot", "./www", "Static web server root folder. Only allow chnage in start paramters")
var allowWebFileManager = flag.Bool("webfm", true, "Enable web file manager for static web server root folder")

var (
name = "Zoraxy"
version = "2.6.6"
version = "2.6.7"
nodeUUID = "generic"
development = false //Set this to false to use embedded web fs
bootTime = time.Now().Unix()
@@ -73,6 +77,7 @@ var (
tcpProxyManager *tcpprox.Manager //TCP Proxy Manager
acmeHandler *acme.ACMEHandler //Handler for ACME Certificate renew
acmeAutoRenewer *acme.AutoRenewer //Handler for ACME auto renew ticking
staticWebServer *webserv.WebServer //Static web server for hosting simple stuffs

//Helper modules
EmailSender *email.Sender //Email sender that handle email sending
16 changes: 10 additions & 6 deletions src/mod/acme/acme.go
Original file line number Diff line number Diff line change
@@ -10,7 +10,6 @@ import (
"encoding/json"
"encoding/pem"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
@@ -164,12 +163,12 @@ func (a *ACMEHandler) ObtainCert(domains []string, certificateName string, email

// Each certificate comes back with the cert bytes, the bytes of the client's
// private key, and a certificate URL.
err = ioutil.WriteFile("./conf/certs/"+certificateName+".crt", certificates.Certificate, 0777)
err = os.WriteFile("./conf/certs/"+certificateName+".crt", certificates.Certificate, 0777)
if err != nil {
log.Println(err)
return false, err
}
err = ioutil.WriteFile("./conf/certs/"+certificateName+".key", certificates.PrivateKey, 0777)
err = os.WriteFile("./conf/certs/"+certificateName+".key", certificates.PrivateKey, 0777)
if err != nil {
log.Println(err)
return false, err
@@ -303,18 +302,23 @@ func (a *ACMEHandler) HandleRenewCertificate(w http.ResponseWriter, r *http.Requ

ca, err := utils.PostPara(r, "ca")
if err != nil {
log.Println("CA not set. Using default")
log.Println("[INFO] CA not set. Using default")
ca, caUrl = "", ""
}

if ca == "custom" {
caUrl, err = utils.PostPara(r, "caURL")
if err != nil {
log.Println("Custom CA set but no URL provide, Using default")
log.Println("[INFO] Custom CA set but no URL provide, Using default")
ca, caUrl = "", ""
}
}

if ca == "" {
//default. Use Let's Encrypt
ca = "Let's Encrypt"
}

var skipTLS bool

if skipTLSString, err := utils.PostPara(r, "skipTLS"); err != nil {
@@ -357,8 +361,8 @@ func IsPortInUse(port int) bool {

}

// Load cert information from json file
func loadCertInfoJSON(filename string) (*CertificateInfoJSON, error) {

certInfoBytes, err := os.ReadFile(filename)
if err != nil {
return nil, err
25 changes: 8 additions & 17 deletions src/mod/acme/autorenew.go
Original file line number Diff line number Diff line change
@@ -40,7 +40,6 @@ type AutoRenewer struct {
type ExpiredCerts struct {
Domains []string
Filepath string
CA string
}

// Create an auto renew agent, require config filepath and auto scan & renew interval (seconds)
@@ -280,12 +279,6 @@ func (a *AutoRenewer) CheckAndRenewCertificates() ([]string, error) {
}
if CertExpireSoon(certBytes) || CertIsExpired(certBytes) {
//This cert is expired
CAName, err := ExtractIssuerName(certBytes)
if err != nil {
//Maybe self signed. Ignore this
log.Println("Unable to extract issuer name for cert " + file.Name())
continue
}

DNSName, err := ExtractDomains(certBytes)
if err != nil {
@@ -296,7 +289,6 @@ func (a *AutoRenewer) CheckAndRenewCertificates() ([]string, error) {

expiredCertList = append(expiredCertList, &ExpiredCerts{
Filepath: filepath.Join(certFolder, file.Name()),
CA: CAName,
Domains: DNSName,
})
}
@@ -315,12 +307,6 @@ func (a *AutoRenewer) CheckAndRenewCertificates() ([]string, error) {
}
if CertExpireSoon(certBytes) || CertIsExpired(certBytes) {
//This cert is expired
CAName, err := ExtractIssuerName(certBytes)
if err != nil {
//Maybe self signed. Ignore this
log.Println("Unable to extract issuer name for cert " + file.Name())
continue
}

DNSName, err := ExtractDomains(certBytes)
if err != nil {
@@ -331,7 +317,6 @@ func (a *AutoRenewer) CheckAndRenewCertificates() ([]string, error) {

expiredCertList = append(expiredCertList, &ExpiredCerts{
Filepath: filepath.Join(certFolder, file.Name()),
CA: CAName,
Domains: DNSName,
})
}
@@ -361,8 +346,14 @@ func (a *AutoRenewer) renewExpiredDomains(certs []*ExpiredCerts) ([]string, erro
certInfoFilename := fmt.Sprintf("%s/%s.json", filepath.Dir(expiredCert.Filepath), certName)
certInfo, err := loadCertInfoJSON(certInfoFilename)
if err != nil {
log.Printf("Renew %s certificate error, can't get the ACME detail for cert: %v, using default ACME", certName, err)
certInfo = &CertificateInfoJSON{}
log.Printf("Renew %s certificate error, can't get the ACME detail for cert: %v, trying org section as ca", certName, err)

if CAName, extractErr := ExtractIssuerNameFromPEM(expiredCert.Filepath); extractErr != nil {
log.Printf("extract issuer name for cert error: %v, using default ca", extractErr)
certInfo = &CertificateInfoJSON{}
} else {
certInfo = &CertificateInfoJSON{AcmeName: CAName}
}
}

_, err = a.AcmeHandler.ObtainCert(expiredCert.Domains, certName, a.RenewerConfig.Email, certInfo.AcmeName, certInfo.AcmeUrl, certInfo.SkipTLS)
13 changes: 12 additions & 1 deletion src/mod/acme/ca.go
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ import (
"encoding/json"
"errors"
"log"
"strings"
)

// CA Defination, load from embeded json when startup
@@ -32,14 +33,24 @@ func init() {
}

caDef = runtimeCaDef

}

// Get the CA ACME server endpoint and error if not found
func loadCAApiServerFromName(caName string) (string, error) {
// handle BuyPass cert org section (Buypass AS-983163327)
if strings.HasPrefix(caName, "Buypass AS") {
caName = "Buypass"
}

val, ok := caDef.Production[caName]
if !ok {
return "", errors.New("This CA is not supported")
}

return val, nil
}

func IsSupportedCA(caName string) bool {
_, err := loadCAApiServerFromName(caName)
return err == nil
}
5 changes: 5 additions & 0 deletions src/mod/acme/utils.go
Original file line number Diff line number Diff line change
@@ -53,6 +53,11 @@ func ExtractIssuerName(certBytes []byte) (string, error) {
return "", fmt.Errorf("failed to parse certificate: %v", err)
}

// Check if exist incase some acme server didn't have org section
if len(cert.Issuer.Organization) == 0 {
return "", fmt.Errorf("cert didn't have org section exist")
}

// Extract the issuer name
issuer := cert.Issuer.Organization[0]

9 changes: 5 additions & 4 deletions src/mod/dynamicproxy/Server.go
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ import (
"net/http"
"net/url"
"os"
"path/filepath"
"strings"

"imuslab.com/zoraxy/mod/geodb"
@@ -192,9 +193,9 @@ func (h *ProxyHandler) handleAccessRouting(w http.ResponseWriter, r *http.Reques
if h.Parent.Option.GeodbStore.IsBlacklisted(clientIpAddr) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusForbidden)
template, err := os.ReadFile("./web/forbidden.html")
template, err := os.ReadFile(filepath.Join(h.Parent.Option.WebDirectory, "templates/blacklist.html"))
if err != nil {
w.Write([]byte("403 - Forbidden"))
w.Write(page_forbidden)
} else {
w.Write(template)
}
@@ -206,9 +207,9 @@ func (h *ProxyHandler) handleAccessRouting(w http.ResponseWriter, r *http.Reques
if !h.Parent.Option.GeodbStore.IsWhitelisted(clientIpAddr) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusForbidden)
template, err := os.ReadFile("./web/forbidden.html")
template, err := os.ReadFile(filepath.Join(h.Parent.Option.WebDirectory, "templates/whitelist.html"))
if err != nil {
w.Write([]byte("403 - Forbidden"))
w.Write(page_forbidden)
} else {
w.Write(template)
}
55 changes: 55 additions & 0 deletions src/mod/dynamicproxy/templates/forbidden.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<html>
<head>
<!-- Zoraxy Forbidden Template -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0 user-scalable=no">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.5.0/semantic.min.css">
<script type="text/javascript" src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.5.0/semantic.min.js"></script>
<title>Forbidden</title>
<style>
#msg{
position: absolute;
top: calc(50% - 150px);
left: calc(50% - 250px);
width: 500px;
height: 300px;
text-align: center;
}

#footer{
position: fixed;
padding: 2em;
padding-left: 5em;
padding-right: 5em;
bottom: 0px;
left: 0px;
width: 100%;
}

small{
word-break: break-word;
}
</style>
</head>
<body>
<div id="msg">
<h1 style="font-size: 6em; margin-bottom: 0px;"><i class="red ban icon"></i></h1>
<div>
<h3 style="margin-top: 1em;">403 - Forbidden</h3>
<div class="ui divider"></div>
<p>You do not have permission to view this directory or page. <br>
This might cause by the region limit setting of this site.</p>
<div class="ui divider"></div>
<div style="text-align: left;">
<small>Request time: <span id="reqtime"></span></small><br>
<small id="reqURLDisplay">Request URI: <span id="requrl"></span></small>
</div>
</div>
</div>
<script>
$("#reqtime").text(new Date().toLocaleString(undefined, {year: 'numeric', month: '2-digit', day: '2-digit', weekday:"long", hour: '2-digit', hour12: false, minute:'2-digit', second:'2-digit'}));
$("#requrl").text(window.location.href);
</script>
</body>
</html>
Loading

0 comments on commit d4bb841

Please sign in to comment.