123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520 |
- package main
- import (
- "encoding/json"
- "net/http"
- "strconv"
- "strings"
- "imuslab.com/arozos/mod/fileservers"
- "imuslab.com/arozos/mod/fileservers/servers/dirserv"
- "imuslab.com/arozos/mod/fileservers/servers/ftpserv"
- "imuslab.com/arozos/mod/fileservers/servers/sftpserv"
- "imuslab.com/arozos/mod/fileservers/servers/webdavserv"
- network "imuslab.com/arozos/mod/network"
- mdns "imuslab.com/arozos/mod/network/mdns"
- "imuslab.com/arozos/mod/network/netstat"
- ssdp "imuslab.com/arozos/mod/network/ssdp"
- upnp "imuslab.com/arozos/mod/network/upnp"
- "imuslab.com/arozos/mod/network/websocket"
- prout "imuslab.com/arozos/mod/prouter"
- "imuslab.com/arozos/mod/utils"
- "imuslab.com/arozos/mod/www"
- )
- var (
- //Network Services Managers
- MDNS *mdns.MDNSHost
- UPNP *upnp.UPnPClient
- SSDP *ssdp.SSDPHost
- WebSocketRouter *websocket.Router
- //File Server Managers
- FTPManager *ftpserv.Manager
- WebDAVManager *webdavserv.Manager
- SFTPManager *sftpserv.Manager
- DirListManager *dirserv.Manager
- )
- func NetworkServiceInit() {
- systemWideLogger.PrintAndLog("Network", "Starting ArOZ Network Services", nil)
- //Create a router that allow users with System Setting access to access these api endpoints
- router := prout.NewModuleRouter(prout.RouterOption{
- ModuleName: "System Setting",
- AdminOnly: false,
- UserHandler: userHandler,
- DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
- utils.SendErrorResponse(w, "Permission Denied")
- },
- })
- /*
- Standard Network Utilties
- */
- //Register handler endpoints
- if *allow_hardware_management {
- router.HandleFunc("/system/network/getNICinfo", network.GetNICInfo)
- router.HandleFunc("/system/network/getPing", network.GetPing)
- //Register as a system setting
- registerSetting(settingModule{
- Name: "Network Info",
- Desc: "System Information",
- IconPath: "SystemAO/network/img/ethernet.png",
- Group: "Network",
- StartDir: "SystemAO/network/hardware.html",
- })
- }
- router.HandleFunc("/system/network/getNICUsage", netstat.HandleGetNetworkInterfaceStats)
- //Start the services that depends on network interface
- StartNetworkServices()
- //Start the port forward configuration interface
- portForwardInit()
- //Start userhomepage if enabled
- //Handle user webroot routings if homepage is enabled
- if *allow_homepage {
- userWwwHandler = www.NewWebRootHandler(www.Options{
- UserHandler: userHandler,
- Database: sysdb,
- AgiGateway: AGIGateway,
- })
- router.HandleFunc("/system/network/www/toggle", userWwwHandler.HandleToggleHomepage)
- router.HandleFunc("/system/network/www/webRoot", userWwwHandler.HandleSetWebRoot)
- //Register as a system setting
- registerSetting(settingModule{
- Name: "Personal Page",
- Desc: "Personal Web Page",
- IconPath: "SystemAO/www/img/homepage.png",
- Group: "Network",
- StartDir: "SystemAO/www/config.html",
- })
- }
- userRouter := prout.NewModuleRouter(prout.RouterOption{
- AdminOnly: false,
- UserHandler: userHandler,
- DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
- utils.SendErrorResponse(w, "Permission Denied")
- },
- })
- WebSocketRouter = websocket.NewRouter()
- userRouter.HandleFunc("/system/ws", WebSocketRouter.HandleWebSocketRouting)
- }
- func StartNetworkServices() {
- /*
- MDNS Services
- */
- if *allow_mdns {
- m, err := mdns.NewMDNS(mdns.NetworkHost{
- HostName: *host_name + "_" + deviceUUID, //To handle more than one identical model within the same network, this must be unique
- Port: *listen_port,
- Domain: "arozos.com",
- Model: deviceModel,
- UUID: deviceUUID,
- Vendor: deviceVendor,
- BuildVersion: build_version,
- MinorVersion: internal_version,
- }, *force_mac)
- if err != nil {
- systemWideLogger.PrintAndLog("Network", "MDNS Startup Failed. Running in Offline Mode.", err)
- } else {
- MDNS = m
- }
- }
- /*
- SSDP Discovery Services
- */
- if *allow_ssdp {
- //Get outbound ip
- obip, err := network.GetOutboundIP()
- if err != nil {
- systemWideLogger.PrintAndLog("Network", "SSDP Startup Failed. Running in Offline Mode.", err)
- } else {
- thisIp := obip.String()
- adv, err := ssdp.NewSSDPHost(thisIp, *listen_port, "system/ssdp.xml", ssdp.SSDPOption{
- URLBase: "http://" + thisIp + ":" + strconv.Itoa(*listen_port), //This must be http if used as local hosting devices
- Hostname: *host_name,
- Vendor: deviceVendor,
- VendorURL: deviceVendorURL,
- ModelName: deviceModel,
- ModelDesc: deviceModelDesc,
- UUID: deviceUUID,
- Serial: "generic",
- })
- if err != nil {
- systemWideLogger.PrintAndLog("Network", "SSDP Startup Failed. Running in Offline Mode.", err)
- } else {
- //OK! Start SSDP Service
- SSDP = adv
- SSDP.Start()
- }
- }
- }
- /*
- UPNP / Setup automatic port forwarding
- */
- if *allow_upnp {
- var u *upnp.UPnPClient
- var err error = nil
- if *use_tls {
- u, err = upnp.NewUPNPClient(*tls_listen_port, *host_name+"-https")
- } else {
- u, err = upnp.NewUPNPClient(*listen_port, *host_name+"-http")
- }
- if err != nil {
- systemWideLogger.PrintAndLog("Network", "UPnP Startup Failed: "+err.Error(), err)
- } else {
- //Bind the http port if running in https and http server is not disabled
- if *use_tls && !*disable_http {
- u.ForwardPort(*listen_port, *host_name+"-http")
- }
- UPNP = u
- //Register nightly listener for upnp renew
- nightlyManager.RegisterNightlyTask(func() {
- UPNP.RenewForwardRules()
- })
- //Show a tip for success port forward
- connectionEndpoint := UPNP.ExternalIP + ":" + strconv.Itoa(*listen_port)
- obip, err := network.GetOutboundIP()
- obipstring := "[Outbound IP]"
- if err != nil {
- } else {
- obipstring = obip.String()
- }
- localEndpoint := obipstring + ":" + strconv.Itoa(*listen_port)
- systemWideLogger.PrintAndLog("Network", "Automatic Port Forwarding Completed. Forwarding all request from "+connectionEndpoint+" to "+localEndpoint, nil)
- }
- }
- }
- func StopNetworkServices() {
- //systemWideLogger.PrintAndLog("Shutting Down Network Services...",nil)
- //Shutdown uPNP service if enabled
- if *allow_upnp {
- systemWideLogger.PrintAndLog("System", "<!> Shutting down uPNP service", nil)
- UPNP.Close()
- }
- //Shutdown SSDP service if enabled
- if *allow_ssdp {
- systemWideLogger.PrintAndLog("System", "<!> Shutting down SSDP service", nil)
- SSDP.Close()
- }
- //Shutdown MDNS if enabled
- if *allow_mdns {
- systemWideLogger.PrintAndLog("System", "<!> Shutting down MDNS service", nil)
- MDNS.Close()
- }
- }
- /*
- File Server Services
- */
- var networkFileServerDaemon []*fileservers.Server = []*fileservers.Server{}
- // 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 request routers
- adminRouter := prout.NewModuleRouter(prout.RouterOption{
- ModuleName: "System Setting",
- AdminOnly: true,
- UserHandler: userHandler,
- DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
- errorHandlePermissionDenied(w, r)
- },
- })
- router := prout.NewModuleRouter(prout.RouterOption{
- ModuleName: "System Setting",
- AdminOnly: false,
- UserHandler: userHandler,
- DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
- utils.SendErrorResponse(w, "Permission Denied")
- },
- })
- //Create File Server Managers
- webdavPort := *listen_port
- if *use_tls {
- webdavPort = *tls_listen_port
- }
- WebDAVManager = webdavserv.NewWebDAVManager(&webdavserv.ManagerOption{
- Sysdb: sysdb,
- Hostname: *host_name,
- TmpDir: *tmp_directory,
- Port: webdavPort,
- UseTls: *use_tls,
- UserHandler: userHandler,
- })
- FTPManager = ftpserv.NewFTPManager(&ftpserv.ManagerOption{
- Hostname: *host_name,
- TmpFolder: *tmp_directory,
- Logger: systemWideLogger,
- UserManager: userHandler,
- FtpServer: nil,
- Sysdb: sysdb,
- Upnp: UPNP,
- AllowUpnp: *allow_upnp,
- })
- SFTPManager = sftpserv.NewSFTPServer(&sftpserv.ManagerOption{
- Hostname: *host_name,
- Upnp: UPNP,
- UserManager: userHandler,
- KeyFile: "system/auth/id_rsa.key",
- Logger: systemWideLogger,
- Sysdb: sysdb,
- })
- listeningPort := *listen_port
- if *use_tls {
- listeningPort = *tls_listen_port
- }
- DirListManager = dirserv.NewDirectoryServer(&dirserv.Option{
- Sysdb: sysdb,
- ServerPort: listeningPort,
- UserManager: userHandler,
- ServerUUID: deviceUUID,
- })
- //Register Endpoints
- //WebDAV
- http.HandleFunc("/system/network/webdav/list", WebDAVManager.HandleConnectionList)
- router.HandleFunc("/system/network/webdav/edit", WebDAVManager.HandlePermissionEdit)
- router.HandleFunc("/system/network/webdav/clear", WebDAVManager.HandleClearAllPending)
- router.HandleFunc("/system/network/webdav/status", WebDAVManager.HandleStatusChange)
- //SFTP
- adminRouter.HandleFunc("/system/storage/sftp/port", SFTPManager.HandleListeningPort)
- adminRouter.HandleFunc("/system/storage/sftp/upnp", SFTPManager.HandleToogleUPnP)
- adminRouter.HandleFunc("/system/storage/sftp/users", SFTPManager.HandleGetConnectedClients)
- //FTP
- //adminRouter.HandleFunc("/system/storage/ftp/start", FTPManager.HandleFTPServerStart)
- //adminRouter.HandleFunc("/system/storage/ftp/stop", FTPManager.HandleFTPServerStop)
- adminRouter.HandleFunc("/system/storage/ftp/upnp", FTPManager.HandleFTPUPnP)
- adminRouter.HandleFunc("/system/storage/ftp/status", FTPManager.HandleFTPServerStatus)
- adminRouter.HandleFunc("/system/storage/ftp/updateGroups", FTPManager.HandleFTPAccessUpdate)
- adminRouter.HandleFunc("/system/storage/ftp/setPort", FTPManager.HandleFTPSetPort)
- adminRouter.HandleFunc("/system/storage/ftp/passivemode", FTPManager.HandleFTPPassiveModeSettings)
- networkFileServerDaemon = append(networkFileServerDaemon, &fileservers.Server{
- ID: "webdav",
- Name: "WebDAV",
- Desc: "WebDAV Server",
- IconPath: "img/system/network-folder-blue.svg",
- DefaultPorts: []int{},
- Ports: []int{},
- ForwardPortIfUpnp: false,
- ConnInstrPage: "SystemAO/disk/instr/webdav.html",
- ConfigPage: "SystemAO/disk/webdav.html",
- EnableCheck: WebDAVManager.GetWebDavEnabled,
- ToggleFunc: WebDAVManager.WebDavToogle,
- GetEndpoints: WebDAVManager.WebDavGetEndpoints,
- })
- networkFileServerDaemon = append(networkFileServerDaemon, &fileservers.Server{
- ID: "sftp",
- Name: "SFTP",
- Desc: "SSH File Transfer Protocol Server",
- IconPath: "img/system/network-folder-sftp.svg",
- DefaultPorts: []int{2022},
- Ports: []int{},
- ForwardPortIfUpnp: true,
- ConnInstrPage: "SystemAO/disk/instr/sftp.html",
- ConfigPage: "SystemAO/disk/sftp.html",
- EnableCheck: SFTPManager.IsEnabled,
- ToggleFunc: SFTPManager.ServerToggle,
- GetEndpoints: SFTPManager.GetEndpoints,
- })
- networkFileServerDaemon = append(networkFileServerDaemon, &fileservers.Server{
- ID: "ftp",
- Name: "FTP",
- Desc: "File Transfer Protocol Server",
- IconPath: "img/system/network-folder.svg",
- DefaultPorts: []int{21, 22, 23},
- Ports: []int{},
- ForwardPortIfUpnp: true,
- ConnInstrPage: "SystemAO/disk/instr/ftp.html",
- ConfigPage: "SystemAO/disk/ftp.html",
- EnableCheck: FTPManager.IsFtpServerEnabled,
- ToggleFunc: FTPManager.FTPServerToggle,
- GetEndpoints: FTPManager.FTPGetEndpoints,
- })
- networkFileServerDaemon = append(networkFileServerDaemon, &fileservers.Server{
- ID: "dirserv",
- Name: "Directory Server",
- Desc: "Web file viewer for legacy devices",
- IconPath: "img/system/network-dirserv.svg",
- DefaultPorts: []int{},
- Ports: []int{},
- ForwardPortIfUpnp: false,
- ConnInstrPage: "SystemAO/disk/instr/dirserv.html",
- ConfigPage: "SystemAO/disk/dirserv.html",
- EnableCheck: DirListManager.DirServerEnabled,
- ToggleFunc: DirListManager.Toggle,
- GetEndpoints: DirListManager.ListEndpoints,
- })
- router.HandleFunc("/system/network/server/list", NetworkHandleGetFileServerServiceList)
- router.HandleFunc("/system/network/server/endpoints", NetworkHandleGetFileServerEndpoints)
- router.HandleFunc("/system/network/server/status", NetworkHandleGetFileServerStatus)
- adminRouter.HandleFunc("/system/network/server/toggle", NetworkHandleFileServerToggle)
- }
- // Toggle the target File Server Services
- func NetworkHandleFileServerToggle(w http.ResponseWriter, r *http.Request) {
- servid, err := utils.PostPara(r, "id")
- if err != nil {
- utils.SendErrorResponse(w, "invalid service id given")
- return
- }
- newState, err := utils.PostPara(r, "enable")
- if err != nil {
- utils.SendErrorResponse(w, "undefined enable state")
- return
- }
- targetfserv := fileservers.GetFileServerById(networkFileServerDaemon, servid)
- if targetfserv == nil {
- utils.SendErrorResponse(w, "target service not exists")
- return
- }
- if newState == "true" {
- //Start up the target service
- err = targetfserv.ToggleFunc(true)
- if err != nil {
- utils.SendErrorResponse(w, "startup failed: "+err.Error())
- return
- }
- } else if newState == "false" {
- err = targetfserv.ToggleFunc(false)
- if err != nil {
- utils.SendErrorResponse(w, "shutdown failed: "+err.Error())
- return
- }
- } else {
- utils.SendErrorResponse(w, "unknown state keyword")
- return
- }
- }
- // Return a list of supported File Server Services
- func NetworkHandleGetFileServerServiceList(w http.ResponseWriter, r *http.Request) {
- js, _ := json.Marshal(networkFileServerDaemon)
- utils.SendJSONResponse(w, string(js))
- }
- // Get the status of a file server type.
- func NetworkHandleGetFileServerStatus(w http.ResponseWriter, r *http.Request) {
- servid, _ := utils.GetPara(r, "id")
- if servid == "" {
- //List all state in map
- result := map[string]bool{}
- for _, fserv := range networkFileServerDaemon {
- result[fserv.ID] = fserv.EnableCheck()
- }
- js, _ := json.Marshal(result)
- utils.SendJSONResponse(w, string(js))
- } else {
- //ID is defined. Get the target server and return its status
- targetfserv := fileservers.GetFileServerById(networkFileServerDaemon, servid)
- if targetfserv == nil {
- utils.SendErrorResponse(w, "target file server type not found")
- return
- }
- js, _ := json.Marshal(targetfserv.EnableCheck())
- utils.SendJSONResponse(w, string(js))
- }
- }
- // Get a list of endpoint usable by this service
- func NetworkHandleGetFileServerEndpoints(w http.ResponseWriter, r *http.Request) {
- userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
- if err != nil {
- utils.SendErrorResponse(w, "user not logged in")
- return
- }
- targetServerTypeID, _ := utils.GetPara(r, "fserv")
- targetServerTypeID = strings.TrimSpace(targetServerTypeID)
- if targetServerTypeID == "" {
- //List all the endpoints
- results := map[string][]*fileservers.Endpoint{}
- for _, fser := range networkFileServerDaemon {
- if fser.GetEndpoints == nil {
- results[fser.ID] = []*fileservers.Endpoint{}
- continue
- }
- thisEndpoints := fser.GetEndpoints(userinfo)
- results[fser.ID] = thisEndpoints
- }
- js, _ := json.Marshal(results)
- utils.SendJSONResponse(w, string(js))
- } else {
- //List the target endpoint
- for _, fser := range networkFileServerDaemon {
- if targetServerTypeID == fser.ID {
- thisEndpoints := fser.GetEndpoints(userinfo)
- js, _ := json.Marshal(thisEndpoints)
- utils.SendJSONResponse(w, string(js))
- return
- }
- }
- utils.SendErrorResponse(w, "target service not found")
- }
- }
|