Skip to content

Commit

Permalink
Merge pull request #138 from tobychui/v3.0.3
Browse files Browse the repository at this point in the history
Update V3.0.3

- Updated SMTP UI for non email login username
- Fixed ACME cert store reload after cert request
- Fixed default rule not applying to default site when default site is set to proxy target
- Fixed blacklist-ip not working with CIDR bug
- Fixed minor vdir bug in tailing slash detection and redirect logic
- Added custom mdns name support (-mdnsname flag)
- Added LAN tag in statistic
  • Loading branch information
tobychui committed Apr 30, 2024
2 parents d00117e + e2a449a commit 176249a
Show file tree
Hide file tree
Showing 14 changed files with 85 additions and 52 deletions.
5 changes: 5 additions & 0 deletions src/acme.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func AcmeCheckAndHandleRenewCertificate(w http.ResponseWriter, r *http.Request)
} else {
//This port do not support ACME
utils.SendErrorResponse(w, "ACME renew only support web server listening on port 80 (http) or 443 (https)")
return
}

//Add a 3 second delay to make sure everything is settle down
Expand All @@ -109,6 +110,10 @@ func AcmeCheckAndHandleRenewCertificate(w http.ResponseWriter, r *http.Request)
// Pass over to the acmeHandler to deal with the communication
acmeHandler.HandleRenewCertificate(w, r)

//Update the TLS cert store buffer
tlsCertManager.UpdateLoadedCertList()

//Restore original settings
if dynamicProxyRouter.Option.Port == 443 {
if !isForceHttpsRedirectEnabledOriginally {
//Default is off. Turn the redirection off
Expand Down
9 changes: 1 addition & 8 deletions src/emails.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,6 @@ func HandleSMTPSet(w http.ResponseWriter, r *http.Request) {
return
}

domain, err := utils.PostPara(r, "domain")
if err != nil {
utils.SendErrorResponse(w, "domain cannot be empty")
return
}

portString, err := utils.PostPara(r, "port")
if err != nil {
utils.SendErrorResponse(w, "port must be a valid integer")
Expand Down Expand Up @@ -76,7 +70,6 @@ func HandleSMTPSet(w http.ResponseWriter, r *http.Request) {
//Set the email sender properties
thisEmailSender := email.Sender{
Hostname: strings.TrimSpace(hostname),
Domain: strings.TrimSpace(domain),
Port: port,
Username: strings.TrimSpace(username),
Password: strings.TrimSpace(password),
Expand Down Expand Up @@ -206,7 +199,7 @@ var (
)

func HandleAdminAccountResetEmail(w http.ResponseWriter, r *http.Request) {
if EmailSender.Username == "" || EmailSender.Domain == "" {
if EmailSender.Username == "" {
//Reset account not setup
utils.SendErrorResponse(w, "Reset account not setup.")
return
Expand Down
3 changes: 2 additions & 1 deletion src/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ var noauth = flag.Bool("noauth", false, "Disable authentication for management i
var showver = flag.Bool("version", false, "Show version of this server")
var allowSshLoopback = flag.Bool("sshlb", false, "Allow loopback web ssh connection (DANGER)")
var allowMdnsScanning = flag.Bool("mdns", true, "Enable mDNS scanner and transponder")
var mdnsName = flag.String("mdnsname", "", "mDNS name, leave empty to use default (zoraxy_{node-uuid}.local)")
var ztAuthToken = flag.String("ztauth", "", "ZeroTier authtoken for the local node")
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)")
Expand All @@ -51,7 +52,7 @@ var logOutputToFile = flag.Bool("log", true, "Log terminal output to file")

var (
name = "Zoraxy"
version = "3.0.2"
version = "3.0.3"
nodeUUID = "generic"
development = false //Set this to false to use embedded web fs
bootTime = time.Now().Unix()
Expand Down
4 changes: 4 additions & 0 deletions src/mod/access/access.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ func NewAccessController(options *Options) (*Controller, error) {
Options: options,
}

//Assign default access rule parent
thisController.DefaultAccessRule.parent = &thisController

//Load all acccess rules from file
configFiles, err := filepath.Glob(options.ConfigFolder + "/*.json")
if err != nil {
Expand Down Expand Up @@ -113,6 +116,7 @@ func (c *Controller) GetGlobalAccessRule() (*AccessRule, error) {
// Load access rules to runtime, require rule ID
func (c *Controller) GetAccessRuleByID(accessRuleID string) (*AccessRule, error) {
if accessRuleID == "default" || accessRuleID == "" {

return c.DefaultAccessRule, nil
}
//Load from sync.Map, should be O(1)
Expand Down
21 changes: 20 additions & 1 deletion src/mod/access/blacklist.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package access

import (
"strings"

"imuslab.com/zoraxy/mod/netutils"
)

/*
Expand Down Expand Up @@ -71,5 +73,22 @@ func (s *AccessRule) GetAllBlacklistedIp() []string {
func (s *AccessRule) IsIPBlacklisted(ipAddr string) bool {
IPBlacklist := *s.BlackListIP
_, ok := IPBlacklist[ipAddr]
return ok
if ok {
return true
}

//Check for CIDR
for ipOrCIDR, _ := range IPBlacklist {
wildcardMatch := netutils.MatchIpWildcard(ipAddr, ipOrCIDR)
if wildcardMatch {
return true
}

cidrMatch := netutils.MatchIpCIDR(ipAddr, ipOrCIDR)
if cidrMatch {
return true
}
}

return false
}
9 changes: 8 additions & 1 deletion src/mod/dynamicproxy/Server.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
} else if !strings.HasSuffix(proxyingPath, "/") && sep.ProxyType != ProxyType_Root {
potentialProxtEndpoint := sep.GetVirtualDirectoryHandlerFromRequestURI(proxyingPath + "/")
if potentialProxtEndpoint != nil && !targetProxyEndpoint.Disabled {
if potentialProxtEndpoint != nil && !potentialProxtEndpoint.Disabled {
//Missing tailing slash. Redirect to target proxy endpoint
http.Redirect(w, r, r.RequestURI+"/", http.StatusTemporaryRedirect)
return
Expand All @@ -102,6 +102,13 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
/*
Root Router Handling
*/

//Root access control based on default rule
blocked := h.handleAccessRouting("default", w, r)
if blocked {
return
}

//Clean up the request URI
proxyingPath := strings.TrimSpace(r.RequestURI)
if !strings.HasSuffix(proxyingPath, "/") {
Expand Down
1 change: 1 addition & 0 deletions src/mod/dynamicproxy/access.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func (h *ProxyHandler) handleAccessRouting(ruleID string, w http.ResponseWriter,
w.Write([]byte("500 - Internal Server Error"))
return true
}

isBlocked, blockedReason := accessRequestBlocked(accessRule, h.Parent.Option.WebDirectory, w, r)
if isBlocked {
h.logRequest(r, false, 403, blockedReason, "")
Expand Down
6 changes: 4 additions & 2 deletions src/mod/dynamicproxy/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ func (ep *ProxyEndpoint) AddUserDefinedHeader(key string, value string) error {
func (ep *ProxyEndpoint) GetVirtualDirectoryHandlerFromRequestURI(requestURI string) *VirtualDirectoryEndpoint {
for _, vdir := range ep.VirtualDirectories {
if strings.HasPrefix(requestURI, vdir.MatchingPath) {
return vdir
thisVdir := vdir
return thisVdir
}
}
return nil
Expand All @@ -80,7 +81,8 @@ func (ep *ProxyEndpoint) GetVirtualDirectoryHandlerFromRequestURI(requestURI str
func (ep *ProxyEndpoint) GetVirtualDirectoryRuleByMatchingPath(matchingPath string) *VirtualDirectoryEndpoint {
for _, vdir := range ep.VirtualDirectories {
if vdir.MatchingPath == matchingPath {
return vdir
thisVdir := vdir
return thisVdir
}
}
return nil
Expand Down
26 changes: 14 additions & 12 deletions src/mod/email/email.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,16 @@ import (

type Sender struct {
Hostname string //E.g. mail.gandi.net
Domain string //E.g. arozos.com
Port int //E.g. 587
Username string //Username of the email account
Password string //Password of the email account
SenderAddr string //e.g. [email protected]
}

//Create a new email sender object
func NewEmailSender(hostname string, domain string, port int, username string, password string, senderAddr string) *Sender {
// Create a new email sender object
func NewEmailSender(hostname string, port int, username string, password string, senderAddr string) *Sender {
return &Sender{
Hostname: hostname,
Domain: domain,
Port: port,
Username: username,
Password: password,
Expand All @@ -33,13 +31,15 @@ func NewEmailSender(hostname string, domain string, port int, username string, p
}

/*
Send a email to a reciving addr
Example Usage:
SendEmail(
[email protected],
"Free donuts",
"Come get your free donuts on this Sunday!"
)
Send a email to a reciving addr
Example Usage:
SendEmail(
[email protected],
"Free donuts",
"Come get your free donuts on this Sunday!"
)
*/
func (s *Sender) SendEmail(to string, subject string, content string) error {
//Parse the email content
Expand All @@ -50,7 +50,9 @@ func (s *Sender) SendEmail(to string, subject string, content string) error {
content + "\n\n")

//Login to the SMTP server
auth := smtp.PlainAuth("", s.Username+"@"+s.Domain, s.Password, s.Hostname)
//Username can be username (e.g. admin) or email (e.g. [email protected]), depending on SMTP service provider
auth := smtp.PlainAuth("", s.Username, s.Password, s.Hostname)

err := smtp.SendMail(s.Hostname+":"+strconv.Itoa(s.Port), auth, s.SenderAddr, []string{to}, msg)
if err != nil {
return err
Expand Down
5 changes: 5 additions & 0 deletions src/mod/geodb/geodb.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ func (s *Store) GetRequesterCountryISOCode(r *http.Request) string {
if ipAddr == "" {
return ""
}

if netutils.IsPrivateIP(ipAddr) {
return "LAN"
}

countryCode, err := s.ResolveCountryCodeFromIP(ipAddr)
if err != nil {
return ""
Expand Down
4 changes: 4 additions & 0 deletions src/mod/netutils/ipmatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ func MatchIpCIDR(ip string, cidr string) bool {

// Check if a ip is private IP range
func IsPrivateIP(ipStr string) bool {
if ipStr == "127.0.0.1" || ipStr == "::1" {
//local loopback
return true
}
ip := net.ParseIP(ipStr)
if ip == nil {
return false
Expand Down
11 changes: 10 additions & 1 deletion src/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,17 @@ func startupSequence() {
if err != nil {
portInt = 8000
}

hostName := *mdnsName
if hostName == "" {
hostName = "zoraxy_" + nodeUUID
} else {
//Trim off the suffix
hostName = strings.TrimSuffix(hostName, ".local")
}

mdnsScanner, err = mdns.NewMDNS(mdns.NetworkHost{
HostName: "zoraxy_" + nodeUUID,
HostName: hostName,
Port: portInt,
Domain: "zoraxy.arozos.com",
Model: "Network Gateway",
Expand Down
5 changes: 4 additions & 1 deletion src/web/components/stats.html
Original file line number Diff line number Diff line change
Expand Up @@ -765,8 +765,11 @@ <h3>Visitor Trend Analysis</h3>
let data = Object.values(visitorData);

Object.keys(visitorData).forEach(function(cc){
console.log(cc);
if (cc == ""){
labels.push("Local / Unknown")
labels.push("Unknown")
}else if (cc == "lan"){
labels.push(`LAN / Loopback`);
}else{
labels.push(`${getCountryName(cc)} [${cc.toUpperCase()}]` );
}
Expand Down
28 changes: 3 additions & 25 deletions src/web/components/utils.html
Original file line number Diff line number Diff line change
Expand Up @@ -65,21 +65,9 @@ <h3>Forget Password Email</h3>

<div class="field">
<p><i class="caret down icon"></i> Credentials for SMTP server authentications</p>
<div class="two fields">
<div class="field">
<label>Sender Username</label>
<input type="text" name="username" placeholder="E.g. admin">
</div>

<div class="field">
<label>Sender Domain</label>
<div class="ui labeled input">
<div class="ui basic label">
@
</div>
<input type="text" name="domain" min="1" max="65534" placeholder="E.g. arozos.com">
</div>
</div>
<div class="field">
<label>Sender Username / Email</label>
<input type="text" name="username" placeholder="e.g. admin or [email protected]">
</div>
</div>
<div class="field">
Expand Down Expand Up @@ -272,7 +260,6 @@ <h3 class="ui header">
e.preventDefault();
var data = {
hostname: $('input[name=hostname]').val(),
domain: $('input[name=domain]').val(),
port: parseInt($('input[name=port]').val()),
username: $('input[name=username]').val(),
password: $('input[name=password]').val(),
Expand Down Expand Up @@ -306,7 +293,6 @@ <h3 class="ui header">
function initSMTPSettings(){
$.get("/api/tools/smtp/get", function(data){
$('#email-form input[name=hostname]').val(data.Hostname);
$('#email-form input[name=domain]').val(data.Domain);
$('#email-form input[name=port]').val(data.Port);
$('#email-form input[name=username]').val(data.Username);
$('#email-form input[name=senderAddr]').val(data.SenderAddr);
Expand Down Expand Up @@ -345,14 +331,6 @@ <h3 class="ui header">
form.find('input[name="hostname"]').parent().removeClass('error');
}

// validate domain
const domain = form.find('input[name="domain"]').val().trim();
if (!domainRegex.test(domain)) {
form.find('input[name="domain"]').parent().addClass('error');
isValid = false;
} else {
form.find('input[name="domain"]').parent().removeClass('error');
}

// validate username
const username = form.find('input[name="username"]').val().trim();
Expand Down

0 comments on commit 176249a

Please sign in to comment.