mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-06-03 06:07:20 +02:00
Merge pull request #138 from tobychui/v3.0.3
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
This commit is contained in:
commit
176249a7d9
@ -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
|
||||
@ -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
|
||||
|
@ -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")
|
||||
@ -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),
|
||||
@ -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
|
||||
|
@ -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)")
|
||||
@ -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()
|
||||
|
@ -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 {
|
||||
@ -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)
|
||||
|
@ -2,6 +2,8 @@ package access
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"imuslab.com/zoraxy/mod/netutils"
|
||||
)
|
||||
|
||||
/*
|
||||
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
@ -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, "/") {
|
||||
|
@ -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, "")
|
||||
|
@ -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
|
||||
@ -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
|
||||
|
@ -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. admin@arozos.com
|
||||
}
|
||||
|
||||
//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,
|
||||
@ -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(
|
||||
test@example.com,
|
||||
"Free donuts",
|
||||
"Come get your free donuts on this Sunday!"
|
||||
)
|
||||
Send a email to a reciving addr
|
||||
Example Usage:
|
||||
SendEmail(
|
||||
|
||||
test@example.com,
|
||||
"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
|
||||
@ -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. admin@example.com), 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
|
||||
|
@ -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 ""
|
||||
|
@ -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
|
||||
|
11
src/start.go
11
src/start.go
@ -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",
|
||||
|
@ -765,8 +765,11 @@
|
||||
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()}]` );
|
||||
}
|
||||
|
@ -65,21 +65,9 @@
|
||||
|
||||
<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 admin@mydomain.com">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
@ -272,7 +260,6 @@
|
||||
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(),
|
||||
@ -306,7 +293,6 @@
|
||||
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);
|
||||
@ -345,14 +331,6 @@
|
||||
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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user