Browse Source

auto update script executed

tobychui 2 years ago
parent
commit
f5c36e05ba
7 changed files with 193 additions and 36 deletions
  1. 5 0
      api.go
  2. 1 0
      main.go
  3. 19 0
      mod/upnp/upnp.go
  4. 24 15
      upnp.go
  5. 1 1
      web/components/redirection.html
  6. 141 19
      web/components/upnp.html
  7. 2 1
      web/components/uptime.html

+ 5 - 0
api.go

@@ -74,6 +74,11 @@ func initAPIs() {
 	authRouter.HandleFunc("/api/utm/list", HandleUptimeMonitorListing)
 	//Upnp
 	authRouter.HandleFunc("/api/upnp/discover", handleUpnpDiscover)
+	authRouter.HandleFunc("/api/upnp/list", handleListOfflineUpnpPorts)
+	authRouter.HandleFunc("/api/upnp/toggle", handleToggleUPnP)
+	authRouter.HandleFunc("/api/upnp/add", handleAddUpnpPort)
+	authRouter.HandleFunc("/api/upnp/remove", handleRemoveUpnpPort)
+
 	//If you got APIs to add, append them here
 }
 

+ 1 - 0
main.go

@@ -49,6 +49,7 @@ func SetupCloseHandler() {
 		log.Println("\r- Shutting down " + name)
 		geodbStore.Close()
 		statisticCollector.Close()
+		upnpClient.Close()
 
 		//Close database, final
 		sysdb.Close()

+ 19 - 0
mod/upnp/upnp.go

@@ -21,6 +21,7 @@ type UPnPClient struct {
 	ExternalIP    string    //Storage of external IP address
 	RequiredPorts []int     //All the required ports will be recored
 	PolicyNames   sync.Map  //Name for the required port nubmer
+	RenewStopChan chan bool
 }
 
 func NewUPNPClient() (*UPnPClient, error) {
@@ -38,11 +39,26 @@ func NewUPNPClient() (*UPnPClient, error) {
 	}
 
 	//Create the final obejcts
+
+	ticker := time.NewTicker(6 * time.Hour)
+	stop := make(chan bool)
 	newUPnPObject := &UPnPClient{
 		Connection:    d,
 		ExternalIP:    ip,
 		RequiredPorts: []int{},
+		RenewStopChan: stop,
 	}
+	go func() {
+		defer ticker.Stop()
+		for {
+			select {
+			case <-stop:
+				return
+			case <-ticker.C:
+				newUPnPObject.RenewForwardRules()
+			}
+		}
+	}()
 
 	return newUPnPObject, nil
 }
@@ -117,6 +133,9 @@ func (u *UPnPClient) RenewForwardRules() {
 func (u *UPnPClient) Close() {
 	//Shutdown the default UPnP Object
 	if u != nil {
+		if u.RenewStopChan != nil {
+			u.RenewStopChan <- true
+		}
 		for _, portNumber := range u.RequiredPorts {
 			err := u.Connection.Clear(uint16(portNumber))
 			if err != nil {

+ 24 - 15
upnp.go

@@ -4,7 +4,6 @@ import (
 	"encoding/json"
 	"log"
 	"net/http"
-	"net/url"
 	"regexp"
 	"strconv"
 	"time"
@@ -52,8 +51,8 @@ func handleUpnpDiscover(w http.ResponseWriter, r *http.Request) {
 	restart, err := utils.PostPara(r, "restart")
 	if err != nil {
 		type UpnpInfo struct {
-			ExternalIp string
-			RouterIp   string
+			ExternalIp    string
+			RequiredPorts []int
 		}
 
 		if upnpClient == nil {
@@ -61,12 +60,9 @@ func handleUpnpDiscover(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 
-		parsedUrl, _ := url.Parse(upnpClient.Connection.Location())
-		ipWithPort := parsedUrl.Host
-
 		result := UpnpInfo{
-			ExternalIp: upnpClient.ExternalIP,
-			RouterIp:   ipWithPort,
+			ExternalIp:    upnpClient.ExternalIP,
+			RequiredPorts: upnpClient.RequiredPorts,
 		}
 
 		//Show if there is a upnpclient
@@ -88,6 +84,12 @@ func handleUpnpDiscover(w http.ResponseWriter, r *http.Request) {
 	}
 }
 
+//List the Upnp ports that is not currently forwarded
+func handleListOfflineUpnpPorts(w http.ResponseWriter, r *http.Request) {
+	js, _ := json.Marshal(preforwardMap)
+	utils.SendJSONResponse(w, string(js))
+}
+
 func handleToggleUPnP(w http.ResponseWriter, r *http.Request) {
 	newMode, err := utils.PostPara(r, "mode")
 	if err != nil {
@@ -97,7 +99,7 @@ func handleToggleUPnP(w http.ResponseWriter, r *http.Request) {
 	} else {
 		if newMode == "true" {
 			upnpEnabled = true
-			sysdb.Read("upnp", "enabled", true)
+			sysdb.Write("upnp", "enabled", true)
 
 			log.Println("UPnP Enabled. Forwarding all required ports")
 			//Mount all Upnp requests from preforward Map
@@ -112,7 +114,7 @@ func handleToggleUPnP(w http.ResponseWriter, r *http.Request) {
 
 		} else if newMode == "false" {
 			upnpEnabled = false
-			sysdb.Read("upnp", "enabled", false)
+			sysdb.Write("upnp", "enabled", false)
 			log.Println("UPnP disabled. Closing all forwarded ports")
 			//Save the current forwarded ports
 			saveForwardingPortsToDatabase()
@@ -163,12 +165,15 @@ func handleAddUpnpPort(w http.ResponseWriter, r *http.Request) {
 
 	policyName = filterRFC2141(policyName)
 
-	err = upnpClient.ForwardPort(portNumber, policyName)
-	if err != nil {
-		utils.SendErrorResponse(w, err.Error())
-		return
+	if upnpEnabled {
+		err = upnpClient.ForwardPort(portNumber, policyName)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
 	}
 
+	preforwardMap[portNumber] = policyName
 	saveForwardingPortsToDatabase()
 
 	utils.SendOK(w)
@@ -187,9 +192,13 @@ func handleRemoveUpnpPort(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
+	if upnpEnabled {
+		upnpClient.ClosePort(portNumber)
+	}
+	delete(preforwardMap, portNumber)
+
 	saveForwardingPortsToDatabase()
 
-	upnpClient.ClosePort(portNumber)
 }
 
 func saveForwardingPortsToDatabase() {

+ 1 - 1
web/components/redirection.html

@@ -50,7 +50,7 @@
       <div class="ui message">
         <p>Append the current pathname after the redirect destination</p>
         <i class="check square outline icon"></i> old.example.com<b>/blog?post=13</b> <i class="long arrow alternate right icon" style="margin-left: 1em;"></i> new.example.com<b>/blog?post=13</b> <br>
-        <i class="square outline icon"></i> Disabled old.example.com<b>/blog?post=13</b> <i class="long arrow alternate right icon" style="margin-left: 1em;"></i> new.example.com
+        <i class="square outline icon"></i> old.example.com<b>/blog?post=13</b> <i class="long arrow alternate right icon" style="margin-left: 1em;"></i> new.example.com
       </div>
     </div>
     <div class="grouped fields">

+ 141 - 19
web/components/upnp.html

@@ -3,15 +3,13 @@
 <p>Port forward using UPnP protocol</p>
 <div class="ui divider"></div>
 <div class="ui message">
-    <h4><i class="ui loading spinner icon"></i> Checking Upnp State</h4> 
+    <h4 id="upnpstatus"><i class="ui loading spinner icon"></i> Checking Upnp State</h4> 
     <p><i class="ui info circle icon"></i> If you are hosting this server under a home router which you have no access to, you can try port forward your services port and expose them to the internet via Upnp protocol.
         Note that not all router support this function, sometime this might be disabled by your ISP or administrator.</p>
-
-        <button style="position: absolute; right: 0.6em; top: 0.6em;" class="ui circular basic icon button"><i class="ui green refresh icon"></i></button>
 </div>
 <div class="ui form">
     <div class="field">
-      <div class="ui toggle checkbox">
+      <div class="ui toggle checkbox" id="currentUpnpState" >
         <input type="checkbox" name="upnp">
         <label>Enable UPnP</label>
       </div>
@@ -19,7 +17,7 @@
     <div class="field">
       <label>Port to Forward</label>
       <div class="ui input">
-        <input type="number" min="1" max="65535" name="forwardPort" placeholder="Forwardable Port">
+        <input type="number" min="1" max="65535" name="forwardPort" placeholder="Forward Port">
       </div>
     </div>
     <div class="field">
@@ -29,7 +27,7 @@
       </div>
     </div>
     <div class="field">
-      <button class="ui teal button" type="button" name="addRule"><i class="ui add icon"></i> Add Rule</button>
+      <button id="addForwardRuleButton" class="ui teal button" type="button" name="addRule" onclick="addForwardRule();"><i class="ui add icon"></i> Add Rule</button>
     </div>
 </div>
   
@@ -43,29 +41,153 @@
           <th></th>
         </tr>
       </thead>
-      <tbody>
+      <tbody id="forwardPortTable">
         <tr>
           <td>80</td>
           <td>HTTP</td>
           <td><button class="ui button negative" type="button" name="deleteRule">Delete</button></td>
         </tr>
-        <tr>
-          <td>22</td>
-          <td>SSH</td>
-          <td><button class="ui button negative" type="button" name="deleteRule">Delete</button></td>
-        </tr>
+
       </tbody>
     </table>
   </div>
   
   <script>
-    //Get value of the form
-    function getFormValues() {
-      var formValues = {};
-      formValues.upnp = $('input[name="upnp"]').prop('checked');
-      formValues.forwardPort = $('input[name="forwardPort"]').val();
-      formValues.ruleName = $('input[name="ruleName"]').val();
-      return formValues;
+    let UpnpRouterFound = false;
+
+    function addForwardRule() {
+      // Get the values of the form inputs
+      var forwardPort = $('input[name="forwardPort"]').val();
+      var ruleName = $('input[name="ruleName"]').val();
+
+      // Make an AJAX request
+      $.ajax({
+        type: 'POST',
+        url: '/api/upnp/add',
+        data: {port: forwardPort, name: ruleName},
+        success: function(data) {
+          if (data.error !== undefined){
+            alert(data.error);
+          }else{
+            $('input[name="forwardPort"]').val("");
+            $('input[name="ruleName"]').val("");
+            initUPnPStatus();
+          }
+        }
+      });
+    }
+
+    function removeForwardRule(portno){
+      $.ajax({
+        url: "/api/upnp/remove",
+        method: "POST",
+        data: {port: portno},
+        success: function(data){
+          if (data.error != undefined){
+            alert(data.error);
+          }else{
+            updateFordwardTable();
+          }
+        }
+      })
+    }
+
+
+    function initUpnpToggleState(){
+      $.get("/api/upnp/toggle", function(data){
+        if (data == true){
+          //Set the current UPnP state to true
+          $("#currentUpnpState").checkbox("set checked");
+        }else{
+          $("#currentUpnpState").checkbox("set unchecked");
+        }
+      });
+
+      $("#currentUpnpState").on("change", function(){
+        let isChecked = $("#currentUpnpState").checkbox("is checked");
+        if (isChecked){
+          $("#addForwardRuleButton").removeClass("disabled");
+        }else{
+          $("#addForwardRuleButton").addClass("disabled");
+        }
+        $.ajax({
+          url: "/api/upnp/toggle",
+          method: "POST",
+          data: {mode: isChecked},
+          success: function(data){
+            console.log(data);
+          }
+        });
+      })
     }
+    initUpnpToggleState();
 
+    function initUPnPStatus(){
+      $.get("/api/upnp/discover", function(data){
+        if (data.error != undefined){
+          $("#upnpstatus").html(`<i class="red remove icon"></i> UPnP Router Not Found`);
+          $("#currentUpnpState").addClass("disabled");
+        }else{
+          $("#upnpstatus").html(`<i class="green check icon"></i> Router WAN IP: ${data.ExternalIp}`);
+          UpnpRouterFound = true;
+          updateFordwardTable();
+        }
+      });
+    }
+    initUPnPStatus();
+
+    function updateFordwardTable(){
+      $.get("/api/upnp/list", function(data){
+        renderForwardTable(data);
+        console.log(data);
+      })
+    }
+
+    function renderForwardTable(data){
+      // Assuming the JSON data is stored in a variable called 'data'
+
+      // Get the table body element
+      var tableBody = $("#forwardPortTable")[0];
+
+      // Clear any existing rows from the table
+      tableBody.innerHTML = '';
+
+      // Loop through the required ports and add a row for each
+      for (const [port, name] of Object.entries(data)) {
+        // Create a new row element
+        var row = document.createElement('tr');
+
+        // Create a cell for the port number
+        var portCell = document.createElement('td');
+        portCell.textContent = port;
+        row.appendChild(portCell);
+
+        // Create a cell for the name of the rule (you can customize this based on your needs)
+        var nameCell = document.createElement('td');
+        nameCell.textContent = name;
+        row.appendChild(nameCell);
+
+        // Create a cell for the delete button
+        var deleteCell = document.createElement('td');
+        var deleteButton = document.createElement('button');
+        deleteButton.textContent = 'Delete';
+        deleteButton.className = 'ui button negative';
+        deleteButton.setAttribute('type', 'button');
+        deleteButton.setAttribute('name', 'deleteRule');
+        deleteButton.onclick = function() {
+          removeForwardRule(port);
+        };
+        deleteCell.appendChild(deleteButton);
+        row.appendChild(deleteCell);
+
+        // Add the row to the table body
+        tableBody.appendChild(row);
+      }
+
+      if (Object.keys(data).length == 0){
+        $("#forwardPortTable").append(`<tr>
+          <td colspan="3"><i class="check icon"></i> No Forwarded Port</td>
+        </tr>`);
+      }
+    }
   </script>

+ 2 - 1
web/components/uptime.html

@@ -1,6 +1,6 @@
 <h3><i class="clock green icon"></i> Uptime Monitor</h3>
 <p>Check the online state of proxied targets</p>
-
+<!--
 <div class="ui toggle checkbox" id="utmEnable">
     <input type="checkbox" name="utmEnable">
     <label>Enable External Access</label>
@@ -10,6 +10,7 @@
     <code>%uptime_monitor%</code> 
     <br>as a subdomain or virtual directory target URL in the "Create Proxy Rules" tab.
 </div>
+-->
 <div class="ui divider"></div>
 <div id="utmrender" class="ui basic segment">
     <div class="ui basic segment">