mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-08-11 15:47:51 +02:00
Added static web server and black / whitelist template
- Added static web server - Added static web server default index - Added embeded templates to blacklist / whitelist - Added wip Web Directory Manager Place the templates at ./www/templates/blacklist.html or whitelist.html to replace the build in embedded template for access control 403 error -
This commit is contained in:
@@ -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
src/mod/dynamicproxy/templates/forbidden.html
Normal file
55
src/mod/dynamicproxy/templates/forbidden.html
Normal file
@@ -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>
|
@@ -1,6 +1,7 @@
|
||||
package dynamicproxy
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
@@ -31,6 +32,7 @@ type RouterOption struct {
|
||||
RedirectRuleTable *redirection.RuleTable
|
||||
GeodbStore *geodb.Store //GeoIP blacklist and whitelist
|
||||
StatisticCollector *statistic.Collector
|
||||
WebDirectory string //The static web server directory containing the templates folder
|
||||
}
|
||||
|
||||
type Router struct {
|
||||
@@ -123,3 +125,11 @@ type SubdOptions struct {
|
||||
BasicAuthCredentials []*BasicAuthCredentials
|
||||
BasicAuthExceptionRules []*BasicAuthExceptionRule
|
||||
}
|
||||
|
||||
/*
|
||||
Web Templates
|
||||
*/
|
||||
var (
|
||||
//go:embed templates/forbidden.html
|
||||
page_forbidden []byte
|
||||
)
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -76,6 +77,22 @@ func PostBool(r *http.Request, key string) (bool, error) {
|
||||
return false, errors.New("invalid boolean given")
|
||||
}
|
||||
|
||||
// Get POST paramter as int
|
||||
func PostInt(r *http.Request, key string) (int, error) {
|
||||
x, err := PostPara(r, key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
x = strings.TrimSpace(x)
|
||||
rx, err := strconv.Atoi(x)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return rx, nil
|
||||
}
|
||||
|
||||
func FileExists(filename string) bool {
|
||||
_, err := os.Stat(filename)
|
||||
if os.IsNotExist(err) {
|
||||
|
@@ -1,5 +1,13 @@
|
||||
package webserv
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"imuslab.com/zoraxy/mod/utils"
|
||||
)
|
||||
|
||||
/*
|
||||
Handler.go
|
||||
|
||||
@@ -7,3 +15,74 @@ package webserv
|
||||
web server is directly listening to the TCP port
|
||||
handlers in this script are for setting change only
|
||||
*/
|
||||
|
||||
type StaticWebServerStatus struct {
|
||||
ListeningPort int
|
||||
EnableDirectoryListing bool
|
||||
WebRoot string
|
||||
Running bool
|
||||
EnableWebDirManager bool
|
||||
}
|
||||
|
||||
// Handle getting current static web server status
|
||||
func (ws *WebServer) HandleGetStatus(w http.ResponseWriter, r *http.Request) {
|
||||
listeningPortInt, _ := strconv.Atoi(ws.option.Port)
|
||||
currentStatus := StaticWebServerStatus{
|
||||
ListeningPort: listeningPortInt,
|
||||
EnableDirectoryListing: ws.option.EnableDirectoryListing,
|
||||
WebRoot: ws.option.WebRoot,
|
||||
Running: ws.isRunning,
|
||||
EnableWebDirManager: ws.option.EnableWebDirManager,
|
||||
}
|
||||
|
||||
js, _ := json.Marshal(currentStatus)
|
||||
utils.SendJSONResponse(w, string(js))
|
||||
}
|
||||
|
||||
// Handle request for starting the static web server
|
||||
func (ws *WebServer) HandleStartServer(w http.ResponseWriter, r *http.Request) {
|
||||
err := ws.Start()
|
||||
if err != nil {
|
||||
utils.SendErrorResponse(w, err.Error())
|
||||
return
|
||||
}
|
||||
utils.SendOK(w)
|
||||
}
|
||||
|
||||
// Handle request for stopping the static web server
|
||||
func (ws *WebServer) HandleStopServer(w http.ResponseWriter, r *http.Request) {
|
||||
err := ws.Stop()
|
||||
if err != nil {
|
||||
utils.SendErrorResponse(w, err.Error())
|
||||
return
|
||||
}
|
||||
utils.SendOK(w)
|
||||
}
|
||||
|
||||
// Handle change server listening port request
|
||||
func (ws *WebServer) HandlePortChange(w http.ResponseWriter, r *http.Request) {
|
||||
newPort, err := utils.PostInt(r, "port")
|
||||
if err != nil {
|
||||
utils.SendErrorResponse(w, "invalid port number given")
|
||||
return
|
||||
}
|
||||
|
||||
err = ws.ChangePort(strconv.Itoa(newPort))
|
||||
if err != nil {
|
||||
utils.SendErrorResponse(w, err.Error())
|
||||
return
|
||||
}
|
||||
utils.SendOK(w)
|
||||
}
|
||||
|
||||
// Change enable directory listing settings
|
||||
func (ws *WebServer) SetEnableDirectoryListing(w http.ResponseWriter, r *http.Request) {
|
||||
enableList, err := utils.PostBool(r, "enable")
|
||||
if err != nil {
|
||||
utils.SendErrorResponse(w, "invalid setting given")
|
||||
return
|
||||
}
|
||||
|
||||
ws.option.EnableDirectoryListing = enableList
|
||||
utils.SendOK(w)
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@ func (ws *WebServer) resolveFileDiskPath(requestPath string) string {
|
||||
// File server middleware to handle directory listing (and future expansion)
|
||||
func (ws *WebServer) fsMiddleware(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if ws.option.EnableDirectoryListing {
|
||||
if !ws.option.EnableDirectoryListing {
|
||||
if strings.HasSuffix(r.URL.Path, "/") {
|
||||
//This is a folder. Let check if index exists
|
||||
if utils.FileExists(filepath.Join(ws.resolveFileDiskPath(r.URL.Path), "index.html")) {
|
||||
|
61
src/mod/webserv/templates/index.html
Normal file
61
src/mod/webserv/templates/index.html
Normal file
@@ -0,0 +1,61 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Hello Zoraxy</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Tahoma, sans-serif;
|
||||
background-color: #f6f6f6;
|
||||
color: #2d2e30;
|
||||
}
|
||||
.sectionHeader{
|
||||
background-color: #c4d0d9;
|
||||
padding: 0.1em;
|
||||
}
|
||||
|
||||
.sectionHeader h3{
|
||||
text-align: center;
|
||||
}
|
||||
.container{
|
||||
margin: 4em;
|
||||
margin-left: 10em;
|
||||
margin-right: 10em;
|
||||
background-color: #fefefe;
|
||||
}
|
||||
|
||||
@media (max-width:960px) {
|
||||
.container{
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.sectionHeader{
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.textcontainer{
|
||||
padding: 1em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="sectionHeader">
|
||||
<h3>Welcome to Zoraxy Static Web Server!</h3>
|
||||
</div>
|
||||
<div class="textcontainer">
|
||||
<p>If you see this page, that means your static web server is running.<br>
|
||||
By default, all the html files are stored under <code>./web/html/</code>
|
||||
relative to the zoraxy runtime directory.<br>
|
||||
You can upload your html files to your web directory via the <b>Web Directory Manager</b>.
|
||||
</p>
|
||||
<p>
|
||||
For online documentation, please refer to <a href="//zoraxy.arozos.com">zoraxy.arozos.com</a> or the <a href="https://github.com/tobychui/zoraxy/wiki">project wiki</a>.<br>
|
||||
Thank you for using Zoraxy!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@@ -1,6 +1,8 @@
|
||||
package webserv
|
||||
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
@@ -9,6 +11,7 @@ import (
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"imuslab.com/zoraxy/mod/database"
|
||||
"imuslab.com/zoraxy/mod/utils"
|
||||
)
|
||||
|
||||
@@ -18,11 +21,17 @@ import (
|
||||
This module host a static web server
|
||||
*/
|
||||
|
||||
//go:embed templates/*
|
||||
var templates embed.FS
|
||||
|
||||
type WebServerOptions struct {
|
||||
Port string //Port for listening
|
||||
EnableDirectoryListing bool //Enable listing of directory
|
||||
WebRoot string //Folder for stroing the static web folders
|
||||
Port string //Port for listening
|
||||
EnableDirectoryListing bool //Enable listing of directory
|
||||
WebRoot string //Folder for stroing the static web folders
|
||||
EnableWebDirManager bool //Enable web file manager to handle files in web directory
|
||||
Sysdb *database.Database //Database for storing configs
|
||||
}
|
||||
|
||||
type WebServer struct {
|
||||
mux *http.ServeMux
|
||||
server *http.Server
|
||||
@@ -31,13 +40,23 @@ type WebServer struct {
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// NewWebServer creates a new WebServer instance.
|
||||
// NewWebServer creates a new WebServer instance. One instance only
|
||||
func NewWebServer(options *WebServerOptions) *WebServer {
|
||||
if !utils.FileExists(options.WebRoot) {
|
||||
//Web root folder not exists. Create one
|
||||
//Web root folder not exists. Create one with default templates
|
||||
os.MkdirAll(filepath.Join(options.WebRoot, "html"), 0775)
|
||||
os.MkdirAll(filepath.Join(options.WebRoot, "templates"), 0775)
|
||||
indexTemplate, err := templates.ReadFile("templates/index.html")
|
||||
if err != nil {
|
||||
log.Println("Failed to read static wev server template file: ", err.Error())
|
||||
} else {
|
||||
os.WriteFile(filepath.Join(options.WebRoot, "html", "index.html"), indexTemplate, 0775)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Create new table to store the config
|
||||
options.Sysdb.NewTable("webserv")
|
||||
return &WebServer{
|
||||
mux: http.NewServeMux(),
|
||||
option: options,
|
||||
@@ -46,11 +65,31 @@ func NewWebServer(options *WebServerOptions) *WebServer {
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the configuration to previous config
|
||||
func (ws *WebServer) RestorePreviousState() {
|
||||
//Set the port
|
||||
port := ws.option.Port
|
||||
ws.option.Sysdb.Read("webserv", "port", &port)
|
||||
ws.option.Port = port
|
||||
|
||||
//Set the enable directory list
|
||||
enableDirList := ws.option.EnableDirectoryListing
|
||||
ws.option.Sysdb.Read("webserv", "dirlist", &enableDirList)
|
||||
ws.option.EnableDirectoryListing = enableDirList
|
||||
|
||||
//Check the running state
|
||||
webservRunning := false
|
||||
ws.option.Sysdb.Read("webserv", "enabled", &webservRunning)
|
||||
if webservRunning {
|
||||
ws.Start()
|
||||
} else {
|
||||
ws.Stop()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ChangePort changes the server's port.
|
||||
func (ws *WebServer) ChangePort(port string) error {
|
||||
ws.mu.Lock()
|
||||
defer ws.mu.Unlock()
|
||||
|
||||
if ws.isRunning {
|
||||
if err := ws.Stop(); err != nil {
|
||||
return err
|
||||
@@ -60,6 +99,13 @@ func (ws *WebServer) ChangePort(port string) error {
|
||||
ws.option.Port = port
|
||||
ws.server.Addr = ":" + port
|
||||
|
||||
err := ws.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ws.option.Sysdb.Write("webserv", "port", port)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -100,7 +146,7 @@ func (ws *WebServer) Start() error {
|
||||
|
||||
log.Println("Static Web Server started. Listeing on :" + ws.option.Port)
|
||||
ws.isRunning = true
|
||||
|
||||
ws.option.Sysdb.Write("webserv", "enabled", true)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -118,17 +164,14 @@ func (ws *WebServer) Stop() error {
|
||||
}
|
||||
|
||||
ws.isRunning = false
|
||||
|
||||
ws.option.Sysdb.Write("webserv", "enabled", false)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateDirectoryListing enables or disables directory listing.
|
||||
func (ws *WebServer) UpdateDirectoryListing(enable bool) {
|
||||
ws.mu.Lock()
|
||||
defer ws.mu.Unlock()
|
||||
|
||||
ws.option.EnableDirectoryListing = enable
|
||||
|
||||
ws.option.Sysdb.Write("webserv", "dirlist", enable)
|
||||
}
|
||||
|
||||
// Close stops the web server without returning an error.
|
||||
|
Reference in New Issue
Block a user