Browse Source

auto update script executed

Toby Chui 1 year ago
parent
commit
34ff2e283a
11 changed files with 289 additions and 144 deletions
  1. 5 0
      api.go
  2. 12 10
      main.go
  3. 15 1
      mod/ganserv/ganserv.go
  4. 35 15
      mod/ganserv/handlers.go
  5. 3 3
      mod/ganserv/network_test.go
  6. 6 0
      start.go
  7. 124 50
      web/components/gan.html
  8. 36 0
      web/components/gandetails.html
  9. 19 13
      web/components/subd.html
  10. 21 16
      web/components/vdir.html
  11. 13 36
      web/main.css

+ 5 - 0
api.go

@@ -78,6 +78,11 @@ func initAPIs() {
 	authRouter.HandleFunc("/api/stats/listnic", netstat.HandleListNetworkInterfaces)
 	authRouter.HandleFunc("/api/utm/list", HandleUptimeMonitorListing)
 
+	//Global Area Network APIs
+	authRouter.HandleFunc("/api/gan/network/add", ganManager.HandleAddNetwork)
+	authRouter.HandleFunc("/api/gan/network/remove", ganManager.HandleRemoveNetwork)
+	authRouter.HandleFunc("/api/gan/network/list", ganManager.HandleListNetwork)
+
 	//mDNS APIs
 	authRouter.HandleFunc("/api/mdns/list", HandleMdnsListing)
 	authRouter.HandleFunc("/api/mdns/discover", HandleMdnsScanning)

+ 12 - 10
main.go

@@ -16,6 +16,7 @@ import (
 	"imuslab.com/zoraxy/mod/auth"
 	"imuslab.com/zoraxy/mod/database"
 	"imuslab.com/zoraxy/mod/dynamicproxy/redirection"
+	"imuslab.com/zoraxy/mod/ganserv"
 	"imuslab.com/zoraxy/mod/geodb"
 	"imuslab.com/zoraxy/mod/mdns"
 	"imuslab.com/zoraxy/mod/sshprox"
@@ -45,16 +46,17 @@ var (
 	/*
 		Handler Modules
 	*/
-	handler            *aroz.ArozHandler      //Handle arozos managed permission system
-	sysdb              *database.Database     //System database
-	authAgent          *auth.AuthAgent        //Authentication agent
-	tlsCertManager     *tlscert.Manager       //TLS / SSL management
-	redirectTable      *redirection.RuleTable //Handle special redirection rule sets
-	geodbStore         *geodb.Store           //GeoIP database
-	statisticCollector *statistic.Collector   //Collecting statistic from visitors
-	uptimeMonitor      *uptime.Monitor        //Uptime monitor service worker
-	mdnsScanner        *mdns.MDNSHost         //mDNS discovery services
-	webSshManager      *sshprox.Manager       //Web SSH connection service
+	handler            *aroz.ArozHandler       //Handle arozos managed permission system
+	sysdb              *database.Database      //System database
+	authAgent          *auth.AuthAgent         //Authentication agent
+	tlsCertManager     *tlscert.Manager        //TLS / SSL management
+	redirectTable      *redirection.RuleTable  //Handle special redirection rule sets
+	geodbStore         *geodb.Store            //GeoIP database
+	statisticCollector *statistic.Collector    //Collecting statistic from visitors
+	uptimeMonitor      *uptime.Monitor         //Uptime monitor service worker
+	mdnsScanner        *mdns.MDNSHost          //mDNS discovery services
+	ganManager         *ganserv.NetworkManager //Global Area Network Manager
+	webSshManager      *sshprox.Manager        //Web SSH connection service
 )
 
 // Kill signal handler. Do something before the system the core terminate.

+ 15 - 1
mod/ganserv/ganserv.go

@@ -61,8 +61,15 @@ type NetworkManager struct {
 
 //Create a new GAN manager
 func NewNetworkManager(option *NetworkManagerOptions) *NetworkManager {
+	option.Database.NewTable("ganserv")
+
+	existingNetworks := []*Network{}
+	if option.Database.KeyExists("ganserv", "networks") {
+		option.Database.Read("ganserv", "networks", &existingNetworks)
+	}
 	return &NetworkManager{
-		option: option,
+		option:   option,
+		networks: existingNetworks,
 	}
 }
 
@@ -76,6 +83,9 @@ func (m *NetworkManager) AddNetwork(n *Network) error {
 		return errors.New("network with given id already exists")
 	}
 	m.networks = append(m.networks, n)
+
+	//Write the latest network list into database
+	m.option.Database.Write("ganserv", "networks", m.networks)
 	return nil
 }
 
@@ -83,9 +93,13 @@ func (m *NetworkManager) RemoveNetwork(id string) error {
 	for i, n := range m.networks {
 		if n.UID == id {
 			m.networks = append(m.networks[:i], m.networks[i+1:]...)
+
+			//Write the latest network list into database
+			m.option.Database.Write("ganserv", "networks", m.networks)
 			return nil
 		}
 	}
+
 	return fmt.Errorf("network not found: %s", id)
 }
 

+ 35 - 15
mod/ganserv/handlers.go

@@ -14,6 +14,12 @@ func (m *NetworkManager) HandleAddNetwork(w http.ResponseWriter, r *http.Request
 		return
 	}
 
+	subnetMask, err := utils.PostPara(r, "subnetMask")
+	if err != nil {
+		utils.SendErrorResponse(w, "invalid or empty subnetMask given")
+		return
+	}
+
 	// Generate a new UUID for this network
 	networkUID := newNetworkID()
 
@@ -21,11 +27,16 @@ func (m *NetworkManager) HandleAddNetwork(w http.ResponseWriter, r *http.Request
 	newNetwork := &Network{
 		UID:         networkUID,
 		Name:        networkName,
-		CIDR:        "",
+		CIDR:        subnetMask,
 		Description: "",
 		Nodes:       []*Node{},
 	}
-	m.networks = append(m.networks, newNetwork)
+
+	err = m.AddNetwork(newNetwork)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
 
 	// Return the new network ID
 	js, _ := json.Marshal(networkUID)
@@ -39,21 +50,30 @@ func (m *NetworkManager) HandleRemoveNetwork(w http.ResponseWriter, r *http.Requ
 		return
 	}
 
-	// Find the network with the given ID and remove it from the list of networks
-	for i, network := range m.networks {
-		if network.UID == networkID {
-			m.networks = append(m.networks[:i], m.networks[i+1:]...)
-			utils.SendOK(w)
-			return
-		}
+	err = m.RemoveNetwork(networkID)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
 	}
-
-	// If the network is not found, return an error response
-	utils.SendErrorResponse(w, "network not found")
+	utils.SendOK(w)
 }
 
 func (m *NetworkManager) HandleListNetwork(w http.ResponseWriter, r *http.Request) {
-	// Return the list of networks as JSON
-	js, _ := json.Marshal(m.networks)
-	utils.SendJSONResponse(w, string(js))
+	netid, _ := utils.GetPara(r, "netid")
+	if netid != "" {
+		targetNet, err := m.GetNetworkByID(netid)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+
+		js, _ := json.Marshal(targetNet)
+		utils.SendJSONResponse(w, string(js))
+
+	} else {
+		// Return the list of networks as JSON
+		js, _ := json.Marshal(m.networks)
+		utils.SendJSONResponse(w, string(js))
+	}
+
 }

+ 3 - 3
mod/ganserv/network_test.go

@@ -11,15 +11,15 @@ import (
 
 func TestGetRandomFreeIP(t *testing.T) {
 	n := ganserv.Network{
-		CIDR: "192.168.22.0/24",
+		CIDR: "172.16.0.0/12",
 		Nodes: []*ganserv.Node{
 			{
 				Name:      "nodeC1",
-				ManagedIP: net.ParseIP("192.168.0.2"),
+				ManagedIP: net.ParseIP("172.16.1.142"),
 			},
 			{
 				Name:      "nodeC2",
-				ManagedIP: net.ParseIP("192.168.0.3"),
+				ManagedIP: net.ParseIP("172.16.5.174"),
 			},
 		},
 	}

+ 6 - 0
start.go

@@ -11,6 +11,7 @@ import (
 	"imuslab.com/zoraxy/mod/auth"
 	"imuslab.com/zoraxy/mod/database"
 	"imuslab.com/zoraxy/mod/dynamicproxy/redirection"
+	"imuslab.com/zoraxy/mod/ganserv"
 	"imuslab.com/zoraxy/mod/geodb"
 	"imuslab.com/zoraxy/mod/mdns"
 	"imuslab.com/zoraxy/mod/sshprox"
@@ -128,6 +129,11 @@ func startupSequence() {
 	}()
 	mdnsTickerStop = stopChan
 
+	//Create GAN Manager
+	ganManager = ganserv.NewNetworkManager(&ganserv.NetworkManagerOptions{
+		Database: sysdb,
+	})
+
 	//Create WebSSH Manager
 	webSshManager = sshprox.NewSSHProxyManager()
 

+ 124 - 50
web/components/gan.html

@@ -1,4 +1,4 @@
-<div class="standardContainer">
+<div id="ganetWindow" class="standardContainer">
     <div class="ui basic segment">
         <h2>Global Area Network</h2>
         <p>Virtual Network Hub that allows all networked devices to communicate as if they all reside in the same physical data center or cloud region</p>
@@ -9,53 +9,57 @@
                 <div class="item">
                     <i class="exchange icon"></i>
                     <div class="content">
-                    <div class="header" style="font-size: 1.2em;">0</div>
+                    <div class="header" style="font-size: 1.2em;" id="ganetCount">0</div>
                     <div class="description">Networks</div>
                     </div>
                 </div>
                 <div class="item">
                     <i class="desktop icon"></i>
                     <div class="content">
-                    <div class="header" style="font-size: 1.2em;">0 / 0</div>
+                    <div class="header" style="font-size: 1.2em;" id="ganodeCount">0</div>
                     <div class="description">Connected Nodes</div>
                     </div>
                 </div>
             </div>
+            <br>
         </div>
         <div class="ganlist">
-            <button class="ui basic orange button">Create New Network</button>
-            <div class="ui icon input">
+            <button class="ui basic orange button" onclick="$('#newGanForm').fadeToggle('fast');">Create New Network</button>
+            <div class="" id="newGanForm" style="display:none; position: relative;">
+                <div class="ui divider"></div>
+                <p>Enter a new network name to create new network</p>
+                <div class="ui action fluid input">
+                    <input type="text" id="networkName" placeholder="Network Name">
+                    <button class="ui basic button" onclick="handleAddNetwork();">
+                        <i class="blue add icon"></i> Add Network
+                    </button>
+                </div>
+                <button onclick="$('#newGanForm').fadeOut('fast');" class="ui mini circular basic icon button" style="position: absolute; right: 0.4em; top: 1em;"><i class="remove icon"></i></button>
+            </div>
+            <div class="ui divider"></div>
+            <div class="ui icon input" style="margin-bottom: 1em;">
                 <input type="text" placeholder="Search a Network">
                 <i class="circular search link icon"></i>
             </div>
-            <div class="ui segment">
-                <div class="ui input">
-                    <input type="text" placeholder="Network Name">
-                </div>
-                <button class="ui basic button">
-                    <i class="blue add icon"></i> Add Network
-                </button>
+            <div style="width: 100%; overflow-x: auto;">
+                <table class="ui celled basic unstackable striped table">
+                    <thead>
+                        <tr>
+                            <th>Network ID</th>
+                            <th>Name</th>
+                            <th>Description</th>
+                            <th>Subnet</th>
+                            <th>Nodes</th>
+                            <th>Actions</th>
+                        </tr>
+                    </thead>
+                    <tbody id="GANetList">
+                        <tr>
+                            <td colspan="6"><i class="ui green circle check icon"></i> No Global Area Network Found on this host</td>
+                        </tr>
+                    </tbody>
+                </table>
             </div>
-           
-            <div class="ui divider"></div>
-            <table class="ui celled basic striped table">
-                <thead>
-                    <tr>
-                        <th>Network ID</th>
-                        <th>Name</th>
-                        <th>Description</th>
-                        <th>Subnet</th>
-                        <th>Nodes</th>
-                        <th>Created</th>
-                    </tr>
-                </thead>
-                <tbody>
-                    <tr>
-                        <td colspan="6"><i class="ui green circle check icon"></i> No Global Area Network Found on this host</td>
-                    </tr>
-                </tbody>
-            </table>
-            
         </div>
     </div>
 </div>
@@ -64,25 +68,18 @@
         Network Management Functions
     */
     function handleAddNetwork(){
-
-    }
-
-    function wildcardToSubnetMask(wildcard) {
-        var octets = wildcard.split('.');
-        var binary = '';
-        for (var i = 0; i < 4; i++) {
-            if (octets[i] === '*') {
-            binary += '00000000';
-            } else {
-            binary += parseInt(octets[i], 10).toString(2).padStart(8, '0');
-            }
+        let networkName = $("#networkName").val().trim();
+        if (networkName == ""){
+            msgbox("Network name cannot be empty", false, 5000);
+            return;
         }
-        var subnetBits = binary.replace(/0+$/, '').length;
-        var subnetMask = subnetBits === 32 ? '255.255.255.255' : (new Array(5).join('0') + parseInt(binary.substr(0, subnetBits), 2).toString(10)).slice(-3).split('').join('.');
-        return subnetMask;
+
+        //Add network with default settings
+        addGANet(networkName, "192.168.196.0/24");
+        $("#networkName").val("");
     }
 
-    function addNetwork(name, subnetMask) {
+    function addGANet(name, subnetMask) {
         $.ajax({
             url: "/api/gan/network/add",
             type: "POST",
@@ -92,11 +89,88 @@
                 subnetMask: subnetMask
             },
             success: function(response) {
-            console.log("Network added successfully:", response);
+                if (response.error != undefined){
+                    msgbox(response.error, false, 5000);
+                }else{
+                    msgbox("Network added successfully");
+                }
+                console.log("Network added successfully:", response);
+                listGANet();
             },
             error: function(xhr, status, error) {
-            console.log("Error adding network:", error);
+                console.log("Error adding network:", error);
+            }
+        });
+    }
+
+    function listGANet(){
+        $.get("/api/gan/network/list", function(data){
+            $("#GANetList").empty();
+            if (data.error != undefined){
+                msgbox(data.error, false, 5000);
+            }else{
+                var nodeCount = 0;
+                data.forEach(function(gan){
+                    $("#GANetList").append(`<tr>
+                        <td>${gan.UID}</td>
+                        <td>${gan.Name}</td>
+                        <td>${gan.Description}</td>
+                        <td>${gan.CIDR}</td>
+                        <td>${gan.Nodes.length}</td>
+                        <td>
+                            <button onclick="openGANetDetails('${gan.UID}');" class="ui tiny basic icon button" title="Edit Network"><i class="edit icon"></i></button>
+                            <button onclick="removeGANet('${gan.UID}');" class="ui tiny basic icon button" title="Remove Network"><i class="red remove icon"></i></button>
+                        </td>
+                    </tr>`);
+
+                    nodeCount += gan.Nodes.length;
+                });
+
+                if (data.length == 0){
+                    $("#GANetList").append(`<tr>
+                        <td colspan="6"><i class="ui green circle check icon"></i> No Global Area Network Found on this host</td>
+                    </tr>`);
+                }
+
+                $("#ganodeCount").text(nodeCount);
+                $("#ganetCount").text(data.length);
+            }
+        })
+    }
+
+    //Remove the given GANet
+    function removeGANet(netid){
+        if (confirm("Confirm remove Network " + netid + " PERMANENTLY ?"))
+        $.ajax({
+            url: "/api/gan/network/remove",
+            type: "POST",
+            dataType: "json",
+            data: {
+                id: netid,
+            },
+            success: function(data){
+                if (data.error != undefined){
+                    msgbox(data.error, false, 5000);
+                }else{
+                    msgbox("Net " + netid + " removed");
+                }
+                listGANet();
             }
         });
     }
+
+    function openGANetDetails(netid){
+        $("#ganetWindow").load("./components/gandetails.html", function(){
+            setTimeout(function(){
+                initGanetDetails(netid);
+            });
+        });
+       
+    }
+
+     //Bind event to tab switch
+     tabSwitchEventBind["gan"] = function(){
+        //On switch over to this page, load info
+        listGANet();
+    }
 </script>

+ 36 - 0
web/components/gandetails.html

@@ -0,0 +1,36 @@
+<div class="standardContainer">
+    <button onclick="exitToGanList();" class="ui large circular black icon button"><i class="angle left icon"></i></button>
+    <div style="float: right; max-width: 300px;">
+        <h1 class="ui header" style="text-align: right;">
+            <span class="ganetID"></span>
+            <div class="sub header ganetName"></div>
+        </h1>
+    </div>
+    
+    <br><br>
+</div>
+<script>
+    var currentGaNetDetails = {};
+    //Entry points
+    function initGanetDetails(ganetId){
+        $(".ganetID").text(ganetId);
+
+        //Get the details of the net
+        $.get("/api/gan/network/list?netid=" + ganetId, function(data){
+            if (data.error !== undefined){
+                msgbox(data.error, false, 6000);
+            }else{
+                $(".ganetName").html(`${data.Name}<br>${data.Description}`);
+            }
+        })
+    }
+
+    //Exit point
+    function exitToGanList(){
+        $("#gan").load("./components/gan.html", function(){
+            if (tabSwitchEventBind["gan"]){
+                tabSwitchEventBind["gan"]();
+            }
+        });
+    }
+</script>

+ 19 - 13
web/components/subd.html

@@ -3,23 +3,24 @@
         <h2>Subdomain</h2>
         <p>Subdomains are a way to organize and identify different sections of a website or domain. They are essentially a prefix to the main domain name, separated by a dot. <br>For example, in the domain "blog.example.com," "blog" is the subdomain.</p>
     </div>
-    <table class="ui celled sortable unstackable compact table">
-        <thead>
-            <tr>
-                <th>Matching Domain</th>
-                <th>Proxy To</th>
-                <th class="no-sort">Remove</th>
-            </tr>
-        </thead>
-        <tbody id="subdList">
-        
-        </tbody>
-    </table>
+    <div style="width: 100%; overflow-x: auto; margin-bottom: 1em;">
+        <table class="ui celled sortable unstackable compact table">
+            <thead>
+                <tr>
+                    <th>Matching Domain</th>
+                    <th>Proxy To</th>
+                    <th class="no-sort">Remove</th>
+                </tr>
+            </thead>
+            <tbody id="subdList">
+            
+            </tbody>
+        </table>
+    </div>
     <button class="ui icon right floated basic button" onclick="listSubd();"><i class="green refresh icon"></i> Refresh</button>
     <br><br>
 </div>
 <script>
-    listSubd();
     function listSubd(){
         $("#subdList").html(``);
         $.get("/api/proxy/list?type=subd", function(data){
@@ -46,4 +47,9 @@
             }
         });
     }
+
+    //Bind on tab switch events
+    tabSwitchEventBind["subd"] = function(){
+        listSubd();
+    }
 </script>

+ 21 - 16
web/components/vdir.html

@@ -3,26 +3,27 @@
         <h2>Virtual Directory</h2>
         <p>A virtual directory is a consolidated view of multiple directories that provides a unified entry point for users to access disparate sources.</p>
     </div>
-    <table class="ui celled sortable unstackable compact table">
-        <thead>
-            <tr>
-                <th>Virtual Directory</th>
-                <th>Proxy To</th>
-                <th class="no-sort">Remove</th>
-            </tr>
-        </thead>
-        <tbody id="vdirList">
-            <tr>
-                <td data-label=""><button class="ui circular mini red basic button"><i class="remove icon"></i> Remove Proxy</button></td>
-            </tr>
-        </tbody>
-    </table>
+    <div style="width: 100%; overflow-x: auto; margin-bottom: 1em;">
+        <table class="ui celled sortable unstackable compact table">
+            <thead>
+                <tr>
+                    <th>Virtual Directory</th>
+                    <th>Proxy To</th>
+                    <th class="no-sort">Remove</th>
+                </tr>
+            </thead>
+            <tbody id="vdirList">
+                <tr>
+                    <td data-label=""><button class="ui circular mini red basic button"><i class="remove icon"></i> Remove Proxy</button></td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
     <button class="ui icon right floated basic button" onclick="listVdirs();"><i class="green refresh icon"></i> Refresh</button>
     <br><br>
 </div>
 <script>
-     //Virtual directories functions
-    listVdirs();
+    //Virtual directories functions
     function listVdirs(){
         $("#vdirList").html(``);
         $.get("/api/proxy/list?type=vdir", function(data){
@@ -50,4 +51,8 @@
         });
     }
 
+    //Bind on tab switch events
+    tabSwitchEventBind["vdir"] = function(){
+        listVdirs();
+    }
 </script>

+ 13 - 36
web/main.css

@@ -42,18 +42,19 @@ body{
 
 .wrapper{
     display: flex;
-    flex-wrap: wrap;
-    margin-top: 4.6em;
+    align-items: flex-start;
+    padding-top: 4.6em;
 }
 
-.toolbar{
+.toolbar {
+    display: inline-block;
     width: 240px;
-    min-width: 240px;
 }
 
 .contentWindow{
-    /*padding: 1em;*/
-    flex: 1;
+    display: inline-block;
+    width: calc(100% - 240px);
+    vertical-align: top;
     background-color: white;
     border-radius: 1em;
     margin-right: 2em;
@@ -86,6 +87,10 @@ body{
 }
 
 /* Standard containers */
+.standardContainer{
+    position: relative;
+}
+
 .standardContainer.noleftright{
     padding-left: 0;
     padding-right: 0;
@@ -140,7 +145,7 @@ body{
     .toolbar {
         position: fixed;
         display: inline-block;
-        width: 50%;
+        width: 240px;
         background-color: white;
         top: 3.6em;
         right: 0;
@@ -430,32 +435,4 @@ body{
 /*
     Global Area Network
     gan.html
-*/
-
-.gansnetworks {
-    display: flex;
-    flex-direction: row;
-}
-
-.ganstats {
-    width: 170px;
-}
-
-.ganlist {
-    flex-grow: 1;
-}
-
-@media screen and (max-width: 750px) {
-    .gansnetworks {
-        flex-direction: column;
-    }
-
-    .ganstats, .ganlist {
-        width: auto;
-    }
-    
-    .ganlist{
-        margin-top: 1em;
-        margin-bottom: 1em;
-    }
-}
+*/