Selaa lähdekoodia

Added WIP new file server page in sys setting (DO NOT DEPLOY)

Toby Chui 2 vuotta sitten
vanhempi
commit
23d71a9785
8 muutettua tiedostoa jossa 820 lisäystä ja 630 poistoa
  1. 0 0
      documents/arozos file system v2.drawio
  2. BIN
      documents/arozos file system v2.png
  3. 81 0
      network.go
  4. 429 369
      network.server.go
  5. 94 92
      network.webdav.go
  6. 165 165
      setting.go
  7. 5 4
      startup.go
  8. 46 0
      web/SystemAO/disk/services.html

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
documents/arozos file system v2.drawio


BIN
documents/arozos file system v2.png


+ 81 - 0
network.go

@@ -1,6 +1,7 @@
 package main
 
 import (
+	"encoding/json"
 	"net/http"
 	"strconv"
 
@@ -221,3 +222,83 @@ func StopNetworkServices() {
 		MDNS.Close()
 	}
 }
+
+/*
+
+	File Server Services
+
+*/
+
+type NetworkFileServer struct {
+	Name              string //Name of the File Server Type. E.g. FTP
+	Desc              string //Description of the File Server Type, e.g. File Transfer Protocol
+	IconPath          string //Path for the protocol Icon, if any
+	DefaultPorts      []int  //Default ports aquire by the Server. Override by Ports if set
+	Ports             []int  //Ports required by the File Server Type that might need port forward. e.g. 21, 22
+	Enabled           bool   //If the server is enabled
+	ForwardPortIfUpnp bool   //Forward the port if UPnP is enabled
+	ConnInstrPage     string //Connection instruction page, visable by all users
+	ConfigPage        string //Config page for changing settings of this File Server Type, admin only
+	InitFunc          func() `json:"-"` //Startup function for this service
+}
+
+var networkFileServerDaemon []NetworkFileServer = []NetworkFileServer{}
+
+//Initiate all File Server services
+func FileServerInit() {
+	//Register System Setting
+	registerSetting(settingModule{
+		Name:         "File Servers",
+		Desc:         "Network File Transfer Servers",
+		IconPath:     "SystemAO/disk/smart/img/small_icon.png",
+		Group:        "Network",
+		StartDir:     "SystemAO/disk/services.html",
+		RequireAdmin: false,
+	})
+
+	//Create a request router
+	router := prout.NewModuleRouter(prout.RouterOption{
+		ModuleName:  "System Setting",
+		AdminOnly:   false,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			common.SendErrorResponse(w, "Permission Denied")
+		},
+	})
+
+	networkFileServerDaemon = append(networkFileServerDaemon, NetworkFileServer{
+		Name:              "FTP",
+		Desc:              "File Transfer Protocol Server",
+		IconPath:          "SystemAO/disk/smart/img/small_icon.png",
+		DefaultPorts:      []int{21, 22, 23},
+		Ports:             []int{},
+		ForwardPortIfUpnp: true,
+		ConnInstrPage:     "SystemAO/disk/ftp.html",
+		ConfigPage:        "SystemAO/disk/ftp.html",
+		InitFunc:          FTPServerInit,
+	})
+
+	networkFileServerDaemon = append(networkFileServerDaemon, NetworkFileServer{
+		Name:              "WebDAV",
+		Desc:              "WebDAV Server",
+		IconPath:          "SystemAO/disk/smart/img/small_icon.png",
+		DefaultPorts:      []int{},
+		Ports:             []int{},
+		ForwardPortIfUpnp: false,
+		ConnInstrPage:     "SystemAO/disk/webdav.html",
+		ConfigPage:        "SystemAO/disk/webdav.html",
+		InitFunc:          WebDAVInit,
+	})
+
+	//Initiate all Network File Servers by calling their init Function
+	for _, nfsd := range networkFileServerDaemon {
+		nfsd.InitFunc()
+	}
+
+	router.HandleFunc("/system/network/fs/list", NetworkHandleGetFileServerServiceList)
+}
+
+func NetworkHandleGetFileServerServiceList(w http.ResponseWriter, r *http.Request) {
+	js, _ := json.Marshal(networkFileServerDaemon)
+	common.SendJSONResponse(w, string(js))
+}

+ 429 - 369
network.ftp.go → network.server.go

@@ -1,369 +1,429 @@
-package main
-
-import (
-	"encoding/json"
-	"errors"
-	"net/http"
-	"strconv"
-	"strings"
-
-	"imuslab.com/arozos/mod/common"
-	prout "imuslab.com/arozos/mod/prouter"
-	ftp "imuslab.com/arozos/mod/storage/ftp"
-)
-
-/*
-	FTP Server related handlers
-*/
-
-var (
-	ftpServer *ftp.Handler
-)
-
-//Handle init of the FTP server endpoints
-func FTPServerInit() {
-	//Register FTP Server Setting page
-	registerSetting(settingModule{
-		Name:         "FTP Server",
-		Desc:         "File Transfer Protocol Server",
-		IconPath:     "SystemAO/disk/smart/img/small_icon.png",
-		Group:        "Network",
-		StartDir:     "SystemAO/disk/ftp.html",
-		RequireAdmin: true,
-	})
-
-	//Register FTP Endpoints
-	adminRouter := prout.NewModuleRouter(prout.RouterOption{
-		ModuleName:  "System Setting",
-		AdminOnly:   true,
-		UserHandler: userHandler,
-		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			errorHandlePermissionDenied(w, r)
-		},
-	})
-
-	//Create database related tables
-	sysdb.NewTable("ftp")
-	defaultEnable := false
-	if sysdb.KeyExists("ftp", "default") {
-		sysdb.Read("ftp", "default", &defaultEnable)
-	} else {
-		sysdb.Write("ftp", "default", false)
-	}
-
-	//Enable this service
-	if defaultEnable {
-		storageFTPServerStart()
-	}
-
-	adminRouter.HandleFunc("/system/storage/ftp/start", storageHandleFTPServerStart)
-	adminRouter.HandleFunc("/system/storage/ftp/stop", storageHandleFTPServerStop)
-	adminRouter.HandleFunc("/system/storage/ftp/upnp", storageHandleFTPuPnP)
-	adminRouter.HandleFunc("/system/storage/ftp/status", storageHandleFTPServerStatus)
-	adminRouter.HandleFunc("/system/storage/ftp/updateGroups", storageHandleFTPAccessUpdate)
-	adminRouter.HandleFunc("/system/storage/ftp/setPort", storageHandleFTPSetPort)
-	adminRouter.HandleFunc("/system/storage/ftp/passivemode", storageHandleFTPPassiveModeSettings)
-}
-
-/*
-	Handle the settings for passive mode related files
-
-	Example set commands
-	set=ip&ip=123.456.789.1
-	set=mode&passive=true
-*/
-func storageHandleFTPPassiveModeSettings(w http.ResponseWriter, r *http.Request) {
-	set, err := common.Mv(r, "set", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid set type")
-		return
-	}
-
-	if set == "ip" {
-		//Updat the public up addr
-		ip, err := common.Mv(r, "ip", true)
-		if err != nil {
-			common.SendErrorResponse(w, "Invalid ip given")
-			return
-		}
-
-		sysdb.Write("ftp", "publicip", ip)
-
-	} else if set == "mode" {
-		//Update the passive mode setting
-		passive, err := common.Mv(r, "passive", true)
-		if err != nil {
-			common.SendErrorResponse(w, "Invalid passive option (true/false)")
-			return
-		}
-
-		systemWideLogger.PrintAndLog("FTP", "Updating FTP Server PassiveMode to"+passive, nil)
-		if passive == "true" {
-			sysdb.Write("ftp", "passive", true)
-		} else {
-			sysdb.Write("ftp", "passive", false)
-		}
-	} else {
-		common.SendErrorResponse(w, "Unknown setting filed")
-		return
-	}
-
-	//Restart the FTP server if it is running now
-	if ftpServer != nil && ftpServer.ServerRunning {
-		storageFTPServerStart()
-	}
-
-}
-
-//Start the FTP Server by request
-func storageHandleFTPServerStart(w http.ResponseWriter, r *http.Request) {
-	err := storageFTPServerStart()
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-	}
-
-	//Remember the FTP server status
-	sysdb.Write("ftp", "default", true)
-	common.SendOK(w)
-}
-
-//Stop the FTP server by request
-func storageHandleFTPServerStop(w http.ResponseWriter, r *http.Request) {
-	if ftpServer != nil {
-		ftpServer.Close()
-	}
-	sysdb.Write("ftp", "default", false)
-	systemWideLogger.PrintAndLog("FTP", "FTP Server Stopped", nil)
-	common.SendOK(w)
-}
-
-//Update UPnP setting on FTP server
-func storageHandleFTPuPnP(w http.ResponseWriter, r *http.Request) {
-	enable, _ := common.Mv(r, "enable", false)
-	if enable == "true" {
-		systemWideLogger.PrintAndLog("FTP", "Enabling UPnP on FTP Server Port", nil)
-		sysdb.Write("ftp", "upnp", true)
-	} else {
-		systemWideLogger.PrintAndLog("FTP", "Disabling UPnP on FTP Server Port", nil)
-		sysdb.Write("ftp", "upnp", false)
-	}
-
-	//Restart FTP Server if server is running
-	if ftpServer != nil && ftpServer.ServerRunning {
-		storageFTPServerStart()
-	}
-
-	common.SendOK(w)
-}
-
-//Update access permission on FTP server
-func storageHandleFTPAccessUpdate(w http.ResponseWriter, r *http.Request) {
-	//Get groups paramter from post req
-	groupString, err := common.Mv(r, "groups", true)
-	if err != nil {
-		common.SendErrorResponse(w, "groups not defined")
-		return
-	}
-
-	//Prase it
-	groups := []string{}
-	err = json.Unmarshal([]byte(groupString), &groups)
-	if err != nil {
-		common.SendErrorResponse(w, "Unable to parse groups")
-		return
-	}
-
-	systemWideLogger.PrintAndLog("FTP", "Updating FTP Access group to: "+strings.Join(groups, ","), nil)
-	//Set the accessable group
-	ftp.UpdateAccessableGroups(sysdb, groups)
-
-	common.SendOK(w)
-}
-
-func storageHandleFTPSetPort(w http.ResponseWriter, r *http.Request) {
-	port, err := common.Mv(r, "port", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Port not defined")
-		return
-	}
-
-	//Try parse the port into int
-	portInt, err := strconv.Atoi(port)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid port number")
-		return
-	}
-
-	//Update the database port configuration
-	sysdb.Write("ftp", "port", portInt)
-
-	//Restart the FTP server
-	storageFTPServerStart()
-
-	common.SendOK(w)
-}
-
-func storageHandleFTPServerStatus(w http.ResponseWriter, r *http.Request) {
-	type ServerStatus struct {
-		Enabled        bool
-		Port           int
-		AllowUPNP      bool
-		UPNPEnabled    bool
-		FTPUpnpEnabled bool
-		PublicAddr     string
-		PassiveMode    bool
-		UserGroups     []string
-	}
-
-	enabled := false
-	if ftpServer != nil && ftpServer.ServerRunning {
-		enabled = true
-	}
-
-	serverPort := 21
-	if sysdb.KeyExists("ftp", "port") {
-		sysdb.Read("ftp", "port", &serverPort)
-	}
-
-	enableUPnP := false
-	if sysdb.KeyExists("ftp", "upnp") {
-		sysdb.Read("ftp", "upnp", &enableUPnP)
-	}
-
-	userGroups := []string{}
-	if sysdb.KeyExists("ftp", "groups") {
-		sysdb.Read("ftp", "groups", &userGroups)
-	}
-
-	ftpUpnp := false
-	if ftpServer != nil && ftpServer.UPNPEnabled {
-		ftpUpnp = true
-	}
-
-	publicAddr := ""
-	if UPNP != nil && UPNP.ExternalIP != "" && ftpUpnp == true {
-		publicAddr = UPNP.ExternalIP
-	} else {
-		manualPublicIpEntry := ""
-		if sysdb.KeyExists("ftp", "publicip") {
-			sysdb.Read("ftp", "publicip", &manualPublicIpEntry)
-		}
-
-		publicAddr = manualPublicIpEntry
-	}
-
-	forcePassiveMode := false
-	if ftpUpnp == true {
-		forcePassiveMode = true
-	} else {
-		if sysdb.KeyExists("ftp", "passive") {
-			sysdb.Read("ftp", "passive", &forcePassiveMode)
-		}
-
-		if forcePassiveMode {
-			//Read the ip setting from database
-			manualPublicIpEntry := ""
-			if sysdb.KeyExists("ftp", "publicip") {
-				sysdb.Read("ftp", "publicip", &manualPublicIpEntry)
-			}
-
-			publicAddr = manualPublicIpEntry
-		}
-	}
-
-	jsonString, _ := json.Marshal(ServerStatus{
-		Enabled:        enabled,
-		Port:           serverPort,
-		AllowUPNP:      *allow_upnp,
-		UPNPEnabled:    enableUPnP,
-		FTPUpnpEnabled: ftpUpnp,
-		PublicAddr:     publicAddr,
-		UserGroups:     userGroups,
-		PassiveMode:    forcePassiveMode,
-	})
-	common.SendJSONResponse(w, string(jsonString))
-}
-
-func storageFTPServerStart() error {
-	if ftpServer != nil {
-		//If the previous ftp server is not closed, close it and open a new one
-		if ftpServer.UPNPEnabled && UPNP != nil {
-			UPNP.ClosePort(ftpServer.Port)
-		}
-		ftpServer.Close()
-	}
-
-	//Load new server config from database
-	serverPort := int(21)
-	if sysdb.KeyExists("ftp", "port") {
-		sysdb.Read("ftp", "port", &serverPort)
-	}
-
-	enableUPnP := false
-	if sysdb.KeyExists("ftp", "upnp") {
-		sysdb.Read("ftp", "upnp", &enableUPnP)
-	}
-
-	forcePassiveMode := false
-	sysdb.Read("ftp", "passive", &forcePassiveMode)
-
-	//Create a new FTP Handler
-	passiveModeIP := ""
-	if *allow_upnp && enableUPnP {
-		//Using External IP address from the UPnP router reply
-		externalIP := UPNP.ExternalIP
-		if externalIP != "" {
-			passiveModeIP = externalIP
-		}
-	} else if forcePassiveMode {
-		//Not allowing upnp but still use passive mode (aka manual port forward)
-		externalIP := ""
-		if sysdb.KeyExists("ftp", "publicip") {
-			sysdb.Read("ftp", "publicip", &externalIP)
-		}
-		passiveModeIP = externalIP
-	}
-
-	h, err := ftp.NewFTPHandler(userHandler, *host_name, serverPort, *tmp_directory, passiveModeIP)
-	if err != nil {
-		return err
-	}
-	h.Start()
-	ftpServer = h
-
-	if *allow_upnp {
-		if enableUPnP {
-			if UPNP == nil {
-				return errors.New("UPnP did not started correctly on this host. Ignore this option")
-			} else {
-				//Forward the port
-				err := UPNP.ForwardPort(ftpServer.Port, *host_name+" FTP Server")
-				if err != nil {
-					systemWideLogger.PrintAndLog("FTP", "Failed to start FTP Server UPnP ", err)
-					ftpServer.UPNPEnabled = false
-					return err
-				} else {
-					//Forward other data ports
-					UPNP.ForwardPort(ftpServer.Port+1, *host_name+" FTP Data 1")
-					UPNP.ForwardPort(ftpServer.Port+2, *host_name+" FTP Data 2")
-					ftpServer.UPNPEnabled = true
-				}
-				return nil
-			}
-
-		} else {
-			//UPNP disabled
-			if UPNP == nil {
-				return errors.New("UPnP did not started correctly on this host. Ignore this option")
-			} else {
-				UPNP.ClosePort(ftpServer.Port)
-				UPNP.ClosePort(ftpServer.Port + 1)
-				UPNP.ClosePort(ftpServer.Port + 2)
-
-				ftpServer.UPNPEnabled = false
-			}
-		}
-	}
-
-	return nil
-}
+package main
+
+import (
+	"encoding/json"
+	"errors"
+	"net/http"
+	"strconv"
+	"strings"
+
+	"imuslab.com/arozos/mod/common"
+	prout "imuslab.com/arozos/mod/prouter"
+	ftp "imuslab.com/arozos/mod/storage/ftp"
+	awebdav "imuslab.com/arozos/mod/storage/webdav"
+)
+
+/*
+	WebDAV Server
+*/
+var (
+	WebDavHandler *awebdav.Server
+)
+
+func WebDAVInit() {
+	//Create a database table for webdav service
+	sysdb.NewTable("webdav")
+
+	//Create a new webdav server
+	newserver := awebdav.NewServer(*host_name, "/webdav", *tmp_directory, *use_tls, userHandler)
+	WebDavHandler = newserver
+
+	//Check the webdav default state
+	enabled := false
+	if sysdb.KeyExists("webdav", "enabled") {
+		sysdb.Read("webdav", "enabled", &enabled)
+	}
+
+	WebDavHandler.Enabled = enabled
+
+	/*
+		http.HandleFunc("/webdav", func(w http.ResponseWriter, r *http.Request) {
+			WebDavHandler.HandleRequest(w, r)
+		})
+	*/
+
+	http.HandleFunc("/system/network/webdav/list", WebDavHandler.HandleConnectionList)
+
+	//Handle setting related functions
+	router := prout.NewModuleRouter(prout.RouterOption{
+		ModuleName:  "File Manager",
+		AdminOnly:   false,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			common.SendErrorResponse(w, "Permission Denied")
+		},
+	})
+
+	router.HandleFunc("/system/network/webdav/edit", WebDavHandler.HandlePermissionEdit)
+	router.HandleFunc("/system/network/webdav/clear", WebDavHandler.HandleClearAllPending)
+
+	router.HandleFunc("/system/network/webdav/status", func(w http.ResponseWriter, r *http.Request) {
+		//Show status for every user, only allow change if admin
+		userinfo, _ := userHandler.GetUserInfoFromRequest(w, r)
+		isAdmin := userinfo.IsAdmin()
+
+		set, _ := common.Mv(r, "set", false)
+		if set == "" {
+			//Return the current status
+			results := []bool{WebDavHandler.Enabled, isAdmin}
+			js, _ := json.Marshal(results)
+			common.SendJSONResponse(w, string(js))
+		} else if isAdmin && set == "disable" {
+			WebDavHandler.Enabled = false
+			sysdb.Write("webdav", "enabled", false)
+			common.SendOK(w)
+		} else if isAdmin && set == "enable" {
+			WebDavHandler.Enabled = true
+			sysdb.Write("webdav", "enabled", true)
+			common.SendOK(w)
+		} else {
+			common.SendErrorResponse(w, "Permission Denied")
+		}
+	})
+}
+
+/*
+	FTP Server
+*/
+
+var (
+	ftpServer *ftp.Handler
+)
+
+//Handle init of the FTP server endpoints
+func FTPServerInit() {
+	//Register FTP Endpoints
+	adminRouter := prout.NewModuleRouter(prout.RouterOption{
+		ModuleName:  "System Setting",
+		AdminOnly:   true,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			errorHandlePermissionDenied(w, r)
+		},
+	})
+
+	//Create database related tables
+	sysdb.NewTable("ftp")
+	defaultEnable := false
+	if sysdb.KeyExists("ftp", "default") {
+		sysdb.Read("ftp", "default", &defaultEnable)
+	} else {
+		sysdb.Write("ftp", "default", false)
+	}
+
+	//Enable this service
+	if defaultEnable {
+		storageFTPServerStart()
+	}
+
+	adminRouter.HandleFunc("/system/storage/ftp/start", storageHandleFTPServerStart)
+	adminRouter.HandleFunc("/system/storage/ftp/stop", storageHandleFTPServerStop)
+	adminRouter.HandleFunc("/system/storage/ftp/upnp", storageHandleFTPuPnP)
+	adminRouter.HandleFunc("/system/storage/ftp/status", storageHandleFTPServerStatus)
+	adminRouter.HandleFunc("/system/storage/ftp/updateGroups", storageHandleFTPAccessUpdate)
+	adminRouter.HandleFunc("/system/storage/ftp/setPort", storageHandleFTPSetPort)
+	adminRouter.HandleFunc("/system/storage/ftp/passivemode", storageHandleFTPPassiveModeSettings)
+}
+
+/*
+	Handle the settings for passive mode related files
+
+	Example set commands
+	set=ip&ip=123.456.789.1
+	set=mode&passive=true
+*/
+func storageHandleFTPPassiveModeSettings(w http.ResponseWriter, r *http.Request) {
+	set, err := common.Mv(r, "set", true)
+	if err != nil {
+		common.SendErrorResponse(w, "Invalid set type")
+		return
+	}
+
+	if set == "ip" {
+		//Updat the public up addr
+		ip, err := common.Mv(r, "ip", true)
+		if err != nil {
+			common.SendErrorResponse(w, "Invalid ip given")
+			return
+		}
+
+		sysdb.Write("ftp", "publicip", ip)
+
+	} else if set == "mode" {
+		//Update the passive mode setting
+		passive, err := common.Mv(r, "passive", true)
+		if err != nil {
+			common.SendErrorResponse(w, "Invalid passive option (true/false)")
+			return
+		}
+
+		systemWideLogger.PrintAndLog("FTP", "Updating FTP Server PassiveMode to"+passive, nil)
+		if passive == "true" {
+			sysdb.Write("ftp", "passive", true)
+		} else {
+			sysdb.Write("ftp", "passive", false)
+		}
+	} else {
+		common.SendErrorResponse(w, "Unknown setting filed")
+		return
+	}
+
+	//Restart the FTP server if it is running now
+	if ftpServer != nil && ftpServer.ServerRunning {
+		storageFTPServerStart()
+	}
+
+}
+
+//Start the FTP Server by request
+func storageHandleFTPServerStart(w http.ResponseWriter, r *http.Request) {
+	err := storageFTPServerStart()
+	if err != nil {
+		common.SendErrorResponse(w, err.Error())
+	}
+
+	//Remember the FTP server status
+	sysdb.Write("ftp", "default", true)
+	common.SendOK(w)
+}
+
+//Stop the FTP server by request
+func storageHandleFTPServerStop(w http.ResponseWriter, r *http.Request) {
+	if ftpServer != nil {
+		ftpServer.Close()
+	}
+	sysdb.Write("ftp", "default", false)
+	systemWideLogger.PrintAndLog("FTP", "FTP Server Stopped", nil)
+	common.SendOK(w)
+}
+
+//Update UPnP setting on FTP server
+func storageHandleFTPuPnP(w http.ResponseWriter, r *http.Request) {
+	enable, _ := common.Mv(r, "enable", false)
+	if enable == "true" {
+		systemWideLogger.PrintAndLog("FTP", "Enabling UPnP on FTP Server Port", nil)
+		sysdb.Write("ftp", "upnp", true)
+	} else {
+		systemWideLogger.PrintAndLog("FTP", "Disabling UPnP on FTP Server Port", nil)
+		sysdb.Write("ftp", "upnp", false)
+	}
+
+	//Restart FTP Server if server is running
+	if ftpServer != nil && ftpServer.ServerRunning {
+		storageFTPServerStart()
+	}
+
+	common.SendOK(w)
+}
+
+//Update access permission on FTP server
+func storageHandleFTPAccessUpdate(w http.ResponseWriter, r *http.Request) {
+	//Get groups paramter from post req
+	groupString, err := common.Mv(r, "groups", true)
+	if err != nil {
+		common.SendErrorResponse(w, "groups not defined")
+		return
+	}
+
+	//Prase it
+	groups := []string{}
+	err = json.Unmarshal([]byte(groupString), &groups)
+	if err != nil {
+		common.SendErrorResponse(w, "Unable to parse groups")
+		return
+	}
+
+	systemWideLogger.PrintAndLog("FTP", "Updating FTP Access group to: "+strings.Join(groups, ","), nil)
+	//Set the accessable group
+	ftp.UpdateAccessableGroups(sysdb, groups)
+
+	common.SendOK(w)
+}
+
+func storageHandleFTPSetPort(w http.ResponseWriter, r *http.Request) {
+	port, err := common.Mv(r, "port", true)
+	if err != nil {
+		common.SendErrorResponse(w, "Port not defined")
+		return
+	}
+
+	//Try parse the port into int
+	portInt, err := strconv.Atoi(port)
+	if err != nil {
+		common.SendErrorResponse(w, "Invalid port number")
+		return
+	}
+
+	//Update the database port configuration
+	sysdb.Write("ftp", "port", portInt)
+
+	//Restart the FTP server
+	storageFTPServerStart()
+
+	common.SendOK(w)
+}
+
+func storageHandleFTPServerStatus(w http.ResponseWriter, r *http.Request) {
+	type ServerStatus struct {
+		Enabled        bool
+		Port           int
+		AllowUPNP      bool
+		UPNPEnabled    bool
+		FTPUpnpEnabled bool
+		PublicAddr     string
+		PassiveMode    bool
+		UserGroups     []string
+	}
+
+	enabled := false
+	if ftpServer != nil && ftpServer.ServerRunning {
+		enabled = true
+	}
+
+	serverPort := 21
+	if sysdb.KeyExists("ftp", "port") {
+		sysdb.Read("ftp", "port", &serverPort)
+	}
+
+	enableUPnP := false
+	if sysdb.KeyExists("ftp", "upnp") {
+		sysdb.Read("ftp", "upnp", &enableUPnP)
+	}
+
+	userGroups := []string{}
+	if sysdb.KeyExists("ftp", "groups") {
+		sysdb.Read("ftp", "groups", &userGroups)
+	}
+
+	ftpUpnp := false
+	if ftpServer != nil && ftpServer.UPNPEnabled {
+		ftpUpnp = true
+	}
+
+	publicAddr := ""
+	if UPNP != nil && UPNP.ExternalIP != "" && ftpUpnp == true {
+		publicAddr = UPNP.ExternalIP
+	} else {
+		manualPublicIpEntry := ""
+		if sysdb.KeyExists("ftp", "publicip") {
+			sysdb.Read("ftp", "publicip", &manualPublicIpEntry)
+		}
+
+		publicAddr = manualPublicIpEntry
+	}
+
+	forcePassiveMode := false
+	if ftpUpnp == true {
+		forcePassiveMode = true
+	} else {
+		if sysdb.KeyExists("ftp", "passive") {
+			sysdb.Read("ftp", "passive", &forcePassiveMode)
+		}
+
+		if forcePassiveMode {
+			//Read the ip setting from database
+			manualPublicIpEntry := ""
+			if sysdb.KeyExists("ftp", "publicip") {
+				sysdb.Read("ftp", "publicip", &manualPublicIpEntry)
+			}
+
+			publicAddr = manualPublicIpEntry
+		}
+	}
+
+	jsonString, _ := json.Marshal(ServerStatus{
+		Enabled:        enabled,
+		Port:           serverPort,
+		AllowUPNP:      *allow_upnp,
+		UPNPEnabled:    enableUPnP,
+		FTPUpnpEnabled: ftpUpnp,
+		PublicAddr:     publicAddr,
+		UserGroups:     userGroups,
+		PassiveMode:    forcePassiveMode,
+	})
+	common.SendJSONResponse(w, string(jsonString))
+}
+
+func storageFTPServerStart() error {
+	if ftpServer != nil {
+		//If the previous ftp server is not closed, close it and open a new one
+		if ftpServer.UPNPEnabled && UPNP != nil {
+			UPNP.ClosePort(ftpServer.Port)
+		}
+		ftpServer.Close()
+	}
+
+	//Load new server config from database
+	serverPort := int(21)
+	if sysdb.KeyExists("ftp", "port") {
+		sysdb.Read("ftp", "port", &serverPort)
+	}
+
+	enableUPnP := false
+	if sysdb.KeyExists("ftp", "upnp") {
+		sysdb.Read("ftp", "upnp", &enableUPnP)
+	}
+
+	forcePassiveMode := false
+	sysdb.Read("ftp", "passive", &forcePassiveMode)
+
+	//Create a new FTP Handler
+	passiveModeIP := ""
+	if *allow_upnp && enableUPnP {
+		//Using External IP address from the UPnP router reply
+		externalIP := UPNP.ExternalIP
+		if externalIP != "" {
+			passiveModeIP = externalIP
+		}
+	} else if forcePassiveMode {
+		//Not allowing upnp but still use passive mode (aka manual port forward)
+		externalIP := ""
+		if sysdb.KeyExists("ftp", "publicip") {
+			sysdb.Read("ftp", "publicip", &externalIP)
+		}
+		passiveModeIP = externalIP
+	}
+
+	h, err := ftp.NewFTPHandler(userHandler, *host_name, serverPort, *tmp_directory, passiveModeIP)
+	if err != nil {
+		return err
+	}
+	h.Start()
+	ftpServer = h
+
+	if *allow_upnp {
+		if enableUPnP {
+			if UPNP == nil {
+				return errors.New("UPnP did not started correctly on this host. Ignore this option")
+			} else {
+				//Forward the port
+				err := UPNP.ForwardPort(ftpServer.Port, *host_name+" FTP Server")
+				if err != nil {
+					systemWideLogger.PrintAndLog("FTP", "Failed to start FTP Server UPnP ", err)
+					ftpServer.UPNPEnabled = false
+					return err
+				} else {
+					//Forward other data ports
+					UPNP.ForwardPort(ftpServer.Port+1, *host_name+" FTP Data 1")
+					UPNP.ForwardPort(ftpServer.Port+2, *host_name+" FTP Data 2")
+					ftpServer.UPNPEnabled = true
+				}
+				return nil
+			}
+
+		} else {
+			//UPNP disabled
+			if UPNP == nil {
+				return errors.New("UPnP did not started correctly on this host. Ignore this option")
+			} else {
+				UPNP.ClosePort(ftpServer.Port)
+				UPNP.ClosePort(ftpServer.Port + 1)
+				UPNP.ClosePort(ftpServer.Port + 2)
+
+				ftpServer.UPNPEnabled = false
+			}
+		}
+	}
+
+	return nil
+}

+ 94 - 92
network.webdav.go

@@ -1,92 +1,94 @@
-package main
-
-/*
-	WebDAV Entry point
-	author: tobychui
-
-*/
-
-import (
-	"encoding/json"
-	"net/http"
-
-	"imuslab.com/arozos/mod/common"
-	prout "imuslab.com/arozos/mod/prouter"
-	awebdav "imuslab.com/arozos/mod/storage/webdav"
-)
-
-var (
-	WebDavHandler *awebdav.Server
-)
-
-func WebDAVInit() {
-	//Create a database table for webdav service
-	sysdb.NewTable("webdav")
-
-	//Create a new webdav server
-	newserver := awebdav.NewServer(*host_name, "/webdav", *tmp_directory, *use_tls, userHandler)
-	WebDavHandler = newserver
-
-	//Check the webdav default state
-	enabled := false
-	if sysdb.KeyExists("webdav", "enabled") {
-		sysdb.Read("webdav", "enabled", &enabled)
-	}
-
-	WebDavHandler.Enabled = enabled
-
-	/*
-		http.HandleFunc("/webdav", func(w http.ResponseWriter, r *http.Request) {
-			WebDavHandler.HandleRequest(w, r)
-		})
-	*/
-
-	http.HandleFunc("/system/network/webdav/list", WebDavHandler.HandleConnectionList)
-
-	//Handle setting related functions
-	router := prout.NewModuleRouter(prout.RouterOption{
-		ModuleName:  "File Manager",
-		AdminOnly:   false,
-		UserHandler: userHandler,
-		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
-		},
-	})
-
-	router.HandleFunc("/system/network/webdav/edit", WebDavHandler.HandlePermissionEdit)
-	router.HandleFunc("/system/network/webdav/clear", WebDavHandler.HandleClearAllPending)
-
-	router.HandleFunc("/system/network/webdav/status", func(w http.ResponseWriter, r *http.Request) {
-		//Show status for every user, only allow change if admin
-		userinfo, _ := userHandler.GetUserInfoFromRequest(w, r)
-		isAdmin := userinfo.IsAdmin()
-
-		set, _ := common.Mv(r, "set", false)
-		if set == "" {
-			//Return the current status
-			results := []bool{WebDavHandler.Enabled, isAdmin}
-			js, _ := json.Marshal(results)
-			common.SendJSONResponse(w, string(js))
-		} else if isAdmin && set == "disable" {
-			WebDavHandler.Enabled = false
-			sysdb.Write("webdav", "enabled", false)
-			common.SendOK(w)
-		} else if isAdmin && set == "enable" {
-			WebDavHandler.Enabled = true
-			sysdb.Write("webdav", "enabled", true)
-			common.SendOK(w)
-		} else {
-			common.SendErrorResponse(w, "Permission Denied")
-		}
-	})
-
-	//Register settings
-	registerSetting(settingModule{
-		Name:     "WebDAV Server",
-		Desc:     "WebDAV Server",
-		IconPath: "SystemAO/info/img/small_icon.png",
-		Group:    "Network",
-		StartDir: "SystemAO/disk/webdav.html",
-	})
-
-}
+package main
+
+/*
+	WebDAV Entry point
+	author: tobychui
+
+*/
+
+import (
+	"encoding/json"
+	"net/http"
+
+	"imuslab.com/arozos/mod/common"
+	prout "imuslab.com/arozos/mod/prouter"
+	awebdav "imuslab.com/arozos/mod/storage/webdav"
+)
+
+var (
+	WebDavHandler *awebdav.Server
+)
+
+func WebDAVInit() {
+	//Create a database table for webdav service
+	sysdb.NewTable("webdav")
+
+	//Create a new webdav server
+	newserver := awebdav.NewServer(*host_name, "/webdav", *tmp_directory, *use_tls, userHandler)
+	WebDavHandler = newserver
+
+	//Check the webdav default state
+	enabled := false
+	if sysdb.KeyExists("webdav", "enabled") {
+		sysdb.Read("webdav", "enabled", &enabled)
+	}
+
+	WebDavHandler.Enabled = enabled
+
+	/*
+		http.HandleFunc("/webdav", func(w http.ResponseWriter, r *http.Request) {
+			WebDavHandler.HandleRequest(w, r)
+		})
+	*/
+
+	http.HandleFunc("/system/network/webdav/list", WebDavHandler.HandleConnectionList)
+
+	//Handle setting related functions
+	router := prout.NewModuleRouter(prout.RouterOption{
+		ModuleName:  "File Manager",
+		AdminOnly:   false,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			common.SendErrorResponse(w, "Permission Denied")
+		},
+	})
+
+	router.HandleFunc("/system/network/webdav/edit", WebDavHandler.HandlePermissionEdit)
+	router.HandleFunc("/system/network/webdav/clear", WebDavHandler.HandleClearAllPending)
+
+	router.HandleFunc("/system/network/webdav/status", func(w http.ResponseWriter, r *http.Request) {
+		//Show status for every user, only allow change if admin
+		userinfo, _ := userHandler.GetUserInfoFromRequest(w, r)
+		isAdmin := userinfo.IsAdmin()
+
+		set, _ := common.Mv(r, "set", false)
+		if set == "" {
+			//Return the current status
+			results := []bool{WebDavHandler.Enabled, isAdmin}
+			js, _ := json.Marshal(results)
+			common.SendJSONResponse(w, string(js))
+		} else if isAdmin && set == "disable" {
+			WebDavHandler.Enabled = false
+			sysdb.Write("webdav", "enabled", false)
+			common.SendOK(w)
+		} else if isAdmin && set == "enable" {
+			WebDavHandler.Enabled = true
+			sysdb.Write("webdav", "enabled", true)
+			common.SendOK(w)
+		} else {
+			common.SendErrorResponse(w, "Permission Denied")
+		}
+	})
+
+	//Register settings
+	/*
+		registerSetting(settingModule{
+			Name:     "WebDAV Server",
+			Desc:     "WebDAV Server",
+			IconPath: "SystemAO/info/img/small_icon.png",
+			Group:    "Network",
+			StartDir: "SystemAO/disk/webdav.html",
+		})
+	*/
+
+}

+ 165 - 165
setting.go

@@ -1,165 +1,165 @@
-package main
-
-import (
-	"encoding/json"
-	"net/http"
-
-	"imuslab.com/arozos/mod/common"
-	module "imuslab.com/arozos/mod/modules"
-)
-
-type settingModule struct {
-	Name         string //Name of the setting module.
-	Desc         string //Description of the setting module
-	IconPath     string //Icon path for the setting module
-	Group        string //Accept {}
-	StartDir     string //Startup Directory / path
-	RequireAdmin bool   //If the setting require admin access.
-	//^ Enable this to hide this setting from non-admin users, but for API call, module has to handle admin check themselves.
-
-}
-
-type settingGroup struct {
-	Name     string
-	Group    string
-	IconPath string
-	Desc     string
-}
-
-var (
-	settingModules []settingModule
-)
-
-func SystemSettingInit() {
-	http.HandleFunc("/system/setting/list", system_setting_handleListing)
-
-	//Register the module
-	moduleHandler.RegisterModule(module.ModuleInfo{
-		Name:        "System Setting",
-		Desc:        "Cutomize your systems to fit your needs",
-		Group:       "System Settings",
-		IconPath:    "SystemAO/system_setting/img/small_icon.png",
-		Version:     "1.0",
-		StartDir:    "SystemAO/system_setting/index.html",
-		SupportFW:   true,
-		InitFWSize:  []int{1080, 580},
-		LaunchFWDir: "SystemAO/system_setting/index.html",
-		SupportEmb:  false,
-	})
-}
-
-//Setting group defination. Your setting module defination must match the group in-order to be shown
-func system_setting_getSettingGroups() []settingGroup {
-	return []settingGroup{
-		{
-			Name:     "Host Information",
-			Group:    "Info",
-			IconPath: "SystemAO/system_setting/img/server.svg",
-			Desc:     "Config and info about the Server Host",
-		},
-		{
-			Name:     "Devices & IoT",
-			Group:    "Device",
-			IconPath: "SystemAO/system_setting/img/device.svg",
-			Desc:     "Connected clients and IoT devices",
-		},
-		{
-			Name:     "Module Management",
-			Group:    "Module",
-			IconPath: "SystemAO/system_setting/img/module.svg",
-			Desc:     "List of modules loaded in the system",
-		},
-		{
-			Name:     "Disk & Storage",
-			Group:    "Disk",
-			IconPath: "SystemAO/system_setting/img/drive.svg",
-			Desc:     "Manage Storage Devices and Disks",
-		},
-		{
-			Name:     "Network & Connection",
-			Group:    "Network",
-			IconPath: "SystemAO/system_setting/img/network.svg",
-			Desc:     "Manage Host Network and Connections",
-		},
-		{
-			Name:     "Users & Groups",
-			Group:    "Users",
-			IconPath: "SystemAO/system_setting/img/users.svg",
-			Desc:     "Add, removed or edit users and groups",
-		},
-		{
-			Name:     "Clusters & Scheduling",
-			Group:    "Cluster",
-			IconPath: "SystemAO/system_setting/img/cluster.svg",
-			Desc:     "System Functions related to Time and Dates",
-		},
-		{
-			Name:     "Security & Keys",
-			Group:    "Security",
-			IconPath: "SystemAO/system_setting/img/security.svg",
-			Desc:     "System Security and Keypairs",
-		},
-		{
-			Name:     "Advance Options",
-			Group:    "Advance",
-			IconPath: "SystemAO/system_setting/img/code.svg",
-			Desc:     "Advance configs for developers",
-		},
-		{
-			Name:     "About ArOZ",
-			Group:    "About",
-			IconPath: "SystemAO/system_setting/img/info.svg",
-			Desc:     "Information of the current running ArOZ Online System",
-		},
-	}
-}
-
-func registerSetting(thismodule settingModule) {
-	settingModules = append(settingModules, thismodule)
-}
-
-//List all the setting modules and output it as JSON
-func system_setting_handleListing(w http.ResponseWriter, r *http.Request) {
-	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
-		return
-	}
-
-	allSettingGroups := system_setting_getSettingGroups()
-	listGroup, _ := common.Mv(r, "listGroup", false)
-	if len(listGroup) > 0 {
-		//List the given group
-		var results []settingModule
-		for _, setMod := range settingModules {
-			if setMod.Group == listGroup {
-				//Check if the module is admin only.
-				if setMod.RequireAdmin && userinfo.IsAdmin() {
-					//Admin module and user is admin. Append to list
-					results = append(results, setMod)
-				} else if setMod.RequireAdmin == false {
-					//Normal module. Append to list
-					results = append(results, setMod)
-				}
-
-			}
-		}
-
-		if len(results) > 0 {
-			jsonString, _ := json.Marshal(results)
-			common.SendJSONResponse(w, string(jsonString))
-			return
-		} else {
-			//This group not found,
-			common.SendErrorResponse(w, "Group not found")
-			return
-		}
-
-	} else {
-		//List all root groups
-		jsonString, _ := json.Marshal(allSettingGroups)
-		common.SendJSONResponse(w, string(jsonString))
-		return
-	}
-
-}
+package main
+
+import (
+	"encoding/json"
+	"net/http"
+
+	"imuslab.com/arozos/mod/common"
+	module "imuslab.com/arozos/mod/modules"
+)
+
+type settingModule struct {
+	Name         string //Name of the setting module.
+	Desc         string //Description of the setting module
+	IconPath     string //Icon path for the setting module
+	Group        string //Accept {}
+	StartDir     string //Startup Directory / path
+	RequireAdmin bool   //If the setting require admin access.
+	//^ Enable this to hide this setting from non-admin users, but for API call, module has to handle admin check themselves.
+
+}
+
+type settingGroup struct {
+	Name     string
+	Group    string
+	IconPath string
+	Desc     string
+}
+
+var (
+	settingModules []settingModule
+)
+
+func SystemSettingInit() {
+	http.HandleFunc("/system/setting/list", system_setting_handleListing)
+
+	//Register the module
+	moduleHandler.RegisterModule(module.ModuleInfo{
+		Name:        "System Setting",
+		Desc:        "Cutomize your systems to fit your needs",
+		Group:       "System Settings",
+		IconPath:    "SystemAO/system_setting/img/small_icon.png",
+		Version:     "1.0",
+		StartDir:    "SystemAO/system_setting/index.html",
+		SupportFW:   true,
+		InitFWSize:  []int{1080, 580},
+		LaunchFWDir: "SystemAO/system_setting/index.html",
+		SupportEmb:  false,
+	})
+}
+
+//Setting group defination. Your setting module defination must match the group in-order to be shown
+func system_setting_getSettingGroups() []settingGroup {
+	return []settingGroup{
+		{
+			Name:     "Host Information",
+			Group:    "Info",
+			IconPath: "SystemAO/system_setting/img/server.svg",
+			Desc:     "Config and info about the Server Host",
+		},
+		{
+			Name:     "Devices & IoT",
+			Group:    "Device",
+			IconPath: "SystemAO/system_setting/img/device.svg",
+			Desc:     "Connected clients and IoT devices",
+		},
+		{
+			Name:     "Module Management",
+			Group:    "Module",
+			IconPath: "SystemAO/system_setting/img/module.svg",
+			Desc:     "List of modules loaded in the system",
+		},
+		{
+			Name:     "Disk & Storage",
+			Group:    "Disk",
+			IconPath: "SystemAO/system_setting/img/drive.svg",
+			Desc:     "Manage Storage Devices and Disks",
+		},
+		{
+			Name:     "Network & Connection",
+			Group:    "Network",
+			IconPath: "SystemAO/system_setting/img/network.svg",
+			Desc:     "Manage Host Network and Connections",
+		},
+		{
+			Name:     "Users & Groups",
+			Group:    "Users",
+			IconPath: "SystemAO/system_setting/img/users.svg",
+			Desc:     "Add, removed or edit users and groups",
+		},
+		{
+			Name:     "Clusters & Scheduling",
+			Group:    "Cluster",
+			IconPath: "SystemAO/system_setting/img/cluster.svg",
+			Desc:     "Cluster, Network Scanning and Task Scheduling",
+		},
+		{
+			Name:     "Security & Auth",
+			Group:    "Security",
+			IconPath: "SystemAO/system_setting/img/security.svg",
+			Desc:     "System Security and Auth Credentials",
+		},
+		{
+			Name:     "Advance Options",
+			Group:    "Advance",
+			IconPath: "SystemAO/system_setting/img/code.svg",
+			Desc:     "Advance configs for developers",
+		},
+		{
+			Name:     "About ArOZ",
+			Group:    "About",
+			IconPath: "SystemAO/system_setting/img/info.svg",
+			Desc:     "Information of the current running ArOZ Online System",
+		},
+	}
+}
+
+func registerSetting(thismodule settingModule) {
+	settingModules = append(settingModules, thismodule)
+}
+
+//List all the setting modules and output it as JSON
+func system_setting_handleListing(w http.ResponseWriter, r *http.Request) {
+	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		common.SendErrorResponse(w, "User not logged in")
+		return
+	}
+
+	allSettingGroups := system_setting_getSettingGroups()
+	listGroup, _ := common.Mv(r, "listGroup", false)
+	if len(listGroup) > 0 {
+		//List the given group
+		var results []settingModule
+		for _, setMod := range settingModules {
+			if setMod.Group == listGroup {
+				//Check if the module is admin only.
+				if setMod.RequireAdmin && userinfo.IsAdmin() {
+					//Admin module and user is admin. Append to list
+					results = append(results, setMod)
+				} else if setMod.RequireAdmin == false {
+					//Normal module. Append to list
+					results = append(results, setMod)
+				}
+
+			}
+		}
+
+		if len(results) > 0 {
+			jsonString, _ := json.Marshal(results)
+			common.SendJSONResponse(w, string(jsonString))
+			return
+		} else {
+			//This group not found,
+			common.SendErrorResponse(w, "Group not found")
+			return
+		}
+
+	} else {
+		//List all root groups
+		jsonString, _ := json.Marshal(allSettingGroups)
+		common.SendJSONResponse(w, string(jsonString))
+		return
+	}
+
+}

+ 5 - 4
startup.go

@@ -118,10 +118,11 @@ func RunStartup() {
 	notificationInit() //Notification system init
 
 	//Start High Level Services that requires full arozos architectures
-	FTPServerInit() //Start FTP Server Endpoints
-	WebDAVInit()    //Start WebDAV Endpoint
-	ClusterInit()   //Start Cluster Services
-	IoTHubInit()    //Inialize ArozOS IoT Hub module
+	FileServerInit()
+	//FTPServerInit() //Start FTP Server Endpoints
+	//WebDAVInit()    //Start WebDAV Endpoint
+	ClusterInit() //Start Cluster Services
+	IoTHubInit()  //Inialize ArozOS IoT Hub module
 
 	ModuleInstallerInit() //Start Module Installer
 

+ 46 - 0
web/SystemAO/disk/services.html

@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<head>
+	<meta name="mobile-web-app-capable" content="yes">
+	<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
+	<meta charset="UTF-8">
+    <link rel="stylesheet" href="../../script/semantic/semantic.min.css">
+    <script src="../../script/jquery.min.js"></script>
+	<script src="../../script/semantic/semantic.min.js"></script>
+    <style>
+        .hidden{
+            display:none;
+        }
+
+        .disabled{
+            opacity: 0.5;
+            pointer-events: none;
+        }
+    </style>
+</head>
+<body>
+    <br>
+   <div class="ui container">
+        <div class="ui header">
+            <i class="folder outline icon"></i> 
+            <div class="content">
+                Network File Transfer Servers
+                <div class="sub header">Manage the exported file server interface for ArozOS Virtual File System</div>
+            </div>
+        </div>
+        <br>
+        <div class="ui stackable grid">
+            <div class="six wide column" style="border-right: 1px solid #e0e0e0;">
+                
+            </div>
+            <div class="ten wide column">
+            
+            </div>
+        </div>
+        <br><br>
+    </div>
+    <script>
+       
+    </script>
+</body>
+</html>

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä