Răsfoiți Sursa

Deprecated common and replaced with utils

Toby Chui 2 ani în urmă
părinte
comite
b23ce82990
90 a modificat fișierele cu 6498 adăugiri și 6499 ștergeri
  1. 2 2
      agi.go
  2. 30 30
      apt.go
  3. 108 108
      auth.go
  4. 299 299
      console.go
  5. 69 69
      desktop.go
  6. 156 156
      disk.go
  7. 144 144
      file_system.go
  8. 171 171
      hardware.power.go
  9. 104 104
      iot.go
  10. 0 1
      legacy/Photo/static/js/2.09744fc4.chunk.js
  11. 0 0
      legacy/Photo/static/js/2.09744fc4.chunk.js.map
  12. 369 369
      legacy/backup.go.disabled
  13. 5 5
      main.router.go
  14. 342 342
      mediaServer.go
  15. 3 3
      mod/agi/agi.appdata.go
  16. 8 8
      mod/agi/agi.go
  17. 2 2
      mod/agi/agi.image.go
  18. 3 3
      mod/agi/agi.serverless.go
  19. 23 23
      mod/agi/external.agi.go
  20. 5 5
      mod/agi/handler.go
  21. 2 2
      mod/agi/static.go
  22. 2 2
      mod/agi/systemFunc.go
  23. 96 96
      mod/auth/accesscontrol/blacklist/handler.go
  24. 82 82
      mod/auth/accesscontrol/whitelist/handler.go
  25. 8 8
      mod/auth/auth.go
  26. 2 2
      mod/auth/authlogger/authlogger.go
  27. 7 7
      mod/auth/authlogger/handlers.go
  28. 3 3
      mod/auth/autologin.go
  29. 12 12
      mod/auth/autologin/autologin.go
  30. 4 4
      mod/auth/batch.go
  31. 180 180
      mod/auth/ldap/web_admin.go
  32. 220 220
      mod/auth/ldap/web_login.go
  33. 35 35
      mod/auth/oauth2/oauth2.go
  34. 21 21
      mod/auth/register/register.go
  35. 121 121
      mod/disk/diskcapacity/diskcapacity.go
  36. 47 47
      mod/disk/diskmg/diskmg.go
  37. 3 3
      mod/disk/smart/smart.go
  38. 4 4
      mod/disk/sortfile/sortfile.go
  39. 23 23
      mod/fileservers/servers/ftpserv/handler.go
  40. 12 12
      mod/fileservers/servers/sftpserv/sftpserv.go
  41. 6 6
      mod/fileservers/servers/webdavserv/webdavserv.go
  42. 250 250
      mod/filesystem/abstractions/localfs/localfs.go
  43. 5 5
      mod/filesystem/metadata/metadata.go
  44. 2 2
      mod/filesystem/metadata/psd.go
  45. 2 2
      mod/filesystem/metadata/video.go
  46. 52 52
      mod/filesystem/shortcut/shortcut.go
  47. 2 2
      mod/info/hardwareinfo/hardwareinfo.go
  48. 6 6
      mod/info/hardwareinfo/sysinfo_window.go
  49. 14 14
      mod/iot/assits.go
  50. 20 20
      mod/iot/handlerManager.go
  51. 9 9
      mod/modules/installer.go
  52. 18 18
      mod/modules/module.go
  53. 9 9
      mod/network/neighbour/handler.go
  54. 147 147
      mod/network/netstat/netstat.go
  55. 4 4
      mod/network/network.go
  56. 3 3
      mod/permission/group.go
  57. 3 3
      mod/permission/permission.go
  58. 42 42
      mod/permission/request.go
  59. 3 3
      mod/security/csrf/handlers.go
  60. 46 46
      mod/share/share.go
  61. 4 4
      mod/storage/webdav/webdav.go
  62. 27 27
      mod/time/scheduler/handlers.go
  63. 2 2
      mod/time/scheduler/scheduler.go
  64. 2 2
      mod/time/timezone/timezone.go
  65. 182 182
      mod/updates/handler.go
  66. 2 2
      mod/user/directoryHandler.go
  67. 4 4
      mod/user/permissionHandler.go
  68. 16 16
      mod/utils/conv.go
  69. 1 1
      mod/utils/template.go
  70. 1 1
      mod/utils/utils.go
  71. 10 10
      mod/www/handler.go
  72. 2 2
      mod/www/www.go
  73. 197 197
      module.go
  74. 172 172
      network.forward.go
  75. 22 22
      network.go
  76. 70 70
      permission.go
  77. 162 162
      quota.go
  78. 151 151
      register.go
  79. 2 2
      scheduler.go
  80. 55 55
      security.go
  81. 68 68
      setting.advance.go
  82. 6 6
      setting.go
  83. 104 104
      startup.flags.go
  84. 727 727
      storage.pool.go
  85. 83 83
      subservice.go
  86. 213 213
      system.go
  87. 10 10
      system.info.go
  88. 151 151
      system.resetpw.go
  89. 414 414
      user.go
  90. 268 268
      wifi.go

+ 2 - 2
agi.go

@@ -4,8 +4,8 @@ import (
 	"net/http"
 
 	agi "imuslab.com/arozos/mod/agi"
-	"imuslab.com/arozos/mod/common"
 	prout "imuslab.com/arozos/mod/prouter"
+	"imuslab.com/arozos/mod/utils"
 )
 
 var (
@@ -46,7 +46,7 @@ func AGIInit() {
 	//Register external API request handler endpoint
 	http.HandleFunc("/api/ajgi/interface", func(w http.ResponseWriter, r *http.Request) {
 		//Check if token exists
-		token, err := common.Mv(r, "token", true)
+		token, err := utils.Mv(r, "token", true)
 		if err != nil {
 			w.WriteHeader(http.StatusUnauthorized)
 			w.Write([]byte("401 - Unauthorized (token is empty)"))

+ 30 - 30
apt.go

@@ -1,30 +1,30 @@
-package main
-
-import (
-	"net/http"
-
-	apt "imuslab.com/arozos/mod/apt"
-	"imuslab.com/arozos/mod/common"
-	prout "imuslab.com/arozos/mod/prouter"
-)
-
-func PackagManagerInit() {
-	//Create a package manager
-	packageManager = apt.NewPackageManager(*allow_package_autoInstall)
-	systemWideLogger.PrintAndLog("APT", "Package Manager Initiated", nil)
-
-	//Create a System Setting handler
-	//aka who can access System Setting can see contents about packages
-	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")
-		},
-	})
-
-	//Handle package listing request
-	router.HandleFunc("/system/apt/list", apt.HandlePackageListRequest)
-
-}
+package main
+
+import (
+	"net/http"
+
+	apt "imuslab.com/arozos/mod/apt"
+	prout "imuslab.com/arozos/mod/prouter"
+	"imuslab.com/arozos/mod/utils"
+)
+
+func PackagManagerInit() {
+	//Create a package manager
+	packageManager = apt.NewPackageManager(*allow_package_autoInstall)
+	systemWideLogger.PrintAndLog("APT", "Package Manager Initiated", nil)
+
+	//Create a System Setting handler
+	//aka who can access System Setting can see contents about packages
+	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")
+		},
+	})
+
+	//Handle package listing request
+	router.HandleFunc("/system/apt/list", apt.HandlePackageListRequest)
+
+}

+ 108 - 108
auth.go

@@ -1,108 +1,108 @@
-package main
-
-import (
-	"crypto/rand"
-	"net/http"
-
-	auth "imuslab.com/arozos/mod/auth"
-	"imuslab.com/arozos/mod/common"
-	prout "imuslab.com/arozos/mod/prouter"
-)
-
-func AuthInit() {
-	//Generate session key for authentication module if empty
-	sysdb.NewTable("auth")
-	if *session_key == "" {
-		//Check if the key was generated already. If not, generate a new one
-		if !sysdb.KeyExists("auth", "sessionkey") {
-			key := make([]byte, 32)
-			rand.Read(key)
-			newSessionKey := string(key)
-			sysdb.Write("auth", "sessionkey", newSessionKey)
-			systemWideLogger.PrintAndLog("Auth", "New authentication session key generated", nil)
-		} else {
-			systemWideLogger.PrintAndLog("Auth", "Authentication session key loaded from database", nil)
-
-		}
-		skeyString := ""
-		sysdb.Read("auth", "sessionkey", &skeyString)
-		session_key = &skeyString
-	}
-
-	//Create an Authentication Agent
-	authAgent = auth.NewAuthenticationAgent("ao_auth", []byte(*session_key), sysdb, *allow_public_registry, func(w http.ResponseWriter, r *http.Request) {
-		//Login Redirection Handler, redirect it login.system
-		w.Header().Set("Cache-Control", "no-cache, no-store, no-transform, must-revalidate, private, max-age=0")
-		http.Redirect(w, r, common.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect="+r.URL.Path, 307)
-	})
-
-	if *allow_autologin {
-		authAgent.AllowAutoLogin = true
-	} else {
-		//Default is false. But just in case
-		authAgent.AllowAutoLogin = false
-	}
-
-	//Register the API endpoints for the authentication UI
-	http.HandleFunc("/system/auth/login", authAgent.HandleLogin)
-	http.HandleFunc("/system/auth/logout", authAgent.HandleLogout)
-	http.HandleFunc("/system/auth/register", authAgent.HandleRegister)
-	http.HandleFunc("/system/auth/checkLogin", authAgent.CheckLogin)
-	http.HandleFunc("/api/auth/login", authAgent.HandleAutologinTokenLogin)
-
-	authAgent.LoadAutologinTokenFromDB()
-}
-
-func AuthSettingsInit() {
-	//Authentication related settings
-	adminRouter := prout.NewModuleRouter(prout.RouterOption{
-		ModuleName:  "System Setting",
-		AdminOnly:   true,
-		UserHandler: userHandler,
-		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
-		},
-	})
-
-	//Handle additional batch operations
-	adminRouter.HandleFunc("/system/auth/csvimport", authAgent.HandleCreateUserAccountsFromCSV)
-	adminRouter.HandleFunc("/system/auth/groupdel", authAgent.HandleUserDeleteByGroup)
-
-	//System for logging and displaying login user information
-	registerSetting(settingModule{
-		Name:         "Connection Log",
-		Desc:         "Logs for login attempts",
-		IconPath:     "SystemAO/security/img/small_icon.png",
-		Group:        "Security",
-		StartDir:     "SystemAO/security/connlog.html",
-		RequireAdmin: true,
-	})
-
-	adminRouter.HandleFunc("/system/auth/logger/index", authAgent.Logger.HandleIndexListing)
-	adminRouter.HandleFunc("/system/auth/logger/list", authAgent.Logger.HandleTableListing)
-
-	//Blacklist Management
-	registerSetting(settingModule{
-		Name:         "Access Control",
-		Desc:         "Prevent / Allow certain IP ranges from logging in",
-		IconPath:     "SystemAO/security/img/small_icon.png",
-		Group:        "Security",
-		StartDir:     "SystemAO/security/accesscontrol.html",
-		RequireAdmin: true,
-	})
-
-	//Whitelist API
-	adminRouter.HandleFunc("/system/auth/whitelist/enable", authAgent.WhitelistManager.HandleSetWhitelistEnable)
-	adminRouter.HandleFunc("/system/auth/whitelist/list", authAgent.WhitelistManager.HandleListWhitelistedIPs)
-	adminRouter.HandleFunc("/system/auth/whitelist/set", authAgent.WhitelistManager.HandleAddWhitelistedIP)
-	adminRouter.HandleFunc("/system/auth/whitelist/unset", authAgent.WhitelistManager.HandleRemoveWhitelistedIP)
-
-	//Blacklist API
-	adminRouter.HandleFunc("/system/auth/blacklist/enable", authAgent.BlacklistManager.HandleSetBlacklistEnable)
-	adminRouter.HandleFunc("/system/auth/blacklist/list", authAgent.BlacklistManager.HandleListBannedIPs)
-	adminRouter.HandleFunc("/system/auth/blacklist/ban", authAgent.BlacklistManager.HandleAddBannedIP)
-	adminRouter.HandleFunc("/system/auth/blacklist/unban", authAgent.BlacklistManager.HandleRemoveBannedIP)
-
-	//Register nightly task for clearup all user retry counter
-	nightlyManager.RegisterNightlyTask(authAgent.ExpDelayHandler.ResetAllUserRetryCounter)
-}
+package main
+
+import (
+	"crypto/rand"
+	"net/http"
+
+	auth "imuslab.com/arozos/mod/auth"
+	prout "imuslab.com/arozos/mod/prouter"
+	"imuslab.com/arozos/mod/utils"
+)
+
+func AuthInit() {
+	//Generate session key for authentication module if empty
+	sysdb.NewTable("auth")
+	if *session_key == "" {
+		//Check if the key was generated already. If not, generate a new one
+		if !sysdb.KeyExists("auth", "sessionkey") {
+			key := make([]byte, 32)
+			rand.Read(key)
+			newSessionKey := string(key)
+			sysdb.Write("auth", "sessionkey", newSessionKey)
+			systemWideLogger.PrintAndLog("Auth", "New authentication session key generated", nil)
+		} else {
+			systemWideLogger.PrintAndLog("Auth", "Authentication session key loaded from database", nil)
+
+		}
+		skeyString := ""
+		sysdb.Read("auth", "sessionkey", &skeyString)
+		session_key = &skeyString
+	}
+
+	//Create an Authentication Agent
+	authAgent = auth.NewAuthenticationAgent("ao_auth", []byte(*session_key), sysdb, *allow_public_registry, func(w http.ResponseWriter, r *http.Request) {
+		//Login Redirection Handler, redirect it login.system
+		w.Header().Set("Cache-Control", "no-cache, no-store, no-transform, must-revalidate, private, max-age=0")
+		http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect="+r.URL.Path, 307)
+	})
+
+	if *allow_autologin {
+		authAgent.AllowAutoLogin = true
+	} else {
+		//Default is false. But just in case
+		authAgent.AllowAutoLogin = false
+	}
+
+	//Register the API endpoints for the authentication UI
+	http.HandleFunc("/system/auth/login", authAgent.HandleLogin)
+	http.HandleFunc("/system/auth/logout", authAgent.HandleLogout)
+	http.HandleFunc("/system/auth/register", authAgent.HandleRegister)
+	http.HandleFunc("/system/auth/checkLogin", authAgent.CheckLogin)
+	http.HandleFunc("/api/auth/login", authAgent.HandleAutologinTokenLogin)
+
+	authAgent.LoadAutologinTokenFromDB()
+}
+
+func AuthSettingsInit() {
+	//Authentication related settings
+	adminRouter := prout.NewModuleRouter(prout.RouterOption{
+		ModuleName:  "System Setting",
+		AdminOnly:   true,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			utils.SendErrorResponse(w, "Permission Denied")
+		},
+	})
+
+	//Handle additional batch operations
+	adminRouter.HandleFunc("/system/auth/csvimport", authAgent.HandleCreateUserAccountsFromCSV)
+	adminRouter.HandleFunc("/system/auth/groupdel", authAgent.HandleUserDeleteByGroup)
+
+	//System for logging and displaying login user information
+	registerSetting(settingModule{
+		Name:         "Connection Log",
+		Desc:         "Logs for login attempts",
+		IconPath:     "SystemAO/security/img/small_icon.png",
+		Group:        "Security",
+		StartDir:     "SystemAO/security/connlog.html",
+		RequireAdmin: true,
+	})
+
+	adminRouter.HandleFunc("/system/auth/logger/index", authAgent.Logger.HandleIndexListing)
+	adminRouter.HandleFunc("/system/auth/logger/list", authAgent.Logger.HandleTableListing)
+
+	//Blacklist Management
+	registerSetting(settingModule{
+		Name:         "Access Control",
+		Desc:         "Prevent / Allow certain IP ranges from logging in",
+		IconPath:     "SystemAO/security/img/small_icon.png",
+		Group:        "Security",
+		StartDir:     "SystemAO/security/accesscontrol.html",
+		RequireAdmin: true,
+	})
+
+	//Whitelist API
+	adminRouter.HandleFunc("/system/auth/whitelist/enable", authAgent.WhitelistManager.HandleSetWhitelistEnable)
+	adminRouter.HandleFunc("/system/auth/whitelist/list", authAgent.WhitelistManager.HandleListWhitelistedIPs)
+	adminRouter.HandleFunc("/system/auth/whitelist/set", authAgent.WhitelistManager.HandleAddWhitelistedIP)
+	adminRouter.HandleFunc("/system/auth/whitelist/unset", authAgent.WhitelistManager.HandleRemoveWhitelistedIP)
+
+	//Blacklist API
+	adminRouter.HandleFunc("/system/auth/blacklist/enable", authAgent.BlacklistManager.HandleSetBlacklistEnable)
+	adminRouter.HandleFunc("/system/auth/blacklist/list", authAgent.BlacklistManager.HandleListBannedIPs)
+	adminRouter.HandleFunc("/system/auth/blacklist/ban", authAgent.BlacklistManager.HandleAddBannedIP)
+	adminRouter.HandleFunc("/system/auth/blacklist/unban", authAgent.BlacklistManager.HandleRemoveBannedIP)
+
+	//Register nightly task for clearup all user retry counter
+	nightlyManager.RegisterNightlyTask(authAgent.ExpDelayHandler.ResetAllUserRetryCounter)
+}

+ 299 - 299
console.go

@@ -1,299 +1,299 @@
-package main
-
-import (
-	"encoding/json"
-	"errors"
-	"fmt"
-	"io/ioutil"
-	"strings"
-
-	"imuslab.com/arozos/mod/common"
-)
-
-//Handle console command from the console module
-func consoleCommandHandler(input string) string {
-	//chunk := strings.Split(input, " ");
-	chunk, err := parseCommandLine(input)
-	if err != nil {
-		return err.Error()
-	}
-	if len(chunk) > 0 && chunk[0] == "auth" {
-		if matchSubfix(chunk, []string{"auth", "new"}, 4, "auth new {username} {password}") {
-			return "Creating a new user " + chunk[2] + " with password " + chunk[3]
-		} else if matchSubfix(chunk, []string{"auth", "dump"}, 4, "auth dump {filename}.csv") {
-			filename := chunk[2]
-			fmt.Println("Dumping user list to " + filename + " csv file")
-			csv := authAgent.ExportUserListAsCSV()
-			err := ioutil.WriteFile(filename, []byte(csv), 0755)
-			if err != nil {
-				return err.Error()
-			}
-			return "OK"
-		}
-	} else if len(chunk) > 0 && chunk[0] == "permission" {
-		if matchSubfix(chunk, []string{"permission", "list"}, 2, "") {
-			fmt.Println("> ", permissionHandler.PermissionGroups)
-			return "OK"
-		} else if matchSubfix(chunk, []string{"permission", "user"}, 3, "permission user {username}") {
-			username := chunk[2]
-			group, _ := permissionHandler.GetUsersPermissionGroup(username)
-			for _, thisGroup := range group {
-				fmt.Println(thisGroup)
-			}
-			return "OK"
-		} else if matchSubfix(chunk, []string{"permission", "group"}, 3, "permission group {groupname}") {
-			groupname := chunk[2]
-			groups := permissionHandler.PermissionGroups
-			for _, thisGroup := range groups {
-				if thisGroup.Name == groupname {
-					fmt.Println(thisGroup)
-				}
-			}
-			return "OK"
-		} else if matchSubfix(chunk, []string{"permission", "getinterface"}, 3, "permission getinterface {username}") {
-			//Get the list of interface module for this user
-			userinfo, err := userHandler.GetUserInfoFromUsername(chunk[2])
-			if err != nil {
-				return err.Error()
-			}
-			return strings.Join(userinfo.GetInterfaceModules(), ",")
-		}
-	} else if len(chunk) > 0 && chunk[0] == "quota" {
-		if matchSubfix(chunk, []string{"quota", "user"}, 3, "quota user {username}") {
-			userinfo, err := userHandler.GetUserInfoFromUsername(chunk[2])
-			if err != nil {
-				return err.Error()
-			}
-
-			fmt.Println("> "+"User Quota: ", userinfo.StorageQuota.UsedStorageQuota, "/", userinfo.StorageQuota.GetUserStorageQuota(), "bytes")
-			return "OK"
-		}
-	} else if len(chunk) > 0 && chunk[0] == "database" {
-		if matchSubfix(chunk, []string{"database", "dump"}, 3, "database dump {filename}") {
-			//Dump the database to file
-
-			return "WIP"
-		} else if matchSubfix(chunk, []string{"database", "list", "tables"}, 3, "") {
-			//List all opened tables
-			sysdb.Tables.Range(func(k, v interface{}) bool {
-				fmt.Println(k.(string))
-				return true
-			})
-			return "OK"
-		} else if matchSubfix(chunk, []string{"database", "view"}, 3, "database list {tablename}") {
-			//List everything in this table
-			tableList := []string{}
-
-			sysdb.Tables.Range(func(k, v interface{}) bool {
-				tableList = append(tableList, k.(string))
-				return true
-			})
-			if !common.StringInArray(tableList, chunk[2]) {
-				return "Table not exists"
-			} else if chunk[2] == "auth" {
-				return "You cannot view this database table"
-			}
-			entries, err := sysdb.ListTable(chunk[2])
-			if err != nil {
-				return err.Error()
-			}
-
-			for _, keypairs := range entries {
-				fmt.Println("> " + string(keypairs[0]) + ":" + string(keypairs[1]))
-			}
-
-			fmt.Println("Total Entry Count: ", len(entries))
-			return "OK"
-		}
-	} else if len(chunk) > 0 && chunk[0] == "user" {
-		if matchSubfix(chunk, []string{"user", "object", "dump"}, 4, "user object dump {username}") {
-			//Dump the given user object as json
-			userinfo, err := userHandler.GetUserInfoFromUsername(chunk[3])
-			if err != nil {
-				return err.Error()
-			}
-
-			jsonString, _ := json.Marshal(userinfo)
-			return string(jsonString)
-		} else if matchSubfix(chunk, []string{"user", "quota"}, 3, "user quota {username}") {
-			//List user quota of the given username
-			userinfo, err := userHandler.GetUserInfoFromUsername(chunk[2])
-			if err != nil {
-				return err.Error()
-			}
-
-			fmt.Println(userinfo.StorageQuota.UsedStorageQuota, "/", userinfo.StorageQuota.TotalStorageQuota)
-			return "OK"
-		}
-	} else if len(chunk) > 0 && chunk[0] == "storage" {
-		if matchSubfix(chunk, []string{"storage", "list", "basepool"}, 3, "") {
-			//Dump the base storage pool
-			jsonString, _ := json.Marshal(userHandler.GetStoragePool())
-			return string(jsonString)
-		}
-	} else if len(chunk) > 0 && chunk[0] == "scan" {
-		if matchSubfix(chunk, []string{"scan", "all"}, 2, "") {
-			//scan all nearby arozos units
-			fmt.Println("Scanning (Should take around 10s)")
-			hosts := MDNS.Scan(10, "")
-			for _, host := range hosts {
-				fmt.Println(host)
-			}
-			return "OK"
-		} else if matchSubfix(chunk, []string{"scan", "aroz"}, 2, "") || matchSubfix(chunk, []string{"scan", "arozos"}, 2, "") {
-			//scan all nearby arozos units
-			fmt.Println("Scanning nearybe ArozOS Hosts (Should take around 10s)")
-			hosts := MDNS.Scan(10, "arozos.com")
-			for _, host := range hosts {
-				fmt.Println(host)
-			}
-			return "OK"
-		}
-	} else if len(chunk) > 0 && chunk[0] == "find" {
-		if matchSubfix(chunk, []string{"find", "module"}, 3, "list module {modulename}") {
-			//Display all loaded modules
-			for _, module := range moduleHandler.LoadedModule {
-				if strings.ToLower(module.Name) == strings.ToLower(chunk[2]) {
-					jsonString, _ := json.Marshal(module)
-					return string(jsonString)
-				}
-			}
-			return string("Module not found")
-
-		} else if matchSubfix(chunk, []string{"find", "modules"}, 2, "") {
-			//Display all loaded modules
-			jsonString, _ := json.Marshal(moduleHandler.LoadedModule)
-			return string(jsonString)
-		} else if matchSubfix(chunk, []string{"find", "subservices"}, 2, "") {
-			//Display all loaded subservices
-			fmt.Println(ssRouter.RunningSubService)
-			return "OK"
-		}
-	} else if len(chunk) > 0 && chunk[0] == "access" {
-		//Handle emergency situation where the user is blocked by himself
-		if matchSubfix(chunk, []string{"access", "whitelist", "disable"}, 3, "") {
-			//Disable whitelist
-			authAgent.WhitelistManager.SetWhitelistEnabled(false)
-			return "Whitelist Disabled"
-		} else if matchSubfix(chunk, []string{"access", "whitelist", "enable"}, 3, "") {
-			//Enable whitelist
-			authAgent.WhitelistManager.SetWhitelistEnabled(true)
-			return "Whitelist Enabled"
-		} else if matchSubfix(chunk, []string{"access", "whitelist", "add"}, 4, "access whitelist add {ip_range}") {
-			err = authAgent.WhitelistManager.SetWhitelist(chunk[3])
-			if err != nil {
-				return err.Error()
-			}
-			return "OK"
-		} else if matchSubfix(chunk, []string{"access", "whitelist", "del"}, 4, "access whitelist del {ip_range}") {
-			err = authAgent.WhitelistManager.UnsetWhitelist(chunk[3])
-			if err != nil {
-				return err.Error()
-			}
-			return "OK"
-		} else if matchSubfix(chunk, []string{"access", "blacklist", "enable"}, 3, "") {
-			//Enable blacklist
-			authAgent.WhitelistManager.SetWhitelistEnabled(true)
-			return "Blacklist Enabled"
-		} else if matchSubfix(chunk, []string{"access", "blacklist", "disable"}, 3, "") {
-			//Disable blacklist
-			authAgent.BlacklistManager.SetBlacklistEnabled(false)
-			return "Blacklist Disabled"
-		} else {
-			return "[Whitelist / Blacklist Console Control API] \nUsage: access {whitelist/blacklist} {action} {data}"
-		}
-	} else if len(chunk) == 1 && chunk[0] == "stop" {
-		//Stopping the server
-		fmt.Println("Shutting down aroz online system by terminal request")
-		executeShutdownSequence()
-	}
-
-	return "Invalid Command. Given: '" + strings.Join(chunk, " ") + "'"
-}
-
-//Check if the given line input match the requirement
-func matchSubfix(chunk []string, match []string, minlength int, usageExample string) bool {
-	matching := true
-	//Check if the chunk contains minmium length of the command request
-	if len(chunk) >= len(match) {
-		for i, cchunk := range match {
-			if chunk[i] != cchunk {
-				matching = false
-			}
-		}
-	} else {
-		matching = false
-	}
-
-	if len(chunk)-minlength == -1 && chunk[len(chunk)-1] == match[len(match)-1] {
-		fmt.Println("Paramter missing. Usage: " + usageExample)
-		return false
-	}
-
-	return matching
-}
-
-func parseCommandLine(command string) ([]string, error) {
-	var args []string
-	state := "start"
-	current := ""
-	quote := "\""
-	escapeNext := true
-	for i := 0; i < len(command); i++ {
-		c := command[i]
-
-		if state == "quotes" {
-			if string(c) != quote {
-				current += string(c)
-			} else {
-				args = append(args, current)
-				current = ""
-				state = "start"
-			}
-			continue
-		}
-
-		if escapeNext {
-			current += string(c)
-			escapeNext = false
-			continue
-		}
-
-		if c == '\\' {
-			escapeNext = true
-			continue
-		}
-
-		if c == '"' || c == '\'' {
-			state = "quotes"
-			quote = string(c)
-			continue
-		}
-
-		if state == "arg" {
-			if c == ' ' || c == '\t' {
-				args = append(args, current)
-				current = ""
-				state = "start"
-			} else {
-				current += string(c)
-			}
-			continue
-		}
-
-		if c != ' ' && c != '\t' {
-			state = "arg"
-			current += string(c)
-		}
-	}
-
-	if state == "quotes" {
-		return []string{}, errors.New(fmt.Sprintf("Unclosed quote in command line: %s", command))
-	}
-
-	if current != "" {
-		args = append(args, current)
-	}
-
-	return args, nil
-}
+package main
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"strings"
+
+	"imuslab.com/arozos/mod/utils"
+)
+
+//Handle console command from the console module
+func consoleCommandHandler(input string) string {
+	//chunk := strings.Split(input, " ");
+	chunk, err := parseCommandLine(input)
+	if err != nil {
+		return err.Error()
+	}
+	if len(chunk) > 0 && chunk[0] == "auth" {
+		if matchSubfix(chunk, []string{"auth", "new"}, 4, "auth new {username} {password}") {
+			return "Creating a new user " + chunk[2] + " with password " + chunk[3]
+		} else if matchSubfix(chunk, []string{"auth", "dump"}, 4, "auth dump {filename}.csv") {
+			filename := chunk[2]
+			fmt.Println("Dumping user list to " + filename + " csv file")
+			csv := authAgent.ExportUserListAsCSV()
+			err := ioutil.WriteFile(filename, []byte(csv), 0755)
+			if err != nil {
+				return err.Error()
+			}
+			return "OK"
+		}
+	} else if len(chunk) > 0 && chunk[0] == "permission" {
+		if matchSubfix(chunk, []string{"permission", "list"}, 2, "") {
+			fmt.Println("> ", permissionHandler.PermissionGroups)
+			return "OK"
+		} else if matchSubfix(chunk, []string{"permission", "user"}, 3, "permission user {username}") {
+			username := chunk[2]
+			group, _ := permissionHandler.GetUsersPermissionGroup(username)
+			for _, thisGroup := range group {
+				fmt.Println(thisGroup)
+			}
+			return "OK"
+		} else if matchSubfix(chunk, []string{"permission", "group"}, 3, "permission group {groupname}") {
+			groupname := chunk[2]
+			groups := permissionHandler.PermissionGroups
+			for _, thisGroup := range groups {
+				if thisGroup.Name == groupname {
+					fmt.Println(thisGroup)
+				}
+			}
+			return "OK"
+		} else if matchSubfix(chunk, []string{"permission", "getinterface"}, 3, "permission getinterface {username}") {
+			//Get the list of interface module for this user
+			userinfo, err := userHandler.GetUserInfoFromUsername(chunk[2])
+			if err != nil {
+				return err.Error()
+			}
+			return strings.Join(userinfo.GetInterfaceModules(), ",")
+		}
+	} else if len(chunk) > 0 && chunk[0] == "quota" {
+		if matchSubfix(chunk, []string{"quota", "user"}, 3, "quota user {username}") {
+			userinfo, err := userHandler.GetUserInfoFromUsername(chunk[2])
+			if err != nil {
+				return err.Error()
+			}
+
+			fmt.Println("> "+"User Quota: ", userinfo.StorageQuota.UsedStorageQuota, "/", userinfo.StorageQuota.GetUserStorageQuota(), "bytes")
+			return "OK"
+		}
+	} else if len(chunk) > 0 && chunk[0] == "database" {
+		if matchSubfix(chunk, []string{"database", "dump"}, 3, "database dump {filename}") {
+			//Dump the database to file
+
+			return "WIP"
+		} else if matchSubfix(chunk, []string{"database", "list", "tables"}, 3, "") {
+			//List all opened tables
+			sysdb.Tables.Range(func(k, v interface{}) bool {
+				fmt.Println(k.(string))
+				return true
+			})
+			return "OK"
+		} else if matchSubfix(chunk, []string{"database", "view"}, 3, "database list {tablename}") {
+			//List everything in this table
+			tableList := []string{}
+
+			sysdb.Tables.Range(func(k, v interface{}) bool {
+				tableList = append(tableList, k.(string))
+				return true
+			})
+			if !utils.StringInArray(tableList, chunk[2]) {
+				return "Table not exists"
+			} else if chunk[2] == "auth" {
+				return "You cannot view this database table"
+			}
+			entries, err := sysdb.ListTable(chunk[2])
+			if err != nil {
+				return err.Error()
+			}
+
+			for _, keypairs := range entries {
+				fmt.Println("> " + string(keypairs[0]) + ":" + string(keypairs[1]))
+			}
+
+			fmt.Println("Total Entry Count: ", len(entries))
+			return "OK"
+		}
+	} else if len(chunk) > 0 && chunk[0] == "user" {
+		if matchSubfix(chunk, []string{"user", "object", "dump"}, 4, "user object dump {username}") {
+			//Dump the given user object as json
+			userinfo, err := userHandler.GetUserInfoFromUsername(chunk[3])
+			if err != nil {
+				return err.Error()
+			}
+
+			jsonString, _ := json.Marshal(userinfo)
+			return string(jsonString)
+		} else if matchSubfix(chunk, []string{"user", "quota"}, 3, "user quota {username}") {
+			//List user quota of the given username
+			userinfo, err := userHandler.GetUserInfoFromUsername(chunk[2])
+			if err != nil {
+				return err.Error()
+			}
+
+			fmt.Println(userinfo.StorageQuota.UsedStorageQuota, "/", userinfo.StorageQuota.TotalStorageQuota)
+			return "OK"
+		}
+	} else if len(chunk) > 0 && chunk[0] == "storage" {
+		if matchSubfix(chunk, []string{"storage", "list", "basepool"}, 3, "") {
+			//Dump the base storage pool
+			jsonString, _ := json.Marshal(userHandler.GetStoragePool())
+			return string(jsonString)
+		}
+	} else if len(chunk) > 0 && chunk[0] == "scan" {
+		if matchSubfix(chunk, []string{"scan", "all"}, 2, "") {
+			//scan all nearby arozos units
+			fmt.Println("Scanning (Should take around 10s)")
+			hosts := MDNS.Scan(10, "")
+			for _, host := range hosts {
+				fmt.Println(host)
+			}
+			return "OK"
+		} else if matchSubfix(chunk, []string{"scan", "aroz"}, 2, "") || matchSubfix(chunk, []string{"scan", "arozos"}, 2, "") {
+			//scan all nearby arozos units
+			fmt.Println("Scanning nearybe ArozOS Hosts (Should take around 10s)")
+			hosts := MDNS.Scan(10, "arozos.com")
+			for _, host := range hosts {
+				fmt.Println(host)
+			}
+			return "OK"
+		}
+	} else if len(chunk) > 0 && chunk[0] == "find" {
+		if matchSubfix(chunk, []string{"find", "module"}, 3, "list module {modulename}") {
+			//Display all loaded modules
+			for _, module := range moduleHandler.LoadedModule {
+				if strings.ToLower(module.Name) == strings.ToLower(chunk[2]) {
+					jsonString, _ := json.Marshal(module)
+					return string(jsonString)
+				}
+			}
+			return string("Module not found")
+
+		} else if matchSubfix(chunk, []string{"find", "modules"}, 2, "") {
+			//Display all loaded modules
+			jsonString, _ := json.Marshal(moduleHandler.LoadedModule)
+			return string(jsonString)
+		} else if matchSubfix(chunk, []string{"find", "subservices"}, 2, "") {
+			//Display all loaded subservices
+			fmt.Println(ssRouter.RunningSubService)
+			return "OK"
+		}
+	} else if len(chunk) > 0 && chunk[0] == "access" {
+		//Handle emergency situation where the user is blocked by himself
+		if matchSubfix(chunk, []string{"access", "whitelist", "disable"}, 3, "") {
+			//Disable whitelist
+			authAgent.WhitelistManager.SetWhitelistEnabled(false)
+			return "Whitelist Disabled"
+		} else if matchSubfix(chunk, []string{"access", "whitelist", "enable"}, 3, "") {
+			//Enable whitelist
+			authAgent.WhitelistManager.SetWhitelistEnabled(true)
+			return "Whitelist Enabled"
+		} else if matchSubfix(chunk, []string{"access", "whitelist", "add"}, 4, "access whitelist add {ip_range}") {
+			err = authAgent.WhitelistManager.SetWhitelist(chunk[3])
+			if err != nil {
+				return err.Error()
+			}
+			return "OK"
+		} else if matchSubfix(chunk, []string{"access", "whitelist", "del"}, 4, "access whitelist del {ip_range}") {
+			err = authAgent.WhitelistManager.UnsetWhitelist(chunk[3])
+			if err != nil {
+				return err.Error()
+			}
+			return "OK"
+		} else if matchSubfix(chunk, []string{"access", "blacklist", "enable"}, 3, "") {
+			//Enable blacklist
+			authAgent.WhitelistManager.SetWhitelistEnabled(true)
+			return "Blacklist Enabled"
+		} else if matchSubfix(chunk, []string{"access", "blacklist", "disable"}, 3, "") {
+			//Disable blacklist
+			authAgent.BlacklistManager.SetBlacklistEnabled(false)
+			return "Blacklist Disabled"
+		} else {
+			return "[Whitelist / Blacklist Console Control API] \nUsage: access {whitelist/blacklist} {action} {data}"
+		}
+	} else if len(chunk) == 1 && chunk[0] == "stop" {
+		//Stopping the server
+		fmt.Println("Shutting down aroz online system by terminal request")
+		executeShutdownSequence()
+	}
+
+	return "Invalid Command. Given: '" + strings.Join(chunk, " ") + "'"
+}
+
+//Check if the given line input match the requirement
+func matchSubfix(chunk []string, match []string, minlength int, usageExample string) bool {
+	matching := true
+	//Check if the chunk contains minmium length of the command request
+	if len(chunk) >= len(match) {
+		for i, cchunk := range match {
+			if chunk[i] != cchunk {
+				matching = false
+			}
+		}
+	} else {
+		matching = false
+	}
+
+	if len(chunk)-minlength == -1 && chunk[len(chunk)-1] == match[len(match)-1] {
+		fmt.Println("Paramter missing. Usage: " + usageExample)
+		return false
+	}
+
+	return matching
+}
+
+func parseCommandLine(command string) ([]string, error) {
+	var args []string
+	state := "start"
+	current := ""
+	quote := "\""
+	escapeNext := true
+	for i := 0; i < len(command); i++ {
+		c := command[i]
+
+		if state == "quotes" {
+			if string(c) != quote {
+				current += string(c)
+			} else {
+				args = append(args, current)
+				current = ""
+				state = "start"
+			}
+			continue
+		}
+
+		if escapeNext {
+			current += string(c)
+			escapeNext = false
+			continue
+		}
+
+		if c == '\\' {
+			escapeNext = true
+			continue
+		}
+
+		if c == '"' || c == '\'' {
+			state = "quotes"
+			quote = string(c)
+			continue
+		}
+
+		if state == "arg" {
+			if c == ' ' || c == '\t' {
+				args = append(args, current)
+				current = ""
+				state = "start"
+			} else {
+				current += string(c)
+			}
+			continue
+		}
+
+		if c != ' ' && c != '\t' {
+			state = "arg"
+			current += string(c)
+		}
+	}
+
+	if state == "quotes" {
+		return []string{}, errors.New(fmt.Sprintf("Unclosed quote in command line: %s", command))
+	}
+
+	if current != "" {
+		args = append(args, current)
+	}
+
+	return args, nil
+}

+ 69 - 69
desktop.go

@@ -11,12 +11,12 @@ import (
 	"strconv"
 	"strings"
 
-	"imuslab.com/arozos/mod/common"
 	fs "imuslab.com/arozos/mod/filesystem"
 	"imuslab.com/arozos/mod/filesystem/arozfs"
 	"imuslab.com/arozos/mod/filesystem/shortcut"
 	module "imuslab.com/arozos/mod/modules"
 	prout "imuslab.com/arozos/mod/prouter"
+	"imuslab.com/arozos/mod/utils"
 )
 
 //Desktop script initiation
@@ -28,7 +28,7 @@ func DesktopInit() {
 		AdminOnly:   false,
 		UserHandler: userHandler,
 		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
+			utils.SendErrorResponse(w, "Permission Denied")
 		},
 	})
 
@@ -118,28 +118,28 @@ func desktop_hostdetailHandler(w http.ResponseWriter, r *http.Request) {
 		VendorIcon:      iconVendor,
 	})
 
-	common.SendJSONResponse(w, string(jsonString))
+	utils.SendJSONResponse(w, string(jsonString))
 }
 
 func desktop_handleShortcutRename(w http.ResponseWriter, r *http.Request) {
 	//Check if the user directory already exists
 	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 
 	//Get the shortcut file that is renaming
-	target, err := common.Mv(r, "src", false)
+	target, err := utils.Mv(r, "src", false)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid shortcut file path given")
+		utils.SendErrorResponse(w, "Invalid shortcut file path given")
 		return
 	}
 
 	//Get the new name
-	new, err := common.Mv(r, "new", false)
+	new, err := utils.Mv(r, "new", false)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid new name given")
+		utils.SendErrorResponse(w, "Invalid new name given")
 		return
 	}
 
@@ -149,31 +149,31 @@ func desktop_handleShortcutRename(w http.ResponseWriter, r *http.Request) {
 	//Check if the file actually exists and it is on desktop
 	rpath, err := fshAbs.VirtualPathToRealPath(subpath, userinfo.Username)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
 	if target[:14] != "user:/Desktop/" {
-		common.SendErrorResponse(w, "Shortcut not on desktop")
+		utils.SendErrorResponse(w, "Shortcut not on desktop")
 		return
 	}
 
 	if !fshAbs.FileExists(rpath) {
-		common.SendErrorResponse(w, "File not exists")
+		utils.SendErrorResponse(w, "File not exists")
 		return
 	}
 
 	//OK. Change the name of the shortcut
 	originalShortcut, err := fshAbs.ReadFile(rpath)
 	if err != nil {
-		common.SendErrorResponse(w, "Shortcut file read failed")
+		utils.SendErrorResponse(w, "Shortcut file read failed")
 		return
 	}
 
 	lines := strings.Split(string(originalShortcut), "\n")
 	if len(lines) < 4 {
 		//Invalid shortcut properties
-		common.SendErrorResponse(w, "Invalid shortcut file")
+		utils.SendErrorResponse(w, "Invalid shortcut file")
 		return
 	}
 
@@ -182,10 +182,10 @@ func desktop_handleShortcutRename(w http.ResponseWriter, r *http.Request) {
 	newShortcutContent := strings.Join(lines, "\n")
 	err = fshAbs.WriteFile(rpath, []byte(newShortcutContent), 0755)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
-	common.SendOK(w)
+	utils.SendOK(w)
 }
 
 func desktop_listFiles(w http.ResponseWriter, r *http.Request) {
@@ -199,7 +199,7 @@ func desktop_listFiles(w http.ResponseWriter, r *http.Request) {
 	//List all files inside the user desktop directory
 	fsh, subpath, err := GetFSHandlerSubpathFromVpath("user:/Desktop/")
 	if err != nil {
-		common.SendErrorResponse(w, "Desktop file load failed")
+		utils.SendErrorResponse(w, "Desktop file load failed")
 		return
 	}
 	fshAbs := fsh.FileSystemAbstraction
@@ -207,7 +207,7 @@ func desktop_listFiles(w http.ResponseWriter, r *http.Request) {
 
 	files, err := fshAbs.Glob(userDesktopRealpath + "/*")
 	if err != nil {
-		common.SendErrorResponse(w, "Desktop file load failed")
+		utils.SendErrorResponse(w, "Desktop file load failed")
 		return
 	}
 
@@ -291,7 +291,7 @@ func desktop_listFiles(w http.ResponseWriter, r *http.Request) {
 
 	//Convert the struct to json string
 	jsonString, _ := json.Marshal(desktopFiles)
-	common.SendJSONResponse(w, string(jsonString))
+	utils.SendJSONResponse(w, string(jsonString))
 }
 
 //functions to handle desktop icon locations. Location is directly written into the center db.
@@ -360,10 +360,10 @@ func delDesktopLocationFromPath(filename string, username string) {
 func desktop_handleUserInfo(w http.ResponseWriter, r *http.Request) {
 	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
-	nic, _ := common.Mv(r, "noicon", true)
+	nic, _ := utils.Mv(r, "noicon", true)
 	noicon := (nic == "true")
 
 	type returnStruct struct {
@@ -401,21 +401,21 @@ func desktop_handleUserInfo(w http.ResponseWriter, r *http.Request) {
 	}
 
 	jsonString, _ := json.Marshal(rs)
-	common.SendJSONResponse(w, string(jsonString))
+	utils.SendJSONResponse(w, string(jsonString))
 }
 
 //Icon handling function for web endpoint
 func desktop_fileLocation_handler(w http.ResponseWriter, r *http.Request) {
-	get, _ := common.Mv(r, "get", true) //Check if there are get request for a given filepath
-	set, _ := common.Mv(r, "set", true) //Check if there are any set request for a given filepath
-	del, _ := common.Mv(r, "del", true) //Delete the given filename coordinate
+	get, _ := utils.Mv(r, "get", true) //Check if there are get request for a given filepath
+	set, _ := utils.Mv(r, "set", true) //Check if there are any set request for a given filepath
+	del, _ := utils.Mv(r, "del", true) //Delete the given filename coordinate
 
 	if set != "" {
 		//Set location with given paramter
 		x := 0
 		y := 0
-		sx, _ := common.Mv(r, "x", true)
-		sy, _ := common.Mv(r, "y", true)
+		sx, _ := utils.Mv(r, "x", true)
+		sy, _ := utils.Mv(r, "y", true)
 		path := set
 
 		x, err := strconv.Atoi(sx)
@@ -432,22 +432,22 @@ func desktop_fileLocation_handler(w http.ResponseWriter, r *http.Request) {
 		username, _ := authAgent.GetUserName(w, r)
 		err = setDesktopLocationFromPath(path, username, x, y)
 		if err != nil {
-			common.SendErrorResponse(w, err.Error())
+			utils.SendErrorResponse(w, err.Error())
 			return
 		}
-		common.SendJSONResponse(w, string("\"OK\""))
+		utils.SendJSONResponse(w, string("\"OK\""))
 	} else if get != "" {
 		username, _ := authAgent.GetUserName(w, r)
 		x, y, _ := getDesktopLocatioFromPath(get, username)
 		result := []int{x, y}
 		json_string, _ := json.Marshal(result)
-		common.SendJSONResponse(w, string(json_string))
+		utils.SendJSONResponse(w, string(json_string))
 	} else if del != "" {
 		username, _ := authAgent.GetUserName(w, r)
 		delDesktopLocationFromPath(del, username)
 	} else {
 		//No argument has been set
-		common.SendJSONResponse(w, "Paramter missing.")
+		utils.SendJSONResponse(w, "Paramter missing.")
 	}
 }
 
@@ -456,15 +456,15 @@ func desktop_fileLocation_handler(w http.ResponseWriter, r *http.Request) {
 func desktop_theme_handler(w http.ResponseWriter, r *http.Request) {
 	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 	username := userinfo.Username
 
 	//Check if the set GET paramter is set.
-	targetTheme, _ := common.Mv(r, "set", false)
-	getUserTheme, _ := common.Mv(r, "get", false)
-	loadUserTheme, _ := common.Mv(r, "load", false)
+	targetTheme, _ := utils.Mv(r, "set", false)
+	getUserTheme, _ := utils.Mv(r, "get", false)
+	loadUserTheme, _ := utils.Mv(r, "load", false)
 	if targetTheme == "" && getUserTheme == "" && loadUserTheme == "" {
 		//List all the currnet themes in the list
 		themes, err := filepath.Glob("web/img/desktop/bg/*")
@@ -494,7 +494,7 @@ func desktop_theme_handler(w http.ResponseWriter, r *http.Request) {
 				for _, bg := range bglist {
 					ext := filepath.Ext(bg)
 					//if (sliceutil.Contains(acceptBGFormats, ext) ){
-					if common.StringInArray(acceptBGFormats, ext) {
+					if utils.StringInArray(acceptBGFormats, ext) {
 						//This file extension is supported
 						thisbglist = append(thisbglist, filepath.Base(bg))
 					}
@@ -509,10 +509,10 @@ func desktop_theme_handler(w http.ResponseWriter, r *http.Request) {
 		jsonString, err := json.Marshal(desktopThemeList)
 		if err != nil {
 			log.Println("[Desktop] Marshal desktop wallpaper list error: " + err.Error())
-			common.SendJSONResponse(w, string("[]"))
+			utils.SendJSONResponse(w, string("[]"))
 			return
 		}
-		common.SendJSONResponse(w, string(jsonString))
+		utils.SendJSONResponse(w, string(jsonString))
 		return
 	} else if getUserTheme == "true" {
 		//Get the user's theme from database
@@ -520,36 +520,36 @@ func desktop_theme_handler(w http.ResponseWriter, r *http.Request) {
 		sysdb.Read("desktop", username+"/theme", &result)
 		if result == "" {
 			//This user has not set a theme yet. Use default
-			common.SendJSONResponse(w, string("\"default\""))
+			utils.SendJSONResponse(w, string("\"default\""))
 			return
 		} else {
 			//This user already set a theme. Use its set theme
-			common.SendJSONResponse(w, string("\""+result+"\""))
+			utils.SendJSONResponse(w, string("\""+result+"\""))
 			return
 		}
 	} else if loadUserTheme != "" {
 		//Load user theme base on folder path
 		userFsh, err := GetFsHandlerByUUID("user:/")
 		if err != nil {
-			common.SendErrorResponse(w, "Unable to resolve user root path")
+			utils.SendErrorResponse(w, "Unable to resolve user root path")
 			return
 		}
 		userFshAbs := userFsh.FileSystemAbstraction
 		rpath, err := userFshAbs.VirtualPathToRealPath(loadUserTheme, userinfo.Username)
 		if err != nil {
-			common.SendErrorResponse(w, "Custom folder load failed")
+			utils.SendErrorResponse(w, "Custom folder load failed")
 			return
 		}
 
 		//Check if the folder exists
 		if !userFshAbs.FileExists(rpath) {
-			common.SendErrorResponse(w, "Custom folder load failed")
+			utils.SendErrorResponse(w, "Custom folder load failed")
 			return
 		}
 
 		if userinfo.CanRead(loadUserTheme) == false {
 			//No read permission
-			common.SendErrorResponse(w, "Permission denied")
+			utils.SendErrorResponse(w, "Permission denied")
 			return
 		}
 
@@ -577,50 +577,50 @@ func desktop_theme_handler(w http.ResponseWriter, r *http.Request) {
 		}
 
 		js, _ := json.Marshal(virtualImageList)
-		common.SendJSONResponse(w, string(js))
+		utils.SendJSONResponse(w, string(js))
 
 	} else if targetTheme != "" {
 		//Set the current user theme
 		sysdb.Write("desktop", username+"/theme", targetTheme)
-		common.SendJSONResponse(w, "\"OK\"")
+		utils.SendJSONResponse(w, "\"OK\"")
 		return
 	}
 
 }
 
 func desktop_preference_handler(w http.ResponseWriter, r *http.Request) {
-	preferenceType, _ := common.Mv(r, "preference", true)
-	value, _ := common.Mv(r, "value", true)
-	remove, _ := common.Mv(r, "remove", true)
+	preferenceType, _ := utils.Mv(r, "preference", true)
+	value, _ := utils.Mv(r, "value", true)
+	remove, _ := utils.Mv(r, "remove", true)
 	username, err := authAgent.GetUserName(w, r)
 	if err != nil {
 		//user not logged in. Redirect to login page.
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 	if preferenceType == "" && value == "" {
 		//Invalid options. Return error reply.
-		common.SendErrorResponse(w, "Error. Undefined paramter.")
+		utils.SendErrorResponse(w, "Error. Undefined paramter.")
 		return
 	} else if preferenceType != "" && value == "" && remove == "" {
 		//Getting config from the key.
 		result := ""
 		sysdb.Read("desktop", username+"/preference/"+preferenceType, &result)
 		jsonString, _ := json.Marshal(result)
-		common.SendJSONResponse(w, string(jsonString))
+		utils.SendJSONResponse(w, string(jsonString))
 		return
 	} else if preferenceType != "" && value == "" && remove == "true" {
 		//Remove mode
 		sysdb.Delete("desktop", username+"/preference/"+preferenceType)
-		common.SendOK(w)
+		utils.SendOK(w)
 		return
 	} else if preferenceType != "" && value != "" {
 		//Setting config from the key
 		sysdb.Write("desktop", username+"/preference/"+preferenceType, value)
-		common.SendOK(w)
+		utils.SendOK(w)
 		return
 	} else {
-		common.SendErrorResponse(w, "Error. Undefined paramter.")
+		utils.SendErrorResponse(w, "Error. Undefined paramter.")
 		return
 	}
 
@@ -630,56 +630,56 @@ func desktop_shortcutHandler(w http.ResponseWriter, r *http.Request) {
 	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
 		//user not logged in. Redirect to login page.
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 
-	shortcutType, err := common.Mv(r, "stype", true)
+	shortcutType, err := utils.Mv(r, "stype", true)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
-	shortcutText, err := common.Mv(r, "stext", true)
+	shortcutText, err := utils.Mv(r, "stext", true)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
-	shortcutPath, err := common.Mv(r, "spath", true)
+	shortcutPath, err := utils.Mv(r, "spath", true)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
-	shortcutIcon, err := common.Mv(r, "sicon", true)
+	shortcutIcon, err := utils.Mv(r, "sicon", true)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
-	shortcutCreationDest, err := common.Mv(r, "sdest", true)
+	shortcutCreationDest, err := utils.Mv(r, "sdest", true)
 	if err != nil {
 		//Default create on desktop
 		shortcutCreationDest = "user:/Desktop/"
 	}
 
 	if !userinfo.CanWrite(shortcutCreationDest) {
-		common.SendErrorResponse(w, "Permission denied")
+		utils.SendErrorResponse(w, "Permission denied")
 		return
 	}
 
 	//Resolve vpath to fsh and subpath
 	fsh, subpath, err := GetFSHandlerSubpathFromVpath(shortcutCreationDest)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 	fshAbs := fsh.FileSystemAbstraction
 
 	shorcutRealDest, err := fshAbs.VirtualPathToRealPath(subpath, userinfo.Username)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
@@ -703,8 +703,8 @@ func desktop_shortcutHandler(w http.ResponseWriter, r *http.Request) {
 	shortcutContent := shortcut.GenerateShortcutBytes(shortcutPath, shortcutType, shortcutText, shortcutIcon)
 	err = fshAbs.WriteFile(shortcutFilename, shortcutContent, 0775)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
-	common.SendOK(w)
+	utils.SendOK(w)
 }

+ 156 - 156
disk.go

@@ -1,156 +1,156 @@
-package main
-
-/*
-	ArOZ Online Disk Service Endpoint Handler
-
-	This is a module to provide access to the disk services
-*/
-
-import (
-	"net/http"
-
-	"imuslab.com/arozos/mod/common"
-	"imuslab.com/arozos/mod/disk/diskcapacity"
-	"imuslab.com/arozos/mod/disk/diskmg"
-	diskspace "imuslab.com/arozos/mod/disk/diskspace"
-	smart "imuslab.com/arozos/mod/disk/smart"
-	sortfile "imuslab.com/arozos/mod/disk/sortfile"
-	prout "imuslab.com/arozos/mod/prouter"
-)
-
-func DiskServiceInit() {
-	//Register Disk Utilities under System Setting
-	//Disk info are only viewable by administrator
-	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")
-		},
-	})
-
-	//Disk Space Display endpoint
-	router.HandleFunc("/system/disk/space/list", diskspace.HandleDiskSpaceList)
-
-	//Handle Virtual Disk Properties display endpoints
-	dc := diskcapacity.NewCapacityResolver(userHandler)
-	router.HandleFunc("/system/disk/space/resolve", dc.HandleCapacityResolving)
-
-	//New Large File Scanner
-	lfs := sortfile.NewLargeFileScanner(userHandler)
-	router.HandleFunc("/system/disk/space/largeFiles", lfs.HandleLargeFileList)
-
-	//Register settings
-	registerSetting(settingModule{
-		Name:         "Space Finder",
-		Desc:         "Reclaim Storage Space on Disks",
-		IconPath:     "SystemAO/disk/space/img/small_icon.png",
-		Group:        "Disk",
-		StartDir:     "SystemAO/disk/space/finder.html",
-		RequireAdmin: false,
-	})
-
-	if *allow_hardware_management {
-		//Displaying remaining space on disk, only enabled when allow hardware is true
-		registerSetting(settingModule{
-			Name:         "Disk Space",
-			Desc:         "System Storage Space on Disks",
-			IconPath:     "SystemAO/disk/space/img/small_icon.png",
-			Group:        "Disk",
-			StartDir:     "SystemAO/disk/space/diskspace.html",
-			RequireAdmin: false,
-		})
-	}
-
-	//Register Disk SMART services
-	if sudo_mode {
-		//Create a new admin router
-		adminRouter := prout.NewModuleRouter(prout.RouterOption{
-			ModuleName:  "System Setting",
-			AdminOnly:   true,
-			UserHandler: userHandler,
-			DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-				common.SendErrorResponse(w, "Permission Denied")
-			},
-		})
-
-		/*
-			SMART Listener
-			Handle disk SMART and disk information
-
-			See disk/SMART for more information
-		*/
-		if *allow_hardware_management {
-			smartListener, err := smart.NewSmartListener()
-			if err != nil {
-				//Listener creation failed
-				systemWideLogger.PrintAndLog("Disk", "Failed to create SMART listener: "+err.Error(), err)
-			} else {
-				//Listener created. Register endpoints
-
-				//Register as a system setting
-				registerSetting(settingModule{
-					Name:         "Disk SMART",
-					Desc:         "HardDisk Health Checking",
-					IconPath:     "SystemAO/disk/smart/img/small_icon.png",
-					Group:        "Disk",
-					StartDir:     "SystemAO/disk/smart/smart.html",
-					RequireAdmin: true,
-				})
-
-				/*
-					registerSetting(settingModule{
-						Name:         "SMART Log",
-						Desc:         "HardDisk Health Log",
-						IconPath:     "SystemAO/disk/smart/img/small_icon.png",
-						Group:        "Disk",
-						StartDir:     "SystemAO/disk/smart/log.html",
-						RequireAdmin: true,
-					})
-				*/
-
-				adminRouter.HandleFunc("/system/disk/smart/getSMART", smartListener.GetSMART)
-			}
-		}
-
-		/*
-			Disk Manager Initialization
-			See disk/diskmg.go for more details
-
-			For setting register, see setting.advance.go
-		*/
-
-		if *allow_hardware_management {
-			adminRouter.HandleFunc("/system/disk/diskmg/view", diskmg.HandleView)
-			adminRouter.HandleFunc("/system/disk/diskmg/platform", diskmg.HandlePlatform)
-			adminRouter.HandleFunc("/system/disk/diskmg/mount", func(w http.ResponseWriter, r *http.Request) {
-				//Mount option require passing in all filesystem handlers
-				allFsh := GetAllLoadedFsh()
-				diskmg.HandleMount(w, r, allFsh)
-			})
-			adminRouter.HandleFunc("/system/disk/diskmg/format", func(w http.ResponseWriter, r *http.Request) {
-				//Check if request are made in POST mode
-				if r.Method != http.MethodPost {
-					w.WriteHeader(http.StatusMethodNotAllowed)
-					w.Write([]byte("405 - Method Not Allowed"))
-					return
-				}
-
-				//Check if ArozOS is running in sudo mode
-				if !sudo_mode {
-					w.WriteHeader(http.StatusUnauthorized)
-					w.Write([]byte("401 - Unauthorized (Is ArozOS running in sudo mode?)"))
-					return
-				}
-
-				//Format option require passing in all filesystem handlers
-				allFsh := GetAllLoadedFsh()
-				diskmg.HandleFormat(w, r, allFsh)
-			})
-			adminRouter.HandleFunc("/system/disk/diskmg/mpt", diskmg.HandleListMountPoints)
-		}
-
-	}
-
-}
+package main
+
+/*
+	ArOZ Online Disk Service Endpoint Handler
+
+	This is a module to provide access to the disk services
+*/
+
+import (
+	"net/http"
+
+	"imuslab.com/arozos/mod/disk/diskcapacity"
+	"imuslab.com/arozos/mod/disk/diskmg"
+	diskspace "imuslab.com/arozos/mod/disk/diskspace"
+	smart "imuslab.com/arozos/mod/disk/smart"
+	sortfile "imuslab.com/arozos/mod/disk/sortfile"
+	prout "imuslab.com/arozos/mod/prouter"
+	"imuslab.com/arozos/mod/utils"
+)
+
+func DiskServiceInit() {
+	//Register Disk Utilities under System Setting
+	//Disk info are only viewable by administrator
+	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")
+		},
+	})
+
+	//Disk Space Display endpoint
+	router.HandleFunc("/system/disk/space/list", diskspace.HandleDiskSpaceList)
+
+	//Handle Virtual Disk Properties display endpoints
+	dc := diskcapacity.NewCapacityResolver(userHandler)
+	router.HandleFunc("/system/disk/space/resolve", dc.HandleCapacityResolving)
+
+	//New Large File Scanner
+	lfs := sortfile.NewLargeFileScanner(userHandler)
+	router.HandleFunc("/system/disk/space/largeFiles", lfs.HandleLargeFileList)
+
+	//Register settings
+	registerSetting(settingModule{
+		Name:         "Space Finder",
+		Desc:         "Reclaim Storage Space on Disks",
+		IconPath:     "SystemAO/disk/space/img/small_icon.png",
+		Group:        "Disk",
+		StartDir:     "SystemAO/disk/space/finder.html",
+		RequireAdmin: false,
+	})
+
+	if *allow_hardware_management {
+		//Displaying remaining space on disk, only enabled when allow hardware is true
+		registerSetting(settingModule{
+			Name:         "Disk Space",
+			Desc:         "System Storage Space on Disks",
+			IconPath:     "SystemAO/disk/space/img/small_icon.png",
+			Group:        "Disk",
+			StartDir:     "SystemAO/disk/space/diskspace.html",
+			RequireAdmin: false,
+		})
+	}
+
+	//Register Disk SMART services
+	if sudo_mode {
+		//Create a new admin router
+		adminRouter := prout.NewModuleRouter(prout.RouterOption{
+			ModuleName:  "System Setting",
+			AdminOnly:   true,
+			UserHandler: userHandler,
+			DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+				utils.SendErrorResponse(w, "Permission Denied")
+			},
+		})
+
+		/*
+			SMART Listener
+			Handle disk SMART and disk information
+
+			See disk/SMART for more information
+		*/
+		if *allow_hardware_management {
+			smartListener, err := smart.NewSmartListener()
+			if err != nil {
+				//Listener creation failed
+				systemWideLogger.PrintAndLog("Disk", "Failed to create SMART listener: "+err.Error(), err)
+			} else {
+				//Listener created. Register endpoints
+
+				//Register as a system setting
+				registerSetting(settingModule{
+					Name:         "Disk SMART",
+					Desc:         "HardDisk Health Checking",
+					IconPath:     "SystemAO/disk/smart/img/small_icon.png",
+					Group:        "Disk",
+					StartDir:     "SystemAO/disk/smart/smart.html",
+					RequireAdmin: true,
+				})
+
+				/*
+					registerSetting(settingModule{
+						Name:         "SMART Log",
+						Desc:         "HardDisk Health Log",
+						IconPath:     "SystemAO/disk/smart/img/small_icon.png",
+						Group:        "Disk",
+						StartDir:     "SystemAO/disk/smart/log.html",
+						RequireAdmin: true,
+					})
+				*/
+
+				adminRouter.HandleFunc("/system/disk/smart/getSMART", smartListener.GetSMART)
+			}
+		}
+
+		/*
+			Disk Manager Initialization
+			See disk/diskmg.go for more details
+
+			For setting register, see setting.advance.go
+		*/
+
+		if *allow_hardware_management {
+			adminRouter.HandleFunc("/system/disk/diskmg/view", diskmg.HandleView)
+			adminRouter.HandleFunc("/system/disk/diskmg/platform", diskmg.HandlePlatform)
+			adminRouter.HandleFunc("/system/disk/diskmg/mount", func(w http.ResponseWriter, r *http.Request) {
+				//Mount option require passing in all filesystem handlers
+				allFsh := GetAllLoadedFsh()
+				diskmg.HandleMount(w, r, allFsh)
+			})
+			adminRouter.HandleFunc("/system/disk/diskmg/format", func(w http.ResponseWriter, r *http.Request) {
+				//Check if request are made in POST mode
+				if r.Method != http.MethodPost {
+					w.WriteHeader(http.StatusMethodNotAllowed)
+					w.Write([]byte("405 - Method Not Allowed"))
+					return
+				}
+
+				//Check if ArozOS is running in sudo mode
+				if !sudo_mode {
+					w.WriteHeader(http.StatusUnauthorized)
+					w.Write([]byte("401 - Unauthorized (Is ArozOS running in sudo mode?)"))
+					return
+				}
+
+				//Format option require passing in all filesystem handlers
+				allFsh := GetAllLoadedFsh()
+				diskmg.HandleFormat(w, r, allFsh)
+			})
+			adminRouter.HandleFunc("/system/disk/diskmg/mpt", diskmg.HandleListMountPoints)
+		}
+
+	}
+
+}

Fișier diff suprimat deoarece este prea mare
+ 144 - 144
file_system.go


+ 171 - 171
hardware.power.go

@@ -1,171 +1,171 @@
-package main
-
-import (
-	"net/http"
-
-	"os/exec"
-	"runtime"
-
-	"imuslab.com/arozos/mod/common"
-)
-
-func HardwarePowerInit() {
-	if *allow_hardware_management {
-		//Only register these paths when hardware management is enabled
-		http.HandleFunc("/system/power/shutdown", hardware_power_poweroff)
-		http.HandleFunc("/system/power/restart", hardware_power_restart)
-
-		//Register a power handler in system setting menu
-		registerSetting(settingModule{
-			Name:         "Power",
-			Desc:         "Set the power state of the host device",
-			IconPath:     "SystemAO/boot/img/boot.png",
-			Group:        "Info",
-			StartDir:     "SystemAO/boot/poweroff.html",
-			RequireAdmin: true,
-		})
-	}
-
-	http.HandleFunc("/system/power/accessCheck", hardware_power_checkIfHardware)
-}
-
-func hardware_power_checkIfHardware(w http.ResponseWriter, r *http.Request) {
-	if *allow_hardware_management {
-		common.SendJSONResponse(w, "true")
-	} else {
-		common.SendJSONResponse(w, "false")
-	}
-}
-
-func hardware_power_poweroff(w http.ResponseWriter, r *http.Request) {
-	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		w.WriteHeader(http.StatusUnauthorized)
-		w.Write([]byte("401 Unauthorized"))
-		return
-	}
-
-	if !userinfo.IsAdmin() {
-		common.SendErrorResponse(w, "Permission Denied")
-		return
-	}
-
-	if !sudo_mode {
-		common.SendErrorResponse(w, "Sudo mode required")
-		return
-	}
-
-	//Double check password for this user
-	password, err := common.Mv(r, "password", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Password Incorrect")
-		return
-	}
-
-	passwordCorrect, rejectionReason := authAgent.ValidateUsernameAndPasswordWithReason(userinfo.Username, password)
-	if !passwordCorrect {
-		common.SendErrorResponse(w, rejectionReason)
-		return
-	}
-
-	if runtime.GOOS == "windows" {
-		//Only allow Linux to do power operation
-		cmd := exec.Command("shutdown", "-s", "-t", "20")
-		out, err := cmd.CombinedOutput()
-		if err != nil {
-			systemWideLogger.PrintAndLog("Power", string(out), err)
-			common.SendErrorResponse(w, string(out))
-		}
-		systemWideLogger.PrintAndLog("Power", string(out), nil)
-	}
-
-	if runtime.GOOS == "linux" {
-		//Only allow Linux to do power operation
-		cmd := exec.Command("/sbin/shutdown")
-		out, err := cmd.CombinedOutput()
-		if err != nil {
-			systemWideLogger.PrintAndLog("Power", string(out), err)
-			common.SendErrorResponse(w, string(out))
-		}
-		systemWideLogger.PrintAndLog("Power", string(out), nil)
-	}
-
-	if runtime.GOOS == "darwin" {
-		//Only allow Linux to do power operation
-		cmd := exec.Command("sudo", "shutdown", "-h", "+1")
-		out, err := cmd.CombinedOutput()
-		if err != nil {
-			systemWideLogger.PrintAndLog("Power", string(out), err)
-			common.SendErrorResponse(w, string(out))
-		}
-		systemWideLogger.PrintAndLog("Power", string(out), nil)
-	}
-
-	common.SendOK(w)
-}
-
-func hardware_power_restart(w http.ResponseWriter, r *http.Request) {
-	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		w.WriteHeader(http.StatusUnauthorized)
-		w.Write([]byte("401 Unauthorized"))
-		return
-	}
-
-	if !userinfo.IsAdmin() {
-		common.SendErrorResponse(w, "Permission Denied")
-		return
-	}
-
-	if !sudo_mode {
-		common.SendErrorResponse(w, "Sudo mode required")
-		return
-	}
-
-	//Double check password for this user
-	password, err := common.Mv(r, "password", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Password Incorrect")
-		return
-	}
-
-	passwordCorrect, rejectionReason := authAgent.ValidateUsernameAndPasswordWithReason(userinfo.Username, password)
-	if !passwordCorrect {
-		common.SendErrorResponse(w, rejectionReason)
-		return
-	}
-
-	if runtime.GOOS == "windows" {
-		//Only allow Linux to do power operation
-		cmd := exec.Command("shutdown", "-r", "-t", "20")
-		out, err := cmd.CombinedOutput()
-		if err != nil {
-			systemWideLogger.PrintAndLog("Power", string(out), err)
-			common.SendErrorResponse(w, string(out))
-		}
-		systemWideLogger.PrintAndLog("Power", string(out), nil)
-	}
-
-	if runtime.GOOS == "linux" {
-		//Only allow Linux to do power operation
-		cmd := exec.Command("systemctl", "reboot")
-		out, err := cmd.CombinedOutput()
-		if err != nil {
-			systemWideLogger.PrintAndLog("Power", string(out), err)
-			common.SendErrorResponse(w, string(out))
-		}
-		systemWideLogger.PrintAndLog("Power", string(out), nil)
-	}
-
-	if runtime.GOOS == "darwin" {
-		//Only allow Linux to do power operation
-		cmd := exec.Command("shutdown", "-r", "+1")
-		out, err := cmd.CombinedOutput()
-		if err != nil {
-			systemWideLogger.PrintAndLog("Power", string(out), err)
-			common.SendErrorResponse(w, string(out))
-		}
-		systemWideLogger.PrintAndLog("Power", string(out), nil)
-	}
-	common.SendOK(w)
-}
+package main
+
+import (
+	"net/http"
+
+	"os/exec"
+	"runtime"
+
+	"imuslab.com/arozos/mod/utils"
+)
+
+func HardwarePowerInit() {
+	if *allow_hardware_management {
+		//Only register these paths when hardware management is enabled
+		http.HandleFunc("/system/power/shutdown", hardware_power_poweroff)
+		http.HandleFunc("/system/power/restart", hardware_power_restart)
+
+		//Register a power handler in system setting menu
+		registerSetting(settingModule{
+			Name:         "Power",
+			Desc:         "Set the power state of the host device",
+			IconPath:     "SystemAO/boot/img/boot.png",
+			Group:        "Info",
+			StartDir:     "SystemAO/boot/poweroff.html",
+			RequireAdmin: true,
+		})
+	}
+
+	http.HandleFunc("/system/power/accessCheck", hardware_power_checkIfHardware)
+}
+
+func hardware_power_checkIfHardware(w http.ResponseWriter, r *http.Request) {
+	if *allow_hardware_management {
+		utils.SendJSONResponse(w, "true")
+	} else {
+		utils.SendJSONResponse(w, "false")
+	}
+}
+
+func hardware_power_poweroff(w http.ResponseWriter, r *http.Request) {
+	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		w.WriteHeader(http.StatusUnauthorized)
+		w.Write([]byte("401 Unauthorized"))
+		return
+	}
+
+	if !userinfo.IsAdmin() {
+		utils.SendErrorResponse(w, "Permission Denied")
+		return
+	}
+
+	if !sudo_mode {
+		utils.SendErrorResponse(w, "Sudo mode required")
+		return
+	}
+
+	//Double check password for this user
+	password, err := utils.Mv(r, "password", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Password Incorrect")
+		return
+	}
+
+	passwordCorrect, rejectionReason := authAgent.ValidateUsernameAndPasswordWithReason(userinfo.Username, password)
+	if !passwordCorrect {
+		utils.SendErrorResponse(w, rejectionReason)
+		return
+	}
+
+	if runtime.GOOS == "windows" {
+		//Only allow Linux to do power operation
+		cmd := exec.Command("shutdown", "-s", "-t", "20")
+		out, err := cmd.CombinedOutput()
+		if err != nil {
+			systemWideLogger.PrintAndLog("Power", string(out), err)
+			utils.SendErrorResponse(w, string(out))
+		}
+		systemWideLogger.PrintAndLog("Power", string(out), nil)
+	}
+
+	if runtime.GOOS == "linux" {
+		//Only allow Linux to do power operation
+		cmd := exec.Command("/sbin/shutdown")
+		out, err := cmd.CombinedOutput()
+		if err != nil {
+			systemWideLogger.PrintAndLog("Power", string(out), err)
+			utils.SendErrorResponse(w, string(out))
+		}
+		systemWideLogger.PrintAndLog("Power", string(out), nil)
+	}
+
+	if runtime.GOOS == "darwin" {
+		//Only allow Linux to do power operation
+		cmd := exec.Command("sudo", "shutdown", "-h", "+1")
+		out, err := cmd.CombinedOutput()
+		if err != nil {
+			systemWideLogger.PrintAndLog("Power", string(out), err)
+			utils.SendErrorResponse(w, string(out))
+		}
+		systemWideLogger.PrintAndLog("Power", string(out), nil)
+	}
+
+	utils.SendOK(w)
+}
+
+func hardware_power_restart(w http.ResponseWriter, r *http.Request) {
+	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		w.WriteHeader(http.StatusUnauthorized)
+		w.Write([]byte("401 Unauthorized"))
+		return
+	}
+
+	if !userinfo.IsAdmin() {
+		utils.SendErrorResponse(w, "Permission Denied")
+		return
+	}
+
+	if !sudo_mode {
+		utils.SendErrorResponse(w, "Sudo mode required")
+		return
+	}
+
+	//Double check password for this user
+	password, err := utils.Mv(r, "password", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Password Incorrect")
+		return
+	}
+
+	passwordCorrect, rejectionReason := authAgent.ValidateUsernameAndPasswordWithReason(userinfo.Username, password)
+	if !passwordCorrect {
+		utils.SendErrorResponse(w, rejectionReason)
+		return
+	}
+
+	if runtime.GOOS == "windows" {
+		//Only allow Linux to do power operation
+		cmd := exec.Command("shutdown", "-r", "-t", "20")
+		out, err := cmd.CombinedOutput()
+		if err != nil {
+			systemWideLogger.PrintAndLog("Power", string(out), err)
+			utils.SendErrorResponse(w, string(out))
+		}
+		systemWideLogger.PrintAndLog("Power", string(out), nil)
+	}
+
+	if runtime.GOOS == "linux" {
+		//Only allow Linux to do power operation
+		cmd := exec.Command("systemctl", "reboot")
+		out, err := cmd.CombinedOutput()
+		if err != nil {
+			systemWideLogger.PrintAndLog("Power", string(out), err)
+			utils.SendErrorResponse(w, string(out))
+		}
+		systemWideLogger.PrintAndLog("Power", string(out), nil)
+	}
+
+	if runtime.GOOS == "darwin" {
+		//Only allow Linux to do power operation
+		cmd := exec.Command("shutdown", "-r", "+1")
+		out, err := cmd.CombinedOutput()
+		if err != nil {
+			systemWideLogger.PrintAndLog("Power", string(out), err)
+			utils.SendErrorResponse(w, string(out))
+		}
+		systemWideLogger.PrintAndLog("Power", string(out), nil)
+	}
+	utils.SendOK(w)
+}

+ 104 - 104
iot.go

@@ -1,104 +1,104 @@
-package main
-
-import (
-	"net/http"
-
-	"imuslab.com/arozos/mod/common"
-	"imuslab.com/arozos/mod/iot"
-	"imuslab.com/arozos/mod/iot/hds"
-	"imuslab.com/arozos/mod/iot/hdsv2"
-	"imuslab.com/arozos/mod/iot/sonoff_s2x"
-	module "imuslab.com/arozos/mod/modules"
-	prout "imuslab.com/arozos/mod/prouter"
-)
-
-/*
-	IoT Hub
-	Author: tobychui
-
-	This script handle the IoT service start up and mangement
-
-	IoT Manager: Manage who can have access to certain IoT devices
-	IoT Panel: The panel for controlling the devices
-*/
-
-var iotManager *iot.Manager
-
-func IoTHubInit() {
-	if *allow_iot && *allow_mdns && MDNS != nil {
-		//Create a new ioT Manager
-		iotManager = iot.NewIoTManager(sysdb)
-
-		//Register IoT Hub Module
-		moduleHandler.RegisterModule(module.ModuleInfo{
-			Name:        "IoT Hub",
-			Group:       "Internet",
-			IconPath:    "SystemAO/iot/hub/img/small_icon.png",
-			Version:     "1.0",
-			StartDir:    "SystemAO/iot/hub/index.html",
-			SupportFW:   true,
-			InitFWSize:  []int{465, 730},
-			LaunchFWDir: "SystemAO/iot/hub/index.html",
-			SupportEmb:  false,
-		})
-
-		//Register IoT Setting Interfaces
-		registerSetting(settingModule{
-			Name:     "IoT Hub",
-			Desc:     "Manage IoT Devices Scanners",
-			IconPath: "SystemAO/iot/img/small_icon.png",
-			Group:    "Device",
-			StartDir: "SystemAO/iot/info.html",
-		})
-
-		//Register IoT Devices Endpoints
-		router := prout.NewModuleRouter(prout.RouterOption{
-			ModuleName:  "IoT Hub",
-			AdminOnly:   false,
-			UserHandler: userHandler,
-			DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-				common.SendErrorResponse(w, "Permission Denied")
-			},
-		})
-
-		adminRouter := prout.NewModuleRouter(prout.RouterOption{
-			ModuleName:  "System Setting",
-			AdminOnly:   true,
-			UserHandler: userHandler,
-			DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-				common.SendErrorResponse(w, "Permission Denied")
-			},
-		})
-
-		//IoT Panel control APIs
-		router.HandleFunc("/system/iot/scan", iotManager.HandleScanning)
-		router.HandleFunc("/system/iot/list", iotManager.HandleListing)
-		router.HandleFunc("/system/iot/status", iotManager.HandleGetDeviceStatus)
-		router.HandleFunc("/system/iot/execute", iotManager.HandleExecute)
-		router.HandleFunc("/system/iot/icon", iotManager.HandleIconLoad)
-		router.HandleFunc("/system/iot/nickname", iotManager.HandleNickName)
-
-		//IoT Hub Info APIs
-		adminRouter.HandleFunc("/system/iot/listScanner", iotManager.HandleScannerList)
-
-		//Start of the IoT Management Handlers
-
-		//Home Dynamic v1 (Legacy)
-		hdsHandler := hds.NewProtocolHandler()
-		iotManager.RegisterHandler(hdsHandler)
-
-		//Home Dynamic v2
-		hdsv2Handler := hdsv2.NewProtocolHandler(MDNS)
-		iotManager.RegisterHandler(hdsv2Handler)
-
-		//Tasmota Sonoff S2X
-		tasmotaSonoffS2x := sonoff_s2x.NewProtocolHandler(MDNS)
-		iotManager.RegisterHandler(tasmotaSonoffS2x)
-
-		//Add more here if needed
-
-		//Finally, inject the gateway into the AGI interface
-		AGIGateway.Option.IotManager = iotManager
-	}
-
-}
+package main
+
+import (
+	"net/http"
+
+	"imuslab.com/arozos/mod/iot"
+	"imuslab.com/arozos/mod/iot/hds"
+	"imuslab.com/arozos/mod/iot/hdsv2"
+	"imuslab.com/arozos/mod/iot/sonoff_s2x"
+	module "imuslab.com/arozos/mod/modules"
+	prout "imuslab.com/arozos/mod/prouter"
+	"imuslab.com/arozos/mod/utils"
+)
+
+/*
+	IoT Hub
+	Author: tobychui
+
+	This script handle the IoT service start up and mangement
+
+	IoT Manager: Manage who can have access to certain IoT devices
+	IoT Panel: The panel for controlling the devices
+*/
+
+var iotManager *iot.Manager
+
+func IoTHubInit() {
+	if *allow_iot && *allow_mdns && MDNS != nil {
+		//Create a new ioT Manager
+		iotManager = iot.NewIoTManager(sysdb)
+
+		//Register IoT Hub Module
+		moduleHandler.RegisterModule(module.ModuleInfo{
+			Name:        "IoT Hub",
+			Group:       "Internet",
+			IconPath:    "SystemAO/iot/hub/img/small_icon.png",
+			Version:     "1.0",
+			StartDir:    "SystemAO/iot/hub/index.html",
+			SupportFW:   true,
+			InitFWSize:  []int{465, 730},
+			LaunchFWDir: "SystemAO/iot/hub/index.html",
+			SupportEmb:  false,
+		})
+
+		//Register IoT Setting Interfaces
+		registerSetting(settingModule{
+			Name:     "IoT Hub",
+			Desc:     "Manage IoT Devices Scanners",
+			IconPath: "SystemAO/iot/img/small_icon.png",
+			Group:    "Device",
+			StartDir: "SystemAO/iot/info.html",
+		})
+
+		//Register IoT Devices Endpoints
+		router := prout.NewModuleRouter(prout.RouterOption{
+			ModuleName:  "IoT Hub",
+			AdminOnly:   false,
+			UserHandler: userHandler,
+			DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+				utils.SendErrorResponse(w, "Permission Denied")
+			},
+		})
+
+		adminRouter := prout.NewModuleRouter(prout.RouterOption{
+			ModuleName:  "System Setting",
+			AdminOnly:   true,
+			UserHandler: userHandler,
+			DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+				utils.SendErrorResponse(w, "Permission Denied")
+			},
+		})
+
+		//IoT Panel control APIs
+		router.HandleFunc("/system/iot/scan", iotManager.HandleScanning)
+		router.HandleFunc("/system/iot/list", iotManager.HandleListing)
+		router.HandleFunc("/system/iot/status", iotManager.HandleGetDeviceStatus)
+		router.HandleFunc("/system/iot/execute", iotManager.HandleExecute)
+		router.HandleFunc("/system/iot/icon", iotManager.HandleIconLoad)
+		router.HandleFunc("/system/iot/nickname", iotManager.HandleNickName)
+
+		//IoT Hub Info APIs
+		adminRouter.HandleFunc("/system/iot/listScanner", iotManager.HandleScannerList)
+
+		//Start of the IoT Management Handlers
+
+		//Home Dynamic v1 (Legacy)
+		hdsHandler := hds.NewProtocolHandler()
+		iotManager.RegisterHandler(hdsHandler)
+
+		//Home Dynamic v2
+		hdsv2Handler := hdsv2.NewProtocolHandler(MDNS)
+		iotManager.RegisterHandler(hdsv2Handler)
+
+		//Tasmota Sonoff S2X
+		tasmotaSonoffS2x := sonoff_s2x.NewProtocolHandler(MDNS)
+		iotManager.RegisterHandler(tasmotaSonoffS2x)
+
+		//Add more here if needed
+
+		//Finally, inject the gateway into the AGI interface
+		AGIGateway.Option.IotManager = iotManager
+	}
+
+}

Fișier diff suprimat deoarece este prea mare
+ 0 - 1
legacy/Photo/static/js/2.09744fc4.chunk.js


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
legacy/Photo/static/js/2.09744fc4.chunk.js.map


+ 369 - 369
legacy/backup.go.disabled

@@ -1,369 +1,369 @@
-package main
-
-import (
-	"encoding/json"
-	"errors"
-	"net/http"
-	"path/filepath"
-	"strings"
-
-	"imuslab.com/arozos/mod/common"
-	"imuslab.com/arozos/mod/disk/hybridBackup"
-	user "imuslab.com/arozos/mod/user"
-
-	prout "imuslab.com/arozos/mod/prouter"
-)
-
-func backup_init() {
-	//Register HybridBackup storage restore endpoints
-	router := prout.NewModuleRouter(prout.RouterOption{
-		AdminOnly:   false,
-		UserHandler: userHandler,
-		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
-		},
-	})
-
-	//Register API endpoints
-	router.HandleFunc("/system/backup/listRestorable", backup_listRestorable)
-	router.HandleFunc("/system/backup/restoreFile", backup_restoreSelected)
-	router.HandleFunc("/system/backup/snapshotSummary", backup_renderSnapshotSummary)
-	router.HandleFunc("/system/backup/listAll", backup_listAllBackupDisk)
-
-	//Register settings
-	registerSetting(settingModule{
-		Name:         "Backup Disks",
-		Desc:         "All backup disk in the system",
-		IconPath:     "img/system/backup.svg",
-		Group:        "Disk",
-		StartDir:     "SystemAO/disk/backup/backups.html",
-		RequireAdmin: true,
-	})
-}
-
-//List all backup disk info
-func backup_listAllBackupDisk(w http.ResponseWriter, r *http.Request) {
-	//Get all fsh from the system
-	runningBackupTasks := []*hybridBackup.BackupTask{}
-
-	//Render base storage pool
-	for _, fsh := range baseStoragePool.Storages {
-		if fsh.Hierarchy == "backup" {
-			task, err := baseStoragePool.HyperBackupManager.GetTaskByBackupDiskID(fsh.UUID)
-			if err != nil {
-				continue
-			}
-
-			runningBackupTasks = append(runningBackupTasks, task)
-		}
-	}
-
-	//Render group storage pool
-	for _, pg := range permissionHandler.PermissionGroups {
-		for _, fsh := range pg.StoragePool.Storages {
-			task, err := pg.StoragePool.HyperBackupManager.GetTaskByBackupDiskID(fsh.UUID)
-			if err != nil {
-				continue
-			}
-
-			runningBackupTasks = append(runningBackupTasks, task)
-		}
-	}
-
-	type backupDrive struct {
-		DiskUID             string //The backup disk UUID
-		DiskName            string // The Backup disk name
-		ParentUID           string //Parent disk UID
-		ParentName          string //Parent disk name
-		BackupMode          string //The backup mode of the drive
-		LastBackupCycleTime int64  //Last backup timestamp
-		BackupCycleCount    int64  //How many backup cycle has proceeded since the system startup
-		Error               bool   //If there are error occured in the last cycle
-		ErrorMessage        string //If there are any error msg
-	}
-
-	backupDrives := []*backupDrive{}
-	for _, task := range runningBackupTasks {
-		diskFsh, diskErr := GetFsHandlerByUUID(task.DiskUID)
-		parentFsh, parentErr := GetFsHandlerByUUID(task.ParentUID)
-
-		//Check for error in getting FS Handler
-		if diskErr != nil || parentErr != nil {
-			common.SendErrorResponse(w, "Unable to get backup task info from backup disk: "+task.DiskUID)
-			return
-		}
-
-		thisBackupDrive := backupDrive{
-			DiskUID:             diskFsh.UUID,
-			DiskName:            diskFsh.Name,
-			ParentUID:           parentFsh.UUID,
-			ParentName:          parentFsh.Name,
-			BackupMode:          task.Mode,
-			LastBackupCycleTime: task.LastCycleTime,
-			BackupCycleCount:    task.CycleCounter,
-			Error:               task.PanicStopped,
-			ErrorMessage:        task.ErrorMessage,
-		}
-
-		backupDrives = append(backupDrives, &thisBackupDrive)
-	}
-
-	js, _ := json.Marshal(backupDrives)
-	common.SendJSONResponse(w, string(js))
-}
-
-//Generate a snapshot summary for vroot
-func backup_renderSnapshotSummary(w http.ResponseWriter, r *http.Request) {
-	//Get user accessiable storage pools
-	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
-		return
-	}
-
-	//Get Backup disk ID from request
-	bdid, err := common.Mv(r, "bdid", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid backup disk ID given")
-		return
-	}
-
-	//Get target snapshot name from request
-	snapshot, err := common.Mv(r, "snapshot", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid snapshot name given")
-		return
-	}
-
-	//Get fsh from the id
-	fsh, err := GetFsHandlerByUUID(bdid)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	//Get parent disk hierarcy
-	parentDiskID, err := userinfo.HomeDirectories.HyperBackupManager.GetParentDiskIDByRestoreDiskID(fsh.UUID)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-	parentFsh, err := GetFsHandlerByUUID(parentDiskID)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	//Get task by the backup disk id
-	task, err := userinfo.HomeDirectories.HyperBackupManager.GetTaskByBackupDiskID(fsh.UUID)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	if task.Mode == "version" {
-		//Generate snapshot summary
-		var summary *hybridBackup.SnapshotSummary
-		if parentFsh.Hierarchy == "user" {
-			s, err := task.GenerateSnapshotSummary(snapshot, &userinfo.Username)
-			if err != nil {
-				common.SendErrorResponse(w, err.Error())
-				return
-			}
-			summary = s
-		} else {
-			s, err := task.GenerateSnapshotSummary(snapshot, nil)
-			if err != nil {
-				common.SendErrorResponse(w, err.Error())
-				return
-			}
-			summary = s
-		}
-
-		js, _ := json.Marshal(summary)
-		common.SendJSONResponse(w, string(js))
-	} else {
-		common.SendErrorResponse(w, "Unable to genreate snapshot summary: Backup mode is not snapshot")
-		return
-	}
-
-}
-
-//Restore a given file
-func backup_restoreSelected(w http.ResponseWriter, r *http.Request) {
-	//Get user accessiable storage pools
-	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
-		return
-	}
-
-	//Get Backup disk ID from request
-	bdid, err := common.Mv(r, "bdid", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid backup disk ID given")
-		return
-	}
-
-	//Get fsh from the id
-	fsh, err := GetFsHandlerByUUID(bdid)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	//Get the relative path for the restorable file
-	relpath, err := common.Mv(r, "relpath", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid relative path given")
-		return
-	}
-
-	//Pick the correct HybridBackup Manager
-	targetHybridBackupManager, err := backup_pickHybridBackupManager(userinfo, fsh.UUID)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	//Handle restore of the file
-	err = targetHybridBackupManager.HandleRestore(fsh.UUID, relpath, &userinfo.Username)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	type RestoreResult struct {
-		RestoreDiskID       string
-		TargetDiskID        string
-		RestoredVirtualPath string
-	}
-
-	result := RestoreResult{
-		RestoreDiskID: fsh.UUID,
-	}
-
-	//Get access path for this file
-	parentDiskId, err := targetHybridBackupManager.GetParentDiskIDByRestoreDiskID(fsh.UUID)
-	if err != nil {
-		//Unable to get parent disk ID???
-
-	} else {
-		//Get the path of the parent disk
-		parentDiskHandler, err := GetFsHandlerByUUID(parentDiskId)
-		if err == nil {
-			//Join the result to create a virtual path
-			assumedRestoreRealPath := filepath.ToSlash(filepath.Join(parentDiskHandler.Path, relpath))
-			restoreVpath, err := userinfo.RealPathToVirtualPath(assumedRestoreRealPath)
-			if err == nil {
-				result.RestoredVirtualPath = restoreVpath
-			}
-			result.TargetDiskID = parentDiskId
-		}
-
-	}
-
-	js, _ := json.Marshal(result)
-	common.SendJSONResponse(w, string(js))
-}
-
-//As one user might be belongs to multiple groups, check which storage pool is this disk ID owned by and return its corect backup maanger
-func backup_pickHybridBackupManager(userinfo *user.User, diskID string) (*hybridBackup.Manager, error) {
-	//Filter out the :/ if it exists in the disk ID
-	if strings.Contains(diskID, ":") {
-		diskID = strings.Split(diskID, ":")[0]
-	}
-
-	//Get all backup managers that this user ac can access
-	userpg := userinfo.GetUserPermissionGroup()
-
-	if userinfo.HomeDirectories.ContainDiskID(diskID) {
-		return userinfo.HomeDirectories.HyperBackupManager, nil
-	}
-
-	//Extract the backup Managers
-	for _, pg := range userpg {
-		if pg.StoragePool.ContainDiskID(diskID) {
-			return pg.StoragePool.HyperBackupManager, nil
-		}
-
-	}
-
-	return nil, errors.New("Disk ID not found in any storage pool this user can access")
-}
-
-//Generate and return a restorable report
-func backup_listRestorable(w http.ResponseWriter, r *http.Request) {
-	//Get user accessiable storage pools
-	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
-		return
-	}
-
-	//Get Vroot ID from request
-	vroot, err := common.Mv(r, "vroot", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid vroot given")
-		return
-	}
-
-	//Get fsh from the id
-	fsh, err := GetFsHandlerByUUID(vroot)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	//Get all backup managers that this user ac can access
-	targetBackupManager, err := backup_pickHybridBackupManager(userinfo, vroot)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	//Get the user's storage pool and list restorable by the user's storage pool access
-	restorableReport, err := targetBackupManager.ListRestorable(fsh.UUID)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	//Get and check if the parent disk has a user Hierarcy
-	paretnfsh, err := GetFsHandlerByUUID(restorableReport.ParentUID)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	result := hybridBackup.RestorableReport{
-		ParentUID:       restorableReport.ParentUID,
-		RestorableFiles: []*hybridBackup.RestorableFile{},
-	}
-
-	if paretnfsh.Hierarchy == "user" {
-		//The file system is user based. Filter out those file that is not belong to this user
-		for _, restorableFile := range restorableReport.RestorableFiles {
-			if restorableFile.IsSnapshot {
-				//Is snapshot. Always allow access
-				result.RestorableFiles = append(result.RestorableFiles, restorableFile)
-			} else {
-				//Is file
-				fileAbsPath := filepath.Join(fsh.Path, restorableFile.RelpathOnDisk)
-				_, err := userinfo.RealPathToVirtualPath(fileAbsPath)
-				if err != nil {
-					//Cannot translate this file. That means the file is not owned by this user
-				} else {
-					//Can translate the path.
-					result.RestorableFiles = append(result.RestorableFiles, restorableFile)
-				}
-			}
-
-		}
-	} else {
-		result = restorableReport
-	}
-
-	js, _ := json.Marshal(result)
-	common.SendJSONResponse(w, string(js))
-}
+package main
+
+import (
+	"encoding/json"
+	"errors"
+	"net/http"
+	"path/filepath"
+	"strings"
+
+	"imuslab.com/arozos/mod/utils"
+	"imuslab.com/arozos/mod/disk/hybridBackup"
+	user "imuslab.com/arozos/mod/user"
+
+	prout "imuslab.com/arozos/mod/prouter"
+)
+
+func backup_init() {
+	//Register HybridBackup storage restore endpoints
+	router := prout.NewModuleRouter(prout.RouterOption{
+		AdminOnly:   false,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			utils.SendErrorResponse(w, "Permission Denied")
+		},
+	})
+
+	//Register API endpoints
+	router.HandleFunc("/system/backup/listRestorable", backup_listRestorable)
+	router.HandleFunc("/system/backup/restoreFile", backup_restoreSelected)
+	router.HandleFunc("/system/backup/snapshotSummary", backup_renderSnapshotSummary)
+	router.HandleFunc("/system/backup/listAll", backup_listAllBackupDisk)
+
+	//Register settings
+	registerSetting(settingModule{
+		Name:         "Backup Disks",
+		Desc:         "All backup disk in the system",
+		IconPath:     "img/system/backup.svg",
+		Group:        "Disk",
+		StartDir:     "SystemAO/disk/backup/backups.html",
+		RequireAdmin: true,
+	})
+}
+
+//List all backup disk info
+func backup_listAllBackupDisk(w http.ResponseWriter, r *http.Request) {
+	//Get all fsh from the system
+	runningBackupTasks := []*hybridBackup.BackupTask{}
+
+	//Render base storage pool
+	for _, fsh := range baseStoragePool.Storages {
+		if fsh.Hierarchy == "backup" {
+			task, err := baseStoragePool.HyperBackupManager.GetTaskByBackupDiskID(fsh.UUID)
+			if err != nil {
+				continue
+			}
+
+			runningBackupTasks = append(runningBackupTasks, task)
+		}
+	}
+
+	//Render group storage pool
+	for _, pg := range permissionHandler.PermissionGroups {
+		for _, fsh := range pg.StoragePool.Storages {
+			task, err := pg.StoragePool.HyperBackupManager.GetTaskByBackupDiskID(fsh.UUID)
+			if err != nil {
+				continue
+			}
+
+			runningBackupTasks = append(runningBackupTasks, task)
+		}
+	}
+
+	type backupDrive struct {
+		DiskUID             string //The backup disk UUID
+		DiskName            string // The Backup disk name
+		ParentUID           string //Parent disk UID
+		ParentName          string //Parent disk name
+		BackupMode          string //The backup mode of the drive
+		LastBackupCycleTime int64  //Last backup timestamp
+		BackupCycleCount    int64  //How many backup cycle has proceeded since the system startup
+		Error               bool   //If there are error occured in the last cycle
+		ErrorMessage        string //If there are any error msg
+	}
+
+	backupDrives := []*backupDrive{}
+	for _, task := range runningBackupTasks {
+		diskFsh, diskErr := GetFsHandlerByUUID(task.DiskUID)
+		parentFsh, parentErr := GetFsHandlerByUUID(task.ParentUID)
+
+		//Check for error in getting FS Handler
+		if diskErr != nil || parentErr != nil {
+			utils.SendErrorResponse(w, "Unable to get backup task info from backup disk: "+task.DiskUID)
+			return
+		}
+
+		thisBackupDrive := backupDrive{
+			DiskUID:             diskFsh.UUID,
+			DiskName:            diskFsh.Name,
+			ParentUID:           parentFsh.UUID,
+			ParentName:          parentFsh.Name,
+			BackupMode:          task.Mode,
+			LastBackupCycleTime: task.LastCycleTime,
+			BackupCycleCount:    task.CycleCounter,
+			Error:               task.PanicStopped,
+			ErrorMessage:        task.ErrorMessage,
+		}
+
+		backupDrives = append(backupDrives, &thisBackupDrive)
+	}
+
+	js, _ := json.Marshal(backupDrives)
+	utils.SendJSONResponse(w, string(js))
+}
+
+//Generate a snapshot summary for vroot
+func backup_renderSnapshotSummary(w http.ResponseWriter, r *http.Request) {
+	//Get user accessiable storage pools
+	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		utils.SendErrorResponse(w, "User not logged in")
+		return
+	}
+
+	//Get Backup disk ID from request
+	bdid, err := utils.Mv(r, "bdid", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid backup disk ID given")
+		return
+	}
+
+	//Get target snapshot name from request
+	snapshot, err := utils.Mv(r, "snapshot", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid snapshot name given")
+		return
+	}
+
+	//Get fsh from the id
+	fsh, err := GetFsHandlerByUUID(bdid)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	//Get parent disk hierarcy
+	parentDiskID, err := userinfo.HomeDirectories.HyperBackupManager.GetParentDiskIDByRestoreDiskID(fsh.UUID)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+	parentFsh, err := GetFsHandlerByUUID(parentDiskID)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	//Get task by the backup disk id
+	task, err := userinfo.HomeDirectories.HyperBackupManager.GetTaskByBackupDiskID(fsh.UUID)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	if task.Mode == "version" {
+		//Generate snapshot summary
+		var summary *hybridBackup.SnapshotSummary
+		if parentFsh.Hierarchy == "user" {
+			s, err := task.GenerateSnapshotSummary(snapshot, &userinfo.Username)
+			if err != nil {
+				utils.SendErrorResponse(w, err.Error())
+				return
+			}
+			summary = s
+		} else {
+			s, err := task.GenerateSnapshotSummary(snapshot, nil)
+			if err != nil {
+				utils.SendErrorResponse(w, err.Error())
+				return
+			}
+			summary = s
+		}
+
+		js, _ := json.Marshal(summary)
+		utils.SendJSONResponse(w, string(js))
+	} else {
+		utils.SendErrorResponse(w, "Unable to genreate snapshot summary: Backup mode is not snapshot")
+		return
+	}
+
+}
+
+//Restore a given file
+func backup_restoreSelected(w http.ResponseWriter, r *http.Request) {
+	//Get user accessiable storage pools
+	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		utils.SendErrorResponse(w, "User not logged in")
+		return
+	}
+
+	//Get Backup disk ID from request
+	bdid, err := utils.Mv(r, "bdid", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid backup disk ID given")
+		return
+	}
+
+	//Get fsh from the id
+	fsh, err := GetFsHandlerByUUID(bdid)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	//Get the relative path for the restorable file
+	relpath, err := utils.Mv(r, "relpath", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid relative path given")
+		return
+	}
+
+	//Pick the correct HybridBackup Manager
+	targetHybridBackupManager, err := backup_pickHybridBackupManager(userinfo, fsh.UUID)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	//Handle restore of the file
+	err = targetHybridBackupManager.HandleRestore(fsh.UUID, relpath, &userinfo.Username)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	type RestoreResult struct {
+		RestoreDiskID       string
+		TargetDiskID        string
+		RestoredVirtualPath string
+	}
+
+	result := RestoreResult{
+		RestoreDiskID: fsh.UUID,
+	}
+
+	//Get access path for this file
+	parentDiskId, err := targetHybridBackupManager.GetParentDiskIDByRestoreDiskID(fsh.UUID)
+	if err != nil {
+		//Unable to get parent disk ID???
+
+	} else {
+		//Get the path of the parent disk
+		parentDiskHandler, err := GetFsHandlerByUUID(parentDiskId)
+		if err == nil {
+			//Join the result to create a virtual path
+			assumedRestoreRealPath := filepath.ToSlash(filepath.Join(parentDiskHandler.Path, relpath))
+			restoreVpath, err := userinfo.RealPathToVirtualPath(assumedRestoreRealPath)
+			if err == nil {
+				result.RestoredVirtualPath = restoreVpath
+			}
+			result.TargetDiskID = parentDiskId
+		}
+
+	}
+
+	js, _ := json.Marshal(result)
+	utils.SendJSONResponse(w, string(js))
+}
+
+//As one user might be belongs to multiple groups, check which storage pool is this disk ID owned by and return its corect backup maanger
+func backup_pickHybridBackupManager(userinfo *user.User, diskID string) (*hybridBackup.Manager, error) {
+	//Filter out the :/ if it exists in the disk ID
+	if strings.Contains(diskID, ":") {
+		diskID = strings.Split(diskID, ":")[0]
+	}
+
+	//Get all backup managers that this user ac can access
+	userpg := userinfo.GetUserPermissionGroup()
+
+	if userinfo.HomeDirectories.ContainDiskID(diskID) {
+		return userinfo.HomeDirectories.HyperBackupManager, nil
+	}
+
+	//Extract the backup Managers
+	for _, pg := range userpg {
+		if pg.StoragePool.ContainDiskID(diskID) {
+			return pg.StoragePool.HyperBackupManager, nil
+		}
+
+	}
+
+	return nil, errors.New("Disk ID not found in any storage pool this user can access")
+}
+
+//Generate and return a restorable report
+func backup_listRestorable(w http.ResponseWriter, r *http.Request) {
+	//Get user accessiable storage pools
+	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		utils.SendErrorResponse(w, "User not logged in")
+		return
+	}
+
+	//Get Vroot ID from request
+	vroot, err := utils.Mv(r, "vroot", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid vroot given")
+		return
+	}
+
+	//Get fsh from the id
+	fsh, err := GetFsHandlerByUUID(vroot)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	//Get all backup managers that this user ac can access
+	targetBackupManager, err := backup_pickHybridBackupManager(userinfo, vroot)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	//Get the user's storage pool and list restorable by the user's storage pool access
+	restorableReport, err := targetBackupManager.ListRestorable(fsh.UUID)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	//Get and check if the parent disk has a user Hierarcy
+	paretnfsh, err := GetFsHandlerByUUID(restorableReport.ParentUID)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	result := hybridBackup.RestorableReport{
+		ParentUID:       restorableReport.ParentUID,
+		RestorableFiles: []*hybridBackup.RestorableFile{},
+	}
+
+	if paretnfsh.Hierarchy == "user" {
+		//The file system is user based. Filter out those file that is not belong to this user
+		for _, restorableFile := range restorableReport.RestorableFiles {
+			if restorableFile.IsSnapshot {
+				//Is snapshot. Always allow access
+				result.RestorableFiles = append(result.RestorableFiles, restorableFile)
+			} else {
+				//Is file
+				fileAbsPath := filepath.Join(fsh.Path, restorableFile.RelpathOnDisk)
+				_, err := userinfo.RealPathToVirtualPath(fileAbsPath)
+				if err != nil {
+					//Cannot translate this file. That means the file is not owned by this user
+				} else {
+					//Can translate the path.
+					result.RestorableFiles = append(result.RestorableFiles, restorableFile)
+				}
+			}
+
+		}
+	} else {
+		result = restorableReport
+	}
+
+	js, _ := json.Marshal(result)
+	utils.SendJSONResponse(w, string(js))
+}

+ 5 - 5
main.router.go

@@ -13,9 +13,9 @@ import (
 	"strconv"
 	"strings"
 
-	"imuslab.com/arozos/mod/common"
 	fs "imuslab.com/arozos/mod/filesystem"
 	"imuslab.com/arozos/mod/network/gzipmiddleware"
+	"imuslab.com/arozos/mod/utils"
 )
 
 func mrouter(h http.Handler) http.Handler {
@@ -30,15 +30,15 @@ func mrouter(h http.Handler) http.Handler {
 		} else if r.URL.Path == "/login.system" {
 			//Login page. Require special treatment for template.
 			//Get the redirection address from the request URL
-			red, _ := common.Mv(r, "redirect", false)
+			red, _ := utils.Mv(r, "redirect", false)
 
 			//Append the redirection addr into the template
 			imgsrc := "./web/" + iconSystem
 			if !fs.FileExists(imgsrc) {
 				imgsrc = "./web/img/public/auth_icon.png"
 			}
-			imageBase64, _ := common.LoadImageAsBase64(imgsrc)
-			parsedPage, err := common.Templateload("web/login.system", map[string]interface{}{
+			imageBase64, _ := utils.LoadImageAsBase64(imgsrc)
+			parsedPage, err := utils.Templateload("web/login.system", map[string]interface{}{
 				"redirection_addr": red,
 				"usercount":        strconv.Itoa(authAgent.GetUserCounts()),
 				"service_logo":     imageBase64,
@@ -162,7 +162,7 @@ func mrouter(h http.Handler) http.Handler {
 				//Other paths
 				//Rediect to login page
 				w.Header().Set("Cache-Control", "no-cache, no-store, no-transform, must-revalidate, private, max-age=0")
-				http.Redirect(w, r, common.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect="+r.URL.String(), 307)
+				http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect="+r.URL.String(), 307)
 			}
 
 		}

+ 342 - 342
mediaServer.go

@@ -1,342 +1,342 @@
-package main
-
-import (
-	"crypto/md5"
-	"encoding/hex"
-	"errors"
-	"io"
-	"net/http"
-	"net/url"
-	"os"
-	"path/filepath"
-	"strconv"
-	"strings"
-	"time"
-
-	"imuslab.com/arozos/mod/common"
-	"imuslab.com/arozos/mod/compatibility"
-	"imuslab.com/arozos/mod/filesystem"
-	fs "imuslab.com/arozos/mod/filesystem"
-	"imuslab.com/arozos/mod/network/gzipmiddleware"
-)
-
-/*
-Media Server
-This function serve large file objects like video and audio file via asynchronize go routine :)
-
-Example usage:
-/media/?file=user:/Desktop/test/02.Orchestra- エミール (Addendum version).mp3
-/media/?file=user:/Desktop/test/02.Orchestra- エミール (Addendum version).mp3&download=true
-
-This will serve / download the file located at files/users/{username}/Desktop/test/02.Orchestra- エミール (Addendum version).mp3
-
-PLEASE ALWAYS USE URLENCODE IN THE LINK PASSED INTO THE /media ENDPOINT
-*/
-
-func mediaServer_init() {
-	if *enable_gzip {
-		http.HandleFunc("/media/", gzipmiddleware.CompressFunc(serverMedia))
-		http.HandleFunc("/media/getMime/", gzipmiddleware.CompressFunc(serveMediaMime))
-	} else {
-		http.HandleFunc("/media/", serverMedia)
-		http.HandleFunc("/media/getMime/", serveMediaMime)
-	}
-
-	//Download API always bypass gzip no matter if gzip mode is enabled
-	http.HandleFunc("/media/download/", serverMedia)
-}
-
-//This function validate the incoming media request and return fsh, vpath, rpath and err if any
-func media_server_validateSourceFile(w http.ResponseWriter, r *http.Request) (*filesystem.FileSystemHandler, string, string, error) {
-	username, err := authAgent.GetUserName(w, r)
-	if err != nil {
-		return nil, "", "", errors.New("User not logged in")
-	}
-
-	userinfo, _ := userHandler.GetUserInfoFromUsername(username)
-
-	//Validate url valid
-	if strings.Count(r.URL.String(), "?") > 1 {
-		return nil, "", "", errors.New("Invalid paramters. Multiple ? found")
-	}
-
-	targetfile, _ := common.Mv(r, "file", false)
-	targetfile, err = url.QueryUnescape(targetfile)
-	if err != nil {
-		return nil, "", "", err
-	}
-	if targetfile == "" {
-		return nil, "", "", errors.New("Missing paramter 'file'")
-	}
-
-	//Translate the virtual directory to realpath
-	fsh, subpath, err := GetFSHandlerSubpathFromVpath(targetfile)
-	if err != nil {
-		return nil, "", "", errors.New("Unable to load from target file system")
-	}
-	fshAbs := fsh.FileSystemAbstraction
-	realFilepath, err := fshAbs.VirtualPathToRealPath(subpath, userinfo.Username)
-	if fshAbs.FileExists(realFilepath) && fshAbs.IsDir(realFilepath) {
-		return nil, "", "", errors.New("Given path is not a file")
-	}
-	if err != nil {
-		return nil, "", "", errors.New("Unable to translate the given filepath")
-	}
-
-	if !fshAbs.FileExists(realFilepath) {
-		//Sometime if url is not URL encoded, this error might be shown as well
-
-		//Try to use manual segmentation
-
-		originalURL := r.URL.String()
-		//Must be pre-processed with system special URI Decode function to handle edge cases
-		originalURL = fs.DecodeURI(originalURL)
-		if strings.Contains(originalURL, "&download=true") {
-			originalURL = strings.ReplaceAll(originalURL, "&download=true", "")
-		} else if strings.Contains(originalURL, "download=true") {
-			originalURL = strings.ReplaceAll(originalURL, "download=true", "")
-		}
-		if strings.Contains(originalURL, "&file=") {
-			originalURL = strings.ReplaceAll(originalURL, "&file=", "file=")
-		}
-		urlInfo := strings.Split(originalURL, "file=")
-		possibleVirtualFilePath := urlInfo[len(urlInfo)-1]
-		possibleRealpath, err := fshAbs.VirtualPathToRealPath(possibleVirtualFilePath, userinfo.Username)
-		if err != nil {
-			systemWideLogger.PrintAndLog("Media Server", "Error when trying to serve file in compatibility mode", err)
-			return nil, "", "", errors.New("Error when trying to serve file in compatibility mode")
-		}
-		if fshAbs.FileExists(possibleRealpath) {
-			realFilepath = possibleRealpath
-			systemWideLogger.PrintAndLog("Media Server", "Serving file "+filepath.Base(possibleRealpath)+" in compatibility mode. Do not to use '&' or '+' sign in filename! ", nil)
-			return fsh, targetfile, realFilepath, nil
-		} else {
-			return nil, "", "", errors.New("File not exists")
-		}
-	}
-
-	return fsh, targetfile, realFilepath, nil
-}
-
-func serveMediaMime(w http.ResponseWriter, r *http.Request) {
-	targetFsh, _, realFilepath, err := media_server_validateSourceFile(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-	targetFshAbs := targetFsh.FileSystemAbstraction
-	if targetFsh.RequireBuffer {
-		//File is not on local. Guess its mime by extension
-		common.SendTextResponse(w, "application/"+filepath.Ext(realFilepath)[1:])
-		return
-	}
-
-	mime := "text/directory"
-	if !targetFshAbs.IsDir(realFilepath) {
-		m, _, err := fs.GetMime(realFilepath)
-		if err != nil {
-			mime = ""
-		}
-		mime = m
-	}
-
-	common.SendTextResponse(w, mime)
-}
-
-func serverMedia(w http.ResponseWriter, r *http.Request) {
-	userinfo, _ := userHandler.GetUserInfoFromRequest(w, r)
-	//Serve normal media files
-	targetFsh, vpath, realFilepath, err := media_server_validateSourceFile(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	targetFshAbs := targetFsh.FileSystemAbstraction
-
-	//Check if downloadMode
-	downloadMode := false
-	dw, _ := common.Mv(r, "download", false)
-	if dw == "true" {
-		downloadMode = true
-	}
-
-	//New download implementations, allow /download to be used instead of &download=true
-	if strings.Contains(r.RequestURI, "media/download/?file=") {
-		downloadMode = true
-	}
-
-	//Serve the file
-	if downloadMode {
-		escapedRealFilepath, err := url.PathUnescape(realFilepath)
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-			return
-		}
-		filename := filepath.Base(escapedRealFilepath)
-
-		/*
-			//12 Jul 2022 Update: Deprecated the browser detection logic
-			userAgent := r.Header.Get("User-Agent")
-			if strings.Contains(userAgent, "Safari/")) {
-				//This is Safari. Use speial header
-				w.Header().Set("Content-Disposition", "attachment; filename="+filepath.Base(realFilepath))
-			} else {
-				//Fixing the header issue on Golang url encode lib problems
-				w.Header().Set("Content-Disposition", "attachment; filename*=UTF-8''"+filename)
-			}
-		*/
-
-		w.Header().Set("Content-Disposition", "attachment; filename=\""+filename+"\"")
-		w.Header().Set("Content-Type", compatibility.BrowserCompatibilityOverrideContentType(r.UserAgent(), filename, r.Header.Get("Content-Type")))
-		if targetFsh.RequireBuffer || !filesystem.FileExists(realFilepath) {
-			//Stream it directly from remote
-			w.Header().Set("Content-Length", strconv.Itoa(int(targetFshAbs.GetFileSize(realFilepath))))
-			remoteStream, err := targetFshAbs.ReadStream(realFilepath)
-			if err != nil {
-				common.SendErrorResponse(w, err.Error())
-				return
-			}
-			io.Copy(w, remoteStream)
-			remoteStream.Close()
-		} else {
-			http.ServeFile(w, r, escapedRealFilepath)
-		}
-
-	} else {
-		if targetFsh.RequireBuffer {
-			w.Header().Set("Content-Length", strconv.Itoa(int(targetFshAbs.GetFileSize(realFilepath))))
-			//Check buffer exists
-			ps, _ := targetFsh.GetUniquePathHash(vpath, userinfo.Username)
-			buffpool := filepath.Join(*tmp_directory, "fsbuffpool")
-			buffFile := filepath.Join(buffpool, ps)
-			if fs.FileExists(buffFile) {
-				//Stream the buff file if hash matches
-				remoteFileHash, err := getHashFromRemoteFile(targetFsh.FileSystemAbstraction, realFilepath)
-				if err == nil {
-					localFileHash, err := os.ReadFile(buffFile + ".hash")
-					if err == nil {
-						if string(localFileHash) == remoteFileHash {
-							//Hash matches. Serve local buffered file
-							http.ServeFile(w, r, buffFile)
-							return
-						}
-					}
-				}
-
-			}
-
-			remoteStream, err := targetFshAbs.ReadStream(realFilepath)
-			if err != nil {
-				common.SendErrorResponse(w, err.Error())
-				return
-			}
-			defer remoteStream.Close()
-			io.Copy(w, remoteStream)
-
-			if *enable_buffering {
-				os.MkdirAll(buffpool, 0775)
-				go func() {
-					BufferRemoteFileToTmp(buffFile, targetFsh, realFilepath)
-				}()
-			}
-
-		} else if !filesystem.FileExists(realFilepath) {
-			//Streaming from remote file system that support fseek
-			f, err := targetFsh.FileSystemAbstraction.Open(realFilepath)
-			if err != nil {
-				w.WriteHeader(http.StatusInternalServerError)
-				w.Write([]byte("500 - Internal Server Error"))
-				return
-			}
-			fstat, _ := f.Stat()
-			defer f.Close()
-			http.ServeContent(w, r, filepath.Base(realFilepath), fstat.ModTime(), f)
-		} else {
-			http.ServeFile(w, r, realFilepath)
-		}
-
-	}
-
-}
-
-func BufferRemoteFileToTmp(buffFile string, fsh *filesystem.FileSystemHandler, rpath string) error {
-	if fs.FileExists(buffFile + ".download") {
-		return errors.New("another buffer process running")
-	}
-
-	//Generate a stat file for the buffer
-	hash, err := getHashFromRemoteFile(fsh.FileSystemAbstraction, rpath)
-	if err != nil {
-		//Do not buffer
-		return err
-	}
-	os.WriteFile(buffFile+".hash", []byte(hash), 0775)
-
-	//Buffer the file from remote to local
-	f, err := fsh.FileSystemAbstraction.ReadStream(rpath)
-	if err != nil {
-		os.Remove(buffFile + ".hash")
-		return err
-	}
-	defer f.Close()
-
-	dest, err := os.OpenFile(buffFile+".download", os.O_CREATE|os.O_WRONLY, 0775)
-	if err != nil {
-		os.Remove(buffFile + ".hash")
-		return err
-	}
-	defer dest.Close()
-
-	io.Copy(dest, f)
-	f.Close()
-	dest.Close()
-
-	os.Rename(buffFile+".download", buffFile)
-
-	//Clean the oldest buffpool item if size too large
-	dirsize, _ := fs.GetDirctorySize(filepath.Dir(buffFile), false)
-	oldestModtime := time.Now().Unix()
-	oldestFile := ""
-	for int(dirsize) > *bufferPoolSize<<20 {
-		//fmt.Println("CLEARNING BUFF", dirsize)
-		files, _ := filepath.Glob(filepath.ToSlash(filepath.Dir(buffFile)) + "/*")
-		for _, file := range files {
-			if filepath.Ext(file) == ".hash" {
-				continue
-			}
-			thisModTime, _ := fs.GetModTime(file)
-			if thisModTime < oldestModtime {
-				oldestModtime = thisModTime
-				oldestFile = file
-			}
-		}
-
-		os.Remove(oldestFile)
-		os.Remove(oldestFile + ".hash")
-
-		dirsize, _ = fs.GetDirctorySize(filepath.Dir(buffFile), false)
-		oldestModtime = time.Now().Unix()
-	}
-	return nil
-}
-
-func getHashFromRemoteFile(fshAbs filesystem.FileSystemAbstraction, rpath string) (string, error) {
-	filestat, err := fshAbs.Stat(rpath)
-	if err != nil {
-		//Always pull from remote
-		return "", err
-	}
-
-	if filestat.Size() >= int64(*bufferPoolSize<<20) {
-		return "", errors.New("Unable to buffer: file larger than buffpool size")
-	}
-
-	if filestat.Size() >= int64(*bufferFileMaxSize<<20) {
-		return "", errors.New("File larger than max buffer file size")
-	}
-
-	statHash := strconv.Itoa(int(filestat.ModTime().Unix() + filestat.Size()))
-	hash := md5.Sum([]byte(statHash))
-	return hex.EncodeToString(hash[:]), nil
-}
+package main
+
+import (
+	"crypto/md5"
+	"encoding/hex"
+	"errors"
+	"io"
+	"net/http"
+	"net/url"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"time"
+
+	"imuslab.com/arozos/mod/compatibility"
+	"imuslab.com/arozos/mod/filesystem"
+	fs "imuslab.com/arozos/mod/filesystem"
+	"imuslab.com/arozos/mod/network/gzipmiddleware"
+	"imuslab.com/arozos/mod/utils"
+)
+
+/*
+Media Server
+This function serve large file objects like video and audio file via asynchronize go routine :)
+
+Example usage:
+/media/?file=user:/Desktop/test/02.Orchestra- エミール (Addendum version).mp3
+/media/?file=user:/Desktop/test/02.Orchestra- エミール (Addendum version).mp3&download=true
+
+This will serve / download the file located at files/users/{username}/Desktop/test/02.Orchestra- エミール (Addendum version).mp3
+
+PLEASE ALWAYS USE URLENCODE IN THE LINK PASSED INTO THE /media ENDPOINT
+*/
+
+func mediaServer_init() {
+	if *enable_gzip {
+		http.HandleFunc("/media/", gzipmiddleware.CompressFunc(serverMedia))
+		http.HandleFunc("/media/getMime/", gzipmiddleware.CompressFunc(serveMediaMime))
+	} else {
+		http.HandleFunc("/media/", serverMedia)
+		http.HandleFunc("/media/getMime/", serveMediaMime)
+	}
+
+	//Download API always bypass gzip no matter if gzip mode is enabled
+	http.HandleFunc("/media/download/", serverMedia)
+}
+
+//This function validate the incoming media request and return fsh, vpath, rpath and err if any
+func media_server_validateSourceFile(w http.ResponseWriter, r *http.Request) (*filesystem.FileSystemHandler, string, string, error) {
+	username, err := authAgent.GetUserName(w, r)
+	if err != nil {
+		return nil, "", "", errors.New("User not logged in")
+	}
+
+	userinfo, _ := userHandler.GetUserInfoFromUsername(username)
+
+	//Validate url valid
+	if strings.Count(r.URL.String(), "?") > 1 {
+		return nil, "", "", errors.New("Invalid paramters. Multiple ? found")
+	}
+
+	targetfile, _ := utils.Mv(r, "file", false)
+	targetfile, err = url.QueryUnescape(targetfile)
+	if err != nil {
+		return nil, "", "", err
+	}
+	if targetfile == "" {
+		return nil, "", "", errors.New("Missing paramter 'file'")
+	}
+
+	//Translate the virtual directory to realpath
+	fsh, subpath, err := GetFSHandlerSubpathFromVpath(targetfile)
+	if err != nil {
+		return nil, "", "", errors.New("Unable to load from target file system")
+	}
+	fshAbs := fsh.FileSystemAbstraction
+	realFilepath, err := fshAbs.VirtualPathToRealPath(subpath, userinfo.Username)
+	if fshAbs.FileExists(realFilepath) && fshAbs.IsDir(realFilepath) {
+		return nil, "", "", errors.New("Given path is not a file")
+	}
+	if err != nil {
+		return nil, "", "", errors.New("Unable to translate the given filepath")
+	}
+
+	if !fshAbs.FileExists(realFilepath) {
+		//Sometime if url is not URL encoded, this error might be shown as well
+
+		//Try to use manual segmentation
+
+		originalURL := r.URL.String()
+		//Must be pre-processed with system special URI Decode function to handle edge cases
+		originalURL = fs.DecodeURI(originalURL)
+		if strings.Contains(originalURL, "&download=true") {
+			originalURL = strings.ReplaceAll(originalURL, "&download=true", "")
+		} else if strings.Contains(originalURL, "download=true") {
+			originalURL = strings.ReplaceAll(originalURL, "download=true", "")
+		}
+		if strings.Contains(originalURL, "&file=") {
+			originalURL = strings.ReplaceAll(originalURL, "&file=", "file=")
+		}
+		urlInfo := strings.Split(originalURL, "file=")
+		possibleVirtualFilePath := urlInfo[len(urlInfo)-1]
+		possibleRealpath, err := fshAbs.VirtualPathToRealPath(possibleVirtualFilePath, userinfo.Username)
+		if err != nil {
+			systemWideLogger.PrintAndLog("Media Server", "Error when trying to serve file in compatibility mode", err)
+			return nil, "", "", errors.New("Error when trying to serve file in compatibility mode")
+		}
+		if fshAbs.FileExists(possibleRealpath) {
+			realFilepath = possibleRealpath
+			systemWideLogger.PrintAndLog("Media Server", "Serving file "+filepath.Base(possibleRealpath)+" in compatibility mode. Do not to use '&' or '+' sign in filename! ", nil)
+			return fsh, targetfile, realFilepath, nil
+		} else {
+			return nil, "", "", errors.New("File not exists")
+		}
+	}
+
+	return fsh, targetfile, realFilepath, nil
+}
+
+func serveMediaMime(w http.ResponseWriter, r *http.Request) {
+	targetFsh, _, realFilepath, err := media_server_validateSourceFile(w, r)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+	targetFshAbs := targetFsh.FileSystemAbstraction
+	if targetFsh.RequireBuffer {
+		//File is not on local. Guess its mime by extension
+		utils.SendTextResponse(w, "application/"+filepath.Ext(realFilepath)[1:])
+		return
+	}
+
+	mime := "text/directory"
+	if !targetFshAbs.IsDir(realFilepath) {
+		m, _, err := fs.GetMime(realFilepath)
+		if err != nil {
+			mime = ""
+		}
+		mime = m
+	}
+
+	utils.SendTextResponse(w, mime)
+}
+
+func serverMedia(w http.ResponseWriter, r *http.Request) {
+	userinfo, _ := userHandler.GetUserInfoFromRequest(w, r)
+	//Serve normal media files
+	targetFsh, vpath, realFilepath, err := media_server_validateSourceFile(w, r)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	targetFshAbs := targetFsh.FileSystemAbstraction
+
+	//Check if downloadMode
+	downloadMode := false
+	dw, _ := utils.Mv(r, "download", false)
+	if dw == "true" {
+		downloadMode = true
+	}
+
+	//New download implementations, allow /download to be used instead of &download=true
+	if strings.Contains(r.RequestURI, "media/download/?file=") {
+		downloadMode = true
+	}
+
+	//Serve the file
+	if downloadMode {
+		escapedRealFilepath, err := url.PathUnescape(realFilepath)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+		filename := filepath.Base(escapedRealFilepath)
+
+		/*
+			//12 Jul 2022 Update: Deprecated the browser detection logic
+			userAgent := r.Header.Get("User-Agent")
+			if strings.Contains(userAgent, "Safari/")) {
+				//This is Safari. Use speial header
+				w.Header().Set("Content-Disposition", "attachment; filename="+filepath.Base(realFilepath))
+			} else {
+				//Fixing the header issue on Golang url encode lib problems
+				w.Header().Set("Content-Disposition", "attachment; filename*=UTF-8''"+filename)
+			}
+		*/
+
+		w.Header().Set("Content-Disposition", "attachment; filename=\""+filename+"\"")
+		w.Header().Set("Content-Type", compatibility.BrowserCompatibilityOverrideContentType(r.UserAgent(), filename, r.Header.Get("Content-Type")))
+		if targetFsh.RequireBuffer || !filesystem.FileExists(realFilepath) {
+			//Stream it directly from remote
+			w.Header().Set("Content-Length", strconv.Itoa(int(targetFshAbs.GetFileSize(realFilepath))))
+			remoteStream, err := targetFshAbs.ReadStream(realFilepath)
+			if err != nil {
+				utils.SendErrorResponse(w, err.Error())
+				return
+			}
+			io.Copy(w, remoteStream)
+			remoteStream.Close()
+		} else {
+			http.ServeFile(w, r, escapedRealFilepath)
+		}
+
+	} else {
+		if targetFsh.RequireBuffer {
+			w.Header().Set("Content-Length", strconv.Itoa(int(targetFshAbs.GetFileSize(realFilepath))))
+			//Check buffer exists
+			ps, _ := targetFsh.GetUniquePathHash(vpath, userinfo.Username)
+			buffpool := filepath.Join(*tmp_directory, "fsbuffpool")
+			buffFile := filepath.Join(buffpool, ps)
+			if fs.FileExists(buffFile) {
+				//Stream the buff file if hash matches
+				remoteFileHash, err := getHashFromRemoteFile(targetFsh.FileSystemAbstraction, realFilepath)
+				if err == nil {
+					localFileHash, err := os.ReadFile(buffFile + ".hash")
+					if err == nil {
+						if string(localFileHash) == remoteFileHash {
+							//Hash matches. Serve local buffered file
+							http.ServeFile(w, r, buffFile)
+							return
+						}
+					}
+				}
+
+			}
+
+			remoteStream, err := targetFshAbs.ReadStream(realFilepath)
+			if err != nil {
+				utils.SendErrorResponse(w, err.Error())
+				return
+			}
+			defer remoteStream.Close()
+			io.Copy(w, remoteStream)
+
+			if *enable_buffering {
+				os.MkdirAll(buffpool, 0775)
+				go func() {
+					BufferRemoteFileToTmp(buffFile, targetFsh, realFilepath)
+				}()
+			}
+
+		} else if !filesystem.FileExists(realFilepath) {
+			//Streaming from remote file system that support fseek
+			f, err := targetFsh.FileSystemAbstraction.Open(realFilepath)
+			if err != nil {
+				w.WriteHeader(http.StatusInternalServerError)
+				w.Write([]byte("500 - Internal Server Error"))
+				return
+			}
+			fstat, _ := f.Stat()
+			defer f.Close()
+			http.ServeContent(w, r, filepath.Base(realFilepath), fstat.ModTime(), f)
+		} else {
+			http.ServeFile(w, r, realFilepath)
+		}
+
+	}
+
+}
+
+func BufferRemoteFileToTmp(buffFile string, fsh *filesystem.FileSystemHandler, rpath string) error {
+	if fs.FileExists(buffFile + ".download") {
+		return errors.New("another buffer process running")
+	}
+
+	//Generate a stat file for the buffer
+	hash, err := getHashFromRemoteFile(fsh.FileSystemAbstraction, rpath)
+	if err != nil {
+		//Do not buffer
+		return err
+	}
+	os.WriteFile(buffFile+".hash", []byte(hash), 0775)
+
+	//Buffer the file from remote to local
+	f, err := fsh.FileSystemAbstraction.ReadStream(rpath)
+	if err != nil {
+		os.Remove(buffFile + ".hash")
+		return err
+	}
+	defer f.Close()
+
+	dest, err := os.OpenFile(buffFile+".download", os.O_CREATE|os.O_WRONLY, 0775)
+	if err != nil {
+		os.Remove(buffFile + ".hash")
+		return err
+	}
+	defer dest.Close()
+
+	io.Copy(dest, f)
+	f.Close()
+	dest.Close()
+
+	os.Rename(buffFile+".download", buffFile)
+
+	//Clean the oldest buffpool item if size too large
+	dirsize, _ := fs.GetDirctorySize(filepath.Dir(buffFile), false)
+	oldestModtime := time.Now().Unix()
+	oldestFile := ""
+	for int(dirsize) > *bufferPoolSize<<20 {
+		//fmt.Println("CLEARNING BUFF", dirsize)
+		files, _ := filepath.Glob(filepath.ToSlash(filepath.Dir(buffFile)) + "/*")
+		for _, file := range files {
+			if filepath.Ext(file) == ".hash" {
+				continue
+			}
+			thisModTime, _ := fs.GetModTime(file)
+			if thisModTime < oldestModtime {
+				oldestModtime = thisModTime
+				oldestFile = file
+			}
+		}
+
+		os.Remove(oldestFile)
+		os.Remove(oldestFile + ".hash")
+
+		dirsize, _ = fs.GetDirctorySize(filepath.Dir(buffFile), false)
+		oldestModtime = time.Now().Unix()
+	}
+	return nil
+}
+
+func getHashFromRemoteFile(fshAbs filesystem.FileSystemAbstraction, rpath string) (string, error) {
+	filestat, err := fshAbs.Stat(rpath)
+	if err != nil {
+		//Always pull from remote
+		return "", err
+	}
+
+	if filestat.Size() >= int64(*bufferPoolSize<<20) {
+		return "", errors.New("Unable to buffer: file larger than buffpool size")
+	}
+
+	if filestat.Size() >= int64(*bufferFileMaxSize<<20) {
+		return "", errors.New("File larger than max buffer file size")
+	}
+
+	statHash := strconv.Itoa(int(filestat.ModTime().Unix() + filestat.Size()))
+	hash := md5.Sum([]byte(statHash))
+	return hex.EncodeToString(hash[:]), nil
+}

+ 3 - 3
mod/agi/agi.appdata.go

@@ -8,9 +8,9 @@ import (
 	"path/filepath"
 
 	"github.com/robertkrimen/otto"
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/filesystem"
 	user "imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -54,7 +54,7 @@ func (g *Gateway) injectAppdataLibFunctions(vm *otto.Otto, u *user.User, scriptF
 
 		//Check if file exists
 		targetFile := filepath.Join(webRoot, relpath)
-		if common.FileExists(targetFile) && !filesystem.IsDir(targetFile) {
+		if utils.FileExists(targetFile) && !filesystem.IsDir(targetFile) {
 			content, err := ioutil.ReadFile(targetFile)
 			if err != nil {
 				g.raiseError(err)
@@ -95,7 +95,7 @@ func (g *Gateway) injectAppdataLibFunctions(vm *otto.Otto, u *user.User, scriptF
 
 		//Check if file exists
 		targetFolder := filepath.Join(webRoot, relpath)
-		if common.FileExists(targetFolder) && filesystem.IsDir(targetFolder) {
+		if utils.FileExists(targetFolder) && filesystem.IsDir(targetFolder) {
 			//Glob the directory for filelist
 			files, err := filepath.Glob(filepath.ToSlash(filepath.Clean(targetFolder)) + "/*")
 			if err != nil {

+ 8 - 8
mod/agi/agi.go

@@ -16,13 +16,13 @@ import (
 	uuid "github.com/satori/go.uuid"
 
 	apt "imuslab.com/arozos/mod/apt"
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/filesystem"
 	metadata "imuslab.com/arozos/mod/filesystem/metadata"
 	"imuslab.com/arozos/mod/iot"
 	"imuslab.com/arozos/mod/share"
 	"imuslab.com/arozos/mod/time/nightly"
 	user "imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -185,7 +185,7 @@ func (g *Gateway) raiseError(err error) {
 //Check if this table is restricted table. Return true if the access is valid
 func (g *Gateway) filterDBTable(tablename string, existsCheck bool) bool {
 	//Check if table is restricted
-	if common.StringInArray(g.ReservedTables, tablename) {
+	if utils.StringInArray(g.ReservedTables, tablename) {
 		return false
 	}
 
@@ -201,7 +201,7 @@ func (g *Gateway) filterDBTable(tablename string, existsCheck bool) bool {
 
 //Handle request from RESTFUL API
 func (g *Gateway) APIHandler(w http.ResponseWriter, r *http.Request, thisuser *user.User) {
-	scriptContent, err := common.Mv(r, "script", true)
+	scriptContent, err := utils.Mv(r, "script", true)
 	if err != nil {
 		w.WriteHeader(http.StatusBadRequest)
 		w.Write([]byte("400 - Bad Request (Missing script content)"))
@@ -217,9 +217,9 @@ func (g *Gateway) InterfaceHandler(w http.ResponseWriter, r *http.Request, thisu
 	startupRoot = filepath.ToSlash(filepath.Clean(startupRoot))
 
 	//Get the script files for the plugin
-	scriptFile, err := common.Mv(r, "script", false)
+	scriptFile, err := utils.Mv(r, "script", false)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid script path")
+		utils.SendErrorResponse(w, "Invalid script path")
 		return
 	}
 	scriptFile = specialURIDecode(scriptFile)
@@ -229,7 +229,7 @@ func (g *Gateway) InterfaceHandler(w http.ResponseWriter, r *http.Request, thisu
 	scriptScope := "./web/"
 	for _, thisScope := range g.Option.ActivateScope {
 		thisScope = filepath.ToSlash(filepath.Clean(thisScope))
-		if common.FileExists(thisScope + "/" + scriptFile) {
+		if utils.FileExists(thisScope + "/" + scriptFile) {
 			scriptExists = true
 			scriptFile = thisScope + "/" + scriptFile
 			scriptScope = thisScope
@@ -237,7 +237,7 @@ func (g *Gateway) InterfaceHandler(w http.ResponseWriter, r *http.Request, thisu
 	}
 
 	if !scriptExists {
-		common.SendErrorResponse(w, "Script not found")
+		utils.SendErrorResponse(w, "Script not found")
 		return
 	}
 
@@ -324,7 +324,7 @@ func (g *Gateway) ExecuteAGIScript(scriptContent string, fsh *filesystem.FileSys
 	//Get the return valu from the script
 	value, err := vm.Get("HTTP_RESP")
 	if err != nil {
-		common.SendTextResponse(w, "")
+		utils.SendTextResponse(w, "")
 		return
 	}
 	valueString, err := value.ToString()

+ 2 - 2
mod/agi/agi.image.go

@@ -18,10 +18,10 @@ import (
 	"github.com/oliamb/cutter"
 	"github.com/robertkrimen/otto"
 
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/filesystem"
 	"imuslab.com/arozos/mod/neuralnet"
 	user "imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -129,7 +129,7 @@ func (g *Gateway) injectImageLibFunctions(vm *otto.Otto, u *user.User, scriptFsh
 		}
 
 		ext := strings.ToLower(filepath.Ext(rdest))
-		if !common.StringInArray([]string{".jpg", ".jpeg", ".png"}, ext) {
+		if !utils.StringInArray([]string{".jpg", ".jpeg", ".png"}, ext) {
 			g.raiseError(errors.New("File extension not supported. Only support .jpg and .png"))
 			return otto.FalseValue()
 		}

+ 3 - 3
mod/agi/agi.serverless.go

@@ -5,8 +5,8 @@ import (
 	"net/http"
 
 	"github.com/robertkrimen/otto"
-	"imuslab.com/arozos/mod/common"
 	user "imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -23,7 +23,7 @@ func (g *Gateway) injectServerlessFunctions(vm *otto.Otto, scriptFile string, sc
 		if key == "" {
 			return otto.NullValue()
 		}
-		value, err := common.Mv(r, key, false)
+		value, err := utils.Mv(r, key, false)
 		if err != nil {
 			return otto.NullValue()
 		}
@@ -40,7 +40,7 @@ func (g *Gateway) injectServerlessFunctions(vm *otto.Otto, scriptFile string, sc
 		if key == "" {
 			return otto.NullValue()
 		}
-		value, err := common.Mv(r, key, true)
+		value, err := utils.Mv(r, key, true)
 		if err != nil {
 			return otto.NullValue()
 		}

+ 23 - 23
mod/agi/external.agi.go

@@ -9,7 +9,7 @@ import (
 	"time"
 
 	"github.com/google/uuid"
-	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/utils"
 )
 
 type endpointFormat struct {
@@ -23,7 +23,7 @@ func (g *Gateway) ExtAPIHandler(w http.ResponseWriter, r *http.Request) {
 	sysdb := g.Option.UserHandler.GetDatabase()
 
 	if !sysdb.TableExists("external_agi") {
-		common.SendErrorResponse(w, "Invalid Request")
+		utils.SendErrorResponse(w, "Invalid Request")
 		return
 	}
 
@@ -33,7 +33,7 @@ func (g *Gateway) ExtAPIHandler(w http.ResponseWriter, r *http.Request) {
 
 	// check if it contains only two part, [rexec uuid]
 	if len(subpathElements) != 3 {
-		common.SendErrorResponse(w, "Invalid Request")
+		utils.SendErrorResponse(w, "Invalid Request")
 		return
 	}
 
@@ -41,7 +41,7 @@ func (g *Gateway) ExtAPIHandler(w http.ResponseWriter, r *http.Request) {
 	// get the info from the database
 	data, isExist := g.checkIfExternalEndpointExist(subpathElements[2])
 	if !isExist {
-		common.SendErrorResponse(w, "Malform Request, invaild UUID given")
+		utils.SendErrorResponse(w, "Malform Request, invaild UUID given")
 		return
 	}
 
@@ -51,12 +51,12 @@ func (g *Gateway) ExtAPIHandler(w http.ResponseWriter, r *http.Request) {
 	// get the userinfo and the realPath
 	userInfo, err := g.Option.UserHandler.GetUserInfoFromUsername(usernameFromDb)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid username")
+		utils.SendErrorResponse(w, "Invalid username")
 		return
 	}
 	fsh, realPath, err := virtualPathToRealPath(pathFromDb, userInfo)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid filepath")
+		utils.SendErrorResponse(w, "Invalid filepath")
 		return
 	}
 
@@ -67,10 +67,10 @@ func (g *Gateway) ExtAPIHandler(w http.ResponseWriter, r *http.Request) {
 	duration := time.Since(start)
 
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
-	common.SendTextResponse(w, result)
+	utils.SendTextResponse(w, result)
 
 	log.Println("[Remote AGI] IP:", r.RemoteAddr, " executed the script ", pathFromDb, "(", realPath, ")", " on behalf of", userInfo.Username, "with total duration: ", duration)
 
@@ -79,7 +79,7 @@ func (g *Gateway) ExtAPIHandler(w http.ResponseWriter, r *http.Request) {
 func (g *Gateway) AddExternalEndPoint(w http.ResponseWriter, r *http.Request) {
 	userInfo, err := g.Option.UserHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 	// get db
@@ -90,9 +90,9 @@ func (g *Gateway) AddExternalEndPoint(w http.ResponseWriter, r *http.Request) {
 	var dat endpointFormat
 
 	// uuid: [path, id]
-	path, err := common.Mv(r, "path", false)
+	path, err := utils.Mv(r, "path", false)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid path given")
+		utils.SendErrorResponse(w, "Invalid path given")
 		return
 	}
 
@@ -104,19 +104,19 @@ func (g *Gateway) AddExternalEndPoint(w http.ResponseWriter, r *http.Request) {
 
 	jsonStr, err := json.Marshal(dat)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid JSON string: "+err.Error())
+		utils.SendErrorResponse(w, "Invalid JSON string: "+err.Error())
 		return
 	}
 	sysdb.Write("external_agi", id, string(jsonStr))
 
 	// send the uuid to frontend
-	common.SendJSONResponse(w, "\""+id+"\"")
+	utils.SendJSONResponse(w, "\""+id+"\"")
 }
 
 func (g *Gateway) RemoveExternalEndPoint(w http.ResponseWriter, r *http.Request) {
 	userInfo, err := g.Option.UserHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 
@@ -126,35 +126,35 @@ func (g *Gateway) RemoveExternalEndPoint(w http.ResponseWriter, r *http.Request)
 		sysdb.NewTable("external_agi")
 	}
 	// get path
-	uuid, err := common.Mv(r, "uuid", false)
+	uuid, err := utils.Mv(r, "uuid", false)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid uuid given")
+		utils.SendErrorResponse(w, "Invalid uuid given")
 		return
 	}
 
 	// check if endpoint is here
 	data, isExist := g.checkIfExternalEndpointExist(uuid)
 	if !isExist {
-		common.SendErrorResponse(w, "UUID does not exists in the database!")
+		utils.SendErrorResponse(w, "UUID does not exists in the database!")
 		return
 	}
 
 	// make sure user cant see other's endpoint
 	if data.Username != userInfo.Username {
-		common.SendErrorResponse(w, "Permission denied")
+		utils.SendErrorResponse(w, "Permission denied")
 		return
 	}
 
 	// delete record
 	sysdb.Delete("external_agi", uuid)
 
-	common.SendOK(w)
+	utils.SendOK(w)
 }
 
 func (g *Gateway) ListExternalEndpoint(w http.ResponseWriter, r *http.Request) {
 	userInfo, err := g.Option.UserHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 
@@ -170,7 +170,7 @@ func (g *Gateway) ListExternalEndpoint(w http.ResponseWriter, r *http.Request) {
 	// O(n) method to do the lookup
 	entries, err := sysdb.ListTable("external_agi")
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid table")
+		utils.SendErrorResponse(w, "Invalid table")
 		return
 	}
 	for _, keypairs := range entries {
@@ -189,10 +189,10 @@ func (g *Gateway) ListExternalEndpoint(w http.ResponseWriter, r *http.Request) {
 	// marhsal and return
 	returnJson, err := json.Marshal(dataFromDB)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid JSON: "+err.Error())
+		utils.SendErrorResponse(w, "Invalid JSON: "+err.Error())
 		return
 	}
-	common.SendJSONResponse(w, string(returnJson))
+	utils.SendJSONResponse(w, string(returnJson))
 }
 
 func (g *Gateway) checkIfExternalEndpointExist(uuid string) (endpointFormat, bool) {

+ 5 - 5
mod/agi/handler.go

@@ -5,22 +5,22 @@ import (
 	"net/http"
 	"path/filepath"
 
-	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/utils"
 )
 
 //Handle AGI Exectuion Request with token, design for letting other web scripting language like php to interface with AGI
 func (g *Gateway) HandleAgiExecutionRequestWithToken(w http.ResponseWriter, r *http.Request) {
-	token, err := common.Mv(r, "token", false)
+	token, err := utils.Mv(r, "token", false)
 	if err != nil {
 		//Username not defined
-		common.SendErrorResponse(w, "Token not defined or empty.")
+		utils.SendErrorResponse(w, "Token not defined or empty.")
 		return
 	}
 
-	script, err := common.Mv(r, "script", false)
+	script, err := utils.Mv(r, "script", false)
 	if err != nil {
 		//Username not defined
-		common.SendErrorResponse(w, "Script path not defined or empty.")
+		utils.SendErrorResponse(w, "Script path not defined or empty.")
 		return
 	}
 

+ 2 - 2
mod/agi/static.go

@@ -6,10 +6,10 @@ import (
 	"strings"
 
 	"github.com/robertkrimen/otto"
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/filesystem"
 	"imuslab.com/arozos/mod/filesystem/arozfs"
 	user "imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/utils"
 )
 
 //Get the full vpath if the passing value is a relative path
@@ -58,7 +58,7 @@ func checkUserAccessToScript(thisuser *user.User, scriptFile string, scriptScope
 
 //validate the given path is a script from webroot
 func isValidAGIScript(scriptPath string) bool {
-	return common.FileExists(filepath.Join("./web", scriptPath)) && (filepath.Ext(scriptPath) == ".js" || filepath.Ext(scriptPath) == ".agi")
+	return utils.FileExists(filepath.Join("./web", scriptPath)) && (filepath.Ext(scriptPath) == ".js" || filepath.Ext(scriptPath) == ".agi")
 }
 
 //Return the script root of the current executing script

+ 2 - 2
mod/agi/systemFunc.go

@@ -12,7 +12,7 @@ import (
 	"time"
 
 	"github.com/robertkrimen/otto"
-	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/utils"
 )
 
 //Inject aroz online custom functions into the virtual machine
@@ -363,7 +363,7 @@ func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptSco
 
 			//Check if the script file exists
 			targetScriptPath := filepath.ToSlash(filepath.Join(filepath.Dir(scriptFile), scriptName))
-			if !common.FileExists(targetScriptPath) {
+			if !utils.FileExists(targetScriptPath) {
 				g.raiseError(errors.New("*AGI* Target path not exists!"))
 				return otto.FalseValue()
 			}

+ 96 - 96
mod/auth/accesscontrol/blacklist/handler.go

@@ -1,96 +1,96 @@
-package blacklist
-
-import (
-	"encoding/json"
-	"net/http"
-	"strings"
-
-	"imuslab.com/arozos/mod/common"
-	"imuslab.com/arozos/mod/network"
-)
-
-/*
-	Handler for blacklist module
-
-*/
-
-func (bl *BlackList) HandleAddBannedIP(w http.ResponseWriter, r *http.Request) {
-	ipRange, err := common.Mv(r, "iprange", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid ip range given")
-		return
-	}
-
-	err = bl.Ban(ipRange)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	common.SendOK(w)
-}
-
-func (bl *BlackList) HandleRemoveBannedIP(w http.ResponseWriter, r *http.Request) {
-	ipRange, err := common.Mv(r, "iprange", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid ip range given")
-		return
-	}
-
-	err = bl.UnBan(ipRange)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	common.SendOK(w)
-}
-
-func (bl *BlackList) HandleSetBlacklistEnable(w http.ResponseWriter, r *http.Request) {
-	enableMode, _ := common.Mv(r, "enable", true)
-	if enableMode == "" {
-		//Get the current blacklist status
-		js, _ := json.Marshal(bl.Enabled)
-		common.SendJSONResponse(w, string(js))
-		return
-	} else {
-		if strings.ToLower(enableMode) == "true" {
-			bl.SetBlacklistEnabled(true)
-			common.SendOK(w)
-		} else if strings.ToLower(enableMode) == "false" {
-			bl.SetBlacklistEnabled(false)
-			common.SendOK(w)
-		} else {
-			common.SendErrorResponse(w, "Invalid mode given")
-		}
-	}
-}
-func (bl *BlackList) SetBlacklistEnabled(enabled bool) {
-	if enabled {
-		bl.Enabled = true
-		bl.database.Write("ipblacklist", "enable", true)
-	} else {
-		bl.Enabled = false
-		bl.database.Write("ipblacklist", "enable", false)
-	}
-}
-
-func (bl *BlackList) HandleListBannedIPs(w http.ResponseWriter, r *http.Request) {
-	bannedIpRanges := bl.ListBannedIpRanges()
-	js, _ := json.Marshal(bannedIpRanges)
-	common.SendJSONResponse(w, string(js))
-}
-
-func (bl *BlackList) CheckIsBannedByRequest(r *http.Request) bool {
-	if bl.Enabled == false {
-		//Blacklist not enabled. Always return not banned
-		return false
-	}
-	//Get the IP address from the request header
-	requestIP, err := network.GetIpFromRequest(r)
-	if err != nil {
-		return false
-	}
-
-	return bl.IsBanned(requestIP)
-}
+package blacklist
+
+import (
+	"encoding/json"
+	"net/http"
+	"strings"
+
+	"imuslab.com/arozos/mod/network"
+	"imuslab.com/arozos/mod/utils"
+)
+
+/*
+	Handler for blacklist module
+
+*/
+
+func (bl *BlackList) HandleAddBannedIP(w http.ResponseWriter, r *http.Request) {
+	ipRange, err := utils.Mv(r, "iprange", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid ip range given")
+		return
+	}
+
+	err = bl.Ban(ipRange)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	utils.SendOK(w)
+}
+
+func (bl *BlackList) HandleRemoveBannedIP(w http.ResponseWriter, r *http.Request) {
+	ipRange, err := utils.Mv(r, "iprange", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid ip range given")
+		return
+	}
+
+	err = bl.UnBan(ipRange)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	utils.SendOK(w)
+}
+
+func (bl *BlackList) HandleSetBlacklistEnable(w http.ResponseWriter, r *http.Request) {
+	enableMode, _ := utils.Mv(r, "enable", true)
+	if enableMode == "" {
+		//Get the current blacklist status
+		js, _ := json.Marshal(bl.Enabled)
+		utils.SendJSONResponse(w, string(js))
+		return
+	} else {
+		if strings.ToLower(enableMode) == "true" {
+			bl.SetBlacklistEnabled(true)
+			utils.SendOK(w)
+		} else if strings.ToLower(enableMode) == "false" {
+			bl.SetBlacklistEnabled(false)
+			utils.SendOK(w)
+		} else {
+			utils.SendErrorResponse(w, "Invalid mode given")
+		}
+	}
+}
+func (bl *BlackList) SetBlacklistEnabled(enabled bool) {
+	if enabled {
+		bl.Enabled = true
+		bl.database.Write("ipblacklist", "enable", true)
+	} else {
+		bl.Enabled = false
+		bl.database.Write("ipblacklist", "enable", false)
+	}
+}
+
+func (bl *BlackList) HandleListBannedIPs(w http.ResponseWriter, r *http.Request) {
+	bannedIpRanges := bl.ListBannedIpRanges()
+	js, _ := json.Marshal(bannedIpRanges)
+	utils.SendJSONResponse(w, string(js))
+}
+
+func (bl *BlackList) CheckIsBannedByRequest(r *http.Request) bool {
+	if bl.Enabled == false {
+		//Blacklist not enabled. Always return not banned
+		return false
+	}
+	//Get the IP address from the request header
+	requestIP, err := network.GetIpFromRequest(r)
+	if err != nil {
+		return false
+	}
+
+	return bl.IsBanned(requestIP)
+}

+ 82 - 82
mod/auth/accesscontrol/whitelist/handler.go

@@ -1,82 +1,82 @@
-package whitelist
-
-import (
-	"encoding/json"
-	"net/http"
-	"strings"
-
-	"imuslab.com/arozos/mod/common"
-	"imuslab.com/arozos/mod/network"
-)
-
-func (wl *WhiteList) HandleAddWhitelistedIP(w http.ResponseWriter, r *http.Request) {
-	ipRange, err := common.Mv(r, "iprange", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid ip range given")
-		return
-	}
-
-	err = wl.SetWhitelist(ipRange)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	common.SendOK(w)
-}
-
-func (wl *WhiteList) HandleRemoveWhitelistedIP(w http.ResponseWriter, r *http.Request) {
-	ipRange, err := common.Mv(r, "iprange", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid ip range given")
-		return
-	}
-
-	err = wl.UnsetWhitelist(ipRange)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	common.SendOK(w)
-}
-
-func (wl *WhiteList) HandleSetWhitelistEnable(w http.ResponseWriter, r *http.Request) {
-	enableMode, _ := common.Mv(r, "enable", true)
-	if enableMode == "" {
-		//Get the current whitelist status
-		js, _ := json.Marshal(wl.Enabled)
-		common.SendJSONResponse(w, string(js))
-		return
-	} else {
-		if strings.ToLower(enableMode) == "true" {
-			wl.SetWhitelistEnabled(true)
-			common.SendOK(w)
-		} else if strings.ToLower(enableMode) == "false" {
-			wl.SetWhitelistEnabled(false)
-			common.SendOK(w)
-		} else {
-			common.SendErrorResponse(w, "Invalid mode given")
-		}
-	}
-}
-
-func (wl *WhiteList) HandleListWhitelistedIPs(w http.ResponseWriter, r *http.Request) {
-	bannedIpRanges := wl.ListWhitelistedIpRanges()
-	js, _ := json.Marshal(bannedIpRanges)
-	common.SendJSONResponse(w, string(js))
-}
-
-func (wl *WhiteList) CheckIsWhitelistedByRequest(r *http.Request) bool {
-	if wl.Enabled == false {
-		//Whitelist not enabled. Always return is whitelisted
-		return true
-	}
-	//Get the IP address from the request header
-	requestIP, err := network.GetIpFromRequest(r)
-	if err != nil {
-		return false
-	}
-
-	return wl.IsWhitelisted(requestIP)
-}
+package whitelist
+
+import (
+	"encoding/json"
+	"net/http"
+	"strings"
+
+	"imuslab.com/arozos/mod/network"
+	"imuslab.com/arozos/mod/utils"
+)
+
+func (wl *WhiteList) HandleAddWhitelistedIP(w http.ResponseWriter, r *http.Request) {
+	ipRange, err := utils.Mv(r, "iprange", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid ip range given")
+		return
+	}
+
+	err = wl.SetWhitelist(ipRange)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	utils.SendOK(w)
+}
+
+func (wl *WhiteList) HandleRemoveWhitelistedIP(w http.ResponseWriter, r *http.Request) {
+	ipRange, err := utils.Mv(r, "iprange", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid ip range given")
+		return
+	}
+
+	err = wl.UnsetWhitelist(ipRange)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	utils.SendOK(w)
+}
+
+func (wl *WhiteList) HandleSetWhitelistEnable(w http.ResponseWriter, r *http.Request) {
+	enableMode, _ := utils.Mv(r, "enable", true)
+	if enableMode == "" {
+		//Get the current whitelist status
+		js, _ := json.Marshal(wl.Enabled)
+		utils.SendJSONResponse(w, string(js))
+		return
+	} else {
+		if strings.ToLower(enableMode) == "true" {
+			wl.SetWhitelistEnabled(true)
+			utils.SendOK(w)
+		} else if strings.ToLower(enableMode) == "false" {
+			wl.SetWhitelistEnabled(false)
+			utils.SendOK(w)
+		} else {
+			utils.SendErrorResponse(w, "Invalid mode given")
+		}
+	}
+}
+
+func (wl *WhiteList) HandleListWhitelistedIPs(w http.ResponseWriter, r *http.Request) {
+	bannedIpRanges := wl.ListWhitelistedIpRanges()
+	js, _ := json.Marshal(bannedIpRanges)
+	utils.SendJSONResponse(w, string(js))
+}
+
+func (wl *WhiteList) CheckIsWhitelistedByRequest(r *http.Request) bool {
+	if wl.Enabled == false {
+		//Whitelist not enabled. Always return is whitelisted
+		return true
+	}
+	//Get the IP address from the request header
+	requestIP, err := network.GetIpFromRequest(r)
+	if err != nil {
+		return false
+	}
+
+	return wl.IsWhitelisted(requestIP)
+}

+ 8 - 8
mod/auth/auth.go

@@ -37,9 +37,9 @@ import (
 	"imuslab.com/arozos/mod/auth/accesscontrol/whitelist"
 	"imuslab.com/arozos/mod/auth/authlogger"
 	"imuslab.com/arozos/mod/auth/explogin"
-	"imuslab.com/arozos/mod/common"
 	db "imuslab.com/arozos/mod/database"
 	"imuslab.com/arozos/mod/network"
+	"imuslab.com/arozos/mod/utils"
 )
 
 type AuthAgent struct {
@@ -168,7 +168,7 @@ func (a *AuthAgent) HandleCheckAuth(w http.ResponseWriter, r *http.Request, hand
 func (a *AuthAgent) HandleLogin(w http.ResponseWriter, r *http.Request) {
 
 	//Get username from request using POST mode
-	username, err := common.Mv(r, "username", true)
+	username, err := utils.Mv(r, "username", true)
 	if err != nil {
 		//Username not defined
 		log.Println("[System Auth] Someone trying to login with username: " + username)
@@ -179,7 +179,7 @@ func (a *AuthAgent) HandleLogin(w http.ResponseWriter, r *http.Request) {
 	}
 
 	//Get password from request using POST mode
-	password, err := common.Mv(r, "password", true)
+	password, err := utils.Mv(r, "password", true)
 	if err != nil {
 		//Password not defined
 		a.Logger.LogAuth(r, false)
@@ -189,7 +189,7 @@ func (a *AuthAgent) HandleLogin(w http.ResponseWriter, r *http.Request) {
 
 	//Get rememberme settings
 	rememberme := false
-	rmbme, _ := common.Mv(r, "rmbme", true)
+	rmbme, _ := utils.Mv(r, "rmbme", true)
 	if rmbme == "true" {
 		rememberme = true
 	}
@@ -363,21 +363,21 @@ func (a *AuthAgent) HandleRegister(w http.ResponseWriter, r *http.Request) {
 	userCount := a.GetUserCounts()
 
 	//Get username from request
-	newusername, err := common.Mv(r, "username", true)
+	newusername, err := utils.Mv(r, "username", true)
 	if err != nil {
 		sendTextResponse(w, "Error. Missing 'username' paramter")
 		return
 	}
 
 	//Get password from request
-	password, err := common.Mv(r, "password", true)
+	password, err := utils.Mv(r, "password", true)
 	if err != nil {
 		sendTextResponse(w, "Error. Missing 'password' paramter")
 		return
 	}
 
 	//Set permission group to default
-	group, err := common.Mv(r, "group", true)
+	group, err := utils.Mv(r, "group", true)
 	if err != nil {
 		sendTextResponse(w, "Error. Missing 'group' paramter")
 		return
@@ -436,7 +436,7 @@ func (a *AuthAgent) HandleUnregister(w http.ResponseWriter, r *http.Request) {
 	*/
 
 	//Get username from request
-	username, err := common.Mv(r, "username", true)
+	username, err := utils.Mv(r, "username", true)
 	if err != nil {
 		sendErrorResponse(w, "Missing 'username' paramter")
 		return

+ 2 - 2
mod/auth/authlogger/authlogger.go

@@ -10,8 +10,8 @@ import (
 	"strings"
 	"time"
 
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/database"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -50,7 +50,7 @@ func NewLogger() (*Logger, error) {
 
 //Log the current authentication to record, Require the request object and login status
 func (l *Logger) LogAuth(r *http.Request, loginStatus bool) error {
-	username, _ := common.Mv(r, "username", true)
+	username, _ := utils.Mv(r, "username", true)
 	timestamp := time.Now().Unix()
 	//handling the reverse proxy remote IP issue
 	remoteIP := r.Header.Get("X-FORWARDED-FOR")

+ 7 - 7
mod/auth/authlogger/handlers.go

@@ -8,7 +8,7 @@ import (
 	"sort"
 	"time"
 
-	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/utils"
 )
 
 type summaryDate []string
@@ -38,25 +38,25 @@ func (l *Logger) HandleIndexListing(w http.ResponseWriter, r *http.Request) {
 	sort.Sort(summaryDate(indexes))
 	js, err := json.Marshal(indexes)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 //Handle of the listing of a given index (month)
 func (l *Logger) HandleTableListing(w http.ResponseWriter, r *http.Request) {
 	//Get the record name request for listing
-	month, err := common.Mv(r, "record", true)
+	month, err := utils.Mv(r, "record", true)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
 	records, err := l.ListRecords(month)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
@@ -71,5 +71,5 @@ func (l *Logger) HandleTableListing(w http.ResponseWriter, r *http.Request) {
 	}
 
 	js, _ := json.Marshal(results)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }

+ 3 - 3
mod/auth/autologin.go

@@ -12,7 +12,7 @@ import (
 
 	"github.com/gorilla/sessions"
 	uuid "github.com/satori/go.uuid"
-	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/utils"
 )
 
 //Autologin token. This token will not expire until admin removal
@@ -113,7 +113,7 @@ func (a *AuthAgent) HandleAutologinTokenLogin(w http.ResponseWriter, r *http.Req
 	}
 
 	session, _ := a.SessionStore.Get(r, a.SessionName)
-	token, err := common.Mv(r, "token", false)
+	token, err := utils.Mv(r, "token", false)
 	if err != nil {
 		//Username not defined
 		sendErrorResponse(w, "Token not defined or empty.")
@@ -164,7 +164,7 @@ func (a *AuthAgent) HandleAutologinTokenLogin(w http.ResponseWriter, r *http.Req
 
 	session.Save(r, w)
 
-	redirectTarget, _ := common.Mv(r, "redirect", false)
+	redirectTarget, _ := utils.Mv(r, "redirect", false)
 	if redirectTarget != "" {
 		//Redirect to target website
 		http.Redirect(w, r, redirectTarget, http.StatusTemporaryRedirect)

+ 12 - 12
mod/auth/autologin/autologin.go

@@ -4,8 +4,8 @@ import (
 	"encoding/json"
 	"net/http"
 
-	"imuslab.com/arozos/mod/common"
 	user "imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/utils"
 )
 
 type AutoLoginHandler struct {
@@ -20,14 +20,14 @@ func NewAutoLoginHandler(uh *user.UserHandler) *AutoLoginHandler {
 
 //List the token given the username
 func (a *AutoLoginHandler) HandleUserTokensListing(w http.ResponseWriter, r *http.Request) {
-	username, err := common.Mv(r, "username", false)
+	username, err := utils.Mv(r, "username", false)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid username")
+		utils.SendErrorResponse(w, "Invalid username")
 		return
 	}
 
 	if !a.userHandler.GetAuthAgent().UserExists(username) {
-		common.SendErrorResponse(w, "User not exists!")
+		utils.SendErrorResponse(w, "User not exists!")
 		return
 	}
 
@@ -37,41 +37,41 @@ func (a *AutoLoginHandler) HandleUserTokensListing(w http.ResponseWriter, r *htt
 		tokensOnly = append(tokensOnly, token.Token)
 	}
 	jsonString, _ := json.Marshal(tokensOnly)
-	common.SendJSONResponse(w, string(jsonString))
+	utils.SendJSONResponse(w, string(jsonString))
 }
 
 //Handle User Token Creation, require username. Please use adminrouter to handle this function
 func (a *AutoLoginHandler) HandleUserTokenCreation(w http.ResponseWriter, r *http.Request) {
-	username, err := common.Mv(r, "username", false)
+	username, err := utils.Mv(r, "username", false)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid username")
+		utils.SendErrorResponse(w, "Invalid username")
 		return
 	}
 
 	//Check if user exists
 	authAgent := a.userHandler.GetAuthAgent()
 	if !authAgent.UserExists(username) {
-		common.SendErrorResponse(w, "User not exists!")
+		utils.SendErrorResponse(w, "User not exists!")
 		return
 	}
 
 	//Generate and send the token to client
 	token := authAgent.NewAutologinToken(username)
 	jsonString, _ := json.Marshal(token)
-	common.SendJSONResponse(w, string(jsonString))
+	utils.SendJSONResponse(w, string(jsonString))
 }
 
 //Remove the user token given the token
 func (a *AutoLoginHandler) HandleUserTokenRemoval(w http.ResponseWriter, r *http.Request) {
-	token, err := common.Mv(r, "token", false)
+	token, err := utils.Mv(r, "token", false)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid username")
+		utils.SendErrorResponse(w, "Invalid username")
 		return
 	}
 
 	authAgent := a.userHandler.GetAuthAgent()
 	authAgent.RemoveAutologinToken(token)
 
-	common.SendOK(w)
+	utils.SendOK(w)
 
 }

+ 4 - 4
mod/auth/batch.go

@@ -15,7 +15,7 @@ import (
 	"net/http"
 	"strings"
 
-	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -26,7 +26,7 @@ import (
 	Each user occupied one new line
 */
 func (a *AuthAgent) HandleCreateUserAccountsFromCSV(w http.ResponseWriter, r *http.Request) {
-	csvContent, err := common.Mv(r, "csv", true)
+	csvContent, err := utils.Mv(r, "csv", true)
 	if err != nil {
 		sendErrorResponse(w, "Invalid csv")
 		return
@@ -70,13 +70,13 @@ func (a *AuthAgent) HandleCreateUserAccountsFromCSV(w http.ResponseWriter, r *ht
 	Require paramter: group, exact
 */
 func (a *AuthAgent) HandleUserDeleteByGroup(w http.ResponseWriter, r *http.Request) {
-	group, err := common.Mv(r, "group", true)
+	group, err := utils.Mv(r, "group", true)
 	if err != nil {
 		sendErrorResponse(w, "Invalid group")
 	}
 
 	requireExact := true //Default true
-	exact, _ := common.Mv(r, "exact", true)
+	exact, _ := utils.Mv(r, "exact", true)
 	if exact == "false" {
 		requireExact = false
 	}

+ 180 - 180
mod/auth/ldap/web_admin.go

@@ -1,180 +1,180 @@
-package ldap
-
-import (
-	"encoding/json"
-	"errors"
-	"net/http"
-	"regexp"
-	"strconv"
-	"strings"
-
-	"imuslab.com/arozos/mod/auth/ldap/ldapreader"
-	"imuslab.com/arozos/mod/common"
-)
-
-func (ldap *ldapHandler) ReadConfig(w http.ResponseWriter, r *http.Request) {
-	//basic components
-	enabled, err := strconv.ParseBool(ldap.readSingleConfig("enabled"))
-	if err != nil {
-		common.SendTextResponse(w, "Invalid config value [key=enabled].")
-		return
-	}
-	//get the LDAP config from db
-	BindUsername := ldap.readSingleConfig("BindUsername")
-	BindPassword := ldap.readSingleConfig("BindPassword")
-	FQDN := ldap.readSingleConfig("FQDN")
-	BaseDN := ldap.readSingleConfig("BaseDN")
-
-	//marshall it and return
-	config, err := json.Marshal(Config{
-		Enabled:      enabled,
-		BindUsername: BindUsername,
-		BindPassword: BindPassword,
-		FQDN:         FQDN,
-		BaseDN:       BaseDN,
-	})
-	if err != nil {
-		empty, err := json.Marshal(Config{})
-		if err != nil {
-			common.SendErrorResponse(w, "Error while marshalling config")
-		}
-		common.SendJSONResponse(w, string(empty))
-	}
-	common.SendJSONResponse(w, string(config))
-}
-
-func (ldap *ldapHandler) WriteConfig(w http.ResponseWriter, r *http.Request) {
-	//receive the parameter
-	enabled, err := common.Mv(r, "enabled", true)
-	if err != nil {
-		common.SendErrorResponse(w, "enabled field can't be empty")
-		return
-	}
-
-	//allow empty fields if enabled is false
-	showError := true
-	if enabled != "true" {
-		showError = false
-	}
-
-	//four fields to store the LDAP authentication information
-	BindUsername, err := common.Mv(r, "bind_username", true)
-	if err != nil {
-		if showError {
-			common.SendErrorResponse(w, "bind_username field can't be empty")
-			return
-		}
-	}
-	BindPassword, err := common.Mv(r, "bind_password", true)
-	if err != nil {
-		if showError {
-			common.SendErrorResponse(w, "bind_password field can't be empty")
-			return
-		}
-	}
-	FQDN, err := common.Mv(r, "fqdn", true)
-	if err != nil {
-		if showError {
-			common.SendErrorResponse(w, "fqdn field can't be empty")
-			return
-		}
-	}
-	BaseDN, err := common.Mv(r, "base_dn", true)
-	if err != nil {
-		if showError {
-			common.SendErrorResponse(w, "base_dn field can't be empty")
-			return
-		}
-	}
-
-	//write the data back to db
-	ldap.coredb.Write("ldap", "enabled", enabled)
-	ldap.coredb.Write("ldap", "BindUsername", BindUsername)
-	ldap.coredb.Write("ldap", "BindPassword", BindPassword)
-	ldap.coredb.Write("ldap", "FQDN", FQDN)
-	ldap.coredb.Write("ldap", "BaseDN", BaseDN)
-
-	//update the new authencation infromation
-	ldap.ldapreader = ldapreader.NewLDAPReader(BindUsername, BindPassword, FQDN, BaseDN)
-
-	//return ok
-	common.SendOK(w)
-}
-
-func (ldap *ldapHandler) TestConnection(w http.ResponseWriter, r *http.Request) {
-	//marshall it and return the connection status
-	userList, totalLength, err := ldap.getAllUser(10)
-	if err != nil {
-		errMessage, err := json.Marshal(syncorizeUserReturnInterface{Error: err.Error()})
-		if err != nil {
-			common.SendErrorResponse(w, "{\"error\":\"Error while marshalling information\"}")
-			return
-		}
-		common.SendJSONResponse(w, string(errMessage))
-		return
-	}
-	returnJSON := syncorizeUserReturnInterface{Userinfo: userList, Length: len(userList), TotalLength: totalLength, Error: ""}
-	accountJSON, err := json.Marshal(returnJSON)
-	if err != nil {
-		errMessage, err := json.Marshal(syncorizeUserReturnInterface{Error: err.Error()})
-		if err != nil {
-			common.SendErrorResponse(w, "{\"error\":\"Error while marshalling information\"}")
-			return
-		}
-		common.SendJSONResponse(w, string(errMessage))
-		return
-	}
-	common.SendJSONResponse(w, string(accountJSON))
-}
-
-func (ldap *ldapHandler) checkCurrUserAdmin(w http.ResponseWriter, r *http.Request) (bool, error) {
-	//check current user is admin and new update will remove it or not
-	currentLoggedInUser, err := ldap.userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		return false, err
-	}
-	ldapCurrUserInfo, err := ldap.ldapreader.GetUser(currentLoggedInUser.Username)
-	if err != nil {
-		return false, errors.New(err.Error() + ", probably due to your account is not in the LDAP server")
-	}
-	isAdmin := false
-	//get the croups out from LDAP group list
-	regexSyntax := regexp.MustCompile("cn=([^,]+),")
-	for _, v := range ldapCurrUserInfo.GetAttributeValues("memberOf") {
-		//loop through all memberOf's array
-		groups := regexSyntax.FindStringSubmatch(v)
-		//if after regex there is still groups exists
-		if len(groups) > 0 {
-			//check if the LDAP group is already exists in ArOZOS system
-			if ldap.permissionHandler.GroupExists(groups[1]) {
-				if ldap.permissionHandler.GetPermissionGroupByName(groups[1]).IsAdmin {
-					isAdmin = true
-				}
-			}
-		}
-	}
-	return isAdmin, nil
-}
-
-func (ldap *ldapHandler) SynchronizeUser(w http.ResponseWriter, r *http.Request) {
-	//check if suer is admin before executing the command
-	//if user is admin then check if user will lost him/her's admin access
-	consistencyCheck, err := ldap.checkCurrUserAdmin(w, r)
-	if err != nil {
-		// escape " symbol manually
-		errorMsg := strings.ReplaceAll(err.Error(), "\"", "\\\"")
-		common.SendErrorResponse(w, errorMsg)
-		return
-	}
-	if !consistencyCheck {
-		common.SendErrorResponse(w, "You will no longer become the admin after synchronizing, synchronize terminated")
-		return
-	}
-
-	err = ldap.SynchronizeUserFromLDAP()
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-	common.SendOK(w)
-}
+package ldap
+
+import (
+	"encoding/json"
+	"errors"
+	"net/http"
+	"regexp"
+	"strconv"
+	"strings"
+
+	"imuslab.com/arozos/mod/auth/ldap/ldapreader"
+	"imuslab.com/arozos/mod/utils"
+)
+
+func (ldap *ldapHandler) ReadConfig(w http.ResponseWriter, r *http.Request) {
+	//basic components
+	enabled, err := strconv.ParseBool(ldap.readSingleConfig("enabled"))
+	if err != nil {
+		utils.SendTextResponse(w, "Invalid config value [key=enabled].")
+		return
+	}
+	//get the LDAP config from db
+	BindUsername := ldap.readSingleConfig("BindUsername")
+	BindPassword := ldap.readSingleConfig("BindPassword")
+	FQDN := ldap.readSingleConfig("FQDN")
+	BaseDN := ldap.readSingleConfig("BaseDN")
+
+	//marshall it and return
+	config, err := json.Marshal(Config{
+		Enabled:      enabled,
+		BindUsername: BindUsername,
+		BindPassword: BindPassword,
+		FQDN:         FQDN,
+		BaseDN:       BaseDN,
+	})
+	if err != nil {
+		empty, err := json.Marshal(Config{})
+		if err != nil {
+			utils.SendErrorResponse(w, "Error while marshalling config")
+		}
+		utils.SendJSONResponse(w, string(empty))
+	}
+	utils.SendJSONResponse(w, string(config))
+}
+
+func (ldap *ldapHandler) WriteConfig(w http.ResponseWriter, r *http.Request) {
+	//receive the parameter
+	enabled, err := utils.Mv(r, "enabled", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "enabled field can't be empty")
+		return
+	}
+
+	//allow empty fields if enabled is false
+	showError := true
+	if enabled != "true" {
+		showError = false
+	}
+
+	//four fields to store the LDAP authentication information
+	BindUsername, err := utils.Mv(r, "bind_username", true)
+	if err != nil {
+		if showError {
+			utils.SendErrorResponse(w, "bind_username field can't be empty")
+			return
+		}
+	}
+	BindPassword, err := utils.Mv(r, "bind_password", true)
+	if err != nil {
+		if showError {
+			utils.SendErrorResponse(w, "bind_password field can't be empty")
+			return
+		}
+	}
+	FQDN, err := utils.Mv(r, "fqdn", true)
+	if err != nil {
+		if showError {
+			utils.SendErrorResponse(w, "fqdn field can't be empty")
+			return
+		}
+	}
+	BaseDN, err := utils.Mv(r, "base_dn", true)
+	if err != nil {
+		if showError {
+			utils.SendErrorResponse(w, "base_dn field can't be empty")
+			return
+		}
+	}
+
+	//write the data back to db
+	ldap.coredb.Write("ldap", "enabled", enabled)
+	ldap.coredb.Write("ldap", "BindUsername", BindUsername)
+	ldap.coredb.Write("ldap", "BindPassword", BindPassword)
+	ldap.coredb.Write("ldap", "FQDN", FQDN)
+	ldap.coredb.Write("ldap", "BaseDN", BaseDN)
+
+	//update the new authencation infromation
+	ldap.ldapreader = ldapreader.NewLDAPReader(BindUsername, BindPassword, FQDN, BaseDN)
+
+	//return ok
+	utils.SendOK(w)
+}
+
+func (ldap *ldapHandler) TestConnection(w http.ResponseWriter, r *http.Request) {
+	//marshall it and return the connection status
+	userList, totalLength, err := ldap.getAllUser(10)
+	if err != nil {
+		errMessage, err := json.Marshal(syncorizeUserReturnInterface{Error: err.Error()})
+		if err != nil {
+			utils.SendErrorResponse(w, "{\"error\":\"Error while marshalling information\"}")
+			return
+		}
+		utils.SendJSONResponse(w, string(errMessage))
+		return
+	}
+	returnJSON := syncorizeUserReturnInterface{Userinfo: userList, Length: len(userList), TotalLength: totalLength, Error: ""}
+	accountJSON, err := json.Marshal(returnJSON)
+	if err != nil {
+		errMessage, err := json.Marshal(syncorizeUserReturnInterface{Error: err.Error()})
+		if err != nil {
+			utils.SendErrorResponse(w, "{\"error\":\"Error while marshalling information\"}")
+			return
+		}
+		utils.SendJSONResponse(w, string(errMessage))
+		return
+	}
+	utils.SendJSONResponse(w, string(accountJSON))
+}
+
+func (ldap *ldapHandler) checkCurrUserAdmin(w http.ResponseWriter, r *http.Request) (bool, error) {
+	//check current user is admin and new update will remove it or not
+	currentLoggedInUser, err := ldap.userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		return false, err
+	}
+	ldapCurrUserInfo, err := ldap.ldapreader.GetUser(currentLoggedInUser.Username)
+	if err != nil {
+		return false, errors.New(err.Error() + ", probably due to your account is not in the LDAP server")
+	}
+	isAdmin := false
+	//get the croups out from LDAP group list
+	regexSyntax := regexp.MustCompile("cn=([^,]+),")
+	for _, v := range ldapCurrUserInfo.GetAttributeValues("memberOf") {
+		//loop through all memberOf's array
+		groups := regexSyntax.FindStringSubmatch(v)
+		//if after regex there is still groups exists
+		if len(groups) > 0 {
+			//check if the LDAP group is already exists in ArOZOS system
+			if ldap.permissionHandler.GroupExists(groups[1]) {
+				if ldap.permissionHandler.GetPermissionGroupByName(groups[1]).IsAdmin {
+					isAdmin = true
+				}
+			}
+		}
+	}
+	return isAdmin, nil
+}
+
+func (ldap *ldapHandler) SynchronizeUser(w http.ResponseWriter, r *http.Request) {
+	//check if suer is admin before executing the command
+	//if user is admin then check if user will lost him/her's admin access
+	consistencyCheck, err := ldap.checkCurrUserAdmin(w, r)
+	if err != nil {
+		// escape " symbol manually
+		errorMsg := strings.ReplaceAll(err.Error(), "\"", "\\\"")
+		utils.SendErrorResponse(w, errorMsg)
+		return
+	}
+	if !consistencyCheck {
+		utils.SendErrorResponse(w, "You will no longer become the admin after synchronizing, synchronize terminated")
+		return
+	}
+
+	err = ldap.SynchronizeUserFromLDAP()
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+	utils.SendOK(w)
+}

+ 220 - 220
mod/auth/ldap/web_login.go

@@ -1,220 +1,220 @@
-package ldap
-
-import (
-	"encoding/json"
-	"log"
-	"net/http"
-	"strconv"
-
-	"imuslab.com/arozos/mod/common"
-)
-
-//LOGIN related function
-//functions basically same as arozos's original function
-func (ldap *ldapHandler) HandleLoginPage(w http.ResponseWriter, r *http.Request) {
-	checkLDAPenabled := ldap.readSingleConfig("enabled")
-	if checkLDAPenabled == "false" {
-		common.SendTextResponse(w, "LDAP not enabled.")
-		return
-	}
-	//load the template from file and inject necessary variables
-	red, _ := common.Mv(r, "redirect", false)
-
-	//Append the redirection addr into the template
-	imgsrc := "./web/" + ldap.iconSystem
-	if !common.FileExists(imgsrc) {
-		imgsrc = "./web/img/public/auth_icon.png"
-	}
-	imageBase64, _ := common.LoadImageAsBase64(imgsrc)
-	parsedPage, err := common.Templateload("web/login.system", map[string]interface{}{
-		"redirection_addr": red,
-		"usercount":        strconv.Itoa(ldap.ag.GetUserCounts()),
-		"service_logo":     imageBase64,
-		"login_addr":       "system/auth/ldap/login",
-	})
-	if err != nil {
-		panic("Error. Unable to parse login page. Is web directory data exists?")
-	}
-	w.Header().Add("Content-Type", "text/html; charset=UTF-8")
-	w.Write([]byte(parsedPage))
-}
-
-func (ldap *ldapHandler) HandleNewPasswordPage(w http.ResponseWriter, r *http.Request) {
-	checkLDAPenabled := ldap.readSingleConfig("enabled")
-	if checkLDAPenabled == "false" {
-		common.SendTextResponse(w, "LDAP not enabled.")
-		return
-	}
-	//get the parameter from the request
-	acc, err := common.Mv(r, "username", false)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-	displayname, err := common.Mv(r, "displayname", false)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-	key, err := common.Mv(r, "authkey", false)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-	//init the web interface
-	imgsrc := "./web/" + ldap.iconSystem
-	if !common.FileExists(imgsrc) {
-		imgsrc = "./web/img/public/auth_icon.png"
-	}
-	imageBase64, _ := common.LoadImageAsBase64(imgsrc)
-	template, err := common.Templateload("system/ldap/newPasswordTemplate.html", map[string]interface{}{
-		"vendor_logo":  imageBase64,
-		"username":     acc,
-		"display_name": displayname,
-		"key":          key,
-	})
-	if err != nil {
-		log.Fatal(err)
-	}
-	w.Header().Set("Content-Type", "text/html; charset=UTF-8")
-	w.Write([]byte(template))
-}
-
-func (ldap *ldapHandler) HandleLogin(w http.ResponseWriter, r *http.Request) {
-	checkLDAPenabled := ldap.readSingleConfig("enabled")
-	if checkLDAPenabled == "false" {
-		common.SendTextResponse(w, "LDAP not enabled.")
-		return
-	}
-	//Get username from request using POST mode
-	username, err := common.Mv(r, "username", true)
-	if err != nil {
-		//Username not defined
-		log.Println("[System Auth] Someone trying to login with username: " + username)
-		//Write to log
-		ldap.ag.Logger.LogAuth(r, false)
-		common.SendErrorResponse(w, "Username not defined or empty.")
-		return
-	}
-
-	//Get password from request using POST mode
-	password, err := common.Mv(r, "password", true)
-	if err != nil {
-		//Password not defined
-		ldap.ag.Logger.LogAuth(r, false)
-		common.SendErrorResponse(w, "Password not defined or empty.")
-		return
-	}
-
-	//Get rememberme settings
-	rememberme := false
-	rmbme, _ := common.Mv(r, "rmbme", true)
-	if rmbme == "true" {
-		rememberme = true
-	}
-
-	//Check the database and see if this user is in the database
-	passwordCorrect, err := ldap.ldapreader.Authenticate(username, password)
-	if err != nil {
-		ldap.ag.Logger.LogAuth(r, false)
-		common.SendErrorResponse(w, "Unable to connect to LDAP server")
-		log.Println("LDAP Authentication error, " + err.Error())
-		return
-	}
-	//The database contain this user information. Check its password if it is correct
-	if passwordCorrect {
-		//Password correct
-		//if user not exist then redirect to create pwd screen
-		if !ldap.ag.UserExists(username) {
-			authkey := ldap.syncdb.Store(username)
-			common.SendJSONResponse(w, "{\"redirect\":\"system/auth/ldap/newPassword?username="+username+"&displayname="+username+"&authkey="+authkey+"\"}")
-		} else {
-			// Set user as authenticated
-			ldap.ag.LoginUserByRequest(w, r, username, rememberme)
-			//Print the login message to console
-			log.Println(username + " logged in.")
-			ldap.ag.Logger.LogAuth(r, true)
-			common.SendOK(w)
-		}
-	} else {
-		//Password incorrect
-		log.Println(username + " has entered an invalid username or password")
-		common.SendErrorResponse(w, "Invalid username or password")
-		ldap.ag.Logger.LogAuth(r, false)
-		return
-	}
-}
-
-func (ldap *ldapHandler) HandleSetPassword(w http.ResponseWriter, r *http.Request) {
-	checkLDAPenabled := ldap.readSingleConfig("enabled")
-	if checkLDAPenabled == "false" {
-		common.SendTextResponse(w, "LDAP not enabled.")
-		return
-	}
-	//get paramters from request
-	username, err := common.Mv(r, "username", true)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-	password, err := common.Mv(r, "password", true)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-	authkey, err := common.Mv(r, "authkey", true)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	//check if the input key matches the database's username
-	isValid := ldap.syncdb.Read(authkey) == username
-	ldap.syncdb.Delete(authkey) // remove the key, aka key is one time use only
-	//if db data match the username, proceed
-	if isValid {
-		//if not exists
-		if !ldap.ag.UserExists(username) {
-			//get the user from ldap server
-			ldapUser, err := ldap.ldapreader.GetUser(username)
-			if err != nil {
-				common.SendErrorResponse(w, err.Error())
-				return
-			}
-			//convert the ldap usergroup to arozos usergroup
-			convertedInfo := ldap.convertGroup(ldapUser)
-			//create user account and login
-			ldap.ag.CreateUserAccount(username, password, convertedInfo.EquivGroup)
-			ldap.ag.Logger.LogAuth(r, true)
-			ldap.ag.LoginUserByRequest(w, r, username, false)
-			common.SendOK(w)
-			return
-		} else {
-			//if exist then return error
-			common.SendErrorResponse(w, "User exists, please contact the system administrator if you believe this is an error.")
-			return
-		}
-	} else {
-		common.SendErrorResponse(w, "Improper key detected")
-		log.Println(r.RemoteAddr + " attempted to use invaild key to create new user but failed")
-		return
-	}
-}
-
-//HandleCheckLDAP check if ldap is enabled
-func (ldap *ldapHandler) HandleCheckLDAP(w http.ResponseWriter, r *http.Request) {
-	enabledB := false
-	enabled := ldap.readSingleConfig("enabled")
-	if enabled == "true" {
-		enabledB = true
-	}
-
-	type returnFormat struct {
-		Enabled bool `json:"enabled"`
-	}
-	json, err := json.Marshal(returnFormat{Enabled: enabledB})
-	if err != nil {
-		common.SendErrorResponse(w, "Error occurred while marshalling JSON response")
-	}
-	common.SendJSONResponse(w, string(json))
-}
+package ldap
+
+import (
+	"encoding/json"
+	"log"
+	"net/http"
+	"strconv"
+
+	"imuslab.com/arozos/mod/utils"
+)
+
+//LOGIN related function
+//functions basically same as arozos's original function
+func (ldap *ldapHandler) HandleLoginPage(w http.ResponseWriter, r *http.Request) {
+	checkLDAPenabled := ldap.readSingleConfig("enabled")
+	if checkLDAPenabled == "false" {
+		utils.SendTextResponse(w, "LDAP not enabled.")
+		return
+	}
+	//load the template from file and inject necessary variables
+	red, _ := utils.Mv(r, "redirect", false)
+
+	//Append the redirection addr into the template
+	imgsrc := "./web/" + ldap.iconSystem
+	if !utils.FileExists(imgsrc) {
+		imgsrc = "./web/img/public/auth_icon.png"
+	}
+	imageBase64, _ := utils.LoadImageAsBase64(imgsrc)
+	parsedPage, err := utils.Templateload("web/login.system", map[string]interface{}{
+		"redirection_addr": red,
+		"usercount":        strconv.Itoa(ldap.ag.GetUserCounts()),
+		"service_logo":     imageBase64,
+		"login_addr":       "system/auth/ldap/login",
+	})
+	if err != nil {
+		panic("Error. Unable to parse login page. Is web directory data exists?")
+	}
+	w.Header().Add("Content-Type", "text/html; charset=UTF-8")
+	w.Write([]byte(parsedPage))
+}
+
+func (ldap *ldapHandler) HandleNewPasswordPage(w http.ResponseWriter, r *http.Request) {
+	checkLDAPenabled := ldap.readSingleConfig("enabled")
+	if checkLDAPenabled == "false" {
+		utils.SendTextResponse(w, "LDAP not enabled.")
+		return
+	}
+	//get the parameter from the request
+	acc, err := utils.Mv(r, "username", false)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+	displayname, err := utils.Mv(r, "displayname", false)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+	key, err := utils.Mv(r, "authkey", false)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+	//init the web interface
+	imgsrc := "./web/" + ldap.iconSystem
+	if !utils.FileExists(imgsrc) {
+		imgsrc = "./web/img/public/auth_icon.png"
+	}
+	imageBase64, _ := utils.LoadImageAsBase64(imgsrc)
+	template, err := utils.Templateload("system/ldap/newPasswordTemplate.html", map[string]interface{}{
+		"vendor_logo":  imageBase64,
+		"username":     acc,
+		"display_name": displayname,
+		"key":          key,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	w.Header().Set("Content-Type", "text/html; charset=UTF-8")
+	w.Write([]byte(template))
+}
+
+func (ldap *ldapHandler) HandleLogin(w http.ResponseWriter, r *http.Request) {
+	checkLDAPenabled := ldap.readSingleConfig("enabled")
+	if checkLDAPenabled == "false" {
+		utils.SendTextResponse(w, "LDAP not enabled.")
+		return
+	}
+	//Get username from request using POST mode
+	username, err := utils.Mv(r, "username", true)
+	if err != nil {
+		//Username not defined
+		log.Println("[System Auth] Someone trying to login with username: " + username)
+		//Write to log
+		ldap.ag.Logger.LogAuth(r, false)
+		utils.SendErrorResponse(w, "Username not defined or empty.")
+		return
+	}
+
+	//Get password from request using POST mode
+	password, err := utils.Mv(r, "password", true)
+	if err != nil {
+		//Password not defined
+		ldap.ag.Logger.LogAuth(r, false)
+		utils.SendErrorResponse(w, "Password not defined or empty.")
+		return
+	}
+
+	//Get rememberme settings
+	rememberme := false
+	rmbme, _ := utils.Mv(r, "rmbme", true)
+	if rmbme == "true" {
+		rememberme = true
+	}
+
+	//Check the database and see if this user is in the database
+	passwordCorrect, err := ldap.ldapreader.Authenticate(username, password)
+	if err != nil {
+		ldap.ag.Logger.LogAuth(r, false)
+		utils.SendErrorResponse(w, "Unable to connect to LDAP server")
+		log.Println("LDAP Authentication error, " + err.Error())
+		return
+	}
+	//The database contain this user information. Check its password if it is correct
+	if passwordCorrect {
+		//Password correct
+		//if user not exist then redirect to create pwd screen
+		if !ldap.ag.UserExists(username) {
+			authkey := ldap.syncdb.Store(username)
+			utils.SendJSONResponse(w, "{\"redirect\":\"system/auth/ldap/newPassword?username="+username+"&displayname="+username+"&authkey="+authkey+"\"}")
+		} else {
+			// Set user as authenticated
+			ldap.ag.LoginUserByRequest(w, r, username, rememberme)
+			//Print the login message to console
+			log.Println(username + " logged in.")
+			ldap.ag.Logger.LogAuth(r, true)
+			utils.SendOK(w)
+		}
+	} else {
+		//Password incorrect
+		log.Println(username + " has entered an invalid username or password")
+		utils.SendErrorResponse(w, "Invalid username or password")
+		ldap.ag.Logger.LogAuth(r, false)
+		return
+	}
+}
+
+func (ldap *ldapHandler) HandleSetPassword(w http.ResponseWriter, r *http.Request) {
+	checkLDAPenabled := ldap.readSingleConfig("enabled")
+	if checkLDAPenabled == "false" {
+		utils.SendTextResponse(w, "LDAP not enabled.")
+		return
+	}
+	//get paramters from request
+	username, err := utils.Mv(r, "username", true)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+	password, err := utils.Mv(r, "password", true)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+	authkey, err := utils.Mv(r, "authkey", true)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	//check if the input key matches the database's username
+	isValid := ldap.syncdb.Read(authkey) == username
+	ldap.syncdb.Delete(authkey) // remove the key, aka key is one time use only
+	//if db data match the username, proceed
+	if isValid {
+		//if not exists
+		if !ldap.ag.UserExists(username) {
+			//get the user from ldap server
+			ldapUser, err := ldap.ldapreader.GetUser(username)
+			if err != nil {
+				utils.SendErrorResponse(w, err.Error())
+				return
+			}
+			//convert the ldap usergroup to arozos usergroup
+			convertedInfo := ldap.convertGroup(ldapUser)
+			//create user account and login
+			ldap.ag.CreateUserAccount(username, password, convertedInfo.EquivGroup)
+			ldap.ag.Logger.LogAuth(r, true)
+			ldap.ag.LoginUserByRequest(w, r, username, false)
+			utils.SendOK(w)
+			return
+		} else {
+			//if exist then return error
+			utils.SendErrorResponse(w, "User exists, please contact the system administrator if you believe this is an error.")
+			return
+		}
+	} else {
+		utils.SendErrorResponse(w, "Improper key detected")
+		log.Println(r.RemoteAddr + " attempted to use invaild key to create new user but failed")
+		return
+	}
+}
+
+//HandleCheckLDAP check if ldap is enabled
+func (ldap *ldapHandler) HandleCheckLDAP(w http.ResponseWriter, r *http.Request) {
+	enabledB := false
+	enabled := ldap.readSingleConfig("enabled")
+	if enabled == "true" {
+		enabledB = true
+	}
+
+	type returnFormat struct {
+		Enabled bool `json:"enabled"`
+	}
+	json, err := json.Marshal(returnFormat{Enabled: enabledB})
+	if err != nil {
+		utils.SendErrorResponse(w, "Error occurred while marshalling JSON response")
+	}
+	utils.SendJSONResponse(w, string(json))
+}

+ 35 - 35
mod/auth/oauth2/oauth2.go

@@ -13,8 +13,8 @@ import (
 	auth "imuslab.com/arozos/mod/auth"
 	syncdb "imuslab.com/arozos/mod/auth/oauth2/syncdb"
 	reg "imuslab.com/arozos/mod/auth/register"
-	"imuslab.com/arozos/mod/common"
 	db "imuslab.com/arozos/mod/database"
+	"imuslab.com/arozos/mod/utils"
 )
 
 type OauthHandler struct {
@@ -64,11 +64,11 @@ func NewOauthHandler(authAgent *auth.AuthAgent, register *reg.RegisterHandler, c
 func (oh *OauthHandler) HandleLogin(w http.ResponseWriter, r *http.Request) {
 	enabled := oh.readSingleConfig("enabled")
 	if enabled == "" || enabled == "false" {
-		common.SendTextResponse(w, "OAuth disabled")
+		utils.SendTextResponse(w, "OAuth disabled")
 		return
 	}
 	//add cookies
-	redirect, err := common.Mv(r, "redirect", false)
+	redirect, err := utils.Mv(r, "redirect", false)
 	//store the redirect url to the sync map
 	uuid := ""
 	if err != nil {
@@ -87,36 +87,36 @@ func (oh *OauthHandler) HandleLogin(w http.ResponseWriter, r *http.Request) {
 func (oh *OauthHandler) HandleAuthorize(w http.ResponseWriter, r *http.Request) {
 	enabled := oh.readSingleConfig("enabled")
 	if enabled == "" || enabled == "false" {
-		common.SendTextResponse(w, "OAuth disabled")
+		utils.SendTextResponse(w, "OAuth disabled")
 		return
 	}
 	//read the uuid(aka the state parameter)
 	uuid, err := r.Cookie("uuid_login")
 	if err != nil {
-		common.SendTextResponse(w, "Invalid redirect URI.")
+		utils.SendTextResponse(w, "Invalid redirect URI.")
 		return
 	}
 
-	state, err := common.Mv(r, "state", true)
+	state, err := utils.Mv(r, "state", true)
 	if state != uuid.Value {
-		common.SendTextResponse(w, "Invalid oauth state.")
+		utils.SendTextResponse(w, "Invalid oauth state.")
 		return
 	}
 	if err != nil {
-		common.SendTextResponse(w, "Invalid state parameter.")
+		utils.SendTextResponse(w, "Invalid state parameter.")
 		return
 	}
 
-	code, err := common.Mv(r, "code", true)
+	code, err := utils.Mv(r, "code", true)
 	if err != nil {
-		common.SendTextResponse(w, "Invalid state parameter.")
+		utils.SendTextResponse(w, "Invalid state parameter.")
 		return
 	}
 
 	//exchange the infromation to get code
 	token, err := oh.googleOauthConfig.Exchange(context.Background(), code)
 	if err != nil {
-		common.SendTextResponse(w, "Code exchange failed.")
+		utils.SendTextResponse(w, "Code exchange failed.")
 		return
 	}
 
@@ -124,7 +124,7 @@ func (oh *OauthHandler) HandleAuthorize(w http.ResponseWriter, r *http.Request)
 	username, err := getUserInfo(token.AccessToken, oh.coredb)
 	if err != nil {
 		oh.ag.Logger.LogAuthByRequestInfo(username, r.RemoteAddr, time.Now().Unix(), false, "web")
-		common.SendTextResponse(w, "Failed to obtain user info.")
+		utils.SendTextResponse(w, "Failed to obtain user info.")
 		return
 	}
 
@@ -137,7 +137,7 @@ func (oh *OauthHandler) HandleAuthorize(w http.ResponseWriter, r *http.Request)
 			http.Redirect(w, r, "/public/register/register.system?user="+username, http.StatusFound)
 		} else {
 			oh.ag.Logger.LogAuthByRequestInfo(username, r.RemoteAddr, time.Now().Unix(), false, "web")
-			common.SendHTMLResponse(w, "You are not allowed to register in this system.&nbsp;<a href=\"/\">Back</a>")
+			utils.SendHTMLResponse(w, "You are not allowed to register in this system.&nbsp;<a href=\"/\">Back</a>")
 		}
 	} else {
 		log.Println(username + " logged in via OAuth.")
@@ -183,9 +183,9 @@ func (oh *OauthHandler) CheckOAuth(w http.ResponseWriter, r *http.Request) {
 	}
 	json, err := json.Marshal(returnFormat{Enabled: enabledB, AutoRedirect: autoredirectB})
 	if err != nil {
-		common.SendErrorResponse(w, "Error occurred while marshalling JSON response")
+		utils.SendErrorResponse(w, "Error occurred while marshalling JSON response")
 	}
-	common.SendJSONResponse(w, string(json))
+	utils.SendJSONResponse(w, string(json))
 }
 
 //https://golangcode.com/add-a-http-cookie/
@@ -202,12 +202,12 @@ func (oh *OauthHandler) addCookie(w http.ResponseWriter, name, value string, ttl
 func (oh *OauthHandler) ReadConfig(w http.ResponseWriter, r *http.Request) {
 	enabled, err := strconv.ParseBool(oh.readSingleConfig("enabled"))
 	if err != nil {
-		common.SendTextResponse(w, "Invalid config value [key=enabled].")
+		utils.SendTextResponse(w, "Invalid config value [key=enabled].")
 		return
 	}
 	autoredirect, err := strconv.ParseBool(oh.readSingleConfig("autoredirect"))
 	if err != nil {
-		common.SendTextResponse(w, "Invalid config value [key=autoredirect].")
+		utils.SendTextResponse(w, "Invalid config value [key=autoredirect].")
 		return
 	}
 	idp := oh.readSingleConfig("idp")
@@ -228,24 +228,24 @@ func (oh *OauthHandler) ReadConfig(w http.ResponseWriter, r *http.Request) {
 	if err != nil {
 		empty, err := json.Marshal(Config{})
 		if err != nil {
-			common.SendErrorResponse(w, "Error while marshalling config")
+			utils.SendErrorResponse(w, "Error while marshalling config")
 			return
 		}
-		common.SendJSONResponse(w, string(empty))
+		utils.SendJSONResponse(w, string(empty))
 		return
 	}
-	common.SendJSONResponse(w, string(config))
+	utils.SendJSONResponse(w, string(config))
 }
 
 func (oh *OauthHandler) WriteConfig(w http.ResponseWriter, r *http.Request) {
-	enabled, err := common.Mv(r, "enabled", true)
+	enabled, err := utils.Mv(r, "enabled", true)
 	if err != nil {
-		common.SendErrorResponse(w, "enabled field can't be empty")
+		utils.SendErrorResponse(w, "enabled field can't be empty")
 		return
 	}
-	autoredirect, err := common.Mv(r, "autoredirect", true)
+	autoredirect, err := utils.Mv(r, "autoredirect", true)
 	if err != nil {
-		common.SendErrorResponse(w, "enabled field can't be empty")
+		utils.SendErrorResponse(w, "enabled field can't be empty")
 		return
 	}
 
@@ -254,27 +254,27 @@ func (oh *OauthHandler) WriteConfig(w http.ResponseWriter, r *http.Request) {
 		showError = false
 	}
 
-	idp, err := common.Mv(r, "idp", true)
+	idp, err := utils.Mv(r, "idp", true)
 	if err != nil {
 		if showError {
-			common.SendErrorResponse(w, "idp field can't be empty")
+			utils.SendErrorResponse(w, "idp field can't be empty")
 			return
 		}
 	}
-	redirecturl, err := common.Mv(r, "redirecturl", true)
+	redirecturl, err := utils.Mv(r, "redirecturl", true)
 	if err != nil {
 		if showError {
-			common.SendErrorResponse(w, "redirecturl field can't be empty")
+			utils.SendErrorResponse(w, "redirecturl field can't be empty")
 			return
 		}
 	}
-	serverurl, err := common.Mv(r, "serverurl", true)
+	serverurl, err := utils.Mv(r, "serverurl", true)
 	if err != nil {
 		if showError {
 			if idp != "Gitlab" {
 				serverurl = ""
 			} else {
-				common.SendErrorResponse(w, "serverurl field can't be empty")
+				utils.SendErrorResponse(w, "serverurl field can't be empty")
 				return
 			}
 		}
@@ -283,17 +283,17 @@ func (oh *OauthHandler) WriteConfig(w http.ResponseWriter, r *http.Request) {
 		serverurl = ""
 	}
 
-	clientid, err := common.Mv(r, "clientid", true)
+	clientid, err := utils.Mv(r, "clientid", true)
 	if err != nil {
 		if showError {
-			common.SendErrorResponse(w, "clientid field can't be empty")
+			utils.SendErrorResponse(w, "clientid field can't be empty")
 			return
 		}
 	}
-	clientsecret, err := common.Mv(r, "clientsecret", true)
+	clientsecret, err := utils.Mv(r, "clientsecret", true)
 	if err != nil {
 		if showError {
-			common.SendErrorResponse(w, "clientsecret field can't be empty")
+			utils.SendErrorResponse(w, "clientsecret field can't be empty")
 			return
 		}
 	}
@@ -315,7 +315,7 @@ func (oh *OauthHandler) WriteConfig(w http.ResponseWriter, r *http.Request) {
 		Endpoint:     getEndpoint(oh.coredb),
 	}
 
-	common.SendOK(w)
+	utils.SendOK(w)
 }
 
 func (oh *OauthHandler) readSingleConfig(key string) string {

+ 21 - 21
mod/auth/register/register.go

@@ -21,9 +21,9 @@ import (
 
 	"github.com/valyala/fasttemplate"
 	auth "imuslab.com/arozos/mod/auth"
-	"imuslab.com/arozos/mod/common"
 	db "imuslab.com/arozos/mod/database"
 	permission "imuslab.com/arozos/mod/permission"
+	"imuslab.com/arozos/mod/utils"
 )
 
 type RegisterOptions struct {
@@ -85,9 +85,9 @@ func createDefaultGroup(ph *permission.PermissionHandler) {
 
 func (h *RegisterHandler) HandleRegisterCheck(w http.ResponseWriter, r *http.Request) {
 	if h.AllowRegistry {
-		common.SendJSONResponse(w, "true")
+		utils.SendJSONResponse(w, "true")
 	} else {
-		common.SendJSONResponse(w, "false")
+		utils.SendJSONResponse(w, "false")
 	}
 }
 
@@ -201,49 +201,49 @@ func (h *RegisterHandler) ListAllUserEmails() [][]interface{} {
 //Handle the request for creating a new user
 func (h *RegisterHandler) HandleRegisterRequest(w http.ResponseWriter, r *http.Request) {
 	if h.AllowRegistry == false {
-		common.SendErrorResponse(w, "Public account registry is currently closed")
+		utils.SendErrorResponse(w, "Public account registry is currently closed")
 		return
 	}
 	//Get input paramter
-	email, err := common.Mv(r, "email", true)
+	email, err := utils.Mv(r, "email", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid Email")
+		utils.SendErrorResponse(w, "Invalid Email")
 		return
 	}
 
 	//Validate the email is a email
 	if !isValidEmail(email) {
-		common.SendErrorResponse(w, "Invalid or malformed email")
+		utils.SendErrorResponse(w, "Invalid or malformed email")
 		return
 	}
 
-	username, err := common.Mv(r, "username", true)
+	username, err := utils.Mv(r, "username", true)
 	if username == "" || strings.TrimSpace(username) == "" || err != nil {
-		common.SendErrorResponse(w, "Invalid Username")
+		utils.SendErrorResponse(w, "Invalid Username")
 		return
 	}
 
-	password, err := common.Mv(r, "password", true)
+	password, err := utils.Mv(r, "password", true)
 	if password == "" || err != nil {
-		common.SendErrorResponse(w, "Invalid Password")
+		utils.SendErrorResponse(w, "Invalid Password")
 		return
 	}
 
 	//Check if password too short
 	if len(password) < 8 {
-		common.SendErrorResponse(w, "Password too short. Must be at least 8 characters.")
+		utils.SendErrorResponse(w, "Password too short. Must be at least 8 characters.")
 		return
 	}
 
 	//Check if the username is too short
 	if len(username) < 2 {
-		common.SendErrorResponse(w, "Username too short. Must be at least 2 characters.")
+		utils.SendErrorResponse(w, "Username too short. Must be at least 2 characters.")
 		return
 	}
 
 	//Check if the user already exists
 	if h.authAgent.UserExists(username) {
-		common.SendErrorResponse(w, "This username has already been used")
+		utils.SendErrorResponse(w, "This username has already been used")
 		return
 	}
 
@@ -252,21 +252,21 @@ func (h *RegisterHandler) HandleRegisterRequest(w http.ResponseWriter, r *http.R
 	if h.permissionHandler.GroupExists(defaultGroup) == false {
 		//Public registry user group not exists. Raise 500 Error
 		log.Println("[CRITICAL] PUBLIC REGISTRY USER GROUP NOT FOUND! PLEASE RESTART YOUR SYSTEM!")
-		common.SendErrorResponse(w, "Internal Server Error")
+		utils.SendErrorResponse(w, "Internal Server Error")
 		return
 	}
 
 	//OK. Record this user to the system
 	err = h.authAgent.CreateUserAccount(username, password, []string{defaultGroup})
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
 	//Write email to database as well
 	h.database.Write("register", "user/email/"+username, email)
 
-	common.SendOK(w)
+	utils.SendOK(w)
 	log.Println("New User Registered: ", email, username, strings.Repeat("*", len(password)))
 
 }
@@ -276,22 +276,22 @@ func (h *RegisterHandler) HandleEmailChange(w http.ResponseWriter, r *http.Reque
 	//Get username from request
 	username, err := h.authAgent.GetUserName(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "Unable to get username from request")
+		utils.SendErrorResponse(w, "Unable to get username from request")
 		return
 	}
 
-	email, err := common.Mv(r, "email", true)
+	email, err := utils.Mv(r, "email", true)
 	if err != nil {
 		//Return the user current email
 		currentEmail, _ := h.GetUserEmail(username)
 		js, _ := json.Marshal(currentEmail)
-		common.SendJSONResponse(w, string(js))
+		utils.SendJSONResponse(w, string(js))
 		return
 	}
 
 	//Validate the email is a email
 	if !isValidEmail(email) {
-		common.SendErrorResponse(w, "Invalid or malformed email")
+		utils.SendErrorResponse(w, "Invalid or malformed email")
 		return
 	}
 

+ 121 - 121
mod/disk/diskcapacity/diskcapacity.go

@@ -1,121 +1,121 @@
-package diskcapacity
-
-import (
-	"encoding/json"
-	"net/http"
-	"path/filepath"
-
-	"imuslab.com/arozos/mod/common"
-	"imuslab.com/arozos/mod/disk/diskcapacity/dftool"
-	"imuslab.com/arozos/mod/filesystem/arozfs"
-	"imuslab.com/arozos/mod/user"
-)
-
-/*
-	Disk Capacity
-	This is a simple module to check how many storage space is remaining
-	on a given directory in accessiable file system paths
-
-	Author: tobychui
-*/
-
-type Resolver struct {
-	UserHandler *user.UserHandler
-}
-
-type CapacityInfo struct {
-	PhysicalDevice    string
-	FileSystemType    string
-	MountingHierarchy string
-	Used              int64
-	Available         int64
-	Total             int64
-}
-
-//Create a new Capacity Resolver with the given user handler
-func NewCapacityResolver(u *user.UserHandler) *Resolver {
-	return &Resolver{
-		UserHandler: u,
-	}
-}
-
-func (cr *Resolver) HandleCapacityResolving(w http.ResponseWriter, r *http.Request) {
-	//Check if the request user is authenticated
-	userinfo, err := cr.UserHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
-		return
-	}
-
-	//Get vpath from paramter
-	vpath, err := common.Mv(r, "path", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Vpath is not defined")
-		return
-	}
-
-	capinfo, err := cr.ResolveCapacityInfo(userinfo.Username, vpath)
-	if err != nil {
-		common.SendErrorResponse(w, "Unable to resolve path capacity information: "+err.Error())
-		return
-	}
-
-	//Get Storage Hierarcy
-	fsh, err := userinfo.GetFileSystemHandlerFromVirtualPath(vpath)
-	if err != nil {
-		capinfo.MountingHierarchy = "Unknown"
-	} else {
-		capinfo.MountingHierarchy = fsh.Hierarchy
-	}
-
-	//Send the requested path capacity information
-	js, _ := json.Marshal(capinfo)
-	common.SendJSONResponse(w, string(js))
-
-}
-
-func (cr *Resolver) ResolveCapacityInfo(username string, vpath string) (*CapacityInfo, error) {
-	//Resolve the vpath for this user
-	userinfo, err := cr.UserHandler.GetUserInfoFromUsername(username)
-	if err != nil {
-		return nil, err
-	}
-
-	fsh, err := userinfo.GetFileSystemHandlerFromVirtualPath(vpath)
-	if err != nil {
-		return nil, err
-	}
-
-	realpath, err := fsh.FileSystemAbstraction.VirtualPathToRealPath(vpath, username)
-	if err != nil {
-		return nil, err
-	}
-
-	realpath = filepath.ToSlash(filepath.Clean(realpath))
-
-	if common.FileExists(realpath) && !arozfs.IsNetworkDrive(fsh.Filesystem) {
-		//This is a local disk
-		capinfo, err := dftool.GetCapacityInfoFromPath(realpath)
-		if err != nil {
-			return nil, err
-		}
-		return &CapacityInfo{
-			PhysicalDevice:    capinfo.PhysicalDevice,
-			FileSystemType:    fsh.Filesystem,
-			MountingHierarchy: fsh.Hierarchy,
-			Used:              capinfo.Used,
-			Available:         capinfo.Available,
-			Total:             capinfo.Total,
-		}, nil
-	} else {
-		//This is a remote disk
-		return &CapacityInfo{
-			PhysicalDevice:    fsh.Path,
-			FileSystemType:    fsh.Filesystem,
-			MountingHierarchy: fsh.Hierarchy,
-			Used:              0,
-			Available:         0,
-			Total:             0,
-		}, nil
-	}
-}
+package diskcapacity
+
+import (
+	"encoding/json"
+	"net/http"
+	"path/filepath"
+
+	"imuslab.com/arozos/mod/disk/diskcapacity/dftool"
+	"imuslab.com/arozos/mod/filesystem/arozfs"
+	"imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/utils"
+)
+
+/*
+	Disk Capacity
+	This is a simple module to check how many storage space is remaining
+	on a given directory in accessiable file system paths
+
+	Author: tobychui
+*/
+
+type Resolver struct {
+	UserHandler *user.UserHandler
+}
+
+type CapacityInfo struct {
+	PhysicalDevice    string
+	FileSystemType    string
+	MountingHierarchy string
+	Used              int64
+	Available         int64
+	Total             int64
+}
+
+//Create a new Capacity Resolver with the given user handler
+func NewCapacityResolver(u *user.UserHandler) *Resolver {
+	return &Resolver{
+		UserHandler: u,
+	}
+}
+
+func (cr *Resolver) HandleCapacityResolving(w http.ResponseWriter, r *http.Request) {
+	//Check if the request user is authenticated
+	userinfo, err := cr.UserHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		utils.SendErrorResponse(w, "User not logged in")
+		return
+	}
+
+	//Get vpath from paramter
+	vpath, err := utils.Mv(r, "path", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Vpath is not defined")
+		return
+	}
+
+	capinfo, err := cr.ResolveCapacityInfo(userinfo.Username, vpath)
+	if err != nil {
+		utils.SendErrorResponse(w, "Unable to resolve path capacity information: "+err.Error())
+		return
+	}
+
+	//Get Storage Hierarcy
+	fsh, err := userinfo.GetFileSystemHandlerFromVirtualPath(vpath)
+	if err != nil {
+		capinfo.MountingHierarchy = "Unknown"
+	} else {
+		capinfo.MountingHierarchy = fsh.Hierarchy
+	}
+
+	//Send the requested path capacity information
+	js, _ := json.Marshal(capinfo)
+	utils.SendJSONResponse(w, string(js))
+
+}
+
+func (cr *Resolver) ResolveCapacityInfo(username string, vpath string) (*CapacityInfo, error) {
+	//Resolve the vpath for this user
+	userinfo, err := cr.UserHandler.GetUserInfoFromUsername(username)
+	if err != nil {
+		return nil, err
+	}
+
+	fsh, err := userinfo.GetFileSystemHandlerFromVirtualPath(vpath)
+	if err != nil {
+		return nil, err
+	}
+
+	realpath, err := fsh.FileSystemAbstraction.VirtualPathToRealPath(vpath, username)
+	if err != nil {
+		return nil, err
+	}
+
+	realpath = filepath.ToSlash(filepath.Clean(realpath))
+
+	if utils.FileExists(realpath) && !arozfs.IsNetworkDrive(fsh.Filesystem) {
+		//This is a local disk
+		capinfo, err := dftool.GetCapacityInfoFromPath(realpath)
+		if err != nil {
+			return nil, err
+		}
+		return &CapacityInfo{
+			PhysicalDevice:    capinfo.PhysicalDevice,
+			FileSystemType:    fsh.Filesystem,
+			MountingHierarchy: fsh.Hierarchy,
+			Used:              capinfo.Used,
+			Available:         capinfo.Available,
+			Total:             capinfo.Total,
+		}, nil
+	} else {
+		//This is a remote disk
+		return &CapacityInfo{
+			PhysicalDevice:    fsh.Path,
+			FileSystemType:    fsh.Filesystem,
+			MountingHierarchy: fsh.Hierarchy,
+			Used:              0,
+			Available:         0,
+			Total:             0,
+		}, nil
+	}
+}

+ 47 - 47
mod/disk/diskmg/diskmg.go

@@ -12,9 +12,9 @@ import (
 	"strings"
 	"time"
 
-	"imuslab.com/arozos/mod/common"
 	db "imuslab.com/arozos/mod/database"
 	fs "imuslab.com/arozos/mod/filesystem"
+	"imuslab.com/arozos/mod/utils"
 )
 
 type Lsblk struct {
@@ -72,17 +72,17 @@ var (
 	code and rewriting the whole thing will save you a lot more time.
 */
 func HandleView(w http.ResponseWriter, r *http.Request) {
-	partition, _ := common.Mv(r, "partition", false)
+	partition, _ := utils.Mv(r, "partition", false)
 	detailMode := (partition != "")
 	if runtime.GOOS == "windows" {
 		//Windows. Use DiskmgWin binary
-		if common.FileExists("./system/disk/diskmg/DiskmgWin.exe") {
+		if utils.FileExists("./system/disk/diskmg/DiskmgWin.exe") {
 			out := ""
 			if detailMode {
 				cmd := exec.Command("./system/disk/diskmg/DiskmgWin.exe", "-d")
 				o, err := cmd.CombinedOutput()
 				if err != nil {
-					common.SendErrorResponse(w, "Permission Denied")
+					utils.SendErrorResponse(w, "Permission Denied")
 					return
 				}
 				out = string(o)
@@ -90,7 +90,7 @@ func HandleView(w http.ResponseWriter, r *http.Request) {
 				cmd := exec.Command("./system/disk/diskmg/DiskmgWin.exe")
 				o, err := cmd.CombinedOutput()
 				if err != nil {
-					common.SendErrorResponse(w, "Permission Denied")
+					utils.SendErrorResponse(w, "Permission Denied")
 					return
 				}
 				out = string(o)
@@ -109,11 +109,11 @@ func HandleView(w http.ResponseWriter, r *http.Request) {
 			}
 
 			js, _ := json.Marshal(results)
-			common.SendJSONResponse(w, string(js))
+			utils.SendJSONResponse(w, string(js))
 
 		} else {
 			log.Println("system/disk/diskmg/DiskmgWin.exe NOT FOUND. Unable to load Window's disk information")
-			common.SendErrorResponse(w, "DiskmgWin.exe not found")
+			utils.SendErrorResponse(w, "DiskmgWin.exe not found")
 			return
 		}
 
@@ -127,12 +127,12 @@ func HandleView(w http.ResponseWriter, r *http.Request) {
 		cmd := exec.Command("lsblk", "-b", "--json")
 		o, err := cmd.CombinedOutput()
 		if err != nil {
-			common.SendErrorResponse(w, err.Error())
+			utils.SendErrorResponse(w, err.Error())
 			return
 		}
 		err = json.Unmarshal(o, &partition)
 		if err != nil {
-			common.SendErrorResponse(w, err.Error())
+			utils.SendErrorResponse(w, err.Error())
 			return
 		}
 
@@ -140,12 +140,12 @@ func HandleView(w http.ResponseWriter, r *http.Request) {
 		cmd = exec.Command("lsblk", "-f", "-b", "--json")
 		o, err = cmd.CombinedOutput()
 		if err != nil {
-			common.SendErrorResponse(w, err.Error())
+			utils.SendErrorResponse(w, err.Error())
 			return
 		}
 		err = json.Unmarshal(o, &format)
 		if err != nil {
-			common.SendErrorResponse(w, err.Error())
+			utils.SendErrorResponse(w, err.Error())
 			return
 		}
 
@@ -153,7 +153,7 @@ func HandleView(w http.ResponseWriter, r *http.Request) {
 		cmd = exec.Command("df")
 		o, err = cmd.CombinedOutput()
 		if err != nil {
-			common.SendErrorResponse(w, err.Error())
+			utils.SendErrorResponse(w, err.Error())
 			return
 		}
 
@@ -180,7 +180,7 @@ func HandleView(w http.ResponseWriter, r *http.Request) {
 			parsedDf,
 		})
 
-		common.SendJSONResponse(w, string(js))
+		utils.SendJSONResponse(w, string(js))
 	}
 }
 
@@ -192,22 +192,22 @@ func HandleView(w http.ResponseWriter, r *http.Request) {
 */
 func HandleMount(w http.ResponseWriter, r *http.Request, fsHandlers []*fs.FileSystemHandler) {
 	if runtime.GOOS == "linux" {
-		targetDev, _ := common.Mv(r, "dev", false)
-		format, err := common.Mv(r, "format", false)
+		targetDev, _ := utils.Mv(r, "dev", false)
+		format, err := utils.Mv(r, "format", false)
 		if err != nil {
-			common.SendErrorResponse(w, "format not defined")
+			utils.SendErrorResponse(w, "format not defined")
 			return
 		}
-		mountPt, err := common.Mv(r, "mnt", false)
+		mountPt, err := utils.Mv(r, "mnt", false)
 		if err != nil {
-			common.SendErrorResponse(w, "Mount Point not defined")
+			utils.SendErrorResponse(w, "Mount Point not defined")
 			return
 		}
 
 		//Check if device is valid
 		ok, devID := checkDeviceValid(targetDev)
 		if !ok {
-			common.SendErrorResponse(w, "Device name is not valid")
+			utils.SendErrorResponse(w, "Device name is not valid")
 			return
 		}
 
@@ -222,39 +222,39 @@ func HandleMount(w http.ResponseWriter, r *http.Request, fsHandlers []*fs.FileSy
 		} else if format == "brtfs" {
 			mountingTool = "brtfs"
 		} else {
-			common.SendErrorResponse(w, "Format not supported")
+			utils.SendErrorResponse(w, "Format not supported")
 			return
 		}
 
 		//Check if mount point exists, only support /medoa/*
 		safeMountPoint := filepath.Clean(strings.ReplaceAll(mountPt, "../", ""))
-		if !common.FileExists(safeMountPoint) {
-			common.SendErrorResponse(w, "Mount point not exists, given: "+safeMountPoint)
+		if !utils.FileExists(safeMountPoint) {
+			utils.SendErrorResponse(w, "Mount point not exists, given: "+safeMountPoint)
 			return
 		}
 
 		//Check if action is mount or umount
-		umount, _ := common.Mv(r, "umount", false)
+		umount, _ := utils.Mv(r, "umount", false)
 		if umount == "true" {
 			//Unmount the given mountpoint
 			output, err := Unmount(safeMountPoint, fsHandlers)
 			if err != nil {
-				common.SendErrorResponse(w, output)
+				utils.SendErrorResponse(w, output)
 				return
 			}
-			common.SendTextResponse(w, output)
+			utils.SendTextResponse(w, output)
 
 		} else {
 			o, err := Mount(devID, safeMountPoint, mountingTool, fsHandlers)
 			if err != nil {
-				common.SendErrorResponse(w, o)
+				utils.SendErrorResponse(w, o)
 				return
 			}
-			common.SendTextResponse(w, o)
+			utils.SendTextResponse(w, o)
 		}
 
 	} else {
-		common.SendErrorResponse(w, "Platform not supported: "+runtime.GOOS)
+		utils.SendErrorResponse(w, "Platform not supported: "+runtime.GOOS)
 		return
 	}
 }
@@ -265,33 +265,33 @@ func HandleMount(w http.ResponseWriter, r *http.Request, fsHandlers []*fs.FileSy
 
 */
 func HandleFormat(w http.ResponseWriter, r *http.Request, fsHandlers []*fs.FileSystemHandler) {
-	dev, err := common.Mv(r, "dev", true)
+	dev, err := utils.Mv(r, "dev", true)
 	if err != nil {
-		common.SendErrorResponse(w, "dev not defined")
+		utils.SendErrorResponse(w, "dev not defined")
 		return
 	}
 
-	format, err := common.Mv(r, "format", true)
+	format, err := utils.Mv(r, "format", true)
 	if err != nil {
-		common.SendErrorResponse(w, "format not defined")
+		utils.SendErrorResponse(w, "format not defined")
 		return
 	}
 
 	if runtime.GOOS == "windows" {
-		common.SendErrorResponse(w, "This function is Linux Only")
+		utils.SendErrorResponse(w, "This function is Linux Only")
 		return
 	}
 
 	//Check if format is supported
-	if !common.StringInArray(supportedFormats, format) {
-		common.SendErrorResponse(w, "Format not supported")
+	if !utils.StringInArray(supportedFormats, format) {
+		utils.SendErrorResponse(w, "Format not supported")
 		return
 	}
 
 	//Check if device is valid
 	ok, devID := checkDeviceValid(dev)
 	if !ok {
-		common.SendErrorResponse(w, "Device name is not valid")
+		utils.SendErrorResponse(w, "Device name is not valid")
 		return
 	}
 
@@ -300,7 +300,7 @@ func HandleFormat(w http.ResponseWriter, r *http.Request, fsHandlers []*fs.FileS
 	if err != nil {
 		//Fail to check if disk mounted
 		log.Println(err.Error())
-		common.SendErrorResponse(w, "Failed to check disk mount status")
+		utils.SendErrorResponse(w, "Failed to check disk mount status")
 		return
 	}
 
@@ -309,7 +309,7 @@ func HandleFormat(w http.ResponseWriter, r *http.Request, fsHandlers []*fs.FileS
 		//Close all the fsHandler related to this disk
 		mountpt, err := getDeviceMountPoint(devID)
 		if err != nil {
-			common.SendErrorResponse(w, err.Error())
+			utils.SendErrorResponse(w, err.Error())
 			return
 		}
 
@@ -317,7 +317,7 @@ func HandleFormat(w http.ResponseWriter, r *http.Request, fsHandlers []*fs.FileS
 		//Unmount the devices
 		out, err := Unmount(mountpt, fsHandlers)
 		if err != nil {
-			common.SendErrorResponse(w, out)
+			utils.SendErrorResponse(w, out)
 			return
 		}
 	}
@@ -331,11 +331,11 @@ func HandleFormat(w http.ResponseWriter, r *http.Request, fsHandlers []*fs.FileS
 	} else if format == "ext4" {
 		cmd = exec.Command("mkfs.ext4", "-F", "/dev/"+devID)
 	} else if format == "ext3" {
-		common.SendErrorResponse(w, "Format to ext3 is Work In Progress")
+		utils.SendErrorResponse(w, "Format to ext3 is Work In Progress")
 	} else if format == "btrfs" {
-		common.SendErrorResponse(w, "Format to btrfs is Work In Progress")
+		utils.SendErrorResponse(w, "Format to btrfs is Work In Progress")
 	} else {
-		common.SendErrorResponse(w, "Format tyoe not supported")
+		utils.SendErrorResponse(w, "Format tyoe not supported")
 	}
 
 	//Execute format comamnd
@@ -343,7 +343,7 @@ func HandleFormat(w http.ResponseWriter, r *http.Request, fsHandlers []*fs.FileS
 	output, err := cmd.CombinedOutput()
 	if err != nil {
 		log.Println("Format failed: " + string(output))
-		common.SendErrorResponse(w, string(output))
+		utils.SendErrorResponse(w, string(output))
 		return
 	}
 
@@ -352,7 +352,7 @@ func HandleFormat(w http.ResponseWriter, r *http.Request, fsHandlers []*fs.FileS
 
 	//Let the system to reload the disk
 	time.Sleep(2 * time.Second)
-	common.SendOK(w)
+	utils.SendOK(w)
 
 }
 
@@ -400,7 +400,7 @@ func Unmount(mountpt string, fsHandlers []*fs.FileSystemHandler) (string, error)
 func HandleListMountPoints(w http.ResponseWriter, r *http.Request) {
 	mp, _ := filepath.Glob("/media/*")
 	js, _ := json.Marshal(mp)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 //Check if the device is mounted
@@ -458,7 +458,7 @@ func checkDeviceValid(devname string) (bool, string) {
 	//Extract the device name from string
 	re := regexp.MustCompile(`sd[a-z][1-9]`)
 	devID := re.FindString(devname)
-	if !common.FileExists("/dev/" + devID) {
+	if !utils.FileExists("/dev/" + devID) {
 		return false, ""
 	}
 
@@ -467,5 +467,5 @@ func checkDeviceValid(devname string) (bool, string) {
 
 func HandlePlatform(w http.ResponseWriter, r *http.Request) {
 	js, _ := json.Marshal(runtime.GOOS)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }

+ 3 - 3
mod/disk/smart/smart.go

@@ -21,7 +21,7 @@ import (
 	"errors"
 	"runtime"
 
-	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/utils"
 	//"time"
 )
 
@@ -40,7 +40,7 @@ func NewSmartListener() (*SMARTListener, error) {
 		return &SMARTListener{}, errors.New("not supported platform")
 	}
 
-	if !(common.FileExists(smartExec)) {
+	if !(utils.FileExists(smartExec)) {
 		return &SMARTListener{}, errors.New("smartctl not found")
 	}
 
@@ -125,7 +125,7 @@ func fillCapacity(devicesList *DevicesList) {
 
 func (s *SMARTListener) GetSMART(w http.ResponseWriter, r *http.Request) {
 	jsonText, _ := json.Marshal(s.DriveList)
-	common.SendJSONResponse(w, string(jsonText))
+	utils.SendJSONResponse(w, string(jsonText))
 }
 
 func getBinary() string {

+ 4 - 4
mod/disk/sortfile/sortfile.go

@@ -9,9 +9,9 @@ import (
 	"sort"
 	"strconv"
 
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/filesystem"
 	user "imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/utils"
 )
 
 type LargeFileScanner struct {
@@ -27,12 +27,12 @@ func NewLargeFileScanner(u *user.UserHandler) *LargeFileScanner {
 func (s *LargeFileScanner) HandleLargeFileList(w http.ResponseWriter, r *http.Request) {
 	userinfo, err := s.userHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
 	//Check if limit is set. If yes, use the limit in return
-	limit, err := common.Mv(r, "number", false)
+	limit, err := utils.Mv(r, "number", false)
 	if err != nil {
 		limit = "20"
 	}
@@ -113,5 +113,5 @@ func (s *LargeFileScanner) HandleLargeFileList(w http.ResponseWriter, r *http.Re
 
 	//Format the results and return
 	jsonString, _ := json.Marshal(fileList[:limitInt])
-	common.SendJSONResponse(w, string(jsonString))
+	utils.SendJSONResponse(w, string(jsonString))
 }

+ 23 - 23
mod/fileservers/servers/ftpserv/handler.go

@@ -6,40 +6,40 @@ import (
 	"strconv"
 	"strings"
 
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/storage/ftp"
+	"imuslab.com/arozos/mod/utils"
 )
 
 //Start the FTP Server by request
 func (m *Manager) HandleFTPServerStart(w http.ResponseWriter, r *http.Request) {
 	err := m.StartFtpServer()
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 	}
-	common.SendOK(w)
+	utils.SendOK(w)
 }
 
 //Stop the FTP server by request
 func (m *Manager) HandleFTPServerStop(w http.ResponseWriter, r *http.Request) {
 	m.StopFtpServer()
-	common.SendOK(w)
+	utils.SendOK(w)
 }
 
 //Get the FTP server status
 func (m *Manager) HandleFTPServerStatus(w http.ResponseWriter, r *http.Request) {
 	status, err := m.GetFtpServerStatus()
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
 	js, _ := json.Marshal(status)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 //Update UPnP setting on FTP server
 func (m *Manager) HandleFTPUPnP(w http.ResponseWriter, r *http.Request) {
-	enable, _ := common.Mv(r, "enable", false)
+	enable, _ := utils.Mv(r, "enable", false)
 	if enable == "true" {
 		m.option.Logger.PrintAndLog("FTP", "Enabling UPnP on FTP Server Port", nil)
 		m.option.Sysdb.Write("ftp", "upnp", true)
@@ -52,15 +52,15 @@ func (m *Manager) HandleFTPUPnP(w http.ResponseWriter, r *http.Request) {
 	if m.option.FtpServer != nil && m.option.FtpServer.ServerRunning {
 		m.StartFtpServer()
 	}
-	common.SendOK(w)
+	utils.SendOK(w)
 }
 
 //Update access permission on FTP server
 func (m *Manager) HandleFTPAccessUpdate(w http.ResponseWriter, r *http.Request) {
 	//Get groups paramter from post req
-	groupString, err := common.Mv(r, "groups", true)
+	groupString, err := utils.Mv(r, "groups", true)
 	if err != nil {
-		common.SendErrorResponse(w, "groups not defined")
+		utils.SendErrorResponse(w, "groups not defined")
 		return
 	}
 
@@ -68,7 +68,7 @@ func (m *Manager) HandleFTPAccessUpdate(w http.ResponseWriter, r *http.Request)
 	groups := []string{}
 	err = json.Unmarshal([]byte(groupString), &groups)
 	if err != nil {
-		common.SendErrorResponse(w, "Unable to parse groups")
+		utils.SendErrorResponse(w, "Unable to parse groups")
 		return
 	}
 
@@ -76,21 +76,21 @@ func (m *Manager) HandleFTPAccessUpdate(w http.ResponseWriter, r *http.Request)
 	//Set the accessable group
 	ftp.UpdateAccessableGroups(m.option.Sysdb, groups)
 
-	common.SendOK(w)
+	utils.SendOK(w)
 }
 
 //Handle FTP Set access port
 func (m *Manager) HandleFTPSetPort(w http.ResponseWriter, r *http.Request) {
-	port, err := common.Mv(r, "port", true)
+	port, err := utils.Mv(r, "port", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Port not defined")
+		utils.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")
+		utils.SendErrorResponse(w, "Invalid port number")
 		return
 	}
 
@@ -100,7 +100,7 @@ func (m *Manager) HandleFTPSetPort(w http.ResponseWriter, r *http.Request) {
 	//Restart the FTP server
 	m.StartFtpServer()
 
-	common.SendOK(w)
+	utils.SendOK(w)
 }
 
 /*
@@ -111,17 +111,17 @@ func (m *Manager) HandleFTPSetPort(w http.ResponseWriter, r *http.Request) {
 	set=mode&passive=true
 */
 func (m *Manager) HandleFTPPassiveModeSettings(w http.ResponseWriter, r *http.Request) {
-	set, err := common.Mv(r, "set", true)
+	set, err := utils.Mv(r, "set", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid set type")
+		utils.SendErrorResponse(w, "Invalid set type")
 		return
 	}
 
 	if set == "ip" {
 		//Update the public up addr
-		ip, err := common.Mv(r, "ip", true)
+		ip, err := utils.Mv(r, "ip", true)
 		if err != nil {
-			common.SendErrorResponse(w, "Invalid ip given")
+			utils.SendErrorResponse(w, "Invalid ip given")
 			return
 		}
 
@@ -129,9 +129,9 @@ func (m *Manager) HandleFTPPassiveModeSettings(w http.ResponseWriter, r *http.Re
 
 	} else if set == "mode" {
 		//Update the passive mode setting
-		passive, err := common.Mv(r, "passive", true)
+		passive, err := utils.Mv(r, "passive", true)
 		if err != nil {
-			common.SendErrorResponse(w, "Invalid passive option (true/false)")
+			utils.SendErrorResponse(w, "Invalid passive option (true/false)")
 			return
 		}
 
@@ -142,7 +142,7 @@ func (m *Manager) HandleFTPPassiveModeSettings(w http.ResponseWriter, r *http.Re
 			m.option.Sysdb.Write("ftp", "passive", false)
 		}
 	} else {
-		common.SendErrorResponse(w, "Unknown setting filed")
+		utils.SendErrorResponse(w, "Unknown setting filed")
 		return
 	}
 

+ 12 - 12
mod/fileservers/servers/sftpserv/sftpserv.go

@@ -6,13 +6,13 @@ import (
 	"strconv"
 	"time"
 
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/database"
 	"imuslab.com/arozos/mod/fileservers"
 	"imuslab.com/arozos/mod/info/logger"
 	"imuslab.com/arozos/mod/network/upnp"
 	"imuslab.com/arozos/mod/storage/sftpserver"
 	user "imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/utils"
 )
 
 type ManagerOption struct {
@@ -90,21 +90,21 @@ func (m *Manager) closeInstance() {
 
 //Get or Set listening port for SFTP
 func (m *Manager) HandleListeningPort(w http.ResponseWriter, r *http.Request) {
-	newport, _ := common.Mv(r, "port", true)
+	newport, _ := utils.Mv(r, "port", true)
 	if newport == "" {
 		//Resp with the current operating port
 		js, _ := json.Marshal(m.listeningPort)
-		common.SendJSONResponse(w, string(js))
+		utils.SendJSONResponse(w, string(js))
 	} else {
 		portInt, err := strconv.Atoi(newport)
 		if err != nil {
-			common.SendErrorResponse(w, "invalid port number given")
+			utils.SendErrorResponse(w, "invalid port number given")
 			return
 		}
 
 		err = m.option.Sysdb.Write("sftp", "port", portInt)
 		if err != nil {
-			common.SendErrorResponse(w, err.Error())
+			utils.SendErrorResponse(w, err.Error())
 			return
 		}
 
@@ -118,7 +118,7 @@ func (m *Manager) HandleListeningPort(w http.ResponseWriter, r *http.Request) {
 			m.ServerToggle(true)
 		}
 
-		common.SendOK(w)
+		utils.SendOK(w)
 	}
 
 }
@@ -142,16 +142,16 @@ func (m *Manager) HandleGetConnectedClients(w http.ResponseWriter, r *http.Reque
 	}
 
 	js, _ := json.Marshal(userCount)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 func (m *Manager) HandleToogleUPnP(w http.ResponseWriter, r *http.Request) {
-	enableUpnp, _ := common.Mv(r, "enabled", true)
+	enableUpnp, _ := utils.Mv(r, "enabled", true)
 	if enableUpnp == "" {
 		//Get the current state of Upnp
 		currentEnabled := getUpnPEnabled(m.option.Sysdb)
 		js, _ := json.Marshal(currentEnabled)
-		common.SendJSONResponse(w, string(js))
+		utils.SendJSONResponse(w, string(js))
 	} else if enableUpnp == "true" {
 		//Enable UpnP
 		m.option.Sysdb.Write("sftp", "upnp", true)
@@ -163,7 +163,7 @@ func (m *Manager) HandleToogleUPnP(w http.ResponseWriter, r *http.Request) {
 			m.ServerToggle(true)
 		}
 
-		common.SendOK(w)
+		utils.SendOK(w)
 	} else if enableUpnp == "false" {
 		//Disable UpnP
 		m.option.Sysdb.Write("sftp", "upnp", false)
@@ -178,9 +178,9 @@ func (m *Manager) HandleToogleUPnP(w http.ResponseWriter, r *http.Request) {
 		//Remove UPnP forwarded port
 		m.option.Upnp.ClosePort(m.listeningPort)
 
-		common.SendOK(w)
+		utils.SendOK(w)
 	} else {
-		common.SendErrorResponse(w, "unknown operation")
+		utils.SendErrorResponse(w, "unknown operation")
 	}
 }
 

+ 6 - 6
mod/fileservers/servers/webdavserv/webdavserv.go

@@ -4,11 +4,11 @@ import (
 	"encoding/json"
 	"net/http"
 
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/database"
 	"imuslab.com/arozos/mod/fileservers"
 	awebdav "imuslab.com/arozos/mod/storage/webdav"
 	"imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -55,22 +55,22 @@ func (m *Manager) HandleStatusChange(w http.ResponseWriter, r *http.Request) {
 	userinfo, _ := m.option.UserHandler.GetUserInfoFromRequest(w, r)
 	isAdmin := userinfo.IsAdmin()
 
-	set, _ := common.Mv(r, "set", false)
+	set, _ := utils.Mv(r, "set", false)
 	if set == "" {
 		//Return the current status
 		results := []bool{m.WebDavHandler.Enabled, isAdmin}
 		js, _ := json.Marshal(results)
-		common.SendJSONResponse(w, string(js))
+		utils.SendJSONResponse(w, string(js))
 	} else if isAdmin && set == "disable" {
 		m.WebDavHandler.Enabled = false
 		m.option.Sysdb.Write("webdav", "enabled", false)
-		common.SendOK(w)
+		utils.SendOK(w)
 	} else if isAdmin && set == "enable" {
 		m.WebDavHandler.Enabled = true
 		m.option.Sysdb.Write("webdav", "enabled", true)
-		common.SendOK(w)
+		utils.SendOK(w)
 	} else {
-		common.SendErrorResponse(w, "Permission Denied")
+		utils.SendErrorResponse(w, "Permission Denied")
 	}
 }
 

+ 250 - 250
mod/filesystem/abstractions/localfs/localfs.go

@@ -1,250 +1,250 @@
-package localfs
-
-import (
-	"io"
-	"io/fs"
-	"os"
-	"path/filepath"
-	"strings"
-	"time"
-
-	"imuslab.com/arozos/mod/common"
-	"imuslab.com/arozos/mod/filesystem/arozfs"
-)
-
-/*
-	filesystemAbstraction.go
-
-	This file contains all the abstraction funtion of a local file system.
-
-*/
-
-type LocalFileSystemAbstraction struct {
-	UUID      string
-	Rootpath  string
-	Hierarchy string
-	ReadOnly  bool
-}
-
-func NewLocalFileSystemAbstraction(uuid, root, hierarchy string, readonly bool) LocalFileSystemAbstraction {
-	return LocalFileSystemAbstraction{
-		UUID:      uuid,
-		Rootpath:  root,
-		Hierarchy: hierarchy,
-		ReadOnly:  readonly,
-	}
-}
-
-func (l LocalFileSystemAbstraction) Chmod(filename string, mode os.FileMode) error {
-	return os.Chmod(filename, mode)
-}
-func (l LocalFileSystemAbstraction) Chown(filename string, uid int, gid int) error {
-	return os.Chown(filename, uid, gid)
-}
-func (l LocalFileSystemAbstraction) Chtimes(filename string, atime time.Time, mtime time.Time) error {
-	return os.Chtimes(filename, atime, mtime)
-}
-func (l LocalFileSystemAbstraction) Create(filename string) (arozfs.File, error) {
-	return os.Create(filename)
-}
-func (l LocalFileSystemAbstraction) Mkdir(filename string, mode os.FileMode) error {
-	return os.Mkdir(filename, mode)
-}
-func (l LocalFileSystemAbstraction) MkdirAll(filename string, mode os.FileMode) error {
-	return os.MkdirAll(filename, mode)
-}
-func (l LocalFileSystemAbstraction) Name() string {
-	return ""
-}
-func (l LocalFileSystemAbstraction) Open(filename string) (arozfs.File, error) {
-	return os.Open(filename)
-}
-func (l LocalFileSystemAbstraction) OpenFile(filename string, flag int, perm os.FileMode) (arozfs.File, error) {
-	return os.OpenFile(filename, flag, perm)
-}
-func (l LocalFileSystemAbstraction) Remove(filename string) error {
-	return os.Remove(filename)
-}
-func (l LocalFileSystemAbstraction) RemoveAll(path string) error {
-	return os.RemoveAll(path)
-}
-func (l LocalFileSystemAbstraction) Rename(oldname, newname string) error {
-	return os.Rename(oldname, newname)
-}
-func (l LocalFileSystemAbstraction) Stat(filename string) (os.FileInfo, error) {
-	return os.Stat(filename)
-}
-func (l LocalFileSystemAbstraction) Close() error {
-	return nil
-}
-
-/*
-	Abstraction Utilities
-*/
-
-func (l LocalFileSystemAbstraction) VirtualPathToRealPath(subpath string, username string) (string, error) {
-	subpath = filepath.ToSlash(subpath)
-	if strings.HasPrefix(subpath, l.UUID+":") {
-		//This is full virtual path. Trim the uuid and correct the subpath
-		subpath = subpath[len(l.UUID+":"):]
-	}
-
-	if l.Hierarchy == "user" {
-		return filepath.ToSlash(filepath.Join(l.Rootpath, "users", username, subpath)), nil
-	} else if l.Hierarchy == "public" {
-		return filepath.ToSlash(filepath.Join(l.Rootpath, subpath)), nil
-	}
-	return "", arozfs.ErrVpathResolveFailed
-}
-
-func (l LocalFileSystemAbstraction) RealPathToVirtualPath(fullpath string, username string) (string, error) {
-	/*
-		thisStorageRootAbs, err := filepath.Abs(l.Rootpath)
-		if err != nil {
-			//Fail to abs this path. Maybe this is a emulated file system?
-			thisStorageRootAbs = l.Rootpath
-		}
-		thisStorageRootAbs = filepath.ToSlash(filepath.Clean(thisStorageRootAbs))
-
-		subPath := ""
-		if len(fullpath) > len(l.Rootpath) && filepath.ToSlash(fullpath[:len(l.Rootpath)]) == filepath.ToSlash(l.Rootpath) {
-			//This realpath is in contained inside this storage root
-			subtractionPath := l.Rootpath
-			if l.Hierarchy == "user" {
-				//Check if this file is belongs to this user
-				startOffset := len(filepath.Clean(l.Rootpath) + "/users/")
-				if len(fullpath) < startOffset+len(username) {
-					//This file is not owned by this user
-					return "", errors.New("File not owned by this user")
-				} else {
-					userNameMatch := fullpath[startOffset : startOffset+len(username)]
-					if userNameMatch != username {
-						//This file is not owned by this user
-						return "", errors.New("File not owned by this user")
-					}
-				}
-
-				//Generate subtraction path
-				subtractionPath = filepath.ToSlash(filepath.Clean(filepath.Join(l.Rootpath, "users", username)))
-			}
-
-			if len(subtractionPath) < len(fullpath) {
-				subPath = fullpath[len(subtractionPath):]
-			}
-
-		} else if len(fullpath) > len(thisStorageRootAbs) && filepath.ToSlash(fullpath[:len(thisStorageRootAbs)]) == filepath.ToSlash(thisStorageRootAbs) {
-			//The realpath contains the absolute path of this storage root
-			subtractionPath := thisStorageRootAbs
-			if l.Hierarchy == "user" {
-				subtractionPath = thisStorageRootAbs + "/users/" + username + "/"
-			}
-
-			if len(subtractionPath) < len(fullpath) {
-				subPath = fullpath[len(subtractionPath):]
-			}
-		} else if filepath.ToSlash(fullpath) == filepath.ToSlash(l.Rootpath) {
-			//Storage Root's root
-			subPath = ""
-		}
-
-		if len(subPath) > 1 && subPath[:1] == "/" {
-			subPath = subPath[1:]
-		}
-	*/
-	fullpath = filepath.ToSlash(fullpath)
-	if strings.HasPrefix(fullpath, l.UUID+":") && !common.FileExists(fullpath) {
-		return "", arozfs.ErrRpathResolveFailed
-	}
-	prefix := filepath.ToSlash(filepath.Join(l.Rootpath, "users", username))
-	if l.Hierarchy == "public" {
-		prefix = filepath.ToSlash(l.Rootpath)
-	}
-	fullpath = filepath.ToSlash(filepath.Clean(fullpath))
-	subPath := strings.TrimPrefix(fullpath, prefix)
-	if !strings.HasPrefix(subPath, "/") {
-		subPath = "/" + subPath
-	}
-
-	return l.UUID + ":" + filepath.ToSlash(subPath), nil
-}
-
-func (l LocalFileSystemAbstraction) FileExists(realpath string) bool {
-	return common.FileExists(realpath)
-}
-
-func (l LocalFileSystemAbstraction) IsDir(realpath string) bool {
-	if !l.FileExists(realpath) {
-		return false
-	}
-	fi, err := l.Stat(realpath)
-	if err != nil {
-		return false
-	}
-	switch mode := fi.Mode(); {
-	case mode.IsDir():
-		return true
-	case mode.IsRegular():
-		return false
-	}
-	return false
-}
-
-func (l LocalFileSystemAbstraction) Glob(realpathWildcard string) ([]string, error) {
-	return filepath.Glob(realpathWildcard)
-}
-
-func (l LocalFileSystemAbstraction) GetFileSize(realpath string) int64 {
-	fi, err := os.Stat(realpath)
-	if err != nil {
-		return 0
-	}
-	// get the size
-	return fi.Size()
-}
-
-func (l LocalFileSystemAbstraction) GetModTime(realpath string) (int64, error) {
-	f, err := os.Open(realpath)
-	if err != nil {
-		return -1, err
-	}
-	statinfo, err := f.Stat()
-	if err != nil {
-		return -1, err
-	}
-	f.Close()
-	return statinfo.ModTime().Unix(), nil
-}
-
-func (l LocalFileSystemAbstraction) WriteFile(filename string, content []byte, mode os.FileMode) error {
-	return os.WriteFile(filename, content, mode)
-}
-func (l LocalFileSystemAbstraction) ReadFile(filename string) ([]byte, error) {
-	return os.ReadFile(filename)
-}
-func (l LocalFileSystemAbstraction) ReadDir(filename string) ([]fs.DirEntry, error) {
-	return os.ReadDir(filename)
-}
-func (l LocalFileSystemAbstraction) WriteStream(filename string, stream io.Reader, mode os.FileMode) error {
-	f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, mode)
-	if err != nil {
-		return err
-	}
-	_, err = io.Copy(f, stream)
-	f.Close()
-	return err
-}
-func (l LocalFileSystemAbstraction) ReadStream(filename string) (io.ReadCloser, error) {
-	f, err := os.OpenFile(filename, os.O_RDONLY, 0644)
-	if err != nil {
-		return nil, err
-	}
-	return f, nil
-}
-
-func (l LocalFileSystemAbstraction) Walk(root string, walkFn filepath.WalkFunc) error {
-	return filepath.Walk(root, walkFn)
-}
-
-func (l LocalFileSystemAbstraction) Heartbeat() error {
-	return nil
-}
+package localfs
+
+import (
+	"io"
+	"io/fs"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+
+	"imuslab.com/arozos/mod/filesystem/arozfs"
+	"imuslab.com/arozos/mod/utils"
+)
+
+/*
+	filesystemAbstraction.go
+
+	This file contains all the abstraction funtion of a local file system.
+
+*/
+
+type LocalFileSystemAbstraction struct {
+	UUID      string
+	Rootpath  string
+	Hierarchy string
+	ReadOnly  bool
+}
+
+func NewLocalFileSystemAbstraction(uuid, root, hierarchy string, readonly bool) LocalFileSystemAbstraction {
+	return LocalFileSystemAbstraction{
+		UUID:      uuid,
+		Rootpath:  root,
+		Hierarchy: hierarchy,
+		ReadOnly:  readonly,
+	}
+}
+
+func (l LocalFileSystemAbstraction) Chmod(filename string, mode os.FileMode) error {
+	return os.Chmod(filename, mode)
+}
+func (l LocalFileSystemAbstraction) Chown(filename string, uid int, gid int) error {
+	return os.Chown(filename, uid, gid)
+}
+func (l LocalFileSystemAbstraction) Chtimes(filename string, atime time.Time, mtime time.Time) error {
+	return os.Chtimes(filename, atime, mtime)
+}
+func (l LocalFileSystemAbstraction) Create(filename string) (arozfs.File, error) {
+	return os.Create(filename)
+}
+func (l LocalFileSystemAbstraction) Mkdir(filename string, mode os.FileMode) error {
+	return os.Mkdir(filename, mode)
+}
+func (l LocalFileSystemAbstraction) MkdirAll(filename string, mode os.FileMode) error {
+	return os.MkdirAll(filename, mode)
+}
+func (l LocalFileSystemAbstraction) Name() string {
+	return ""
+}
+func (l LocalFileSystemAbstraction) Open(filename string) (arozfs.File, error) {
+	return os.Open(filename)
+}
+func (l LocalFileSystemAbstraction) OpenFile(filename string, flag int, perm os.FileMode) (arozfs.File, error) {
+	return os.OpenFile(filename, flag, perm)
+}
+func (l LocalFileSystemAbstraction) Remove(filename string) error {
+	return os.Remove(filename)
+}
+func (l LocalFileSystemAbstraction) RemoveAll(path string) error {
+	return os.RemoveAll(path)
+}
+func (l LocalFileSystemAbstraction) Rename(oldname, newname string) error {
+	return os.Rename(oldname, newname)
+}
+func (l LocalFileSystemAbstraction) Stat(filename string) (os.FileInfo, error) {
+	return os.Stat(filename)
+}
+func (l LocalFileSystemAbstraction) Close() error {
+	return nil
+}
+
+/*
+	Abstraction Utilities
+*/
+
+func (l LocalFileSystemAbstraction) VirtualPathToRealPath(subpath string, username string) (string, error) {
+	subpath = filepath.ToSlash(subpath)
+	if strings.HasPrefix(subpath, l.UUID+":") {
+		//This is full virtual path. Trim the uuid and correct the subpath
+		subpath = subpath[len(l.UUID+":"):]
+	}
+
+	if l.Hierarchy == "user" {
+		return filepath.ToSlash(filepath.Join(l.Rootpath, "users", username, subpath)), nil
+	} else if l.Hierarchy == "public" {
+		return filepath.ToSlash(filepath.Join(l.Rootpath, subpath)), nil
+	}
+	return "", arozfs.ErrVpathResolveFailed
+}
+
+func (l LocalFileSystemAbstraction) RealPathToVirtualPath(fullpath string, username string) (string, error) {
+	/*
+		thisStorageRootAbs, err := filepath.Abs(l.Rootpath)
+		if err != nil {
+			//Fail to abs this path. Maybe this is a emulated file system?
+			thisStorageRootAbs = l.Rootpath
+		}
+		thisStorageRootAbs = filepath.ToSlash(filepath.Clean(thisStorageRootAbs))
+
+		subPath := ""
+		if len(fullpath) > len(l.Rootpath) && filepath.ToSlash(fullpath[:len(l.Rootpath)]) == filepath.ToSlash(l.Rootpath) {
+			//This realpath is in contained inside this storage root
+			subtractionPath := l.Rootpath
+			if l.Hierarchy == "user" {
+				//Check if this file is belongs to this user
+				startOffset := len(filepath.Clean(l.Rootpath) + "/users/")
+				if len(fullpath) < startOffset+len(username) {
+					//This file is not owned by this user
+					return "", errors.New("File not owned by this user")
+				} else {
+					userNameMatch := fullpath[startOffset : startOffset+len(username)]
+					if userNameMatch != username {
+						//This file is not owned by this user
+						return "", errors.New("File not owned by this user")
+					}
+				}
+
+				//Generate subtraction path
+				subtractionPath = filepath.ToSlash(filepath.Clean(filepath.Join(l.Rootpath, "users", username)))
+			}
+
+			if len(subtractionPath) < len(fullpath) {
+				subPath = fullpath[len(subtractionPath):]
+			}
+
+		} else if len(fullpath) > len(thisStorageRootAbs) && filepath.ToSlash(fullpath[:len(thisStorageRootAbs)]) == filepath.ToSlash(thisStorageRootAbs) {
+			//The realpath contains the absolute path of this storage root
+			subtractionPath := thisStorageRootAbs
+			if l.Hierarchy == "user" {
+				subtractionPath = thisStorageRootAbs + "/users/" + username + "/"
+			}
+
+			if len(subtractionPath) < len(fullpath) {
+				subPath = fullpath[len(subtractionPath):]
+			}
+		} else if filepath.ToSlash(fullpath) == filepath.ToSlash(l.Rootpath) {
+			//Storage Root's root
+			subPath = ""
+		}
+
+		if len(subPath) > 1 && subPath[:1] == "/" {
+			subPath = subPath[1:]
+		}
+	*/
+	fullpath = filepath.ToSlash(fullpath)
+	if strings.HasPrefix(fullpath, l.UUID+":") && !utils.FileExists(fullpath) {
+		return "", arozfs.ErrRpathResolveFailed
+	}
+	prefix := filepath.ToSlash(filepath.Join(l.Rootpath, "users", username))
+	if l.Hierarchy == "public" {
+		prefix = filepath.ToSlash(l.Rootpath)
+	}
+	fullpath = filepath.ToSlash(filepath.Clean(fullpath))
+	subPath := strings.TrimPrefix(fullpath, prefix)
+	if !strings.HasPrefix(subPath, "/") {
+		subPath = "/" + subPath
+	}
+
+	return l.UUID + ":" + filepath.ToSlash(subPath), nil
+}
+
+func (l LocalFileSystemAbstraction) FileExists(realpath string) bool {
+	return utils.FileExists(realpath)
+}
+
+func (l LocalFileSystemAbstraction) IsDir(realpath string) bool {
+	if !l.FileExists(realpath) {
+		return false
+	}
+	fi, err := l.Stat(realpath)
+	if err != nil {
+		return false
+	}
+	switch mode := fi.Mode(); {
+	case mode.IsDir():
+		return true
+	case mode.IsRegular():
+		return false
+	}
+	return false
+}
+
+func (l LocalFileSystemAbstraction) Glob(realpathWildcard string) ([]string, error) {
+	return filepath.Glob(realpathWildcard)
+}
+
+func (l LocalFileSystemAbstraction) GetFileSize(realpath string) int64 {
+	fi, err := os.Stat(realpath)
+	if err != nil {
+		return 0
+	}
+	// get the size
+	return fi.Size()
+}
+
+func (l LocalFileSystemAbstraction) GetModTime(realpath string) (int64, error) {
+	f, err := os.Open(realpath)
+	if err != nil {
+		return -1, err
+	}
+	statinfo, err := f.Stat()
+	if err != nil {
+		return -1, err
+	}
+	f.Close()
+	return statinfo.ModTime().Unix(), nil
+}
+
+func (l LocalFileSystemAbstraction) WriteFile(filename string, content []byte, mode os.FileMode) error {
+	return os.WriteFile(filename, content, mode)
+}
+func (l LocalFileSystemAbstraction) ReadFile(filename string) ([]byte, error) {
+	return os.ReadFile(filename)
+}
+func (l LocalFileSystemAbstraction) ReadDir(filename string) ([]fs.DirEntry, error) {
+	return os.ReadDir(filename)
+}
+func (l LocalFileSystemAbstraction) WriteStream(filename string, stream io.Reader, mode os.FileMode) error {
+	f, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY, mode)
+	if err != nil {
+		return err
+	}
+	_, err = io.Copy(f, stream)
+	f.Close()
+	return err
+}
+func (l LocalFileSystemAbstraction) ReadStream(filename string) (io.ReadCloser, error) {
+	f, err := os.OpenFile(filename, os.O_RDONLY, 0644)
+	if err != nil {
+		return nil, err
+	}
+	return f, nil
+}
+
+func (l LocalFileSystemAbstraction) Walk(root string, walkFn filepath.WalkFunc) error {
+	return filepath.Walk(root, walkFn)
+}
+
+func (l LocalFileSystemAbstraction) Heartbeat() error {
+	return nil
+}

+ 5 - 5
mod/filesystem/metadata/metadata.go

@@ -14,10 +14,10 @@ import (
 
 	"github.com/gorilla/websocket"
 
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/filesystem"
 	"imuslab.com/arozos/mod/filesystem/fssort"
 	hidden "imuslab.com/arozos/mod/filesystem/hidden"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -138,7 +138,7 @@ func (rh *RenderHandler) LoadCache(fsh *filesystem.FileSystemHandler, rpath stri
 	//That object not exists. Generate cache image
 	//Audio formats that might contains id4 thumbnail
 	id4Formats := []string{".mp3", ".ogg", ".flac"}
-	if common.StringInArray(id4Formats, strings.ToLower(filepath.Ext(rpath))) {
+	if utils.StringInArray(id4Formats, strings.ToLower(filepath.Ext(rpath))) {
 		img, err := generateThumbnailForAudio(fsh, cacheFolder, rpath, generateOnly)
 		rh.renderingFiles.Delete(rpath)
 		return img, err
@@ -146,7 +146,7 @@ func (rh *RenderHandler) LoadCache(fsh *filesystem.FileSystemHandler, rpath stri
 
 	//Generate resized image for images
 	imageFormats := []string{".png", ".jpeg", ".jpg"}
-	if common.StringInArray(imageFormats, strings.ToLower(filepath.Ext(rpath))) {
+	if utils.StringInArray(imageFormats, strings.ToLower(filepath.Ext(rpath))) {
 		img, err := generateThumbnailForImage(fsh, cacheFolder, rpath, generateOnly)
 		rh.renderingFiles.Delete(rpath)
 		return img, err
@@ -154,7 +154,7 @@ func (rh *RenderHandler) LoadCache(fsh *filesystem.FileSystemHandler, rpath stri
 
 	//Video formats, extract from the 5 sec mark
 	vidFormats := []string{".mkv", ".mp4", ".webm", ".ogv", ".avi", ".rmvb"}
-	if common.StringInArray(vidFormats, strings.ToLower(filepath.Ext(rpath))) {
+	if utils.StringInArray(vidFormats, strings.ToLower(filepath.Ext(rpath))) {
 		img, err := generateThumbnailForVideo(fsh, cacheFolder, rpath, generateOnly)
 		rh.renderingFiles.Delete(rpath)
 		return img, err
@@ -162,7 +162,7 @@ func (rh *RenderHandler) LoadCache(fsh *filesystem.FileSystemHandler, rpath stri
 
 	//3D Model Formats
 	modelFormats := []string{".stl", ".obj"}
-	if common.StringInArray(modelFormats, strings.ToLower(filepath.Ext(rpath))) {
+	if utils.StringInArray(modelFormats, strings.ToLower(filepath.Ext(rpath))) {
 		img, err := generateThumbnailForModel(fsh, cacheFolder, rpath, generateOnly)
 		rh.renderingFiles.Delete(rpath)
 		return img, err

+ 2 - 2
mod/filesystem/metadata/psd.go

@@ -9,8 +9,8 @@ import (
 	"github.com/nfnt/resize"
 	"github.com/oliamb/cutter"
 	_ "github.com/oov/psd"
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/filesystem"
+	"imuslab.com/arozos/mod/utils"
 )
 
 func generateThumbnailForPSD(fsh *filesystem.FileSystemHandler, cacheFolder string, file string, generateOnly bool) (string, error) {
@@ -74,7 +74,7 @@ func generateThumbnailForPSD(fsh *filesystem.FileSystemHandler, cacheFolder stri
 		//return the image as well
 		ctx, err := getImageAsBase64(fsh, outputFile)
 		return ctx, err
-	} else if !common.FileExists(outputFile) {
+	} else if !utils.FileExists(outputFile) {
 		return "", errors.New("Image generation failed")
 	}
 	return "", nil

+ 2 - 2
mod/filesystem/metadata/video.go

@@ -10,8 +10,8 @@ import (
 
 	"github.com/oliamb/cutter"
 	"imuslab.com/arozos/mod/apt"
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/filesystem"
+	"imuslab.com/arozos/mod/utils"
 )
 
 func generateThumbnailForVideo(fsh *filesystem.FileSystemHandler, cacheFolder string, file string, generateOnly bool) (string, error) {
@@ -69,7 +69,7 @@ func generateThumbnailForVideo(fsh *filesystem.FileSystemHandler, cacheFolder st
 			//return the image as well
 			ctx, err := getImageAsBase64(fsh, outputFile)
 			return ctx, err
-		} else if !common.FileExists(outputFile) {
+		} else if !utils.FileExists(outputFile) {
 			return "", errors.New("Image generation failed")
 		}
 		return "", nil

+ 52 - 52
mod/filesystem/shortcut/shortcut.go

@@ -1,52 +1,52 @@
-package shortcut
-
-import (
-	"errors"
-	"path/filepath"
-	"strings"
-
-	"imuslab.com/arozos/mod/common"
-	"imuslab.com/arozos/mod/filesystem/arozfs"
-)
-
-/*
-	A simple package to better handle shortcuts in ArozOS
-
-	Author: tobychui
-*/
-
-func ReadShortcut(shortcutContent []byte) (*arozfs.ShortcutData, error) {
-	//Split the content of the shortcut files into lines
-	fileContent := strings.ReplaceAll(strings.TrimSpace(string(shortcutContent)), "\r\n", "\n")
-	lines := strings.Split(fileContent, "\n")
-
-	if len(lines) < 4 {
-		return nil, errors.New("Corrupted Shortcut File")
-	}
-
-	for i := 0; i < len(lines); i++ {
-		lines[i] = strings.TrimSpace(lines[i])
-	}
-
-	//Render it as shortcut data
-	result := arozfs.ShortcutData{
-		Type: lines[0],
-		Name: lines[1],
-		Path: lines[2],
-		Icon: lines[3],
-	}
-
-	return &result, nil
-}
-
-//Generate the content of a shortcut base the the four important field of shortcut information
-func GenerateShortcutBytes(shortcutTarget string, shortcutType string, shortcutText string, shortcutIcon string) []byte {
-	//Check if there are desktop icon. If yes, override icon on module
-	if shortcutType == "module" && common.FileExists(arozfs.ToSlash(filepath.Join("./web/", filepath.Dir(shortcutIcon), "/desktop_icon.png"))) {
-		shortcutIcon = arozfs.ToSlash(filepath.Join(filepath.Dir(shortcutIcon), "/desktop_icon.png"))
-	}
-
-	//Clean the shortcut text
-	shortcutText = arozfs.FilterIllegalCharInFilename(shortcutText, " ")
-	return []byte(shortcutType + "\n" + shortcutText + "\n" + shortcutTarget + "\n" + shortcutIcon)
-}
+package shortcut
+
+import (
+	"errors"
+	"path/filepath"
+	"strings"
+
+	"imuslab.com/arozos/mod/filesystem/arozfs"
+	"imuslab.com/arozos/mod/utils"
+)
+
+/*
+	A simple package to better handle shortcuts in ArozOS
+
+	Author: tobychui
+*/
+
+func ReadShortcut(shortcutContent []byte) (*arozfs.ShortcutData, error) {
+	//Split the content of the shortcut files into lines
+	fileContent := strings.ReplaceAll(strings.TrimSpace(string(shortcutContent)), "\r\n", "\n")
+	lines := strings.Split(fileContent, "\n")
+
+	if len(lines) < 4 {
+		return nil, errors.New("Corrupted Shortcut File")
+	}
+
+	for i := 0; i < len(lines); i++ {
+		lines[i] = strings.TrimSpace(lines[i])
+	}
+
+	//Render it as shortcut data
+	result := arozfs.ShortcutData{
+		Type: lines[0],
+		Name: lines[1],
+		Path: lines[2],
+		Icon: lines[3],
+	}
+
+	return &result, nil
+}
+
+//Generate the content of a shortcut base the the four important field of shortcut information
+func GenerateShortcutBytes(shortcutTarget string, shortcutType string, shortcutText string, shortcutIcon string) []byte {
+	//Check if there are desktop icon. If yes, override icon on module
+	if shortcutType == "module" && utils.FileExists(arozfs.ToSlash(filepath.Join("./web/", filepath.Dir(shortcutIcon), "/desktop_icon.png"))) {
+		shortcutIcon = arozfs.ToSlash(filepath.Join(filepath.Dir(shortcutIcon), "/desktop_icon.png"))
+	}
+
+	//Clean the shortcut text
+	shortcutText = arozfs.FilterIllegalCharInFilename(shortcutText, " ")
+	return []byte(shortcutType + "\n" + shortcutText + "\n" + shortcutTarget + "\n" + shortcutIcon)
+}

+ 2 - 2
mod/info/hardwareinfo/hardwareinfo.go

@@ -7,7 +7,7 @@ import (
 	"os/exec"
 	"strings"
 
-	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -74,7 +74,7 @@ func (s *Server) GetArOZInfo(w http.ResponseWriter, r *http.Request) {
 		log.Println(err)
 	}
 
-	common.SendJSONResponse(w, string(jsonData))
+	utils.SendJSONResponse(w, string(jsonData))
 }
 
 func wmicGetinfo(wmicName string, itemName string) []string {

+ 6 - 6
mod/info/hardwareinfo/sysinfo_window.go

@@ -9,7 +9,7 @@ import (
 	"net/http"
 	"strconv"
 
-	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/utils"
 )
 
 func GetCPUInfo(w http.ResponseWriter, r *http.Request) {
@@ -27,7 +27,7 @@ func GetCPUInfo(w http.ResponseWriter, r *http.Request) {
 	if err != nil {
 		log.Println(err)
 	}
-	common.SendTextResponse(w, string(jsonData))
+	utils.SendTextResponse(w, string(jsonData))
 }
 
 func Ifconfig(w http.ResponseWriter, r *http.Request) {
@@ -41,7 +41,7 @@ func Ifconfig(w http.ResponseWriter, r *http.Request) {
 	if err != nil {
 		log.Println(err)
 	}
-	common.SendTextResponse(w, string(jsonData))
+	utils.SendTextResponse(w, string(jsonData))
 }
 
 func GetDriveStat(w http.ResponseWriter, r *http.Request) {
@@ -65,7 +65,7 @@ func GetDriveStat(w http.ResponseWriter, r *http.Request) {
 	if err != nil {
 		log.Println(err)
 	}
-	common.SendTextResponse(w, string(jsonData))
+	utils.SendTextResponse(w, string(jsonData))
 }
 
 func GetUSB(w http.ResponseWriter, r *http.Request) {
@@ -79,7 +79,7 @@ func GetUSB(w http.ResponseWriter, r *http.Request) {
 	if err != nil {
 		log.Println(err)
 	}
-	common.SendTextResponse(w, string(jsonData))
+	utils.SendTextResponse(w, string(jsonData))
 }
 
 func GetRamInfo(w http.ResponseWriter, r *http.Request) {
@@ -94,5 +94,5 @@ func GetRamInfo(w http.ResponseWriter, r *http.Request) {
 	if err != nil {
 		log.Println(err)
 	}
-	common.SendTextResponse(w, string(jsonData))
+	utils.SendTextResponse(w, string(jsonData))
 }

+ 14 - 14
mod/iot/assits.go

@@ -4,7 +4,7 @@ import (
 	"encoding/json"
 	"net/http"
 
-	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -17,15 +17,15 @@ import (
 
 //Handle the set and get nickname of a particular IoT device
 func (m *Manager) HandleNickName(w http.ResponseWriter, r *http.Request) {
-	opr, err := common.Mv(r, "opr", true)
+	opr, err := utils.Mv(r, "opr", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid operation mode")
+		utils.SendErrorResponse(w, "Invalid operation mode")
 		return
 	}
 
-	uuid, err := common.Mv(r, "uuid", true)
+	uuid, err := utils.Mv(r, "uuid", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid uuid given")
+		utils.SendErrorResponse(w, "Invalid uuid given")
 		return
 	}
 
@@ -40,7 +40,7 @@ func (m *Manager) HandleNickName(w http.ResponseWriter, r *http.Request) {
 
 	//Reject operation if device not exists
 	if deviceExist == false {
-		common.SendErrorResponse(w, "Target device UUID not exists")
+		utils.SendErrorResponse(w, "Target device UUID not exists")
 		return
 	}
 
@@ -50,32 +50,32 @@ func (m *Manager) HandleNickName(w http.ResponseWriter, r *http.Request) {
 			deviceNickname := ""
 			err := m.db.Read("iot", uuid, &deviceNickname)
 			if err != nil {
-				common.SendErrorResponse(w, "Unable to read nickname from database")
+				utils.SendErrorResponse(w, "Unable to read nickname from database")
 				return
 			}
 			js, _ := json.Marshal(deviceNickname)
-			common.SendJSONResponse(w, string(js))
+			utils.SendJSONResponse(w, string(js))
 		} else {
-			common.SendErrorResponse(w, "Nickname not exists")
+			utils.SendErrorResponse(w, "Nickname not exists")
 		}
 	} else if opr == "set" {
 		//Get name from paramter
-		name, err := common.Mv(r, "name", true)
+		name, err := utils.Mv(r, "name", true)
 		if err != nil {
-			common.SendErrorResponse(w, "No nickname was given to the device")
+			utils.SendErrorResponse(w, "No nickname was given to the device")
 			return
 		}
 
 		//Set the name in database
 		err = m.db.Write("iot", uuid, name)
 		if err != nil {
-			common.SendErrorResponse(w, err.Error())
+			utils.SendErrorResponse(w, err.Error())
 			return
 		}
 
-		common.SendOK(w)
+		utils.SendOK(w)
 	} else {
-		common.SendErrorResponse(w, "Unknown operation mode")
+		utils.SendErrorResponse(w, "Unknown operation mode")
 		return
 	}
 }

+ 20 - 20
mod/iot/handlerManager.go

@@ -5,8 +5,8 @@ import (
 	"log"
 	"net/http"
 
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/database"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -62,7 +62,7 @@ func (m *Manager) HandleScannerList(w http.ResponseWriter, r *http.Request) {
 	}
 
 	js, _ := json.Marshal(stats)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 //Get the device object by id
@@ -77,9 +77,9 @@ func (m *Manager) GetDeviceByID(devid string) *Device {
 
 //Handle listing of all avaible scanner and its stats
 func (m *Manager) HandleIconLoad(w http.ResponseWriter, r *http.Request) {
-	devid, err := common.Mv(r, "devid", false)
+	devid, err := utils.Mv(r, "devid", false)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid device id")
+		utils.SendErrorResponse(w, "Invalid device id")
 		return
 	}
 
@@ -89,7 +89,7 @@ func (m *Manager) HandleIconLoad(w http.ResponseWriter, r *http.Request) {
 
 	iconFilePath := "./web/SystemAO/iot/hub/img/devices/" + iconName + ".png"
 	//fmt.Println(iconFilePath)
-	if common.FileExists(iconFilePath) {
+	if utils.FileExists(iconFilePath) {
 		http.ServeFile(w, r, iconFilePath)
 	} else {
 		http.ServeFile(w, r, "./web/SystemAO/iot/hub/img/devices/unknown.png")
@@ -98,24 +98,24 @@ func (m *Manager) HandleIconLoad(w http.ResponseWriter, r *http.Request) {
 
 //Handle listing of all avaible scanner and its stats
 func (m *Manager) HandleExecute(w http.ResponseWriter, r *http.Request) {
-	devid, err := common.Mv(r, "devid", true)
+	devid, err := utils.Mv(r, "devid", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid device id")
+		utils.SendErrorResponse(w, "Invalid device id")
 		return
 	}
 
-	eptname, err := common.Mv(r, "eptname", true)
+	eptname, err := utils.Mv(r, "eptname", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid endpoint name")
+		utils.SendErrorResponse(w, "Invalid endpoint name")
 		return
 	}
 
-	payload, _ := common.Mv(r, "payload", true)
+	payload, _ := utils.Mv(r, "payload", true)
 
 	//Get device by device id
 	dev := m.GetDeviceByID(devid)
 	if dev == nil {
-		common.SendErrorResponse(w, "Given device id not found")
+		utils.SendErrorResponse(w, "Given device id not found")
 		return
 	}
 
@@ -134,19 +134,19 @@ func (m *Manager) HandleExecute(w http.ResponseWriter, r *http.Request) {
 	//Send request to the target IoT device
 	result, err := dev.Handler.Execute(dev, &targetEndpoint, payload)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
 	js, _ := json.Marshal(result)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 //Get status of the given device ID
 func (m *Manager) HandleGetDeviceStatus(w http.ResponseWriter, r *http.Request) {
-	devid, err := common.Mv(r, "devid", true)
+	devid, err := utils.Mv(r, "devid", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid device id")
+		utils.SendErrorResponse(w, "Invalid device id")
 		return
 	}
 
@@ -156,19 +156,19 @@ func (m *Manager) HandleGetDeviceStatus(w http.ResponseWriter, r *http.Request)
 			//Found. Get it status and return
 			status, err := dev.Handler.Status(dev)
 			if err != nil {
-				common.SendErrorResponse(w, err.Error())
+				utils.SendErrorResponse(w, err.Error())
 				return
 			}
 
 			//Return the status
 			js, _ := json.Marshal(status)
-			common.SendJSONResponse(w, string(js))
+			utils.SendJSONResponse(w, string(js))
 			return
 		}
 	}
 
 	//Not found
-	common.SendErrorResponse(w, "Given device ID does not match any scanned devices")
+	utils.SendErrorResponse(w, "Given device ID does not match any scanned devices")
 }
 
 //Handle IoT Scanning Request
@@ -177,7 +177,7 @@ func (m *Manager) HandleScanning(w http.ResponseWriter, r *http.Request) {
 	scannedDevices := m.ScanDevices()
 
 	js, _ := json.Marshal(scannedDevices)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 //Handle IoT Listing Request
@@ -188,7 +188,7 @@ func (m *Manager) HandleListing(w http.ResponseWriter, r *http.Request) {
 	}
 
 	js, _ := json.Marshal(m.cachedDeviceList)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 func (m *Manager) GetCachedDeviceList() []*Device {

+ 9 - 9
mod/modules/installer.go

@@ -14,8 +14,8 @@ import (
 	"github.com/go-git/go-git/v5"
 	uuid "github.com/satori/go.uuid"
 	agi "imuslab.com/arozos/mod/agi"
-	"imuslab.com/arozos/mod/common"
 	fs "imuslab.com/arozos/mod/filesystem"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -29,7 +29,7 @@ import (
 //Install a module via selecting a zip file
 func (m *ModuleHandler) InstallViaZip(realpath string, gateway *agi.Gateway) error {
 	//Check if file exists
-	if !common.FileExists(realpath) {
+	if !utils.FileExists(realpath) {
 		return errors.New("*Module Installer* Installer file not found. Given: " + realpath)
 	}
 
@@ -44,7 +44,7 @@ func (m *ModuleHandler) InstallViaZip(realpath string, gateway *agi.Gateway) err
 	files, _ := filepath.Glob(unzipTmpFolder + "/*")
 	folders := []string{}
 	for _, file := range files {
-		if common.IsDir(file) && common.FileExists(filepath.Join(file, "init.agi")) {
+		if utils.IsDir(file) && utils.FileExists(filepath.Join(file, "init.agi")) {
 			//This looks like a module folder
 			folders = append(folders, file)
 		}
@@ -112,7 +112,7 @@ func (m *ModuleHandler) InstallModuleViaGit(gitURL string, gateway *agi.Gateway)
 	downloadedFiles, _ := filepath.Glob(downloadFolder + "/*")
 	copyPendingList := []string{}
 	for _, file := range downloadedFiles {
-		if common.IsDir(file) {
+		if utils.IsDir(file) {
 			//Exclude two special folder: github and images
 			if filepath.Base(file) == ".github" || filepath.Base(file) == "images" || filepath.Base(file)[:1] == "." {
 				//Reserved folder for putting Github readme screenshots or other things
@@ -151,8 +151,8 @@ func (m *ModuleHandler) InstallModuleViaGit(gitURL string, gateway *agi.Gateway)
 func (m *ModuleHandler) ActivateModuleByRoot(moduleFolder string, gateway *agi.Gateway) error {
 	//Check if there is init.agi. If yes, load it as an module
 	thisModuleEstimataedRoot := filepath.Join("./web/", filepath.Base(moduleFolder))
-	if common.FileExists(thisModuleEstimataedRoot) {
-		if common.FileExists(filepath.Join(thisModuleEstimataedRoot, "init.agi")) {
+	if utils.FileExists(thisModuleEstimataedRoot) {
+		if utils.FileExists(filepath.Join(thisModuleEstimataedRoot, "init.agi")) {
 			//Load this as an module
 			startDef, err := ioutil.ReadFile(filepath.Join(thisModuleEstimataedRoot, "init.agi"))
 			if err != nil {
@@ -195,7 +195,7 @@ func (m *ModuleHandler) HandleModuleInstallationListing(w http.ResponseWriter, r
 			//Only allow uninstalling of modules with start dir (aka installable)
 
 			//Check if WebApp or subservice
-			if common.FileExists(filepath.Join("./web", mod.StartDir)) {
+			if utils.FileExists(filepath.Join("./web", mod.StartDir)) {
 				//This is a WebApp module
 				totalsize, _ := fs.GetDirctorySize(filepath.Join("./web", filepath.Dir(mod.StartDir)), false)
 
@@ -231,7 +231,7 @@ func (m *ModuleHandler) HandleModuleInstallationListing(w http.ResponseWriter, r
 	}
 
 	js, _ := json.Marshal(results)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 //Uninstall the given module
@@ -251,7 +251,7 @@ func (m *ModuleHandler) UninstallModule(moduleName string) error {
 	}
 
 	//Check if the module exists
-	if common.FileExists(filepath.Join("./web", moduleName)) {
+	if utils.FileExists(filepath.Join("./web", moduleName)) {
 		//Remove the module
 		log.Println("Removing Module: ", moduleName)
 		os.RemoveAll(filepath.Join("./web", moduleName))

+ 18 - 18
mod/modules/module.go

@@ -6,8 +6,8 @@ import (
 	"sort"
 	"strings"
 
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/utils"
 )
 
 type ModuleInfo struct {
@@ -111,9 +111,9 @@ func (m *ModuleHandler) GetModuleNameList() []string {
 //Handle Default Launcher
 func (m *ModuleHandler) HandleDefaultLauncher(w http.ResponseWriter, r *http.Request) {
 	username, _ := m.userHandler.GetAuthAgent().GetUserName(w, r)
-	opr, _ := common.Mv(r, "opr", false) //Operation, accept {get, set, launch}
-	ext, _ := common.Mv(r, "ext", false)
-	moduleName, _ := common.Mv(r, "module", false)
+	opr, _ := utils.Mv(r, "opr", false) //Operation, accept {get, set, launch}
+	ext, _ := utils.Mv(r, "ext", false)
+	moduleName, _ := utils.Mv(r, "module", false)
 
 	ext = strings.ToLower(ext)
 
@@ -123,18 +123,18 @@ func (m *ModuleHandler) HandleDefaultLauncher(w http.ResponseWriter, r *http.Req
 		value := ""
 		err := m.userHandler.GetDatabase().Read("module", "default/"+username+"/"+ext, &value)
 		if err != nil {
-			common.SendErrorResponse(w, "No default opener")
+			utils.SendErrorResponse(w, "No default opener")
 			return
 		}
 		js, _ := json.Marshal(value)
-		common.SendJSONResponse(w, string(js))
+		utils.SendJSONResponse(w, string(js))
 		return
 	} else if opr == "launch" {
 		//Get launch paramter for this extension
 		value := ""
 		err := m.userHandler.GetDatabase().Read("module", "default/"+username+"/"+ext, &value)
 		if err != nil {
-			common.SendErrorResponse(w, "No default opener")
+			utils.SendErrorResponse(w, "No default opener")
 			return
 		}
 		//Get the launch paramter of this module
@@ -149,18 +149,18 @@ func (m *ModuleHandler) HandleDefaultLauncher(w http.ResponseWriter, r *http.Req
 
 		if !modExists {
 			//This module has been removed or not exists anymore
-			common.SendErrorResponse(w, "Default opener no longer exists.")
+			utils.SendErrorResponse(w, "Default opener no longer exists.")
 			return
 		} else {
 			//Return launch inforamtion
 			jsonString, _ := json.Marshal(modInfo)
-			common.SendJSONResponse(w, string(jsonString))
+			utils.SendJSONResponse(w, string(jsonString))
 		}
 
 	} else if opr == "set" {
 		//Set the opener for this filetype
 		if moduleName == "" {
-			common.SendErrorResponse(w, "Missing paratmer 'module'")
+			utils.SendErrorResponse(w, "Missing paratmer 'module'")
 			return
 		}
 
@@ -173,9 +173,9 @@ func (m *ModuleHandler) HandleDefaultLauncher(w http.ResponseWriter, r *http.Req
 		}
 		if moduleValid {
 			m.userHandler.GetDatabase().Write("module", "default/"+username+"/"+ext, moduleName)
-			common.SendJSONResponse(w, "\"OK\"")
+			utils.SendJSONResponse(w, "\"OK\"")
 		} else {
-			common.SendErrorResponse(w, "Given module not exists.")
+			utils.SendErrorResponse(w, "Given module not exists.")
 		}
 
 	} else if opr == "list" {
@@ -195,7 +195,7 @@ func (m *ModuleHandler) HandleDefaultLauncher(w http.ResponseWriter, r *http.Req
 		}
 
 		jsonString, _ := json.Marshal(results)
-		common.SendJSONResponse(w, string(jsonString))
+		utils.SendJSONResponse(w, string(jsonString))
 		return
 	}
 }
@@ -213,7 +213,7 @@ func (m *ModuleHandler) ListLoadedModules(w http.ResponseWriter, r *http.Request
 	}
 	//Return the loaded modules as a list of JSON string
 	jsonString, _ := json.Marshal(userAccessableModules)
-	common.SendJSONResponse(w, string(jsonString))
+	utils.SendJSONResponse(w, string(jsonString))
 }
 
 func (m *ModuleHandler) GetModuleInfoByID(moduleid string) *ModuleInfo {
@@ -226,9 +226,9 @@ func (m *ModuleHandler) GetModuleInfoByID(moduleid string) *ModuleInfo {
 }
 
 func (m *ModuleHandler) GetLaunchParameter(w http.ResponseWriter, r *http.Request) {
-	moduleName, _ := common.Mv(r, "module", false)
+	moduleName, _ := utils.Mv(r, "module", false)
 	if moduleName == "" {
-		common.SendErrorResponse(w, "Missing paramter 'module'.")
+		utils.SendErrorResponse(w, "Missing paramter 'module'.")
 		return
 	}
 
@@ -245,10 +245,10 @@ func (m *ModuleHandler) GetLaunchParameter(w http.ResponseWriter, r *http.Reques
 
 	if found {
 		jsonString, _ := json.Marshal(targetLaunchInfo)
-		common.SendJSONResponse(w, string(jsonString))
+		utils.SendJSONResponse(w, string(jsonString))
 		return
 	} else {
-		common.SendErrorResponse(w, "Given module not exists.")
+		utils.SendErrorResponse(w, "Given module not exists.")
 		return
 	}
 

+ 9 - 9
mod/network/neighbour/handler.go

@@ -4,8 +4,8 @@ import (
 	"encoding/json"
 	"net/http"
 
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/network/mdns"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -38,39 +38,39 @@ func (d *Discoverer) HandleScanningRequest(w http.ResponseWriter, r *http.Reques
 	result.LastUpdate = d.LastScanningTime
 
 	js, _ := json.Marshal(result)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 //Get networkHosts that are offline
 func (d *Discoverer) HandleScanRecord(w http.ResponseWriter, r *http.Request) {
 	offlineNodes, err := d.GetOfflineHosts()
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
 	js, err := json.Marshal(offlineNodes)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 //Send wake on land to target
 func (d *Discoverer) HandleWakeOnLan(w http.ResponseWriter, r *http.Request) {
-	mac, err := common.Mv(r, "mac", false)
+	mac, err := utils.Mv(r, "mac", false)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid mac address")
+		utils.SendErrorResponse(w, "Invalid mac address")
 		return
 	}
 
 	err = d.SendWakeOnLan(mac)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
-	common.SendOK(w)
+	utils.SendOK(w)
 }

+ 147 - 147
mod/network/netstat/netstat.go

@@ -1,147 +1,147 @@
-package netstat
-
-import (
-	"encoding/json"
-	"errors"
-	"io/ioutil"
-	"net/http"
-	"os/exec"
-	"path/filepath"
-	"runtime"
-	"strconv"
-	"strings"
-
-	"imuslab.com/arozos/mod/common"
-)
-
-func HandleGetNetworkInterfaceStats(w http.ResponseWriter, r *http.Request) {
-	rx, tx, err := GetNetworkInterfaceStats()
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	currnetNetSpec := struct {
-		RX int64
-		TX int64
-	}{
-		rx,
-		tx,
-	}
-
-	js, _ := json.Marshal(currnetNetSpec)
-	common.SendJSONResponse(w, string(js))
-}
-
-//Get network interface stats, return accumulated rx bits, tx bits and error if any
-func GetNetworkInterfaceStats() (int64, int64, error) {
-	if runtime.GOOS == "windows" {
-		cmd := exec.Command("wmic", "path", "Win32_PerfRawData_Tcpip_NetworkInterface", "Get", "BytesReceivedPersec,BytesSentPersec,BytesTotalPersec")
-		out, err := cmd.Output()
-		if err != nil {
-			return 0, 0, err
-		}
-
-		//Filter out the first line
-
-		lines := strings.Split(strings.ReplaceAll(string(out), "\r\n", "\n"), "\n")
-		if len(lines) >= 2 && len(lines[1]) >= 0 {
-			dataLine := lines[1]
-			for strings.Contains(dataLine, "  ") {
-				dataLine = strings.ReplaceAll(dataLine, "  ", " ")
-			}
-			dataLine = strings.TrimSpace(dataLine)
-			info := strings.Split(dataLine, " ")
-			if len(info) < 3 {
-				return 0, 0, errors.New("Invalid wmic results")
-			}
-			rxString := info[0]
-			txString := info[1]
-
-			rx := int64(0)
-			tx := int64(0)
-			if s, err := strconv.ParseInt(rxString, 10, 64); err == nil {
-				rx = s
-			}
-
-			if s, err := strconv.ParseInt(txString, 10, 64); err == nil {
-				tx = s
-			}
-
-			//log.Println(rx, tx)
-			return rx * 4, tx * 4, nil
-		} else {
-			//Invalid data
-			return 0, 0, errors.New("Invalid wmic results")
-		}
-
-	} else if runtime.GOOS == "linux" {
-		allIfaceRxByteFiles, err := filepath.Glob("/sys/class/net/*/statistics/rx_bytes")
-		if err != nil {
-			//Permission denied
-			return 0, 0, errors.New("Access denied")
-		}
-
-		if len(allIfaceRxByteFiles) == 0 {
-			return 0, 0, errors.New("No valid iface found")
-		}
-
-		rxSum := int64(0)
-		txSum := int64(0)
-		for _, rxByteFile := range allIfaceRxByteFiles {
-			rxBytes, err := ioutil.ReadFile(rxByteFile)
-			if err == nil {
-				rxBytesInt, err := strconv.Atoi(strings.TrimSpace(string(rxBytes)))
-				if err == nil {
-					rxSum += int64(rxBytesInt)
-				}
-			}
-
-			//Usually the tx_bytes file is nearby it. Read it as well
-			txByteFile := filepath.Join(filepath.Dir(rxByteFile), "tx_bytes")
-			txBytes, err := ioutil.ReadFile(txByteFile)
-			if err == nil {
-				txBytesInt, err := strconv.Atoi(strings.TrimSpace(string(txBytes)))
-				if err == nil {
-					txSum += int64(txBytesInt)
-				}
-			}
-
-		}
-
-		//Return value as bits
-		return rxSum * 8, txSum * 8, nil
-
-	} else if runtime.GOOS == "darwin" {
-		cmd := exec.Command("netstat", "-ib") //get data from netstat -ib
-		out, err := cmd.Output()
-		if err != nil {
-			return 0, 0, err
-		}
-
-		outStrs := string(out)                                                          //byte array to multi-line string
-		for _, outStr := range strings.Split(strings.TrimSuffix(outStrs, "\n"), "\n") { //foreach multi-line string
-			if strings.HasPrefix(outStr, "en") { //search for ethernet interface
-				if strings.Contains(outStr, "<Link#") { //search for the link with <Link#?>
-					outStrSplit := strings.Fields(outStr) //split by white-space
-
-					rxSum, errRX := strconv.Atoi(outStrSplit[6]) //received bytes sum
-					if errRX != nil {
-						return 0, 0, errRX
-					}
-
-					txSum, errTX := strconv.Atoi(outStrSplit[9]) //transmitted bytes sum
-					if errTX != nil {
-						return 0, 0, errTX
-					}
-
-					return int64(rxSum) * 8, int64(txSum) * 8, nil
-				}
-			}
-		}
-
-		return 0, 0, nil //no ethernet adapters with en*/<Link#*>
-	}
-
-	return 0, 0, errors.New("Platform not supported")
-}
+package netstat
+
+import (
+	"encoding/json"
+	"errors"
+	"io/ioutil"
+	"net/http"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"strconv"
+	"strings"
+
+	"imuslab.com/arozos/mod/utils"
+)
+
+func HandleGetNetworkInterfaceStats(w http.ResponseWriter, r *http.Request) {
+	rx, tx, err := GetNetworkInterfaceStats()
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	currnetNetSpec := struct {
+		RX int64
+		TX int64
+	}{
+		rx,
+		tx,
+	}
+
+	js, _ := json.Marshal(currnetNetSpec)
+	utils.SendJSONResponse(w, string(js))
+}
+
+//Get network interface stats, return accumulated rx bits, tx bits and error if any
+func GetNetworkInterfaceStats() (int64, int64, error) {
+	if runtime.GOOS == "windows" {
+		cmd := exec.Command("wmic", "path", "Win32_PerfRawData_Tcpip_NetworkInterface", "Get", "BytesReceivedPersec,BytesSentPersec,BytesTotalPersec")
+		out, err := cmd.Output()
+		if err != nil {
+			return 0, 0, err
+		}
+
+		//Filter out the first line
+
+		lines := strings.Split(strings.ReplaceAll(string(out), "\r\n", "\n"), "\n")
+		if len(lines) >= 2 && len(lines[1]) >= 0 {
+			dataLine := lines[1]
+			for strings.Contains(dataLine, "  ") {
+				dataLine = strings.ReplaceAll(dataLine, "  ", " ")
+			}
+			dataLine = strings.TrimSpace(dataLine)
+			info := strings.Split(dataLine, " ")
+			if len(info) < 3 {
+				return 0, 0, errors.New("Invalid wmic results")
+			}
+			rxString := info[0]
+			txString := info[1]
+
+			rx := int64(0)
+			tx := int64(0)
+			if s, err := strconv.ParseInt(rxString, 10, 64); err == nil {
+				rx = s
+			}
+
+			if s, err := strconv.ParseInt(txString, 10, 64); err == nil {
+				tx = s
+			}
+
+			//log.Println(rx, tx)
+			return rx * 4, tx * 4, nil
+		} else {
+			//Invalid data
+			return 0, 0, errors.New("Invalid wmic results")
+		}
+
+	} else if runtime.GOOS == "linux" {
+		allIfaceRxByteFiles, err := filepath.Glob("/sys/class/net/*/statistics/rx_bytes")
+		if err != nil {
+			//Permission denied
+			return 0, 0, errors.New("Access denied")
+		}
+
+		if len(allIfaceRxByteFiles) == 0 {
+			return 0, 0, errors.New("No valid iface found")
+		}
+
+		rxSum := int64(0)
+		txSum := int64(0)
+		for _, rxByteFile := range allIfaceRxByteFiles {
+			rxBytes, err := ioutil.ReadFile(rxByteFile)
+			if err == nil {
+				rxBytesInt, err := strconv.Atoi(strings.TrimSpace(string(rxBytes)))
+				if err == nil {
+					rxSum += int64(rxBytesInt)
+				}
+			}
+
+			//Usually the tx_bytes file is nearby it. Read it as well
+			txByteFile := filepath.Join(filepath.Dir(rxByteFile), "tx_bytes")
+			txBytes, err := ioutil.ReadFile(txByteFile)
+			if err == nil {
+				txBytesInt, err := strconv.Atoi(strings.TrimSpace(string(txBytes)))
+				if err == nil {
+					txSum += int64(txBytesInt)
+				}
+			}
+
+		}
+
+		//Return value as bits
+		return rxSum * 8, txSum * 8, nil
+
+	} else if runtime.GOOS == "darwin" {
+		cmd := exec.Command("netstat", "-ib") //get data from netstat -ib
+		out, err := cmd.Output()
+		if err != nil {
+			return 0, 0, err
+		}
+
+		outStrs := string(out)                                                          //byte array to multi-line string
+		for _, outStr := range strings.Split(strings.TrimSuffix(outStrs, "\n"), "\n") { //foreach multi-line string
+			if strings.HasPrefix(outStr, "en") { //search for ethernet interface
+				if strings.Contains(outStr, "<Link#") { //search for the link with <Link#?>
+					outStrSplit := strings.Fields(outStr) //split by white-space
+
+					rxSum, errRX := strconv.Atoi(outStrSplit[6]) //received bytes sum
+					if errRX != nil {
+						return 0, 0, errRX
+					}
+
+					txSum, errTX := strconv.Atoi(outStrSplit[9]) //transmitted bytes sum
+					if errTX != nil {
+						return 0, 0, errTX
+					}
+
+					return int64(rxSum) * 8, int64(txSum) * 8, nil
+				}
+			}
+		}
+
+		return 0, 0, nil //no ethernet adapters with en*/<Link#*>
+	}
+
+	return 0, 0, errors.New("Platform not supported")
+}

+ 4 - 4
mod/network/network.go

@@ -10,7 +10,7 @@ import (
 	"strings"
 
 	"gitlab.com/NebulousLabs/go-upnp"
-	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/utils"
 )
 
 type NICS struct {
@@ -28,7 +28,7 @@ type NICS struct {
 func GetNICInfo(w http.ResponseWriter, r *http.Request) {
 	interfaces, err := net.Interfaces()
 	if err != nil {
-		common.SendJSONResponse(w, err.Error())
+		utils.SendJSONResponse(w, err.Error())
 	}
 	var NICList []NICS
 	for _, i := range interfaces {
@@ -112,7 +112,7 @@ func GetNICInfo(w http.ResponseWriter, r *http.Request) {
 	if err != nil {
 		log.Println(err)
 	}
-	common.SendJSONResponse(w, string(jsonData))
+	utils.SendJSONResponse(w, string(jsonData))
 }
 
 //Get the IP address of the NIC that can conncet to the internet
@@ -193,7 +193,7 @@ func IsIPv6Addr(ip string) (bool, error) {
 }
 
 func GetPing(w http.ResponseWriter, r *http.Request) {
-	common.SendJSONResponse(w, "pong")
+	utils.SendJSONResponse(w, "pong")
 }
 
 func GetIpFromRequest(r *http.Request) (string, error) {

+ 3 - 3
mod/permission/group.go

@@ -1,16 +1,16 @@
 package permission
 
-import "imuslab.com/arozos/mod/common"
+import "imuslab.com/arozos/mod/utils"
 
 func (gp *PermissionGroup) AddModule(modulename string) {
-	if !common.StringInArray(gp.AccessibleModules, modulename) {
+	if !utils.StringInArray(gp.AccessibleModules, modulename) {
 		gp.AccessibleModules = append(gp.AccessibleModules, modulename)
 	}
 }
 
 func (gp *PermissionGroup) RemoveModule(modulename string) {
 	newModuleList := []string{}
-	if common.StringInArray(gp.AccessibleModules, modulename) {
+	if utils.StringInArray(gp.AccessibleModules, modulename) {
 		for _, thisModuleName := range gp.AccessibleModules {
 			if thisModuleName != modulename {
 				newModuleList = append(newModuleList, thisModuleName)

+ 3 - 3
mod/permission/permission.go

@@ -6,10 +6,10 @@ import (
 	"log"
 	"strings"
 
-	"imuslab.com/arozos/mod/common"
 	db "imuslab.com/arozos/mod/database"
 	fs "imuslab.com/arozos/mod/filesystem"
 	storage "imuslab.com/arozos/mod/storage"
+	"imuslab.com/arozos/mod/utils"
 )
 
 type PermissionGroup struct {
@@ -115,7 +115,7 @@ func (h *PermissionHandler) GetUsersPermissionGroup(username string) ([]*Permiss
 	//Look for all the avaible permission groups
 	results := []*PermissionGroup{}
 	for _, gp := range h.PermissionGroups {
-		if common.StringInArray(permissionGroupNames, gp.Name) {
+		if utils.StringInArray(permissionGroupNames, gp.Name) {
 			//Change the pointer to a new varable to it won't get overwritten by the range function
 			newPointer := gp
 			results = append(results, newPointer)
@@ -197,7 +197,7 @@ func (h *PermissionHandler) NewPermissionGroup(name string, isadmin bool, storag
 func (h *PermissionHandler) GetPermissionGroupByNameList(namelist []string) []*PermissionGroup {
 	results := []*PermissionGroup{}
 	for _, gp := range h.PermissionGroups {
-		if common.StringInArray(namelist, gp.Name) {
+		if utils.StringInArray(namelist, gp.Name) {
 			thisPointer := gp
 			results = append(results, thisPointer)
 		}

+ 42 - 42
mod/permission/request.go

@@ -16,12 +16,12 @@ import (
 	"net/http"
 	"strconv"
 
-	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/utils"
 )
 
 //Handle group editing operations
 func (h *PermissionHandler) HandleListGroup(w http.ResponseWriter, r *http.Request) {
-	listPermission, _ := common.Mv(r, "showper", false)
+	listPermission, _ := utils.Mv(r, "showper", false)
 	if listPermission == "" {
 		//Only show the user group name
 		results := []string{}
@@ -29,7 +29,7 @@ func (h *PermissionHandler) HandleListGroup(w http.ResponseWriter, r *http.Reque
 			results = append(results, gp.Name)
 		}
 		jsonString, _ := json.Marshal(results)
-		common.SendJSONResponse(w, string(jsonString))
+		utils.SendJSONResponse(w, string(jsonString))
 	} else {
 		//Show user group and its module permissions
 		results := make(map[string][]interface{})
@@ -41,78 +41,78 @@ func (h *PermissionHandler) HandleListGroup(w http.ResponseWriter, r *http.Reque
 			results[gp.Name] = thisGroupInfo
 		}
 		jsonString, _ := json.Marshal(results)
-		common.SendJSONResponse(w, string(jsonString))
+		utils.SendJSONResponse(w, string(jsonString))
 	}
 }
 
 //Listing a group's detail for editing or updating the group content
 func (h *PermissionHandler) HandleGroupEdit(w http.ResponseWriter, r *http.Request) {
-	groupname, err := common.Mv(r, "groupname", true)
+	groupname, err := utils.Mv(r, "groupname", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Group name not defined")
+		utils.SendErrorResponse(w, "Group name not defined")
 		return
 	}
 
-	listmode, _ := common.Mv(r, "list", false)
+	listmode, _ := utils.Mv(r, "list", false)
 	if listmode == "" {
 		//Edit update mode
-		permission, err := common.Mv(r, "permission", true)
+		permission, err := utils.Mv(r, "permission", true)
 		if err != nil {
-			common.SendErrorResponse(w, "Group name not defined")
+			utils.SendErrorResponse(w, "Group name not defined")
 			return
 		}
 
 		permissionSlice := []string{}
 		err = json.Unmarshal([]byte(permission), &permissionSlice)
 		if err != nil {
-			common.SendErrorResponse(w, "Failed to parse module list")
+			utils.SendErrorResponse(w, "Failed to parse module list")
 			return
 		}
 
-		isAdmin, err := common.Mv(r, "isAdmin", true)
+		isAdmin, err := utils.Mv(r, "isAdmin", true)
 		if err != nil {
-			common.SendErrorResponse(w, "Admin permission not defined")
+			utils.SendErrorResponse(w, "Admin permission not defined")
 			return
 		}
 
 		//Do not allow removal of admin permission from administrator group
 		if isAdmin == "false" && groupname == "administrator" {
-			common.SendErrorResponse(w, "You cannot unset admin permission from administrator group")
+			utils.SendErrorResponse(w, "You cannot unset admin permission from administrator group")
 			return
 		}
 
-		quota, err := common.Mv(r, "defaultQuota", true)
+		quota, err := utils.Mv(r, "defaultQuota", true)
 		if err != nil {
-			common.SendErrorResponse(w, "Default Quota not defined")
+			utils.SendErrorResponse(w, "Default Quota not defined")
 			return
 		}
 
-		interfaceModule, err := common.Mv(r, "interfaceModule", true)
+		interfaceModule, err := utils.Mv(r, "interfaceModule", true)
 		if err != nil {
-			common.SendErrorResponse(w, "Default Interface Module not defined")
+			utils.SendErrorResponse(w, "Default Interface Module not defined")
 			return
 		}
 
 		//Check if the group name already exists
 		if !h.GroupExists(groupname) {
-			common.SendErrorResponse(w, "Group not exists")
+			utils.SendErrorResponse(w, "Group not exists")
 			return
 		}
 
 		quotaInt, err := strconv.Atoi(quota)
 		if err != nil {
-			common.SendErrorResponse(w, "Invalid Quota.")
+			utils.SendErrorResponse(w, "Invalid Quota.")
 			return
 		}
 
 		h.UpdatePermissionGroup(groupname, isAdmin == "true", int64(quotaInt), permissionSlice, interfaceModule)
-		common.SendOK(w)
+		utils.SendOK(w)
 	} else {
 		//Listing mode
 
 		//Check if the group exists
 		if !h.GroupExists(groupname) {
-			common.SendErrorResponse(w, "Group not exists")
+			utils.SendErrorResponse(w, "Group not exists")
 			return
 		}
 
@@ -121,64 +121,64 @@ func (h *PermissionHandler) HandleGroupEdit(w http.ResponseWriter, r *http.Reque
 
 		//pg will not be nil because group exists has checked it availbilty
 		jsonString, _ := json.Marshal(pg)
-		common.SendJSONResponse(w, string(jsonString))
+		utils.SendJSONResponse(w, string(jsonString))
 
 	}
 
 }
 
 func (h *PermissionHandler) HandleGroupCreate(w http.ResponseWriter, r *http.Request) {
-	groupname, err := common.Mv(r, "groupname", true)
+	groupname, err := utils.Mv(r, "groupname", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Group name not defined")
+		utils.SendErrorResponse(w, "Group name not defined")
 		return
 	}
 
-	permission, err := common.Mv(r, "permission", true)
+	permission, err := utils.Mv(r, "permission", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Group name not defined")
+		utils.SendErrorResponse(w, "Group name not defined")
 		return
 	}
 
 	permissionSlice := []string{}
 	err = json.Unmarshal([]byte(permission), &permissionSlice)
 	if err != nil {
-		common.SendErrorResponse(w, "Failed to parse module list")
+		utils.SendErrorResponse(w, "Failed to parse module list")
 		return
 	}
 
-	isAdmin, err := common.Mv(r, "isAdmin", true)
+	isAdmin, err := utils.Mv(r, "isAdmin", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Admin permission not defined")
+		utils.SendErrorResponse(w, "Admin permission not defined")
 		return
 	}
 
-	quota, err := common.Mv(r, "defaultQuota", true)
+	quota, err := utils.Mv(r, "defaultQuota", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Default Quota not defined")
+		utils.SendErrorResponse(w, "Default Quota not defined")
 		return
 	}
 
-	interfaceModule, err := common.Mv(r, "interfaceModule", true)
+	interfaceModule, err := utils.Mv(r, "interfaceModule", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Default Interface Module not defined")
+		utils.SendErrorResponse(w, "Default Interface Module not defined")
 		return
 	}
 
 	//Check if the group name already exists
 	if h.GroupExists(groupname) {
-		common.SendErrorResponse(w, "Group already exists")
+		utils.SendErrorResponse(w, "Group already exists")
 		return
 	}
 
 	quotaInt, err := strconv.Atoi(quota)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid Quota.")
+		utils.SendErrorResponse(w, "Invalid Quota.")
 		return
 	}
 
 	if quotaInt < -1 {
-		common.SendErrorResponse(w, "Quota cannot be smaller than -1. (Set to -1 for unlimited quota)")
+		utils.SendErrorResponse(w, "Quota cannot be smaller than -1. (Set to -1 for unlimited quota)")
 		return
 	}
 
@@ -196,26 +196,26 @@ func (h *PermissionHandler) HandleGroupCreate(w http.ResponseWriter, r *http.Req
 		h.LoadPermissionGroupsFromDatabase()
 	*/
 
-	common.SendOK(w)
+	utils.SendOK(w)
 	log.Println("Creating New Permission Group:", groupname, permission, isAdmin, quota)
 }
 
 func (h *PermissionHandler) HandleGroupRemove(w http.ResponseWriter, r *http.Request) {
-	groupname, err := common.Mv(r, "groupname", true)
+	groupname, err := utils.Mv(r, "groupname", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Group name not defined")
+		utils.SendErrorResponse(w, "Group name not defined")
 		return
 	}
 
 	//Check if the group name  exists
 	if !h.GroupExists(groupname) {
-		common.SendErrorResponse(w, "Group not exists")
+		utils.SendErrorResponse(w, "Group not exists")
 		return
 	}
 
 	//Check if this is administrator group
 	if groupname == "administrator" {
-		common.SendErrorResponse(w, "You cannot remove Administrator group.")
+		utils.SendErrorResponse(w, "You cannot remove Administrator group.")
 		return
 	}
 
@@ -238,5 +238,5 @@ func (h *PermissionHandler) HandleGroupRemove(w http.ResponseWriter, r *http.Req
 	//Update 27-12-2020: Replaced database reload with new group list creation
 	//h.LoadPermissionGroupsFromDatabase()
 
-	common.SendOK(w)
+	utils.SendOK(w)
 }

+ 3 - 3
mod/security/csrf/handlers.go

@@ -4,7 +4,7 @@ import (
 	"encoding/json"
 	"net/http"
 
-	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/utils"
 )
 
 func (m *TokenManager) HandleNewToken(w http.ResponseWriter, r *http.Request) {
@@ -16,7 +16,7 @@ func (m *TokenManager) HandleNewToken(w http.ResponseWriter, r *http.Request) {
 
 	newUUID := m.GenerateNewToken(userinfo.Username)
 	js, _ := json.Marshal(newUUID)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 //validate the token validation from request
@@ -26,7 +26,7 @@ func (m *TokenManager) HandleTokenValidation(w http.ResponseWriter, r *http.Requ
 		return false
 	}
 
-	token, _ := common.Mv(r, "csrft", true)
+	token, _ := utils.Mv(r, "csrft", true)
 	if token == "" {
 		return false
 	} else {

+ 46 - 46
mod/share/share.go

@@ -36,12 +36,12 @@ import (
 	"github.com/valyala/fasttemplate"
 
 	"imuslab.com/arozos/mod/auth"
-	"imuslab.com/arozos/mod/common"
 	filesystem "imuslab.com/arozos/mod/filesystem"
 	"imuslab.com/arozos/mod/filesystem/arozfs"
 	"imuslab.com/arozos/mod/filesystem/metadata"
 	"imuslab.com/arozos/mod/share/shareEntry"
 	"imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/utils"
 )
 
 type Options struct {
@@ -236,7 +236,7 @@ func (s *Manager) HandleOPGServing(w http.ResponseWriter, r *http.Request, share
 
 		resizedThumb := resize.Resize(250, 0, thumb, resize.Lanczos3)
 		draw.Draw(resultopg, resultopg.Bounds(), resizedThumb, image.Point{-(resultopg.Bounds().Dx() - resizedThumb.Bounds().Dx() - 90), -60}, draw.Over)
-	} else if common.IsDir(shareEntry.FileRealPath) {
+	} else if utils.IsDir(shareEntry.FileRealPath) {
 		//Is directory but no thumbnail. Use default foldr share thumbnail
 		thumbnailFile, err := os.Open("./system/share/folder.png")
 		if err != nil {
@@ -269,7 +269,7 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 	directServe := false
 	relpath := ""
 
-	id, err := common.Mv(r, "id", false)
+	id, err := utils.Mv(r, "id", false)
 	if err != nil {
 		//ID is not defined in the URL paramter. New ID defination is based on the subpath content
 		requestURI := filepath.ToSlash(filepath.Clean(r.URL.Path))
@@ -347,17 +347,17 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 	} else {
 
 		//Parse and redirect to new share path
-		download, _ := common.Mv(r, "download", false)
+		download, _ := utils.Mv(r, "download", false)
 		if download == "true" {
 			directDownload = true
 		}
 
-		serve, _ := common.Mv(r, "serve", false)
+		serve, _ := utils.Mv(r, "serve", false)
 		if serve == "true" {
 			directServe = true
 		}
 
-		relpath, _ = common.Mv(r, "rel", false)
+		relpath, _ = utils.Mv(r, "rel", false)
 
 		redirectURL := "./" + id + "/"
 		if directDownload == true {
@@ -383,7 +383,7 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 					w.WriteHeader(http.StatusUnauthorized)
 					w.Write([]byte("401 - Unauthorized"))
 				} else {
-					http.Redirect(w, r, common.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect=/share/"+id, 307)
+					http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect=/share/"+id, 307)
 				}
 				return
 			} else {
@@ -396,7 +396,7 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 					w.WriteHeader(http.StatusUnauthorized)
 					w.Write([]byte("401 - Unauthorized"))
 				} else {
-					http.Redirect(w, r, common.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect=/share/"+id, 307)
+					http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect=/share/"+id, 307)
 				}
 				return
 			}
@@ -409,7 +409,7 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 			}
 
 			for _, allowedpg := range shareOption.Accessibles {
-				if common.StringInArray(thisUsersGroupByName, allowedpg) {
+				if utils.StringInArray(thisUsersGroupByName, allowedpg) {
 					//This required group is inside this user's group. OK
 				} else {
 					//This required group is not inside user's group. Reject
@@ -436,13 +436,13 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 					w.WriteHeader(http.StatusUnauthorized)
 					w.Write([]byte("401 - Unauthorized"))
 				} else {
-					http.Redirect(w, r, common.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect=/share/"+id, 307)
+					http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect=/share/"+id, 307)
 				}
 				return
 			}
 
 			//Check if username in the allowed user list
-			if !common.StringInArray(shareOption.Accessibles, thisuserinfo.Username) && shareOption.Owner != thisuserinfo.Username {
+			if !utils.StringInArray(shareOption.Accessibles, thisuserinfo.Username) && shareOption.Owner != thisuserinfo.Username {
 				//Serve permission denied page
 				if directDownload || directServe {
 					w.WriteHeader(http.StatusForbidden)
@@ -461,7 +461,7 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 					w.WriteHeader(http.StatusUnauthorized)
 					w.Write([]byte("401 - Unauthorized"))
 				} else {
-					http.Redirect(w, r, common.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect=/share/"+id, 307)
+					http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect=/share/"+id, 307)
 				}
 				return
 			}
@@ -474,7 +474,7 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 			}
 
 			for _, thisUserPg := range thisUsersGroupByName {
-				if common.StringInArray(shareOption.Accessibles, thisUserPg) {
+				if utils.StringInArray(shareOption.Accessibles, thisUserPg) {
 					allowAccess = true
 				}
 			}
@@ -886,23 +886,23 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 //Check if a file is shared
 func (s *Manager) HandleShareCheck(w http.ResponseWriter, r *http.Request) {
 	//Get the vpath from paramters
-	vpath, err := common.Mv(r, "path", true)
+	vpath, err := utils.Mv(r, "path", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid path given")
+		utils.SendErrorResponse(w, "Invalid path given")
 		return
 	}
 
 	//Get userinfo
 	userinfo, err := s.options.UserHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 
 	fsh, _ := userinfo.GetFileSystemHandlerFromVirtualPath(vpath)
 	pathHash, err := shareEntry.GetPathHash(fsh, vpath, userinfo.Username)
 	if err != nil {
-		common.SendErrorResponse(w, "Unable to get share from given path")
+		utils.SendErrorResponse(w, "Unable to get share from given path")
 		return
 	}
 	type Result struct {
@@ -918,7 +918,7 @@ func (s *Manager) HandleShareCheck(w http.ResponseWriter, r *http.Request) {
 			IsShared:  false,
 			ShareUUID: &shareEntry.ShareOption{},
 		})
-		common.SendJSONResponse(w, string(js))
+		utils.SendJSONResponse(w, string(js))
 
 	} else {
 		//Share exists
@@ -927,7 +927,7 @@ func (s *Manager) HandleShareCheck(w http.ResponseWriter, r *http.Request) {
 			IsShared:  true,
 			ShareUUID: thisSharedInfo,
 		})
-		common.SendJSONResponse(w, string(js))
+		utils.SendJSONResponse(w, string(js))
 	}
 
 }
@@ -935,34 +935,34 @@ func (s *Manager) HandleShareCheck(w http.ResponseWriter, r *http.Request) {
 //Create new share from the given path
 func (s *Manager) HandleCreateNewShare(w http.ResponseWriter, r *http.Request) {
 	//Get the vpath from paramters
-	vpath, err := common.Mv(r, "path", true)
+	vpath, err := utils.Mv(r, "path", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid path given")
+		utils.SendErrorResponse(w, "Invalid path given")
 		return
 	}
 
 	//Get userinfo
 	userinfo, err := s.options.UserHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 
 	//Get the target fsh that this vpath come from
 	vpathSourceFsh := userinfo.GetRootFSHFromVpathInUserScope(vpath)
 	if vpathSourceFsh == nil {
-		common.SendErrorResponse(w, "Invalid vpath given")
+		utils.SendErrorResponse(w, "Invalid vpath given")
 		return
 	}
 
 	share, err := s.CreateNewShare(userinfo, vpathSourceFsh, vpath)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
 	js, _ := json.Marshal(share)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 // Handle Share Edit.
@@ -977,17 +977,17 @@ func (s *Manager) HandleCreateNewShare(w http.ResponseWriter, r *http.Request) {
 func (s *Manager) HandleEditShare(w http.ResponseWriter, r *http.Request) {
 	userinfo, err := s.options.UserHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 
-	uuid, err := common.Mv(r, "uuid", true)
+	uuid, err := utils.Mv(r, "uuid", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid path given")
+		utils.SendErrorResponse(w, "Invalid path given")
 		return
 	}
 
-	shareMode, _ := common.Mv(r, "mode", true)
+	shareMode, _ := utils.Mv(r, "mode", true)
 	if shareMode == "" {
 		shareMode = "signedin"
 	}
@@ -996,20 +996,20 @@ func (s *Manager) HandleEditShare(w http.ResponseWriter, r *http.Request) {
 	so := s.options.ShareEntryTable.GetShareObjectFromUUID(uuid)
 	if so == nil {
 		//This share url not exists
-		common.SendErrorResponse(w, "Share UUID not exists")
+		utils.SendErrorResponse(w, "Share UUID not exists")
 		return
 	}
 
 	//Check if the user has permission to edit this share
 	if !s.CanModifyShareEntry(userinfo, so.FileVirtualPath) {
-		common.SendErrorResponse(w, "Permission Denied")
+		utils.SendErrorResponse(w, "Permission Denied")
 		return
 	}
 
 	//Validate and extract the storage mode
 	ok, sharetype, settings := validateShareModes(shareMode)
 	if !ok {
-		common.SendErrorResponse(w, "Invalid share setting")
+		utils.SendErrorResponse(w, "Invalid share setting")
 		return
 	}
 
@@ -1039,7 +1039,7 @@ func (s *Manager) HandleEditShare(w http.ResponseWriter, r *http.Request) {
 		s.options.ShareEntryTable.Database.Write("share", uuid, so)
 	}
 
-	common.SendOK(w)
+	utils.SendOK(w)
 
 }
 
@@ -1047,23 +1047,23 @@ func (s *Manager) HandleDeleteShare(w http.ResponseWriter, r *http.Request) {
 	//Get userinfo
 	userinfo, err := s.options.UserHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 
 	//Get the vpath from paramters
-	uuid, err := common.Mv(r, "uuid", true)
+	uuid, err := utils.Mv(r, "uuid", true)
 	if err != nil {
 		//Try to get it from vpath
-		vpath, err := common.Mv(r, "vpath", true)
+		vpath, err := utils.Mv(r, "vpath", true)
 		if err != nil {
-			common.SendErrorResponse(w, "Invalid uuid or vpath given")
+			utils.SendErrorResponse(w, "Invalid uuid or vpath given")
 			return
 		}
 
 		targetSa := s.GetShareObjectFromUserAndVpath(userinfo, vpath)
 		if targetSa == nil {
-			common.SendErrorResponse(w, "Invalid uuid or vpath given")
+			utils.SendErrorResponse(w, "Invalid uuid or vpath given")
 			return
 		}
 		uuid = targetSa.UUID
@@ -1073,19 +1073,19 @@ func (s *Manager) HandleDeleteShare(w http.ResponseWriter, r *http.Request) {
 	err = s.DeleteShareByUUID(userinfo, uuid)
 
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 	} else {
-		common.SendOK(w)
+		utils.SendOK(w)
 	}
 }
 
 func (s *Manager) HandleListAllShares(w http.ResponseWriter, r *http.Request) {
 	userinfo, err := s.options.UserHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
-	fshId, _ := common.Mv(r, "fsh", false)
+	fshId, _ := utils.Mv(r, "fsh", false)
 	results := []*shareEntry.ShareOption{}
 	if fshId == "" {
 		//List all
@@ -1103,7 +1103,7 @@ func (s *Manager) HandleListAllShares(w http.ResponseWriter, r *http.Request) {
 		//List fsh only
 		targetFsh, err := userinfo.GetFileSystemHandlerFromVirtualPath(fshId)
 		if err != nil {
-			common.SendErrorResponse(w, err.Error())
+			utils.SendErrorResponse(w, err.Error())
 			return
 		}
 		sharesInThisFsh := s.ListAllShareByFshId(targetFsh.UUID, userinfo)
@@ -1149,7 +1149,7 @@ func (s *Manager) HandleListAllShares(w http.ResponseWriter, r *http.Request) {
 	}
 
 	js, _ := json.Marshal(reducedResult)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 /*
@@ -1188,7 +1188,7 @@ func (s *Manager) CreateNewShare(userinfo *user.User, srcFsh *filesystem.FileSys
 func ServePermissionDeniedPage(w http.ResponseWriter) {
 	w.WriteHeader(http.StatusForbidden)
 	pageContent := []byte("Permissioned Denied")
-	if common.FileExists("system/share/permissionDenied.html") {
+	if utils.FileExists("system/share/permissionDenied.html") {
 		content, err := ioutil.ReadFile("system/share/permissionDenied.html")
 		if err == nil {
 			pageContent = content
@@ -1208,7 +1208,7 @@ func ServePermissionDeniedPage(w http.ResponseWriter) {
 func validateShareModes(mode string) (bool, string, []string) {
 	// user:a,b,c,d
 	validModes := []string{"anyone", "signedin", "samegroup"}
-	if common.StringInArray(validModes, mode) {
+	if utils.StringInArray(validModes, mode) {
 		//Standard modes
 		return true, mode, []string{}
 	} else if len(mode) > 7 && mode[:7] == "groups:" {

+ 4 - 4
mod/storage/webdav/webdav.go

@@ -19,12 +19,12 @@ import (
 	"sync"
 	"time"
 
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/filesystem"
 	"imuslab.com/arozos/mod/filesystem/hidden"
 	"imuslab.com/arozos/mod/filesystem/metadata"
 	"imuslab.com/arozos/mod/network/webdav"
 	"imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/utils"
 )
 
 type Server struct {
@@ -89,13 +89,13 @@ func (s *Server) HandleClearAllPending(w http.ResponseWriter, r *http.Request) {
 
 //Handle allow and remove permission of a windows WebDAV Client
 func (s *Server) HandlePermissionEdit(w http.ResponseWriter, r *http.Request) {
-	opr, err := common.Mv(r, "opr", true)
+	opr, err := utils.Mv(r, "opr", true)
 	if err != nil {
 		sendErrorResponse(w, "Invalid operations")
 		return
 	}
 
-	uuid, err := common.Mv(r, "uuid", true)
+	uuid, err := utils.Mv(r, "uuid", true)
 	if err != nil {
 		sendErrorResponse(w, "Invalid uuid")
 		return
@@ -148,7 +148,7 @@ func (s *Server) HandlePermissionEdit(w http.ResponseWriter, r *http.Request) {
 }
 
 func (s *Server) HandleConnectionList(w http.ResponseWriter, r *http.Request) {
-	target, _ := common.Mv(r, "target", false)
+	target, _ := utils.Mv(r, "target", false)
 	results := []*WindowClientInfo{}
 	if target == "" {
 		//List not logged in clients

+ 27 - 27
mod/time/scheduler/handlers.go

@@ -6,14 +6,14 @@ import (
 	"strconv"
 	"time"
 
-	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/utils"
 )
 
 //List all the jobs related to the given user
 func (a *Scheduler) HandleListJobs(w http.ResponseWriter, r *http.Request) {
 	userinfo, err := a.options.UserHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 
@@ -22,7 +22,7 @@ func (a *Scheduler) HandleListJobs(w http.ResponseWriter, r *http.Request) {
 
 	//Check if the user request list all
 	listAll := false
-	la, _ := common.Mv(r, "listall", false)
+	la, _ := utils.Mv(r, "listall", false)
 	if la == "true" && userinfo.IsAdmin() {
 		listAll = true
 	}
@@ -45,65 +45,65 @@ func (a *Scheduler) HandleListJobs(w http.ResponseWriter, r *http.Request) {
 
 	//Return the values as json
 	js, _ := json.Marshal(userCreatedJobs)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 func (a *Scheduler) HandleAddJob(w http.ResponseWriter, r *http.Request) {
 	userinfo, err := a.options.UserHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 
 	//Get required paramaters
-	taskName, err := common.Mv(r, "name", true)
+	taskName, err := utils.Mv(r, "name", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid task name")
+		utils.SendErrorResponse(w, "Invalid task name")
 		return
 	}
 
 	//Check taskname length valid
 	if len(taskName) > 32 {
-		common.SendErrorResponse(w, "Task name must be shorter than 32 characters")
+		utils.SendErrorResponse(w, "Task name must be shorter than 32 characters")
 		return
 	}
 
 	//Check if the name already existsed
 	for _, runningJob := range a.jobs {
 		if runningJob.Name == taskName {
-			common.SendErrorResponse(w, "Task Name already occupied")
+			utils.SendErrorResponse(w, "Task Name already occupied")
 			return
 		}
 	}
 
-	scriptpath, err := common.Mv(r, "path", true)
+	scriptpath, err := utils.Mv(r, "path", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid script path")
+		utils.SendErrorResponse(w, "Invalid script path")
 		return
 	}
 
 	//Can be empty
-	jobDescription, _ := common.Mv(r, "desc", true)
+	jobDescription, _ := utils.Mv(r, "desc", true)
 	fsh, err := userinfo.GetFileSystemHandlerFromVirtualPath(scriptpath)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 	fshAbs := fsh.FileSystemAbstraction
 	realScriptPath, err := fshAbs.VirtualPathToRealPath(scriptpath, userinfo.Username)
 	if err != nil {
-		common.SendErrorResponse(w, err.Error())
+		utils.SendErrorResponse(w, err.Error())
 		return
 	}
 
 	//Check if the file exists
 	if !fshAbs.FileExists(realScriptPath) {
-		common.SendErrorResponse(w, "script file not exists")
+		utils.SendErrorResponse(w, "script file not exists")
 		return
 	}
 
 	interval := int64(86400) //default 1 day in seconds
-	intervalString, err := common.Mv(r, "interval", true)
+	intervalString, err := utils.Mv(r, "interval", true)
 	if err != nil {
 		//Default 1 day
 
@@ -112,7 +112,7 @@ func (a *Scheduler) HandleAddJob(w http.ResponseWriter, r *http.Request) {
 		intervalInt, err := strconv.ParseInt(intervalString, 10, 64)
 		if err != nil {
 			//Failed to parse interval to int
-			common.SendErrorResponse(w, "invalid interval")
+			utils.SendErrorResponse(w, "invalid interval")
 			return
 		}
 
@@ -120,7 +120,7 @@ func (a *Scheduler) HandleAddJob(w http.ResponseWriter, r *http.Request) {
 	}
 
 	baseUnixTime := time.Now().Unix()
-	baseTimeString, err := common.Mv(r, "base", true)
+	baseTimeString, err := utils.Mv(r, "base", true)
 	if err != nil {
 		//Use curent timestamp as base
 
@@ -128,7 +128,7 @@ func (a *Scheduler) HandleAddJob(w http.ResponseWriter, r *http.Request) {
 		baseTimeInt, err := strconv.Atoi(baseTimeString)
 		if err != nil {
 			//Failed to parse interval to int
-			common.SendErrorResponse(w, "Invalid Base Time")
+			utils.SendErrorResponse(w, "Invalid Base Time")
 			return
 		}
 
@@ -151,27 +151,27 @@ func (a *Scheduler) HandleAddJob(w http.ResponseWriter, r *http.Request) {
 	a.saveJobsToCronFile()
 
 	//OK
-	common.SendOK(w)
+	utils.SendOK(w)
 }
 
 func (a *Scheduler) HandleJobRemoval(w http.ResponseWriter, r *http.Request) {
 	userinfo, err := a.options.UserHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 
 	//Get required paramaters
-	taskName, err := common.Mv(r, "name", true)
+	taskName, err := utils.Mv(r, "name", true)
 	if err != nil {
-		common.SendErrorResponse(w, "Invalid task name")
+		utils.SendErrorResponse(w, "Invalid task name")
 		return
 	}
 
 	//Check if Job exists
 	if !a.JobExists(taskName) {
 		//Job with that name not exists
-		common.SendErrorResponse(w, "Job not exists")
+		utils.SendErrorResponse(w, "Job not exists")
 		return
 	}
 
@@ -187,7 +187,7 @@ func (a *Scheduler) HandleJobRemoval(w http.ResponseWriter, r *http.Request) {
 	}
 
 	if !allowRemove {
-		common.SendErrorResponse(w, "Permission Denied")
+		utils.SendErrorResponse(w, "Permission Denied")
 		return
 	}
 
@@ -197,13 +197,13 @@ func (a *Scheduler) HandleJobRemoval(w http.ResponseWriter, r *http.Request) {
 	//Write current job lists to file
 	a.saveJobsToCronFile()
 
-	common.SendOK(w)
+	utils.SendOK(w)
 }
 
 //Deprecated. Replace with system wide logger
 /*
 func (a *Scheduler) HandleShowLog(w http.ResponseWriter, r *http.Request) {
-	filename, _ := common.Mv(r, "filename", false)
+	filename, _ := utils.Mv(r, "filename", false)
 	if filename == "" {
 		//Show index
 		logFiles, _ := filepath.Glob(logFolder + "*.log")

+ 2 - 2
mod/time/scheduler/scheduler.go

@@ -9,9 +9,9 @@ import (
 	"time"
 
 	"imuslab.com/arozos/mod/agi"
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/info/logger"
 	"imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -51,7 +51,7 @@ type Scheduler struct {
 var ()
 
 func NewScheduler(option *ScheudlerOption) (*Scheduler, error) {
-	if !common.FileExists(option.CronFile) {
+	if !utils.FileExists(option.CronFile) {
 		//Cronfile not exists. Create it
 		emptyJobList := []*Job{}
 		ls, _ := json.Marshal(emptyJobList)

+ 2 - 2
mod/time/timezone/timezone.go

@@ -9,7 +9,7 @@ import (
 	"strings"
 	"time"
 
-	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -77,7 +77,7 @@ func ShowTime(w http.ResponseWriter, r *http.Request) {
 		Timezone: Timezone,
 	}
 	returnString, _ := json.Marshal(returnStruct)
-	common.SendJSONResponse(w, string(returnString))
+	utils.SendJSONResponse(w, string(returnString))
 }
 
 func ConvertWinTZtoLinuxTZ(WinTZ string) string {

+ 182 - 182
mod/updates/handler.go

@@ -1,182 +1,182 @@
-package updates
-
-import (
-	"encoding/json"
-	"fmt"
-	"io/ioutil"
-	"log"
-	"net/http"
-	"runtime"
-	"time"
-
-	"github.com/gorilla/websocket"
-	"imuslab.com/arozos/mod/common"
-)
-
-type UpdateConfig struct {
-	Vendor string `json:"vendor"`
-	Binary struct {
-		Windows struct {
-			Amd64 string `json:"amd64"`
-			Arm   string `json:"arm"`
-			Arm64 string `json:"arm64"`
-			I386  string `json:"i386"`
-		} `json:"windows"`
-		Linux struct {
-			Arm    string `json:"arm"`
-			Armv7  string `json:"armv7"`
-			Arm64  string `json:"arm64"`
-			Amd64  string `json:"amd64"`
-			Mipsle string `json:"mipsle"`
-		} `json:"linux"`
-		Darwin struct {
-			Amd64 string `json:"amd64"`
-			Arm64 string `json:"arm64"`
-		} `json:"darwin"`
-		Freebsd struct {
-			Amd64 string `json:"amd64"`
-			Arm   string `json:"arm"`
-			Arm64 string `json:"arm64"`
-			I386  string `json:"i386"`
-		} `json:"freebsd"`
-	} `json:"binary"`
-	Webpack  string `json:"webpack"`
-	Checksum string `json:"checksum"`
-}
-
-func HandleUpdateCheckSize(w http.ResponseWriter, r *http.Request) {
-	webpack, err := common.Mv(r, "webpack", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid or empty webpack download URL")
-		return
-	}
-
-	binary, err := common.Mv(r, "binary", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid or empty binary download URL")
-		return
-	}
-
-	bsize, wsize, err := GetUpdateSizes(binary, webpack)
-	if err != nil {
-		common.SendErrorResponse(w, "Failed to get update size: "+err.Error())
-		return
-	}
-
-	js, _ := json.Marshal([]int{bsize, wsize})
-	common.SendJSONResponse(w, string(js))
-}
-
-func HandleUpdateDownloadRequest(w http.ResponseWriter, r *http.Request) {
-	webpack, err := common.Mv(r, "webpack", false)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid or empty webpack download URL")
-		return
-	}
-
-	binary, err := common.Mv(r, "binary", false)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid or empty binary download URL")
-		return
-	}
-
-	checksum, err := common.Mv(r, "checksum", true)
-	if err != nil {
-		checksum = ""
-	}
-
-	//Update the connection to websocket
-	requireWebsocket, _ := common.Mv(r, "ws", false)
-	if requireWebsocket == "true" {
-		//Upgrade to websocket
-		var upgrader = websocket.Upgrader{}
-		upgrader.CheckOrigin = func(r *http.Request) bool { return true }
-		c, err := upgrader.Upgrade(w, r, nil)
-		if err != nil {
-			common.SendErrorResponse(w, "Upgrade websocket failed: "+err.Error())
-			return
-		}
-
-		type Progress struct {
-			Stage      int
-			Progress   float64
-			StatusText string
-		}
-		err = DownloadUpdatesFromURL(binary, webpack, checksum, func(stage int, progress float64, statusText string) {
-			thisProgress := Progress{
-				Stage:      stage,
-				Progress:   progress,
-				StatusText: statusText,
-			}
-			js, _ := json.Marshal(thisProgress)
-			c.WriteMessage(1, js)
-		})
-		if err != nil {
-			//Finish with error
-			c.WriteMessage(1, []byte("{\"error\":\""+err.Error()+"\"}"))
-		} else {
-			//Done without error
-			c.WriteMessage(1, []byte("OK"))
-		}
-
-		//Close WebSocket connection after finished
-		c.WriteControl(8, []byte{}, time.Now().Add(time.Second))
-		c.Close()
-
-	} else {
-		//Just download and return ok after finish
-		err = DownloadUpdatesFromURL(binary, webpack, checksum, func(stage int, progress float64, statusText string) {
-			fmt.Println("Downloading Update, Stage: ", stage, " Progress: ", progress, " Status: ", statusText)
-		})
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-		} else {
-			common.SendOK(w)
-		}
-	}
-
-}
-
-//Handle getting information for vendor update
-func HandleGetUpdatePlatformInfo(w http.ResponseWriter, r *http.Request) {
-	type UpdatePackageInfo struct {
-		Config UpdateConfig
-		OS     string
-		ARCH   string
-	}
-
-	//Check if update config find. If yes, parse that
-	updateFileContent, err := ioutil.ReadFile("./system/update.json")
-	if err != nil {
-		common.SendErrorResponse(w, "No vendor update config found")
-		return
-	}
-
-	//Read from the update config
-	vendorUpdateConfig := UpdateConfig{}
-	err = json.Unmarshal(updateFileContent, &vendorUpdateConfig)
-	if err != nil {
-		log.Println("[Updates] Failed to parse update config file: ", err.Error())
-		common.SendErrorResponse(w, "Invalid or corrupted update config")
-		return
-	}
-
-	updateinfo := UpdatePackageInfo{
-		Config: vendorUpdateConfig,
-		OS:     runtime.GOOS,
-		ARCH:   runtime.GOARCH,
-	}
-
-	js, _ := json.Marshal(updateinfo)
-	common.SendJSONResponse(w, string(js))
-}
-
-//Handle check if there is a pending update
-func HandlePendingCheck(w http.ResponseWriter, r *http.Request) {
-	if common.FileExists("./updates/") && common.FileExists("./updates/web/") && common.FileExists("./updates/system/") {
-		//Update is pending
-		common.SendJSONResponse(w, "true")
-	} else {
-		common.SendJSONResponse(w, "false")
-	}
-}
+package updates
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"runtime"
+	"time"
+
+	"github.com/gorilla/websocket"
+	"imuslab.com/arozos/mod/utils"
+)
+
+type UpdateConfig struct {
+	Vendor string `json:"vendor"`
+	Binary struct {
+		Windows struct {
+			Amd64 string `json:"amd64"`
+			Arm   string `json:"arm"`
+			Arm64 string `json:"arm64"`
+			I386  string `json:"i386"`
+		} `json:"windows"`
+		Linux struct {
+			Arm    string `json:"arm"`
+			Armv7  string `json:"armv7"`
+			Arm64  string `json:"arm64"`
+			Amd64  string `json:"amd64"`
+			Mipsle string `json:"mipsle"`
+		} `json:"linux"`
+		Darwin struct {
+			Amd64 string `json:"amd64"`
+			Arm64 string `json:"arm64"`
+		} `json:"darwin"`
+		Freebsd struct {
+			Amd64 string `json:"amd64"`
+			Arm   string `json:"arm"`
+			Arm64 string `json:"arm64"`
+			I386  string `json:"i386"`
+		} `json:"freebsd"`
+	} `json:"binary"`
+	Webpack  string `json:"webpack"`
+	Checksum string `json:"checksum"`
+}
+
+func HandleUpdateCheckSize(w http.ResponseWriter, r *http.Request) {
+	webpack, err := utils.Mv(r, "webpack", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid or empty webpack download URL")
+		return
+	}
+
+	binary, err := utils.Mv(r, "binary", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid or empty binary download URL")
+		return
+	}
+
+	bsize, wsize, err := GetUpdateSizes(binary, webpack)
+	if err != nil {
+		utils.SendErrorResponse(w, "Failed to get update size: "+err.Error())
+		return
+	}
+
+	js, _ := json.Marshal([]int{bsize, wsize})
+	utils.SendJSONResponse(w, string(js))
+}
+
+func HandleUpdateDownloadRequest(w http.ResponseWriter, r *http.Request) {
+	webpack, err := utils.Mv(r, "webpack", false)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid or empty webpack download URL")
+		return
+	}
+
+	binary, err := utils.Mv(r, "binary", false)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid or empty binary download URL")
+		return
+	}
+
+	checksum, err := utils.Mv(r, "checksum", true)
+	if err != nil {
+		checksum = ""
+	}
+
+	//Update the connection to websocket
+	requireWebsocket, _ := utils.Mv(r, "ws", false)
+	if requireWebsocket == "true" {
+		//Upgrade to websocket
+		var upgrader = websocket.Upgrader{}
+		upgrader.CheckOrigin = func(r *http.Request) bool { return true }
+		c, err := upgrader.Upgrade(w, r, nil)
+		if err != nil {
+			utils.SendErrorResponse(w, "Upgrade websocket failed: "+err.Error())
+			return
+		}
+
+		type Progress struct {
+			Stage      int
+			Progress   float64
+			StatusText string
+		}
+		err = DownloadUpdatesFromURL(binary, webpack, checksum, func(stage int, progress float64, statusText string) {
+			thisProgress := Progress{
+				Stage:      stage,
+				Progress:   progress,
+				StatusText: statusText,
+			}
+			js, _ := json.Marshal(thisProgress)
+			c.WriteMessage(1, js)
+		})
+		if err != nil {
+			//Finish with error
+			c.WriteMessage(1, []byte("{\"error\":\""+err.Error()+"\"}"))
+		} else {
+			//Done without error
+			c.WriteMessage(1, []byte("OK"))
+		}
+
+		//Close WebSocket connection after finished
+		c.WriteControl(8, []byte{}, time.Now().Add(time.Second))
+		c.Close()
+
+	} else {
+		//Just download and return ok after finish
+		err = DownloadUpdatesFromURL(binary, webpack, checksum, func(stage int, progress float64, statusText string) {
+			fmt.Println("Downloading Update, Stage: ", stage, " Progress: ", progress, " Status: ", statusText)
+		})
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+		} else {
+			utils.SendOK(w)
+		}
+	}
+
+}
+
+//Handle getting information for vendor update
+func HandleGetUpdatePlatformInfo(w http.ResponseWriter, r *http.Request) {
+	type UpdatePackageInfo struct {
+		Config UpdateConfig
+		OS     string
+		ARCH   string
+	}
+
+	//Check if update config find. If yes, parse that
+	updateFileContent, err := ioutil.ReadFile("./system/update.json")
+	if err != nil {
+		utils.SendErrorResponse(w, "No vendor update config found")
+		return
+	}
+
+	//Read from the update config
+	vendorUpdateConfig := UpdateConfig{}
+	err = json.Unmarshal(updateFileContent, &vendorUpdateConfig)
+	if err != nil {
+		log.Println("[Updates] Failed to parse update config file: ", err.Error())
+		utils.SendErrorResponse(w, "Invalid or corrupted update config")
+		return
+	}
+
+	updateinfo := UpdatePackageInfo{
+		Config: vendorUpdateConfig,
+		OS:     runtime.GOOS,
+		ARCH:   runtime.GOARCH,
+	}
+
+	js, _ := json.Marshal(updateinfo)
+	utils.SendJSONResponse(w, string(js))
+}
+
+//Handle check if there is a pending update
+func HandlePendingCheck(w http.ResponseWriter, r *http.Request) {
+	if utils.FileExists("./updates/") && utils.FileExists("./updates/web/") && utils.FileExists("./updates/system/") {
+		//Update is pending
+		utils.SendJSONResponse(w, "true")
+	} else {
+		utils.SendJSONResponse(w, "false")
+	}
+}

+ 2 - 2
mod/user/directoryHandler.go

@@ -5,9 +5,9 @@ import (
 	"os"
 	"path/filepath"
 
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/filesystem"
 	fs "imuslab.com/arozos/mod/filesystem"
+	"imuslab.com/arozos/mod/utils"
 )
 
 func (u *User) GetHomeDirectory() (string, error) {
@@ -68,7 +68,7 @@ func (u *User) GetAllFileSystemHandler() []*fs.FileSystemHandler {
 		//For each permission group that this user is in
 		for _, store := range pg.StoragePool.Storages {
 			//Get each of the storage of this permission group is assigned to
-			if !common.StringInArray(uuids, store.UUID) {
+			if !utils.StringInArray(uuids, store.UUID) {
 				if store.Closed == false {
 					//Only return opened file system handlers
 					results = append(results, store)

+ 4 - 4
mod/user/permissionHandler.go

@@ -6,10 +6,10 @@ import (
 	"path/filepath"
 	"strings"
 
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/filesystem/arozfs"
 	permission "imuslab.com/arozos/mod/permission"
 	storage "imuslab.com/arozos/mod/storage"
+	"imuslab.com/arozos/mod/utils"
 )
 
 //Permissions related to modules
@@ -20,10 +20,10 @@ func (u *User) GetModuleAccessPermission(moduleName string) bool {
 		if pg.IsAdmin == true {
 			//This user is admin. Allow all module access
 			return true
-		} else if common.StringInArrayIgnoreCase(pg.AccessibleModules, moduleName) {
+		} else if utils.StringInArrayIgnoreCase(pg.AccessibleModules, moduleName) {
 			//This permission group contain the module we want. Allow accessed
 			return true
-		} else if common.StringInArrayIgnoreCase(u.parent.UniversalModules, moduleName) {
+		} else if utils.StringInArrayIgnoreCase(u.parent.UniversalModules, moduleName) {
 			//This is system tools or utilities that everyone is allowed to access
 			return true
 		} else if moduleName == strings.ToLower(pg.DefaultInterfaceModule) {
@@ -77,7 +77,7 @@ func (u *User) IsAdmin() bool {
 func (u *User) GetInterfaceModules() []string {
 	results := []string{}
 	for _, pg := range u.PermissionGroup {
-		if !common.StringInArray(results, pg.DefaultInterfaceModule) {
+		if !utils.StringInArray(results, pg.DefaultInterfaceModule) {
 			results = append(results, pg.DefaultInterfaceModule)
 		}
 

+ 16 - 16
mod/common/conv.go → mod/utils/conv.go

@@ -1,16 +1,16 @@
-package common
-
-import "strconv"
-
-func StringToInt64(number string) (int64, error) {
-	i, err := strconv.ParseInt(number, 10, 64)
-	if err != nil {
-		return -1, err
-	}
-	return i, nil
-}
-
-func Int64ToString(number int64) string {
-	convedNumber := strconv.FormatInt(number, 10)
-	return convedNumber
-}
+package utils
+
+import "strconv"
+
+func StringToInt64(number string) (int64, error) {
+	i, err := strconv.ParseInt(number, 10, 64)
+	if err != nil {
+		return -1, err
+	}
+	return i, nil
+}
+
+func Int64ToString(number int64) string {
+	convedNumber := strconv.FormatInt(number, 10)
+	return convedNumber
+}

+ 1 - 1
mod/common/template.go → mod/utils/template.go

@@ -1,4 +1,4 @@
-package common
+package utils
 
 import (
 	"io/ioutil"

+ 1 - 1
mod/common/common.go → mod/utils/utils.go

@@ -1,4 +1,4 @@
-package common
+package utils
 
 import (
 	"bufio"

+ 10 - 10
mod/www/handler.go

@@ -5,7 +5,7 @@ import (
 	"errors"
 	"net/http"
 
-	"imuslab.com/arozos/mod/common"
+	"imuslab.com/arozos/mod/utils"
 )
 
 func (h *Handler) CheckUserHomePageEnabled(username string) bool {
@@ -40,16 +40,16 @@ func (h *Handler) GetUserWebRoot(username string) (string, error) {
 func (h *Handler) HandleToggleHomepage(w http.ResponseWriter, r *http.Request) {
 	userinfo, err := h.Options.UserHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 
-	set, _ := common.Mv(r, "set", true)
+	set, _ := utils.Mv(r, "set", true)
 	if set == "" {
 		//Read mode
 		result := h.CheckUserHomePageEnabled(userinfo.Username)
 		js, _ := json.Marshal(result)
-		common.SendJSONResponse(w, string(js))
+		utils.SendJSONResponse(w, string(js))
 
 	} else {
 		//Set mode
@@ -60,7 +60,7 @@ func (h *Handler) HandleToggleHomepage(w http.ResponseWriter, r *http.Request) {
 			//Disable homepage
 			h.Options.Database.Write("www", userinfo.Username+"_enable", "false")
 		}
-		common.SendOK(w)
+		utils.SendOK(w)
 	}
 
 }
@@ -68,26 +68,26 @@ func (h *Handler) HandleToggleHomepage(w http.ResponseWriter, r *http.Request) {
 func (h *Handler) HandleSetWebRoot(w http.ResponseWriter, r *http.Request) {
 	userinfo, err := h.Options.UserHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 
-	set, _ := common.Mv(r, "set", true)
+	set, _ := utils.Mv(r, "set", true)
 	if set == "" {
 		//Read mode
 		webroot, err := h.GetUserWebRoot(userinfo.Username)
 		if err != nil {
-			common.SendErrorResponse(w, err.Error())
+			utils.SendErrorResponse(w, err.Error())
 			return
 		}
 
 		js, _ := json.Marshal(webroot)
-		common.SendJSONResponse(w, string(js))
+		utils.SendJSONResponse(w, string(js))
 
 	} else {
 		//Set mode
 		h.Options.Database.Write("www", userinfo.Username+"_webroot", set)
 
-		common.SendOK(w)
+		utils.SendOK(w)
 	}
 }

+ 2 - 2
mod/www/www.go

@@ -9,9 +9,9 @@ import (
 	"strings"
 
 	"imuslab.com/arozos/mod/agi"
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/database"
 	"imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -177,7 +177,7 @@ func serveNotFoundTemplate(w http.ResponseWriter, r *http.Request) {
 
 func handleWebrootError(w http.ResponseWriter) {
 	w.WriteHeader(http.StatusInternalServerError)
-	if common.FileExists("./system/www/nowebroot.html") {
+	if utils.FileExists("./system/www/nowebroot.html") {
 		content, err := ioutil.ReadFile("./system/www/nowebroot.html")
 		if err != nil {
 			w.Write([]byte("500 - Internal Server Error"))

+ 197 - 197
module.go

@@ -1,197 +1,197 @@
-package main
-
-import (
-	"log"
-	"net/http"
-	"os"
-
-	"imuslab.com/arozos/mod/common"
-	module "imuslab.com/arozos/mod/modules"
-	prout "imuslab.com/arozos/mod/prouter"
-)
-
-var (
-	moduleHandler *module.ModuleHandler
-)
-
-func ModuleServiceInit() {
-	//Create a new module handler
-	moduleHandler = module.NewModuleHandler(userHandler, *tmp_directory)
-
-	//Register FTP Endpoints
-	adminRouter := prout.NewModuleRouter(prout.RouterOption{
-		AdminOnly:   true,
-		UserHandler: userHandler,
-		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			errorHandlePermissionDenied(w, r)
-		},
-	})
-
-	//Pass through the endpoint to authAgent
-	http.HandleFunc("/system/modules/list", func(w http.ResponseWriter, r *http.Request) {
-		authAgent.HandleCheckAuth(w, r, moduleHandler.ListLoadedModules)
-	})
-	http.HandleFunc("/system/modules/getDefault", func(w http.ResponseWriter, r *http.Request) {
-		authAgent.HandleCheckAuth(w, r, moduleHandler.HandleDefaultLauncher)
-	})
-	http.HandleFunc("/system/modules/getLaunchPara", func(w http.ResponseWriter, r *http.Request) {
-		authAgent.HandleCheckAuth(w, r, moduleHandler.GetLaunchParameter)
-	})
-
-	adminRouter.HandleFunc("/system/modules/reload", func(w http.ResponseWriter, r *http.Request) {
-		moduleHandler.ReloadAllModules(AGIGateway)
-		common.SendOK(w)
-	})
-
-	//Handle module installer. Require admin
-	http.HandleFunc("/system/modules/installViaZip", func(w http.ResponseWriter, r *http.Request) {
-		//Check if the user is admin
-		userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
-		if err != nil {
-			common.SendErrorResponse(w, "User not logged in")
-			return
-		}
-
-		//Validate the user is admin
-		if userinfo.IsAdmin() {
-			//Get the installation file path
-			installerPath, err := common.Mv(r, "path", true)
-			if err != nil {
-				common.SendErrorResponse(w, "Invalid installer path")
-				return
-			}
-
-			fsh, subpath, err := GetFSHandlerSubpathFromVpath(installerPath)
-			if err != nil {
-				common.SendErrorResponse(w, "Invalid installer path")
-				return
-			}
-
-			//Translate it to realpath
-			rpath, err := fsh.FileSystemAbstraction.VirtualPathToRealPath(subpath, userinfo.Username)
-			if err != nil {
-				systemWideLogger.PrintAndLog("Module Installer", "Failed to install module: "+err.Error(), err)
-				common.SendErrorResponse(w, "Invalid installer path")
-				return
-			}
-
-			//Install it
-			moduleHandler.InstallViaZip(rpath, AGIGateway)
-		} else {
-			//Permission denied
-			common.SendErrorResponse(w, "Permission Denied")
-		}
-
-	})
-
-	//Register setting interface for module configuration
-	registerSetting(settingModule{
-		Name:     "Module List",
-		Desc:     "A list of module currently loaded in the system",
-		IconPath: "SystemAO/modules/img/small_icon.png",
-		Group:    "Module",
-		StartDir: "SystemAO/modules/moduleList.html",
-	})
-
-	registerSetting(settingModule{
-		Name:     "Default Module",
-		Desc:     "Default module use to open a file",
-		IconPath: "SystemAO/modules/img/small_icon.png",
-		Group:    "Module",
-		StartDir: "SystemAO/modules/defaultOpener.html",
-	})
-
-	if !*disable_subservices {
-		registerSetting(settingModule{
-			Name:         "Subservices",
-			Desc:         "Launch and kill subservices",
-			IconPath:     "SystemAO/modules/img/small_icon.png",
-			Group:        "Module",
-			StartDir:     "SystemAO/modules/subservices.html",
-			RequireAdmin: true,
-		})
-	}
-
-	err := sysdb.NewTable("module")
-	if err != nil {
-		log.Fatal(err)
-		os.Exit(1)
-	}
-
-}
-
-/*
-	Handle endpoint registry for Module installer
-
-*/
-func ModuleInstallerInit() {
-	//Register module installation setting
-	registerSetting(settingModule{
-		Name:         "Add & Remove Module",
-		Desc:         "Install & Remove Module to the system",
-		IconPath:     "SystemAO/modules/img/small_icon.png",
-		Group:        "Module",
-		StartDir:     "SystemAO/modules/addAndRemove.html",
-		RequireAdmin: true,
-	})
-
-	//Create new permission router
-	router := prout.NewModuleRouter(prout.RouterOption{
-		ModuleName:  "System Setting",
-		UserHandler: userHandler,
-		AdminOnly:   true,
-		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			errorHandlePermissionDenied(w, r)
-		},
-	})
-
-	router.HandleFunc("/system/module/install", HandleModuleInstall)
-
-}
-
-//Handle module installation request
-func HandleModuleInstall(w http.ResponseWriter, r *http.Request) {
-	opr, _ := common.Mv(r, "opr", true)
-
-	if opr == "gitinstall" {
-		//Get URL from request
-		url, _ := common.Mv(r, "url", true)
-		if url == "" {
-			common.SendErrorResponse(w, "Invalid URL")
-			return
-		}
-
-		//Install the module using git
-		err := moduleHandler.InstallModuleViaGit(url, AGIGateway)
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-			return
-		}
-
-		//Reply ok
-		common.SendOK(w)
-	} else if opr == "zipinstall" {
-
-	} else if opr == "remove" {
-		//Get the module name from list
-		module, _ := common.Mv(r, "module", true)
-		if module == "" {
-			common.SendErrorResponse(w, "Invalid Module Name")
-			return
-		}
-
-		//Remove the module
-		err := moduleHandler.UninstallModule(module)
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-			return
-		}
-
-		//Reply ok
-		common.SendOK(w)
-
-	} else {
-		//List all the modules
-		moduleHandler.HandleModuleInstallationListing(w, r)
-	}
-}
+package main
+
+import (
+	"log"
+	"net/http"
+	"os"
+
+	module "imuslab.com/arozos/mod/modules"
+	prout "imuslab.com/arozos/mod/prouter"
+	"imuslab.com/arozos/mod/utils"
+)
+
+var (
+	moduleHandler *module.ModuleHandler
+)
+
+func ModuleServiceInit() {
+	//Create a new module handler
+	moduleHandler = module.NewModuleHandler(userHandler, *tmp_directory)
+
+	//Register FTP Endpoints
+	adminRouter := prout.NewModuleRouter(prout.RouterOption{
+		AdminOnly:   true,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			errorHandlePermissionDenied(w, r)
+		},
+	})
+
+	//Pass through the endpoint to authAgent
+	http.HandleFunc("/system/modules/list", func(w http.ResponseWriter, r *http.Request) {
+		authAgent.HandleCheckAuth(w, r, moduleHandler.ListLoadedModules)
+	})
+	http.HandleFunc("/system/modules/getDefault", func(w http.ResponseWriter, r *http.Request) {
+		authAgent.HandleCheckAuth(w, r, moduleHandler.HandleDefaultLauncher)
+	})
+	http.HandleFunc("/system/modules/getLaunchPara", func(w http.ResponseWriter, r *http.Request) {
+		authAgent.HandleCheckAuth(w, r, moduleHandler.GetLaunchParameter)
+	})
+
+	adminRouter.HandleFunc("/system/modules/reload", func(w http.ResponseWriter, r *http.Request) {
+		moduleHandler.ReloadAllModules(AGIGateway)
+		utils.SendOK(w)
+	})
+
+	//Handle module installer. Require admin
+	http.HandleFunc("/system/modules/installViaZip", func(w http.ResponseWriter, r *http.Request) {
+		//Check if the user is admin
+		userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
+		if err != nil {
+			utils.SendErrorResponse(w, "User not logged in")
+			return
+		}
+
+		//Validate the user is admin
+		if userinfo.IsAdmin() {
+			//Get the installation file path
+			installerPath, err := utils.Mv(r, "path", true)
+			if err != nil {
+				utils.SendErrorResponse(w, "Invalid installer path")
+				return
+			}
+
+			fsh, subpath, err := GetFSHandlerSubpathFromVpath(installerPath)
+			if err != nil {
+				utils.SendErrorResponse(w, "Invalid installer path")
+				return
+			}
+
+			//Translate it to realpath
+			rpath, err := fsh.FileSystemAbstraction.VirtualPathToRealPath(subpath, userinfo.Username)
+			if err != nil {
+				systemWideLogger.PrintAndLog("Module Installer", "Failed to install module: "+err.Error(), err)
+				utils.SendErrorResponse(w, "Invalid installer path")
+				return
+			}
+
+			//Install it
+			moduleHandler.InstallViaZip(rpath, AGIGateway)
+		} else {
+			//Permission denied
+			utils.SendErrorResponse(w, "Permission Denied")
+		}
+
+	})
+
+	//Register setting interface for module configuration
+	registerSetting(settingModule{
+		Name:     "Module List",
+		Desc:     "A list of module currently loaded in the system",
+		IconPath: "SystemAO/modules/img/small_icon.png",
+		Group:    "Module",
+		StartDir: "SystemAO/modules/moduleList.html",
+	})
+
+	registerSetting(settingModule{
+		Name:     "Default Module",
+		Desc:     "Default module use to open a file",
+		IconPath: "SystemAO/modules/img/small_icon.png",
+		Group:    "Module",
+		StartDir: "SystemAO/modules/defaultOpener.html",
+	})
+
+	if !*disable_subservices {
+		registerSetting(settingModule{
+			Name:         "Subservices",
+			Desc:         "Launch and kill subservices",
+			IconPath:     "SystemAO/modules/img/small_icon.png",
+			Group:        "Module",
+			StartDir:     "SystemAO/modules/subservices.html",
+			RequireAdmin: true,
+		})
+	}
+
+	err := sysdb.NewTable("module")
+	if err != nil {
+		log.Fatal(err)
+		os.Exit(1)
+	}
+
+}
+
+/*
+	Handle endpoint registry for Module installer
+
+*/
+func ModuleInstallerInit() {
+	//Register module installation setting
+	registerSetting(settingModule{
+		Name:         "Add & Remove Module",
+		Desc:         "Install & Remove Module to the system",
+		IconPath:     "SystemAO/modules/img/small_icon.png",
+		Group:        "Module",
+		StartDir:     "SystemAO/modules/addAndRemove.html",
+		RequireAdmin: true,
+	})
+
+	//Create new permission router
+	router := prout.NewModuleRouter(prout.RouterOption{
+		ModuleName:  "System Setting",
+		UserHandler: userHandler,
+		AdminOnly:   true,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			errorHandlePermissionDenied(w, r)
+		},
+	})
+
+	router.HandleFunc("/system/module/install", HandleModuleInstall)
+
+}
+
+//Handle module installation request
+func HandleModuleInstall(w http.ResponseWriter, r *http.Request) {
+	opr, _ := utils.Mv(r, "opr", true)
+
+	if opr == "gitinstall" {
+		//Get URL from request
+		url, _ := utils.Mv(r, "url", true)
+		if url == "" {
+			utils.SendErrorResponse(w, "Invalid URL")
+			return
+		}
+
+		//Install the module using git
+		err := moduleHandler.InstallModuleViaGit(url, AGIGateway)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+
+		//Reply ok
+		utils.SendOK(w)
+	} else if opr == "zipinstall" {
+
+	} else if opr == "remove" {
+		//Get the module name from list
+		module, _ := utils.Mv(r, "module", true)
+		if module == "" {
+			utils.SendErrorResponse(w, "Invalid Module Name")
+			return
+		}
+
+		//Remove the module
+		err := moduleHandler.UninstallModule(module)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+
+		//Reply ok
+		utils.SendOK(w)
+
+	} else {
+		//List all the modules
+		moduleHandler.HandleModuleInstallationListing(w, r)
+	}
+}

+ 172 - 172
network.forward.go

@@ -1,172 +1,172 @@
-package main
-
-import (
-	"encoding/json"
-	"net/http"
-	"strconv"
-
-	"imuslab.com/arozos/mod/common"
-	prout "imuslab.com/arozos/mod/prouter"
-)
-
-/*
-	Network Forward Interface
-	author: tobychui
-
-	This is an interface for providing a web UI for port forwarding to this host
-	on different ports. Useful if you need to forward alternative ports for your
-	services.
-*/
-
-func portForwardInit() {
-
-	//Create database table if not exists
-	sysdb.NewTable("portforward")
-
-	//Register modules
-	if *allow_upnp {
-		//Forward the previous registered paths
-		entries, _ := sysdb.ListTable("portforward")
-		for _, keypairs := range entries {
-			portNumber, _ := strconv.Atoi(string(keypairs[0]))
-			policyName := "Unknown Forward Rule"
-			json.Unmarshal(keypairs[1], &policyName)
-
-			//Forward the recorded port
-			err := UPNP.ForwardPort(portNumber, policyName)
-			if err != nil {
-				systemWideLogger.PrintAndLog("UpnP", "Port Fordware Failed: "+err.Error()+". Skipping "+policyName, err)
-			}
-
-		}
-
-		//Create a setting interface for port forward
-		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")
-			},
-		})
-
-		registerSetting(settingModule{
-			Name:     "Port Forward",
-			Desc:     "UPnP based port forwarding",
-			IconPath: "SystemAO/network/img/portforward.png",
-			Group:    "Network",
-			StartDir: "SystemAO/network/portforward.html",
-		})
-
-		router.HandleFunc("/system/network/portforward", portforward_handleForward)
-	}
-}
-
-func portforward_handleForward(w http.ResponseWriter, r *http.Request) {
-	opr, _ := common.Mv(r, "opr", true)
-	if opr == "" {
-		if UPNP == nil {
-			common.SendErrorResponse(w, "UPNP is not enabled")
-			return
-		}
-		//List the current forward port and names
-		type register struct {
-			Port     int
-			Name     string
-			ReadOnly bool
-		}
-		forwardPorts := []register{}
-		for _, port := range UPNP.RequiredPorts {
-			//Get the name of the policy
-			name, ok := UPNP.PolicyNames.Load(port)
-			if !ok {
-				name = "Unknown Service"
-			}
-
-			readOnly := false
-			if port == *listen_port {
-				//This is the port where the webUI is hosted. No change allowed
-				readOnly = true
-			}
-			thisPort := register{
-				Port:     port,
-				Name:     name.(string),
-				ReadOnly: readOnly,
-			}
-
-			//systemWideLogger.PrintAndLog(thisPort,nil)
-
-			forwardPorts = append(forwardPorts, thisPort)
-		}
-
-		//Send the result as json
-		js, _ := json.Marshal(forwardPorts)
-		common.SendJSONResponse(w, string(js))
-	} else if opr == "add" {
-		port, err := common.Mv(r, "port", true)
-		if err != nil {
-			common.SendErrorResponse(w, "Invalid port number")
-			return
-		}
-
-		//Convert port to int
-		portNumberic, err := strconv.Atoi(port)
-		if err != nil {
-			common.SendErrorResponse(w, "Invalid port number")
-			return
-		}
-
-		//Get the policy name
-		policyName, err := common.Mv(r, "name", true)
-		if err != nil {
-			policyName = "Unnamed Forward Policy"
-		}
-
-		//Write port forward rules to database
-		sysdb.Write("portforward", strconv.Itoa(portNumberic), policyName)
-
-		if UPNP != nil {
-			//Forward the port
-			err := UPNP.ForwardPort(portNumberic, policyName)
-			if err != nil {
-				common.SendErrorResponse(w, err.Error())
-			} else {
-				common.SendOK(w)
-			}
-		} else {
-			common.SendErrorResponse(w, "UPNP is not enabled")
-			return
-		}
-	} else if opr == "remove" {
-		port, err := common.Mv(r, "port", true)
-		if err != nil {
-			common.SendErrorResponse(w, "Invalid port number")
-			return
-		}
-
-		//Convert port to int
-		portNumberic, err := strconv.Atoi(port)
-		if err != nil {
-			common.SendErrorResponse(w, "Invalid port number")
-			return
-		}
-
-		//Remove it from db if exists
-		if sysdb.KeyExists("portforward", strconv.Itoa(portNumberic)) {
-			//Key exists. Remove it from db
-			sysdb.Delete("portforward", strconv.Itoa(portNumberic))
-		}
-
-		if UPNP != nil {
-			err := UPNP.ClosePort(portNumberic)
-			if err != nil {
-				common.SendErrorResponse(w, err.Error())
-			} else {
-				common.SendOK(w)
-			}
-		} else {
-			common.SendErrorResponse(w, "UPNP is not enabled")
-			return
-		}
-	}
-}
+package main
+
+import (
+	"encoding/json"
+	"net/http"
+	"strconv"
+
+	prout "imuslab.com/arozos/mod/prouter"
+	"imuslab.com/arozos/mod/utils"
+)
+
+/*
+	Network Forward Interface
+	author: tobychui
+
+	This is an interface for providing a web UI for port forwarding to this host
+	on different ports. Useful if you need to forward alternative ports for your
+	services.
+*/
+
+func portForwardInit() {
+
+	//Create database table if not exists
+	sysdb.NewTable("portforward")
+
+	//Register modules
+	if *allow_upnp {
+		//Forward the previous registered paths
+		entries, _ := sysdb.ListTable("portforward")
+		for _, keypairs := range entries {
+			portNumber, _ := strconv.Atoi(string(keypairs[0]))
+			policyName := "Unknown Forward Rule"
+			json.Unmarshal(keypairs[1], &policyName)
+
+			//Forward the recorded port
+			err := UPNP.ForwardPort(portNumber, policyName)
+			if err != nil {
+				systemWideLogger.PrintAndLog("UpnP", "Port Fordware Failed: "+err.Error()+". Skipping "+policyName, err)
+			}
+
+		}
+
+		//Create a setting interface for port forward
+		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")
+			},
+		})
+
+		registerSetting(settingModule{
+			Name:     "Port Forward",
+			Desc:     "UPnP based port forwarding",
+			IconPath: "SystemAO/network/img/portforward.png",
+			Group:    "Network",
+			StartDir: "SystemAO/network/portforward.html",
+		})
+
+		router.HandleFunc("/system/network/portforward", portforward_handleForward)
+	}
+}
+
+func portforward_handleForward(w http.ResponseWriter, r *http.Request) {
+	opr, _ := utils.Mv(r, "opr", true)
+	if opr == "" {
+		if UPNP == nil {
+			utils.SendErrorResponse(w, "UPNP is not enabled")
+			return
+		}
+		//List the current forward port and names
+		type register struct {
+			Port     int
+			Name     string
+			ReadOnly bool
+		}
+		forwardPorts := []register{}
+		for _, port := range UPNP.RequiredPorts {
+			//Get the name of the policy
+			name, ok := UPNP.PolicyNames.Load(port)
+			if !ok {
+				name = "Unknown Service"
+			}
+
+			readOnly := false
+			if port == *listen_port {
+				//This is the port where the webUI is hosted. No change allowed
+				readOnly = true
+			}
+			thisPort := register{
+				Port:     port,
+				Name:     name.(string),
+				ReadOnly: readOnly,
+			}
+
+			//systemWideLogger.PrintAndLog(thisPort,nil)
+
+			forwardPorts = append(forwardPorts, thisPort)
+		}
+
+		//Send the result as json
+		js, _ := json.Marshal(forwardPorts)
+		utils.SendJSONResponse(w, string(js))
+	} else if opr == "add" {
+		port, err := utils.Mv(r, "port", true)
+		if err != nil {
+			utils.SendErrorResponse(w, "Invalid port number")
+			return
+		}
+
+		//Convert port to int
+		portNumberic, err := strconv.Atoi(port)
+		if err != nil {
+			utils.SendErrorResponse(w, "Invalid port number")
+			return
+		}
+
+		//Get the policy name
+		policyName, err := utils.Mv(r, "name", true)
+		if err != nil {
+			policyName = "Unnamed Forward Policy"
+		}
+
+		//Write port forward rules to database
+		sysdb.Write("portforward", strconv.Itoa(portNumberic), policyName)
+
+		if UPNP != nil {
+			//Forward the port
+			err := UPNP.ForwardPort(portNumberic, policyName)
+			if err != nil {
+				utils.SendErrorResponse(w, err.Error())
+			} else {
+				utils.SendOK(w)
+			}
+		} else {
+			utils.SendErrorResponse(w, "UPNP is not enabled")
+			return
+		}
+	} else if opr == "remove" {
+		port, err := utils.Mv(r, "port", true)
+		if err != nil {
+			utils.SendErrorResponse(w, "Invalid port number")
+			return
+		}
+
+		//Convert port to int
+		portNumberic, err := strconv.Atoi(port)
+		if err != nil {
+			utils.SendErrorResponse(w, "Invalid port number")
+			return
+		}
+
+		//Remove it from db if exists
+		if sysdb.KeyExists("portforward", strconv.Itoa(portNumberic)) {
+			//Key exists. Remove it from db
+			sysdb.Delete("portforward", strconv.Itoa(portNumberic))
+		}
+
+		if UPNP != nil {
+			err := UPNP.ClosePort(portNumberic)
+			if err != nil {
+				utils.SendErrorResponse(w, err.Error())
+			} else {
+				utils.SendOK(w)
+			}
+		} else {
+			utils.SendErrorResponse(w, "UPNP is not enabled")
+			return
+		}
+	}
+}

+ 22 - 22
network.go

@@ -6,7 +6,6 @@ import (
 	"strconv"
 	"strings"
 
-	"imuslab.com/arozos/mod/common"
 	"imuslab.com/arozos/mod/fileservers"
 	"imuslab.com/arozos/mod/fileservers/servers/ftpserv"
 	"imuslab.com/arozos/mod/fileservers/servers/sftpserv"
@@ -18,6 +17,7 @@ import (
 	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"
 )
 
@@ -43,7 +43,7 @@ func NetworkServiceInit() {
 		AdminOnly:   false,
 		UserHandler: userHandler,
 		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
+			utils.SendErrorResponse(w, "Permission Denied")
 		},
 	})
 
@@ -101,7 +101,7 @@ func NetworkServiceInit() {
 		AdminOnly:   false,
 		UserHandler: userHandler,
 		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
+			utils.SendErrorResponse(w, "Permission Denied")
 		},
 	})
 
@@ -269,7 +269,7 @@ func FileServerInit() {
 		AdminOnly:   false,
 		UserHandler: userHandler,
 		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
+			utils.SendErrorResponse(w, "Permission Denied")
 		},
 	})
 
@@ -381,21 +381,21 @@ func FileServerInit() {
 
 //Toggle the target File Server Services
 func NetworkHandleFileServerToggle(w http.ResponseWriter, r *http.Request) {
-	servid, err := common.Mv(r, "id", true)
+	servid, err := utils.Mv(r, "id", true)
 	if err != nil {
-		common.SendErrorResponse(w, "invalid service id given")
+		utils.SendErrorResponse(w, "invalid service id given")
 		return
 	}
 
-	newState, err := common.Mv(r, "enable", true)
+	newState, err := utils.Mv(r, "enable", true)
 	if err != nil {
-		common.SendErrorResponse(w, "undefined enable state")
+		utils.SendErrorResponse(w, "undefined enable state")
 		return
 	}
 
 	targetfserv := fileservers.GetFileServerById(networkFileServerDaemon, servid)
 	if targetfserv == nil {
-		common.SendErrorResponse(w, "target service not exists")
+		utils.SendErrorResponse(w, "target service not exists")
 		return
 	}
 
@@ -403,17 +403,17 @@ func NetworkHandleFileServerToggle(w http.ResponseWriter, r *http.Request) {
 		//Start up the target service
 		err = targetfserv.ToggleFunc(true)
 		if err != nil {
-			common.SendErrorResponse(w, "startup failed: "+err.Error())
+			utils.SendErrorResponse(w, "startup failed: "+err.Error())
 			return
 		}
 	} else if newState == "false" {
 		err = targetfserv.ToggleFunc(false)
 		if err != nil {
-			common.SendErrorResponse(w, "shutdown failed: "+err.Error())
+			utils.SendErrorResponse(w, "shutdown failed: "+err.Error())
 			return
 		}
 	} else {
-		common.SendErrorResponse(w, "unknown state keyword")
+		utils.SendErrorResponse(w, "unknown state keyword")
 		return
 	}
 
@@ -422,12 +422,12 @@ func NetworkHandleFileServerToggle(w http.ResponseWriter, r *http.Request) {
 //Return a list of supported File Server Services
 func NetworkHandleGetFileServerServiceList(w http.ResponseWriter, r *http.Request) {
 	js, _ := json.Marshal(networkFileServerDaemon)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 //Get the status of a file server type.
 func NetworkHandleGetFileServerStatus(w http.ResponseWriter, r *http.Request) {
-	servid, _ := common.Mv(r, "id", false)
+	servid, _ := utils.Mv(r, "id", false)
 	if servid == "" {
 		//List all state in map
 		result := map[string]bool{}
@@ -436,17 +436,17 @@ func NetworkHandleGetFileServerStatus(w http.ResponseWriter, r *http.Request) {
 		}
 
 		js, _ := json.Marshal(result)
-		common.SendJSONResponse(w, string(js))
+		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 {
-			common.SendErrorResponse(w, "target file server type not found")
+			utils.SendErrorResponse(w, "target file server type not found")
 			return
 		}
 
 		js, _ := json.Marshal(targetfserv.EnableCheck())
-		common.SendJSONResponse(w, string(js))
+		utils.SendJSONResponse(w, string(js))
 	}
 }
 
@@ -454,11 +454,11 @@ func NetworkHandleGetFileServerStatus(w http.ResponseWriter, r *http.Request) {
 func NetworkHandleGetFileServerEndpoints(w http.ResponseWriter, r *http.Request) {
 	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
-		common.SendErrorResponse(w, "user not logged in")
+		utils.SendErrorResponse(w, "user not logged in")
 		return
 	}
 
-	targetServerTypeID, _ := common.Mv(r, "fserv", false)
+	targetServerTypeID, _ := utils.Mv(r, "fserv", false)
 	targetServerTypeID = strings.TrimSpace(targetServerTypeID)
 
 	if targetServerTypeID == "" {
@@ -474,19 +474,19 @@ func NetworkHandleGetFileServerEndpoints(w http.ResponseWriter, r *http.Request)
 		}
 
 		js, _ := json.Marshal(results)
-		common.SendJSONResponse(w, string(js))
+		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)
-				common.SendJSONResponse(w, string(js))
+				utils.SendJSONResponse(w, string(js))
 				return
 			}
 		}
 
-		common.SendErrorResponse(w, "target service not found")
+		utils.SendErrorResponse(w, "target service not found")
 	}
 
 }

+ 70 - 70
permission.go

@@ -1,70 +1,70 @@
-package main
-
-import (
-	"encoding/json"
-	"net/http"
-
-	"imuslab.com/arozos/mod/common"
-	permission "imuslab.com/arozos/mod/permission"
-	prout "imuslab.com/arozos/mod/prouter"
-)
-
-func permissionNewHandler() {
-	ph, err := permission.NewPermissionHandler(sysdb)
-	if err != nil {
-		systemWideLogger.PrintAndLog("Permission", "Permission Handler creation failed.", err)
-		panic(err)
-	}
-	permissionHandler = ph
-	permissionHandler.LoadPermissionGroupsFromDatabase()
-
-}
-
-func permissionInit() {
-	//Register the permission handler, require authentication except listgroup
-	adminRouter := prout.NewModuleRouter(prout.RouterOption{
-		ModuleName:  "System Setting",
-		AdminOnly:   true,
-		UserHandler: userHandler,
-		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
-		},
-	})
-
-	//Must be handled by default router
-	http.HandleFunc("/system/permission/listgroup", func(w http.ResponseWriter, r *http.Request) {
-		if authAgent.GetUserCounts() == 0 {
-			//There is no user within the system. Only allow register of admin account
-			js, _ := json.Marshal([]string{"administrator"})
-			common.SendJSONResponse(w, string(js))
-			//permissionHandler.HandleListGroup(w, r)
-		} else {
-			//There are already users in the system. Only allow authorized users
-			if authAgent.CheckAuth(r) {
-				requestingUser, _ := userHandler.GetUserInfoFromRequest(w, r)
-				if requestingUser != nil && requestingUser.IsAdmin() {
-					permissionHandler.HandleListGroup(w, r)
-				} else {
-					errorHandlePermissionDenied(w, r)
-				}
-
-			} else {
-				errorHandlePermissionDenied(w, r)
-				return
-			}
-		}
-
-	})
-	adminRouter.HandleFunc("/system/permission/newgroup", permissionHandler.HandleGroupCreate)
-	adminRouter.HandleFunc("/system/permission/editgroup", permissionHandler.HandleGroupEdit)
-	adminRouter.HandleFunc("/system/permission/delgroup", permissionHandler.HandleGroupRemove)
-
-	registerSetting(settingModule{
-		Name:         "Permission Groups",
-		Desc:         "Handle the permission of access in groups",
-		IconPath:     "SystemAO/users/img/small_icon.png",
-		Group:        "Users",
-		StartDir:     "SystemAO/users/group.html",
-		RequireAdmin: true,
-	})
-}
+package main
+
+import (
+	"encoding/json"
+	"net/http"
+
+	permission "imuslab.com/arozos/mod/permission"
+	prout "imuslab.com/arozos/mod/prouter"
+	"imuslab.com/arozos/mod/utils"
+)
+
+func permissionNewHandler() {
+	ph, err := permission.NewPermissionHandler(sysdb)
+	if err != nil {
+		systemWideLogger.PrintAndLog("Permission", "Permission Handler creation failed.", err)
+		panic(err)
+	}
+	permissionHandler = ph
+	permissionHandler.LoadPermissionGroupsFromDatabase()
+
+}
+
+func permissionInit() {
+	//Register the permission handler, require authentication except listgroup
+	adminRouter := prout.NewModuleRouter(prout.RouterOption{
+		ModuleName:  "System Setting",
+		AdminOnly:   true,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			utils.SendErrorResponse(w, "Permission Denied")
+		},
+	})
+
+	//Must be handled by default router
+	http.HandleFunc("/system/permission/listgroup", func(w http.ResponseWriter, r *http.Request) {
+		if authAgent.GetUserCounts() == 0 {
+			//There is no user within the system. Only allow register of admin account
+			js, _ := json.Marshal([]string{"administrator"})
+			utils.SendJSONResponse(w, string(js))
+			//permissionHandler.HandleListGroup(w, r)
+		} else {
+			//There are already users in the system. Only allow authorized users
+			if authAgent.CheckAuth(r) {
+				requestingUser, _ := userHandler.GetUserInfoFromRequest(w, r)
+				if requestingUser != nil && requestingUser.IsAdmin() {
+					permissionHandler.HandleListGroup(w, r)
+				} else {
+					errorHandlePermissionDenied(w, r)
+				}
+
+			} else {
+				errorHandlePermissionDenied(w, r)
+				return
+			}
+		}
+
+	})
+	adminRouter.HandleFunc("/system/permission/newgroup", permissionHandler.HandleGroupCreate)
+	adminRouter.HandleFunc("/system/permission/editgroup", permissionHandler.HandleGroupEdit)
+	adminRouter.HandleFunc("/system/permission/delgroup", permissionHandler.HandleGroupRemove)
+
+	registerSetting(settingModule{
+		Name:         "Permission Groups",
+		Desc:         "Handle the permission of access in groups",
+		IconPath:     "SystemAO/users/img/small_icon.png",
+		Group:        "Users",
+		StartDir:     "SystemAO/users/group.html",
+		RequireAdmin: true,
+	})
+}

+ 162 - 162
quota.go

@@ -1,162 +1,162 @@
-package main
-
-import (
-	"encoding/json"
-	"net/http"
-	"os"
-	"path/filepath"
-	"sort"
-	"strconv"
-	"strings"
-
-	"imuslab.com/arozos/mod/common"
-	fs "imuslab.com/arozos/mod/filesystem"
-	//user "imuslab.com/arozos/mod/user"
-)
-
-func DiskQuotaInit() {
-	//Register Endpoints
-	http.HandleFunc("/system/disk/quota/setQuota", system_disk_quota_setQuota)
-	http.HandleFunc("/system/disk/quota/quotaInfo", system_disk_quota_handleQuotaInfo)
-	http.HandleFunc("/system/disk/quota/quotaDist", system_disk_quota_handleFileDistributionView)
-
-	//Register Setting Interfaces
-	registerSetting(settingModule{
-		Name:     "Storage Quota",
-		Desc:     "User Remaining Space",
-		IconPath: "SystemAO/disk/quota/img/small_icon.png",
-		Group:    "Disk",
-		StartDir: "SystemAO/disk/quota/quota.html",
-	})
-
-	//Register the timer for running the global user quota recalculation
-	nightlyManager.RegisterNightlyTask(system_disk_quota_updateAllUserQuotaEstimation)
-}
-
-//Register the handler for automatically updating all user storage quota
-func system_disk_quota_updateAllUserQuotaEstimation() {
-	registeredUsers := authAgent.ListUsers()
-	for _, username := range registeredUsers {
-		//For each user, update their current quota usage
-		userinfo, _ := userHandler.GetUserInfoFromUsername(username)
-		userinfo.StorageQuota.CalculateQuotaUsage()
-	}
-}
-
-//Set the storage quota of the particular user
-func system_disk_quota_setQuota(w http.ResponseWriter, r *http.Request) {
-	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, "Unknown User")
-		return
-	}
-
-	//Check if admin
-	if !userinfo.IsAdmin() {
-		common.SendErrorResponse(w, "Permission Denied")
-		return
-	}
-
-	groupname, err := common.Mv(r, "groupname", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Group name not defned")
-		return
-	}
-
-	quotaSizeString, err := common.Mv(r, "quota", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Quota not defined")
-		return
-	}
-
-	quotaSize, err := common.StringToInt64(quotaSizeString)
-	if err != nil || quotaSize < 0 {
-		common.SendErrorResponse(w, "Invalid quota size given")
-		return
-	}
-	//Qutasize unit is in MB
-	quotaSize = quotaSize << 20
-
-	systemWideLogger.PrintAndLog("Quota", "Updating "+groupname+" to "+strconv.FormatInt(quotaSize, 10)+"WIP", nil)
-	common.SendOK(w)
-
-}
-
-func system_disk_quota_handleQuotaInfo(w http.ResponseWriter, r *http.Request) {
-	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, "Unknown User")
-		return
-	}
-
-	//Get quota information
-	type quotaInformation struct {
-		Remaining int64
-		Used      int64
-		Total     int64
-	}
-
-	jsonString, _ := json.Marshal(quotaInformation{
-		Remaining: userinfo.StorageQuota.TotalStorageQuota - userinfo.StorageQuota.UsedStorageQuota,
-		Used:      userinfo.StorageQuota.UsedStorageQuota,
-		Total:     userinfo.StorageQuota.TotalStorageQuota,
-	})
-
-	common.SendJSONResponse(w, string(jsonString))
-
-	go func() {
-		//Update this user's quota estimation in go routine
-		userinfo.StorageQuota.CalculateQuotaUsage()
-	}()
-}
-
-//Get all the users file and see how
-func system_disk_quota_handleFileDistributionView(w http.ResponseWriter, r *http.Request) {
-	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, "Unknown User")
-		return
-	}
-
-	fileDist := map[string]int64{}
-	userFileSystemHandlers := userinfo.GetAllFileSystemHandler()
-	for _, thisHandler := range userFileSystemHandlers {
-		if thisHandler.Hierarchy == "user" {
-			thispath := filepath.ToSlash(filepath.Clean(thisHandler.Path)) + "/users/" + userinfo.Username + "/"
-			filepath.Walk(thispath, func(filepath string, info os.FileInfo, err error) error {
-				if err != nil {
-					return err
-				}
-				if !info.IsDir() {
-					mime, _, err := fs.GetMime(filepath)
-					if err != nil {
-						return err
-					}
-					mediaType := strings.SplitN(mime, "/", 2)[0]
-					mediaType = strings.Title(mediaType)
-					fileDist[mediaType] = fileDist[mediaType] + info.Size()
-				}
-				return err
-			})
-		}
-	}
-
-	//Sort the file according to the number of files in the
-	type kv struct {
-		Mime string
-		Size int64
-	}
-
-	var ss []kv
-	for k, v := range fileDist {
-		ss = append(ss, kv{k, v})
-	}
-
-	sort.Slice(ss, func(i, j int) bool {
-		return ss[i].Size > ss[j].Size
-	})
-
-	//Return the distrubution using json string
-	jsonString, _ := json.Marshal(ss)
-	common.SendJSONResponse(w, string(jsonString))
-}
+package main
+
+import (
+	"encoding/json"
+	"net/http"
+	"os"
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+
+	fs "imuslab.com/arozos/mod/filesystem"
+	"imuslab.com/arozos/mod/utils"
+	//user "imuslab.com/arozos/mod/user"
+)
+
+func DiskQuotaInit() {
+	//Register Endpoints
+	http.HandleFunc("/system/disk/quota/setQuota", system_disk_quota_setQuota)
+	http.HandleFunc("/system/disk/quota/quotaInfo", system_disk_quota_handleQuotaInfo)
+	http.HandleFunc("/system/disk/quota/quotaDist", system_disk_quota_handleFileDistributionView)
+
+	//Register Setting Interfaces
+	registerSetting(settingModule{
+		Name:     "Storage Quota",
+		Desc:     "User Remaining Space",
+		IconPath: "SystemAO/disk/quota/img/small_icon.png",
+		Group:    "Disk",
+		StartDir: "SystemAO/disk/quota/quota.html",
+	})
+
+	//Register the timer for running the global user quota recalculation
+	nightlyManager.RegisterNightlyTask(system_disk_quota_updateAllUserQuotaEstimation)
+}
+
+//Register the handler for automatically updating all user storage quota
+func system_disk_quota_updateAllUserQuotaEstimation() {
+	registeredUsers := authAgent.ListUsers()
+	for _, username := range registeredUsers {
+		//For each user, update their current quota usage
+		userinfo, _ := userHandler.GetUserInfoFromUsername(username)
+		userinfo.StorageQuota.CalculateQuotaUsage()
+	}
+}
+
+//Set the storage quota of the particular user
+func system_disk_quota_setQuota(w http.ResponseWriter, r *http.Request) {
+	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		utils.SendErrorResponse(w, "Unknown User")
+		return
+	}
+
+	//Check if admin
+	if !userinfo.IsAdmin() {
+		utils.SendErrorResponse(w, "Permission Denied")
+		return
+	}
+
+	groupname, err := utils.Mv(r, "groupname", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Group name not defned")
+		return
+	}
+
+	quotaSizeString, err := utils.Mv(r, "quota", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Quota not defined")
+		return
+	}
+
+	quotaSize, err := utils.StringToInt64(quotaSizeString)
+	if err != nil || quotaSize < 0 {
+		utils.SendErrorResponse(w, "Invalid quota size given")
+		return
+	}
+	//Qutasize unit is in MB
+	quotaSize = quotaSize << 20
+
+	systemWideLogger.PrintAndLog("Quota", "Updating "+groupname+" to "+strconv.FormatInt(quotaSize, 10)+"WIP", nil)
+	utils.SendOK(w)
+
+}
+
+func system_disk_quota_handleQuotaInfo(w http.ResponseWriter, r *http.Request) {
+	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		utils.SendErrorResponse(w, "Unknown User")
+		return
+	}
+
+	//Get quota information
+	type quotaInformation struct {
+		Remaining int64
+		Used      int64
+		Total     int64
+	}
+
+	jsonString, _ := json.Marshal(quotaInformation{
+		Remaining: userinfo.StorageQuota.TotalStorageQuota - userinfo.StorageQuota.UsedStorageQuota,
+		Used:      userinfo.StorageQuota.UsedStorageQuota,
+		Total:     userinfo.StorageQuota.TotalStorageQuota,
+	})
+
+	utils.SendJSONResponse(w, string(jsonString))
+
+	go func() {
+		//Update this user's quota estimation in go routine
+		userinfo.StorageQuota.CalculateQuotaUsage()
+	}()
+}
+
+//Get all the users file and see how
+func system_disk_quota_handleFileDistributionView(w http.ResponseWriter, r *http.Request) {
+	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		utils.SendErrorResponse(w, "Unknown User")
+		return
+	}
+
+	fileDist := map[string]int64{}
+	userFileSystemHandlers := userinfo.GetAllFileSystemHandler()
+	for _, thisHandler := range userFileSystemHandlers {
+		if thisHandler.Hierarchy == "user" {
+			thispath := filepath.ToSlash(filepath.Clean(thisHandler.Path)) + "/users/" + userinfo.Username + "/"
+			filepath.Walk(thispath, func(filepath string, info os.FileInfo, err error) error {
+				if err != nil {
+					return err
+				}
+				if !info.IsDir() {
+					mime, _, err := fs.GetMime(filepath)
+					if err != nil {
+						return err
+					}
+					mediaType := strings.SplitN(mime, "/", 2)[0]
+					mediaType = strings.Title(mediaType)
+					fileDist[mediaType] = fileDist[mediaType] + info.Size()
+				}
+				return err
+			})
+		}
+	}
+
+	//Sort the file according to the number of files in the
+	type kv struct {
+		Mime string
+		Size int64
+	}
+
+	var ss []kv
+	for k, v := range fileDist {
+		ss = append(ss, kv{k, v})
+	}
+
+	sort.Slice(ss, func(i, j int) bool {
+		return ss[i].Size > ss[j].Size
+	})
+
+	//Return the distrubution using json string
+	jsonString, _ := json.Marshal(ss)
+	utils.SendJSONResponse(w, string(jsonString))
+}

+ 151 - 151
register.go

@@ -1,151 +1,151 @@
-package main
-
-import (
-	"encoding/json"
-	"fmt"
-	"net/http"
-
-	reg "imuslab.com/arozos/mod/auth/register"
-	"imuslab.com/arozos/mod/common"
-	prout "imuslab.com/arozos/mod/prouter"
-)
-
-var (
-	registerHandler *reg.RegisterHandler
-)
-
-func RegisterSystemInit() {
-	//Register the endpoints for public registration
-	rh := reg.NewRegisterHandler(sysdb, authAgent, permissionHandler, reg.RegisterOptions{
-		Hostname:   *host_name,
-		VendorIcon: "web/" + iconVendor,
-	})
-
-	registerHandler = rh
-
-	//Set the allow registry states
-	if *allow_public_registry {
-		registerHandler.AllowRegistry = true
-	} else {
-		registerHandler.AllowRegistry = false
-	}
-
-	http.HandleFunc("/public/register/register.system", registerHandler.HandleRegisterInterface)
-	http.HandleFunc("/public/register/handleRegister.system", registerHandler.HandleRegisterRequest)
-	http.HandleFunc("/public/register/checkPublicRegister", registerHandler.HandleRegisterCheck)
-
-	//General user functions
-	router := prout.NewModuleRouter(prout.RouterOption{
-		AdminOnly:   false,
-		UserHandler: userHandler,
-		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
-		},
-	})
-
-	router.HandleFunc("/system/register/email", registerHandler.HandleEmailChange)
-
-	//Register settings
-	registerSetting(settingModule{
-		Name:         "Public Registry",
-		Desc:         "Allow public users to create account in this host",
-		IconPath:     "SystemAO/users/img/small_icon.png",
-		Group:        "Users",
-		StartDir:     "SystemAO/users/pubreg.html",
-		RequireAdmin: true,
-	})
-
-	//Register Setting Interface for setting interfaces
-
-	adminrouter := prout.NewModuleRouter(prout.RouterOption{
-		ModuleName:  "System Setting",
-		AdminOnly:   true,
-		UserHandler: userHandler,
-		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
-		},
-	})
-
-	//Handle updates of the default group
-	adminrouter.HandleFunc("/system/register/setDefaultGroup", register_handleSetDefaultGroup)
-
-	//Handle if the current handler allow registry
-	adminrouter.HandleFunc("/system/register/getAllowRegistry", register_handleGetAllowRegistry)
-
-	//Handle toggle
-	adminrouter.HandleFunc("/system/register/setAllowRegistry", register_handleToggleRegistry)
-
-	//Get a list of email registered in the system
-	adminrouter.HandleFunc("/system/register/listUserEmails", register_handleEmailListing)
-
-	//Clear User record that has no longer use this service
-	adminrouter.HandleFunc("/system/register/cleanUserRegisterInfo", register_handleRegisterCleaning)
-}
-
-func register_handleRegisterCleaning(w http.ResponseWriter, r *http.Request) {
-	//Get all user emails from the registerHandler
-	registerHandler.CleanRegisters()
-	common.SendOK(w)
-}
-
-func register_handleEmailListing(w http.ResponseWriter, r *http.Request) {
-	//Get all user emails from the registerHandler
-	userRegisterInfos := registerHandler.ListAllUserEmails()
-
-	useCSV, _ := common.Mv(r, "csv", false)
-	if useCSV == "true" {
-		//Prase as csv
-		csvString := "Username,Email,Still Registered\n"
-		for _, v := range userRegisterInfos {
-			registered := "false"
-			s, _ := v[2].(bool)
-			if s == true {
-				registered = "true"
-			}
-			csvString += fmt.Sprintf("%v", v[0]) + "," + fmt.Sprintf("%v", v[1]) + "," + registered + "\n"
-		}
-
-		w.Header().Set("Content-Disposition", "attachment; filename=registerInfo.csv")
-		w.Header().Set("Content-Type", "text/csv")
-		w.Write([]byte(csvString))
-	} else {
-		//Prase as json
-		jsonString, _ := json.Marshal(userRegisterInfos)
-		common.SendJSONResponse(w, string(jsonString))
-	}
-
-}
-
-func register_handleSetDefaultGroup(w http.ResponseWriter, r *http.Request) {
-	getDefaultGroup, _ := common.Mv(r, "get", true)
-	if getDefaultGroup == "true" {
-		jsonString, _ := json.Marshal(registerHandler.DefaultUserGroup)
-		common.SendJSONResponse(w, string(jsonString))
-		return
-	}
-	newDefaultGroup, err := common.Mv(r, "defaultGroup", true)
-	if err != nil {
-		common.SendErrorResponse(w, "defaultGroup not defined")
-		return
-	}
-	err = registerHandler.SetDefaultUserGroup(newDefaultGroup)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-	common.SendOK(w)
-}
-
-func register_handleGetAllowRegistry(w http.ResponseWriter, r *http.Request) {
-	jsonString, _ := json.Marshal(registerHandler.AllowRegistry)
-	common.SendJSONResponse(w, string(jsonString))
-}
-
-func register_handleToggleRegistry(w http.ResponseWriter, r *http.Request) {
-	allowReg, err := common.Mv(r, "allow", true)
-	if err != nil {
-		allowReg = "false"
-	}
-	registerHandler.SetAllowRegistry(allowReg == "true")
-	common.SendOK(w)
-}
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+
+	reg "imuslab.com/arozos/mod/auth/register"
+	prout "imuslab.com/arozos/mod/prouter"
+	"imuslab.com/arozos/mod/utils"
+)
+
+var (
+	registerHandler *reg.RegisterHandler
+)
+
+func RegisterSystemInit() {
+	//Register the endpoints for public registration
+	rh := reg.NewRegisterHandler(sysdb, authAgent, permissionHandler, reg.RegisterOptions{
+		Hostname:   *host_name,
+		VendorIcon: "web/" + iconVendor,
+	})
+
+	registerHandler = rh
+
+	//Set the allow registry states
+	if *allow_public_registry {
+		registerHandler.AllowRegistry = true
+	} else {
+		registerHandler.AllowRegistry = false
+	}
+
+	http.HandleFunc("/public/register/register.system", registerHandler.HandleRegisterInterface)
+	http.HandleFunc("/public/register/handleRegister.system", registerHandler.HandleRegisterRequest)
+	http.HandleFunc("/public/register/checkPublicRegister", registerHandler.HandleRegisterCheck)
+
+	//General user functions
+	router := prout.NewModuleRouter(prout.RouterOption{
+		AdminOnly:   false,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			utils.SendErrorResponse(w, "Permission Denied")
+		},
+	})
+
+	router.HandleFunc("/system/register/email", registerHandler.HandleEmailChange)
+
+	//Register settings
+	registerSetting(settingModule{
+		Name:         "Public Registry",
+		Desc:         "Allow public users to create account in this host",
+		IconPath:     "SystemAO/users/img/small_icon.png",
+		Group:        "Users",
+		StartDir:     "SystemAO/users/pubreg.html",
+		RequireAdmin: true,
+	})
+
+	//Register Setting Interface for setting interfaces
+
+	adminrouter := prout.NewModuleRouter(prout.RouterOption{
+		ModuleName:  "System Setting",
+		AdminOnly:   true,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			utils.SendErrorResponse(w, "Permission Denied")
+		},
+	})
+
+	//Handle updates of the default group
+	adminrouter.HandleFunc("/system/register/setDefaultGroup", register_handleSetDefaultGroup)
+
+	//Handle if the current handler allow registry
+	adminrouter.HandleFunc("/system/register/getAllowRegistry", register_handleGetAllowRegistry)
+
+	//Handle toggle
+	adminrouter.HandleFunc("/system/register/setAllowRegistry", register_handleToggleRegistry)
+
+	//Get a list of email registered in the system
+	adminrouter.HandleFunc("/system/register/listUserEmails", register_handleEmailListing)
+
+	//Clear User record that has no longer use this service
+	adminrouter.HandleFunc("/system/register/cleanUserRegisterInfo", register_handleRegisterCleaning)
+}
+
+func register_handleRegisterCleaning(w http.ResponseWriter, r *http.Request) {
+	//Get all user emails from the registerHandler
+	registerHandler.CleanRegisters()
+	utils.SendOK(w)
+}
+
+func register_handleEmailListing(w http.ResponseWriter, r *http.Request) {
+	//Get all user emails from the registerHandler
+	userRegisterInfos := registerHandler.ListAllUserEmails()
+
+	useCSV, _ := utils.Mv(r, "csv", false)
+	if useCSV == "true" {
+		//Prase as csv
+		csvString := "Username,Email,Still Registered\n"
+		for _, v := range userRegisterInfos {
+			registered := "false"
+			s, _ := v[2].(bool)
+			if s == true {
+				registered = "true"
+			}
+			csvString += fmt.Sprintf("%v", v[0]) + "," + fmt.Sprintf("%v", v[1]) + "," + registered + "\n"
+		}
+
+		w.Header().Set("Content-Disposition", "attachment; filename=registerInfo.csv")
+		w.Header().Set("Content-Type", "text/csv")
+		w.Write([]byte(csvString))
+	} else {
+		//Prase as json
+		jsonString, _ := json.Marshal(userRegisterInfos)
+		utils.SendJSONResponse(w, string(jsonString))
+	}
+
+}
+
+func register_handleSetDefaultGroup(w http.ResponseWriter, r *http.Request) {
+	getDefaultGroup, _ := utils.Mv(r, "get", true)
+	if getDefaultGroup == "true" {
+		jsonString, _ := json.Marshal(registerHandler.DefaultUserGroup)
+		utils.SendJSONResponse(w, string(jsonString))
+		return
+	}
+	newDefaultGroup, err := utils.Mv(r, "defaultGroup", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "defaultGroup not defined")
+		return
+	}
+	err = registerHandler.SetDefaultUserGroup(newDefaultGroup)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+	utils.SendOK(w)
+}
+
+func register_handleGetAllowRegistry(w http.ResponseWriter, r *http.Request) {
+	jsonString, _ := json.Marshal(registerHandler.AllowRegistry)
+	utils.SendJSONResponse(w, string(jsonString))
+}
+
+func register_handleToggleRegistry(w http.ResponseWriter, r *http.Request) {
+	allowReg, err := utils.Mv(r, "allow", true)
+	if err != nil {
+		allowReg = "false"
+	}
+	registerHandler.SetAllowRegistry(allowReg == "true")
+	utils.SendOK(w)
+}

+ 2 - 2
scheduler.go

@@ -3,11 +3,11 @@ package main
 import (
 	"net/http"
 
-	"imuslab.com/arozos/mod/common"
 	module "imuslab.com/arozos/mod/modules"
 	prout "imuslab.com/arozos/mod/prouter"
 	"imuslab.com/arozos/mod/time/nightly"
 	"imuslab.com/arozos/mod/time/scheduler"
+	"imuslab.com/arozos/mod/utils"
 )
 
 /*
@@ -48,7 +48,7 @@ func SchedulerInit() {
 		AdminOnly:   false,
 		UserHandler: userHandler,
 		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
+			utils.SendErrorResponse(w, "Permission Denied")
 		},
 	})
 

+ 55 - 55
security.go

@@ -1,55 +1,55 @@
-package main
-
-import (
-	"net/http"
-	"time"
-
-	"imuslab.com/arozos/mod/common"
-	prout "imuslab.com/arozos/mod/prouter"
-	"imuslab.com/arozos/mod/security/csrf"
-)
-
-/*
-	Security.go
-	Author: tobychui
-
-	This module handles the system security related functions.
-	If you are looking for authentication or login related features, see auth.go
-*/
-
-var (
-	CSRFTokenManager  *csrf.TokenManager
-	tokenExpireTime   int64 = 10                        //Token expire in 10 seconds
-	tokenCleaningTime int   = int(tokenExpireTime) * 12 //Tokens are cleared every 12 x tokenExpireTime
-)
-
-//Initiation function
-func security_init() {
-	//Create a default permission router accessable by everyone
-	router := prout.NewModuleRouter(prout.RouterOption{
-		ModuleName:  "",
-		AdminOnly:   false,
-		UserHandler: userHandler,
-		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
-		},
-	})
-
-	//Creat a new CSRF Token Manager and token expire in 30 seconds
-	CSRFTokenManager = csrf.NewTokenManager(userHandler, tokenExpireTime)
-
-	//Register functions related to CSRF Tokens
-	router.HandleFunc("/system/csrf/new", CSRFTokenManager.HandleNewToken)
-
-	//Create a timer to clear expired tokens
-	ticker := time.NewTicker(time.Duration(tokenCleaningTime) * time.Second)
-	go func() {
-		for {
-			select {
-			case <-ticker.C:
-				CSRFTokenManager.ClearExpiredTokens()
-			}
-		}
-	}()
-
-}
+package main
+
+import (
+	"net/http"
+	"time"
+
+	prout "imuslab.com/arozos/mod/prouter"
+	"imuslab.com/arozos/mod/security/csrf"
+	"imuslab.com/arozos/mod/utils"
+)
+
+/*
+	Security.go
+	Author: tobychui
+
+	This module handles the system security related functions.
+	If you are looking for authentication or login related features, see auth.go
+*/
+
+var (
+	CSRFTokenManager  *csrf.TokenManager
+	tokenExpireTime   int64 = 10                        //Token expire in 10 seconds
+	tokenCleaningTime int   = int(tokenExpireTime) * 12 //Tokens are cleared every 12 x tokenExpireTime
+)
+
+//Initiation function
+func security_init() {
+	//Create a default permission router accessable by everyone
+	router := prout.NewModuleRouter(prout.RouterOption{
+		ModuleName:  "",
+		AdminOnly:   false,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			utils.SendErrorResponse(w, "Permission Denied")
+		},
+	})
+
+	//Creat a new CSRF Token Manager and token expire in 30 seconds
+	CSRFTokenManager = csrf.NewTokenManager(userHandler, tokenExpireTime)
+
+	//Register functions related to CSRF Tokens
+	router.HandleFunc("/system/csrf/new", CSRFTokenManager.HandleNewToken)
+
+	//Create a timer to clear expired tokens
+	ticker := time.NewTicker(time.Duration(tokenCleaningTime) * time.Second)
+	go func() {
+		for {
+			select {
+			case <-ticker.C:
+				CSRFTokenManager.ClearExpiredTokens()
+			}
+		}
+	}()
+
+}

+ 68 - 68
setting.advance.go

@@ -1,68 +1,68 @@
-package main
-
-import (
-	"net/http"
-
-	autologin "imuslab.com/arozos/mod/auth/autologin"
-	"imuslab.com/arozos/mod/common"
-	prout "imuslab.com/arozos/mod/prouter"
-)
-
-/*
-	Advance Setting Group
-	This is a function group that help handles system advance functions
-
-*/
-
-func AdvanceSettingInit() {
-	/*
-
-		Define common routers
-
-	*/
-	adminRouter := prout.NewModuleRouter(prout.RouterOption{
-		ModuleName:  "System Settings",
-		AdminOnly:   true,
-		UserHandler: userHandler,
-		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
-		},
-	})
-
-	/*
-		Billboard mode / Bot login mode
-
-		This method allows users or machine to login with token instead of login interface
-	*/
-	registerSetting(settingModule{
-		Name:         "Auto Login Mode",
-		Desc:         "Allow bots logging into the system automatically",
-		IconPath:     "SystemAO/advance/img/small_icon.png",
-		Group:        "Advance",
-		StartDir:     "SystemAO/advance/autologin.html",
-		RequireAdmin: true,
-	})
-
-	autoLoginHandler := autologin.NewAutoLoginHandler(userHandler)
-
-	adminRouter.HandleFunc("/system/autologin/list", autoLoginHandler.HandleUserTokensListing)
-	adminRouter.HandleFunc("/system/autologin/create", autoLoginHandler.HandleUserTokenCreation)
-	adminRouter.HandleFunc("/system/autologin/delete", autoLoginHandler.HandleUserTokenRemoval)
-
-	/*
-		Advance Disk Management Interface
-
-		This methods allow hot swapping / mounting of storage devices
-
-	*/
-	if *allow_hardware_management {
-		registerSetting(settingModule{
-			Name:         "Disk Manager",
-			Desc:         "Mount, Unmount and Formatting Local Disks",
-			IconPath:     "SystemAO/disk/img/small_icon.png",
-			Group:        "Advance",
-			StartDir:     "SystemAO/disk/diskmg.html",
-			RequireAdmin: true,
-		})
-	}
-}
+package main
+
+import (
+	"net/http"
+
+	autologin "imuslab.com/arozos/mod/auth/autologin"
+	prout "imuslab.com/arozos/mod/prouter"
+	"imuslab.com/arozos/mod/utils"
+)
+
+/*
+	Advance Setting Group
+	This is a function group that help handles system advance functions
+
+*/
+
+func AdvanceSettingInit() {
+	/*
+
+		Define common routers
+
+	*/
+	adminRouter := prout.NewModuleRouter(prout.RouterOption{
+		ModuleName:  "System Settings",
+		AdminOnly:   true,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			utils.SendErrorResponse(w, "Permission Denied")
+		},
+	})
+
+	/*
+		Billboard mode / Bot login mode
+
+		This method allows users or machine to login with token instead of login interface
+	*/
+	registerSetting(settingModule{
+		Name:         "Auto Login Mode",
+		Desc:         "Allow bots logging into the system automatically",
+		IconPath:     "SystemAO/advance/img/small_icon.png",
+		Group:        "Advance",
+		StartDir:     "SystemAO/advance/autologin.html",
+		RequireAdmin: true,
+	})
+
+	autoLoginHandler := autologin.NewAutoLoginHandler(userHandler)
+
+	adminRouter.HandleFunc("/system/autologin/list", autoLoginHandler.HandleUserTokensListing)
+	adminRouter.HandleFunc("/system/autologin/create", autoLoginHandler.HandleUserTokenCreation)
+	adminRouter.HandleFunc("/system/autologin/delete", autoLoginHandler.HandleUserTokenRemoval)
+
+	/*
+		Advance Disk Management Interface
+
+		This methods allow hot swapping / mounting of storage devices
+
+	*/
+	if *allow_hardware_management {
+		registerSetting(settingModule{
+			Name:         "Disk Manager",
+			Desc:         "Mount, Unmount and Formatting Local Disks",
+			IconPath:     "SystemAO/disk/img/small_icon.png",
+			Group:        "Advance",
+			StartDir:     "SystemAO/disk/diskmg.html",
+			RequireAdmin: true,
+		})
+	}
+}

+ 6 - 6
setting.go

@@ -4,8 +4,8 @@ import (
 	"encoding/json"
 	"net/http"
 
-	"imuslab.com/arozos/mod/common"
 	module "imuslab.com/arozos/mod/modules"
+	"imuslab.com/arozos/mod/utils"
 )
 
 type settingModule struct {
@@ -122,12 +122,12 @@ func registerSetting(thismodule settingModule) {
 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")
+		utils.SendErrorResponse(w, "User not logged in")
 		return
 	}
 
 	allSettingGroups := system_setting_getSettingGroups()
-	listGroup, _ := common.Mv(r, "listGroup", false)
+	listGroup, _ := utils.Mv(r, "listGroup", false)
 	if len(listGroup) > 0 {
 		//List the given group
 		var results []settingModule
@@ -147,18 +147,18 @@ func system_setting_handleListing(w http.ResponseWriter, r *http.Request) {
 
 		if len(results) > 0 {
 			jsonString, _ := json.Marshal(results)
-			common.SendJSONResponse(w, string(jsonString))
+			utils.SendJSONResponse(w, string(jsonString))
 			return
 		} else {
 			//This group not found,
-			common.SendErrorResponse(w, "Group not found")
+			utils.SendErrorResponse(w, "Group not found")
 			return
 		}
 
 	} else {
 		//List all root groups
 		jsonString, _ := json.Marshal(allSettingGroups)
-		common.SendJSONResponse(w, string(jsonString))
+		utils.SendJSONResponse(w, string(jsonString))
 		return
 	}
 

+ 104 - 104
startup.flags.go

@@ -1,104 +1,104 @@
-package main
-
-import (
-	"encoding/json"
-	"net/http"
-
-	"imuslab.com/arozos/mod/common"
-	prout "imuslab.com/arozos/mod/prouter"
-)
-
-/*
-	Startup Flags Manager
-
-	This script is design to provide interface for editing the boot flags
-	during the system is running
-
-*/
-
-func StartupFlagsInit() {
-	//Create a admin permission router for handling requests
-	//Register a boot flag modifier
-	registerSetting(settingModule{
-		Name:         "Runtime",
-		Desc:         "Change startup paramter in runtime",
-		IconPath:     "SystemAO/info/img/small_icon.png",
-		Group:        "Info",
-		StartDir:     "SystemAO/boot/bootflags.html",
-		RequireAdmin: true,
-	})
-
-	adminRouter := prout.NewModuleRouter(prout.RouterOption{
-		AdminOnly:   true,
-		UserHandler: userHandler,
-		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
-		},
-	})
-
-	adminRouter.HandleFunc("/system/bootflags", handleBootFlagsFunction)
-}
-
-func handleBootFlagsFunction(w http.ResponseWriter, r *http.Request) {
-	type bootFlags struct {
-		Hostname          string
-		MaxUploadSize     int
-		MaxFileUploadBuff int
-		FileIOBuffer      int
-		DisableIPResolver bool
-		EnableHomePage    bool
-		EnableDirListing  bool
-	}
-	opr, _ := common.Mv(r, "opr", true)
-	if opr == "" {
-		//List the current boot flag, all units in MB
-		js, _ := json.Marshal(bootFlags{
-			*host_name,
-			int(max_upload_size >> 20),
-			*upload_buf,
-			*file_opr_buff,
-			*disable_ip_resolve_services,
-			*allow_homepage,
-			*enable_dir_listing,
-		})
-
-		common.SendJSONResponse(w, string(js))
-	} else if opr == "set" {
-		//Set and update the boot flags
-		newSettings, err := common.Mv(r, "value", true)
-		if err != nil {
-			common.SendErrorResponse(w, "Invalid new seting value")
-			return
-		}
-
-		//Try parse it
-		newConfig := bootFlags{
-			"My ArOZ",
-			8192,
-			25,
-			1024,
-			false,
-			false,
-			true,
-		}
-		err = json.Unmarshal([]byte(newSettings), &newConfig)
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-			return
-		}
-
-		//Update the current global flags
-		systemWideLogger.PrintAndLog("System", "Updating boot flag to:"+newSettings, nil)
-		*host_name = newConfig.Hostname
-		max_upload_size = int64(newConfig.MaxUploadSize << 20)
-		*upload_buf = newConfig.MaxFileUploadBuff
-		*file_opr_buff = newConfig.FileIOBuffer
-		*disable_ip_resolve_services = newConfig.DisableIPResolver
-		*allow_homepage = newConfig.EnableHomePage
-		*enable_dir_listing = newConfig.EnableDirListing
-
-		common.SendOK(w)
-	} else {
-		common.SendErrorResponse(w, "Unknown operation")
-	}
-}
+package main
+
+import (
+	"encoding/json"
+	"net/http"
+
+	prout "imuslab.com/arozos/mod/prouter"
+	"imuslab.com/arozos/mod/utils"
+)
+
+/*
+	Startup Flags Manager
+
+	This script is design to provide interface for editing the boot flags
+	during the system is running
+
+*/
+
+func StartupFlagsInit() {
+	//Create a admin permission router for handling requests
+	//Register a boot flag modifier
+	registerSetting(settingModule{
+		Name:         "Runtime",
+		Desc:         "Change startup paramter in runtime",
+		IconPath:     "SystemAO/info/img/small_icon.png",
+		Group:        "Info",
+		StartDir:     "SystemAO/boot/bootflags.html",
+		RequireAdmin: true,
+	})
+
+	adminRouter := prout.NewModuleRouter(prout.RouterOption{
+		AdminOnly:   true,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			utils.SendErrorResponse(w, "Permission Denied")
+		},
+	})
+
+	adminRouter.HandleFunc("/system/bootflags", handleBootFlagsFunction)
+}
+
+func handleBootFlagsFunction(w http.ResponseWriter, r *http.Request) {
+	type bootFlags struct {
+		Hostname          string
+		MaxUploadSize     int
+		MaxFileUploadBuff int
+		FileIOBuffer      int
+		DisableIPResolver bool
+		EnableHomePage    bool
+		EnableDirListing  bool
+	}
+	opr, _ := utils.Mv(r, "opr", true)
+	if opr == "" {
+		//List the current boot flag, all units in MB
+		js, _ := json.Marshal(bootFlags{
+			*host_name,
+			int(max_upload_size >> 20),
+			*upload_buf,
+			*file_opr_buff,
+			*disable_ip_resolve_services,
+			*allow_homepage,
+			*enable_dir_listing,
+		})
+
+		utils.SendJSONResponse(w, string(js))
+	} else if opr == "set" {
+		//Set and update the boot flags
+		newSettings, err := utils.Mv(r, "value", true)
+		if err != nil {
+			utils.SendErrorResponse(w, "Invalid new seting value")
+			return
+		}
+
+		//Try parse it
+		newConfig := bootFlags{
+			"My ArOZ",
+			8192,
+			25,
+			1024,
+			false,
+			false,
+			true,
+		}
+		err = json.Unmarshal([]byte(newSettings), &newConfig)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+
+		//Update the current global flags
+		systemWideLogger.PrintAndLog("System", "Updating boot flag to:"+newSettings, nil)
+		*host_name = newConfig.Hostname
+		max_upload_size = int64(newConfig.MaxUploadSize << 20)
+		*upload_buf = newConfig.MaxFileUploadBuff
+		*file_opr_buff = newConfig.FileIOBuffer
+		*disable_ip_resolve_services = newConfig.DisableIPResolver
+		*allow_homepage = newConfig.EnableHomePage
+		*enable_dir_listing = newConfig.EnableDirListing
+
+		utils.SendOK(w)
+	} else {
+		utils.SendErrorResponse(w, "Unknown operation")
+	}
+}

+ 727 - 727
storage.pool.go

@@ -1,727 +1,727 @@
-package main
-
-import (
-	"encoding/json"
-	"errors"
-	"io/ioutil"
-	"net/http"
-	"os"
-	"path/filepath"
-	"strings"
-	"time"
-
-	"imuslab.com/arozos/mod/common"
-	"imuslab.com/arozos/mod/database"
-	"imuslab.com/arozos/mod/permission"
-	"imuslab.com/arozos/mod/storage/bridge"
-
-	"github.com/tidwall/pretty"
-	fs "imuslab.com/arozos/mod/filesystem"
-	prout "imuslab.com/arozos/mod/prouter"
-	storage "imuslab.com/arozos/mod/storage"
-)
-
-/*
-	Storage Pool Handler
-	author: tobychui
-
-	This script handle the storage pool editing of different permission groups
-
-*/
-
-func StoragePoolEditorInit() {
-
-	adminRouter := prout.NewModuleRouter(prout.RouterOption{
-		ModuleName:  "System Settings",
-		AdminOnly:   true,
-		UserHandler: userHandler,
-		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
-		},
-	})
-
-	adminRouter.HandleFunc("/system/storage/pool/list", HandleListStoragePools)
-	adminRouter.HandleFunc("/system/storage/pool/listraw", HandleListStoragePoolsConfig)
-	//adminRouter.HandleFunc("/system/storage/pool/newHandler", HandleStorageNewFsHandler)
-	adminRouter.HandleFunc("/system/storage/pool/removeHandler", HandleStoragePoolRemove)
-	adminRouter.HandleFunc("/system/storage/pool/reload", HandleStoragePoolReload)
-	adminRouter.HandleFunc("/system/storage/pool/toggle", HandleFSHToggle)
-	adminRouter.HandleFunc("/system/storage/pool/edit", HandleFSHEdit)
-	adminRouter.HandleFunc("/system/storage/pool/bridge", HandleFSHBridging)
-	adminRouter.HandleFunc("/system/storage/pool/checkBridge", HandleFSHBridgeCheck)
-}
-
-//Handle editing of a given File System Handler
-func HandleFSHEdit(w http.ResponseWriter, r *http.Request) {
-	opr, _ := common.Mv(r, "opr", true)
-	group, err := common.Mv(r, "group", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid group given")
-		return
-	}
-
-	if opr == "get" {
-		uuid, err := common.Mv(r, "uuid", true)
-		if err != nil {
-			common.SendErrorResponse(w, "Invalid UUID")
-			return
-		}
-
-		//Load
-		fshOption, err := getFSHConfigFromGroupAndUUID(group, uuid)
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-			return
-		}
-		//Hide the password info
-		fshOption.Username = ""
-		fshOption.Password = ""
-
-		//Return as JSON
-		js, _ := json.Marshal(fshOption)
-		common.SendJSONResponse(w, string(js))
-		return
-	} else if opr == "set" {
-		config, err := common.Mv(r, "config", true)
-		if err != nil {
-			common.SendErrorResponse(w, "Invalid UUID")
-			return
-		}
-
-		newFsOption, err := buildOptionFromRequestForm(config)
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-			return
-		}
-		//systemWideLogger.PrintAndLog("Storage", newFsOption, nil)
-
-		uuid := newFsOption.Uuid
-
-		//Read and remove the original settings from the config file
-		err = setFSHConfigByGroupAndId(group, uuid, newFsOption)
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-		} else {
-			common.SendOK(w)
-		}
-	} else if opr == "new" {
-		//New handler
-		config, err := common.Mv(r, "config", true)
-		if err != nil {
-			common.SendErrorResponse(w, "Invalid config")
-			return
-		}
-		newFsOption, err := buildOptionFromRequestForm(config)
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-			return
-		}
-
-		//Check if group exists
-		if !permissionHandler.GroupExists(group) && group != "system" {
-			common.SendErrorResponse(w, "Group not exists: "+group)
-			return
-		}
-
-		//Validate the config is correct
-		err = fs.ValidateOption(&newFsOption)
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-			return
-		}
-
-		configFile := "./system/storage.json"
-		if group != "system" {
-			configFile = "./system/storage/" + group + ".json"
-		}
-
-		//Merge the old config file if exists
-		oldConfigs := []fs.FileSystemOption{}
-		if fs.FileExists(configFile) {
-			originalConfigFile, _ := ioutil.ReadFile(configFile)
-			err := json.Unmarshal(originalConfigFile, &oldConfigs)
-			if err != nil {
-				systemWideLogger.PrintAndLog("Storage", err.Error(), err)
-			}
-		}
-
-		oldConfigs = append(oldConfigs, newFsOption)
-		js, _ := json.MarshalIndent(oldConfigs, "", " ")
-		err = ioutil.WriteFile(configFile, js, 0775)
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-			return
-		}
-
-		common.SendOK(w)
-
-	} else {
-		//Unknown
-		common.SendErrorResponse(w, "Unknown opr given")
-		return
-	}
-}
-
-//Get the FSH configuration for the given group and uuid
-func getFSHConfigFromGroupAndUUID(group string, uuid string) (*fs.FileSystemOption, error) {
-	//Spot the desired config file
-	targerFile := ""
-	if group == "system" {
-		targerFile = "./system/storage.json"
-	} else {
-		targerFile = "./system/storage/" + group + ".json"
-	}
-
-	//Check if file exists.
-	if !fs.FileExists(targerFile) {
-		systemWideLogger.PrintAndLog("Storage", "Config file not found: "+targerFile, nil)
-		return nil, errors.New("Configuration file not found")
-	}
-
-	if !fs.FileExists(filepath.Dir(targerFile)) {
-		os.MkdirAll(filepath.Dir(targerFile), 0775)
-	}
-
-	//Load and parse the file
-	configContent, err := ioutil.ReadFile(targerFile)
-	if err != nil {
-		return nil, err
-	}
-
-	loadedConfig := []fs.FileSystemOption{}
-	err = json.Unmarshal(configContent, &loadedConfig)
-	if err != nil {
-		systemWideLogger.PrintAndLog("Storage", "Request to parse config error: "+err.Error()+targerFile, err)
-		return nil, err
-	}
-
-	//Look for the target fsh uuid
-	for _, thisFshConfig := range loadedConfig {
-		if thisFshConfig.Uuid == uuid {
-			return &thisFshConfig, nil
-		}
-	}
-
-	return nil, errors.New("No FSH config found with the uuid")
-
-}
-
-func setFSHConfigByGroupAndId(group string, uuid string, options fs.FileSystemOption) error {
-	//Spot the desired config file
-	targerFile := ""
-	if group == "system" {
-		targerFile = "./system/storage.json"
-	} else {
-		targerFile = "./system/storage/" + group + ".json"
-	}
-
-	//Check if file exists.
-	if !fs.FileExists(targerFile) {
-		systemWideLogger.PrintAndLog("Storage", "Config file not found: "+targerFile, nil)
-		return errors.New("Configuration file not found")
-	}
-
-	if !fs.FileExists(filepath.Dir(targerFile)) {
-		os.MkdirAll(filepath.Dir(targerFile), 0775)
-	}
-
-	//Load and parse the file
-	configContent, err := ioutil.ReadFile(targerFile)
-	if err != nil {
-		return err
-	}
-
-	loadedConfig := []fs.FileSystemOption{}
-	err = json.Unmarshal(configContent, &loadedConfig)
-	if err != nil {
-		systemWideLogger.PrintAndLog("Storage", "Request to parse config error: "+err.Error()+targerFile, err)
-		return err
-	}
-
-	//Filter the old fs handler option with given uuid
-	newConfig := []fs.FileSystemOption{}
-	var overwritingConfig fs.FileSystemOption
-	for _, fso := range loadedConfig {
-		if fso.Uuid != uuid {
-			newConfig = append(newConfig, fso)
-		} else {
-			overwritingConfig = fso
-		}
-	}
-
-	//Continue using the old username and password if it is left empty
-	if options.Username == "" {
-		options.Username = overwritingConfig.Username
-	}
-	if options.Password == "" {
-		options.Password = overwritingConfig.Password
-	}
-
-	//Append the new fso to config
-	newConfig = append(newConfig, options)
-
-	//Write config back to file
-	js, _ := json.MarshalIndent(newConfig, "", " ")
-	return ioutil.WriteFile(targerFile, js, 0775)
-}
-
-//Handle Storage Pool toggle on-off
-func HandleFSHToggle(w http.ResponseWriter, r *http.Request) {
-	fsh, _ := common.Mv(r, "fsh", true)
-	if fsh == "" {
-		common.SendErrorResponse(w, "Invalid File System Handler ID")
-		return
-	}
-
-	group, _ := common.Mv(r, "group", true)
-	if group == "" {
-		common.SendErrorResponse(w, "Invalid group ID")
-		return
-	}
-
-	//Check if group exists
-	if group != "system" && !permissionHandler.GroupExists(group) {
-		common.SendErrorResponse(w, "Group not exists")
-		return
-	}
-
-	//Not allow to modify system reserved fsh
-	if fsh == "user" || fsh == "tmp" {
-		common.SendErrorResponse(w, "Cannot toggle system reserved File System Handler")
-		return
-	}
-
-	//Check if fsh exists
-	var targetpg *permission.PermissionGroup
-	var storagePool *storage.StoragePool
-	if group == "system" {
-		//System storage pool.
-		storagePool = baseStoragePool
-	} else {
-		targetpg = permissionHandler.GetPermissionGroupByName(group)
-		storagePool = targetpg.StoragePool
-	}
-
-	var targetFSH *fs.FileSystemHandler
-	for _, thisFsh := range storagePool.Storages {
-		if thisFsh.UUID == fsh {
-			targetFSH = thisFsh
-		}
-	}
-
-	//Target File System Handler not found
-	if targetFSH == nil {
-		common.SendErrorResponse(w, "Target File System Handler not found, given: "+fsh)
-		return
-	}
-
-	if targetFSH.Closed {
-		//Reopen the fsh database and set this to false
-		aofsPath := filepath.ToSlash(filepath.Clean(targetFSH.Path)) + "/aofs.db"
-		conn, err := database.NewDatabase(aofsPath, false)
-		if err == nil {
-			targetFSH.FilesystemDatabase = conn
-		}
-		targetFSH.Closed = false
-	} else {
-		//Close the fsh database and set this to true
-		if targetFSH.FilesystemDatabase != nil {
-			targetFSH.FilesystemDatabase.Close()
-		}
-		targetFSH.Closed = true
-	}
-
-	//Give it some time to finish unloading
-	time.Sleep(1 * time.Second)
-
-	//Return ok
-	common.SendOK(w)
-
-}
-
-//Handle reload of storage pool
-func HandleStoragePoolReload(w http.ResponseWriter, r *http.Request) {
-	pool, _ := common.Mv(r, "pool", true)
-
-	//Basepool super long string just to prevent any typo
-	if pool == "1eb201a3-d0f6-6630-5e6d-2f40480115c5" {
-		//Reload ALL storage pools
-		//Reload basepool
-		baseStoragePool.Close()
-		emptyPool := storage.StoragePool{}
-		baseStoragePool = &emptyPool
-
-		//Start BasePool again
-		err := LoadBaseStoragePool()
-		if err != nil {
-			systemWideLogger.PrintAndLog("Storage", err.Error(), err)
-		} else {
-			//Update userHandler's basePool
-			userHandler.UpdateStoragePool(baseStoragePool)
-		}
-
-		//Reload all permission group's pool
-		for _, pg := range permissionHandler.PermissionGroups {
-			systemWideLogger.PrintAndLog("Storage", "Reloading Storage Pool for: "+pg.Name, err)
-
-			//Pool should be exists. Close it
-			pg.StoragePool.Close()
-
-			//Create an empty pool for this permission group
-			newEmptyPool := storage.StoragePool{}
-			pg.StoragePool = &newEmptyPool
-
-			//Recreate a new pool for this permission group
-			//If there is no handler in config, the empty one will be kept
-			LoadStoragePoolForGroup(pg)
-		}
-
-		BridgeStoragePoolInit()
-
-	} else {
-
-		if pool == "system" {
-			//Reload basepool
-			baseStoragePool.Close()
-			emptyPool := storage.StoragePool{}
-			baseStoragePool = &emptyPool
-
-			//Start BasePool again
-			err := LoadBaseStoragePool()
-			if err != nil {
-				systemWideLogger.PrintAndLog("Storage", err.Error(), err)
-			} else {
-				//Update userHandler's basePool
-				userHandler.UpdateStoragePool(baseStoragePool)
-			}
-
-			BridgeStoragePoolForGroup("system")
-
-		} else {
-			//Reload the given storage pool
-			if !permissionHandler.GroupExists(pool) {
-				common.SendErrorResponse(w, "Permission Pool owner not exists")
-				return
-			}
-
-			systemWideLogger.PrintAndLog("Storage", "Reloading Storage Pool for: "+pool, nil)
-
-			//Pool should be exists. Close it
-			pg := permissionHandler.GetPermissionGroupByName(pool)
-
-			pg.StoragePool.Close()
-
-			//Create an empty pool for this permission group
-			newEmptyPool := storage.StoragePool{}
-			pg.StoragePool = &newEmptyPool
-
-			//Recreate a new pool for this permission group
-			//If there is no handler in config, the empty one will be kept
-			LoadStoragePoolForGroup(pg)
-			BridgeStoragePoolForGroup(pg.Name)
-		}
-	}
-
-	common.SendOK(w)
-}
-
-func HandleStoragePoolRemove(w http.ResponseWriter, r *http.Request) {
-	groupname, err := common.Mv(r, "group", true)
-	if err != nil {
-		common.SendErrorResponse(w, "group not defined")
-		return
-	}
-
-	uuid, err := common.Mv(r, "uuid", true)
-	if err != nil {
-		common.SendErrorResponse(w, "File system handler UUID not defined")
-		return
-	}
-
-	targetConfigFile := "./system/storage.json"
-	if groupname == "system" {
-		if uuid == "user" || uuid == "tmp" {
-			common.SendErrorResponse(w, "Cannot remove system reserved file system handlers")
-			return
-		}
-		//Ok to continue
-	} else {
-		//Check group exists
-		if !permissionHandler.GroupExists(groupname) {
-			common.SendErrorResponse(w, "Group not exists")
-			return
-		}
-
-		targetConfigFile = "./system/storage/" + groupname + ".json"
-		if !fs.FileExists(targetConfigFile) {
-			//No config. Create an empty one
-			initConfig := []fs.FileSystemOption{}
-			js, _ := json.MarshalIndent(initConfig, "", " ")
-			ioutil.WriteFile(targetConfigFile, js, 0775)
-		}
-	}
-
-	//Check if this handler is bridged handler
-	bridged, _ := bridgeManager.IsBridgedFSH(uuid, groupname)
-	if bridged {
-		//Bridged FSH. Remove it from bridge config
-		basePool, err := GetStoragePoolByOwner(groupname)
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-			return
-		}
-		err = DebridgeFSHandlerFromGroup(uuid, basePool)
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-			return
-		}
-
-		//Remove it from the config
-		bridgeManager.RemoveFromConfig(uuid, groupname)
-		common.SendOK(w)
-		return
-	} else {
-		//Remove it from the json file
-		//Read and parse from old config
-		oldConfigs := []fs.FileSystemOption{}
-		originalConfigFile, _ := ioutil.ReadFile(targetConfigFile)
-		err = json.Unmarshal(originalConfigFile, &oldConfigs)
-		if err != nil {
-			common.SendErrorResponse(w, "Failed to parse original config file")
-			return
-		}
-
-		//Generate new confic by filtering
-		newConfigs := []fs.FileSystemOption{}
-		for _, config := range oldConfigs {
-			if config.Uuid != uuid {
-				newConfigs = append(newConfigs, config)
-			}
-		}
-
-		//Parse and put it into file
-		if len(newConfigs) > 0 {
-			js, _ := json.Marshal(newConfigs)
-			resultingJson := pretty.Pretty(js)
-			ioutil.WriteFile(targetConfigFile, resultingJson, 0777)
-		} else {
-			os.Remove(targetConfigFile)
-		}
-	}
-
-	common.SendOK(w)
-}
-
-//Constract a fsoption from form
-func buildOptionFromRequestForm(payload string) (fs.FileSystemOption, error) {
-	newFsOption := fs.FileSystemOption{}
-	err := json.Unmarshal([]byte(payload), &newFsOption)
-	if err != nil {
-		return fs.FileSystemOption{}, err
-	}
-	return newFsOption, nil
-}
-
-/*
-func HandleStorageNewFsHandler(w http.ResponseWriter, r *http.Request) {
-	newFsOption, _ := buildOptionFromRequestForm(r)
-
-	type errorObject struct {
-		Message string
-		Source  string
-	}
-
-	//Get group from form data
-	groupName := r.FormValue("group")
-
-	//Check if group exists
-	if !permissionHandler.GroupExists(groupName) && groupName != "system" {
-		js, _ := json.Marshal(errorObject{
-			Message: "Group not exists: " + groupName,
-			Source:  "",
-		})
-		http.Redirect(w, r, "../../../SystemAO/storage/error.html#"+string(js), 307)
-	}
-
-	//Validate the config
-	err := fs.ValidateOption(&newFsOption)
-	if err != nil {
-		//Serve an error page
-		js, _ := json.Marshal(errorObject{
-			Message: err.Error(),
-			Source:  groupName,
-		})
-		http.Redirect(w, r, "../../../SystemAO/storage/error.html#"+string(js), 307)
-		return
-	}
-
-	//Ok. Append to the record
-	configFile := "./system/storage.json"
-	if groupName != "system" {
-		configFile = "./system/storage/" + groupName + ".json"
-	}
-
-	//If file exists, merge it to
-	oldConfigs := []fs.FileSystemOption{}
-	if fs.FileExists(configFile) {
-		originalConfigFile, _ := ioutil.ReadFile(configFile)
-		err := json.Unmarshal(originalConfigFile, &oldConfigs)
-		if err != nil {
-			systemWideLogger.PrintAndLog(err,nil)
-		}
-	}
-
-	oldConfigs = append(oldConfigs, newFsOption)
-
-	//Prepare the content to be written
-	js, _ := json.Marshal(oldConfigs)
-	resultingJson := pretty.Pretty(js)
-
-	err = ioutil.WriteFile(configFile, resultingJson, 0775)
-	if err != nil {
-		//Write Error. This could sometime happens on Windows host for unknown reason
-		js, _ := json.Marshal(errorObject{
-			Message: err.Error(),
-			Source:  groupName,
-		})
-		http.Redirect(w, r, "../../../SystemAO/storage/error.html#"+string(js), 307)
-		return
-	}
-	w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0")
-	http.Redirect(w, r, "../../../SystemAO/storage/poolEditor.html#"+groupName, 307)
-}
-*/
-
-func HandleListStoragePoolsConfig(w http.ResponseWriter, r *http.Request) {
-	target, _ := common.Mv(r, "target", false)
-	if target == "" {
-		target = "system"
-	}
-
-	target = strings.ReplaceAll(filepath.ToSlash(target), "/", "")
-
-	//List the target storage pool config
-	targetFile := "./system/storage.json"
-	if target != "system" {
-		targetFile = "./system/storage/" + target + ".json"
-	}
-
-	if !fs.FileExists(targetFile) {
-		//Assume no storage.
-		nofsh := []*fs.FileSystemOption{}
-		js, _ := json.Marshal(nofsh)
-		common.SendJSONResponse(w, string(js))
-		return
-	}
-
-	//Read and serve it
-	configContent, err := ioutil.ReadFile(targetFile)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	} else {
-		common.SendJSONResponse(w, string(configContent))
-	}
-}
-
-//Return all storage pool mounted to the system, aka base pool + pg pools
-func HandleListStoragePools(w http.ResponseWriter, r *http.Request) {
-	filter, _ := common.Mv(r, "filter", false)
-
-	storagePools := []*storage.StoragePool{}
-
-	if filter != "" {
-		if filter == "system" {
-			storagePools = append(storagePools, baseStoragePool)
-		} else {
-			for _, pg := range userHandler.GetPermissionHandler().PermissionGroups {
-				if pg.Name == filter {
-					storagePools = append(storagePools, pg.StoragePool)
-				}
-			}
-		}
-	} else {
-		//Add the base pool into the list
-		storagePools = append(storagePools, baseStoragePool)
-
-		for _, pg := range userHandler.GetPermissionHandler().PermissionGroups {
-			storagePools = append(storagePools, pg.StoragePool)
-		}
-
-	}
-
-	js, _ := json.Marshal(storagePools)
-	common.SendJSONResponse(w, string(js))
-}
-
-//Handler for bridging two FSH, require admin permission
-func HandleFSHBridging(w http.ResponseWriter, r *http.Request) {
-	//Get the target pool and fsh to bridge
-	basePool, err := common.Mv(r, "base", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid base pool")
-		return
-	}
-
-	//Add the target FSH into the base pool
-	basePoolObject, err := GetStoragePoolByOwner(basePool)
-	if err != nil {
-		systemWideLogger.PrintAndLog("Storage", "Bridge FSH failed: "+err.Error(), err)
-		common.SendErrorResponse(w, "Storage pool not found")
-		return
-	}
-
-	targetFSH, err := common.Mv(r, "fsh", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid File System Handler given")
-		return
-	}
-
-	fsh, err := GetFsHandlerByUUID(targetFSH)
-	if err != nil {
-		common.SendErrorResponse(w, "Given File System Handler UUID does not exists")
-		return
-	}
-
-	err = BridgeFSHandlerToGroup(fsh, basePoolObject)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	bridgeConfig := bridge.BridgeConfig{
-		FSHUUID: fsh.UUID,
-		SPOwner: basePoolObject.Owner,
-	}
-
-	//Write changes to file
-	err = bridgeManager.AppendToConfig(&bridgeConfig)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-	common.SendOK(w)
-}
-
-func HandleFSHBridgeCheck(w http.ResponseWriter, r *http.Request) {
-	basePool, err := common.Mv(r, "base", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid base pool")
-		return
-	}
-
-	fsh, err := common.Mv(r, "fsh", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid fsh UUID")
-		return
-	}
-
-	isBridged, err := bridgeManager.IsBridgedFSH(fsh, basePool)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	js, _ := json.Marshal(isBridged)
-	common.SendJSONResponse(w, string(js))
-}
+package main
+
+import (
+	"encoding/json"
+	"errors"
+	"io/ioutil"
+	"net/http"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+
+	"imuslab.com/arozos/mod/database"
+	"imuslab.com/arozos/mod/permission"
+	"imuslab.com/arozos/mod/storage/bridge"
+	"imuslab.com/arozos/mod/utils"
+
+	"github.com/tidwall/pretty"
+	fs "imuslab.com/arozos/mod/filesystem"
+	prout "imuslab.com/arozos/mod/prouter"
+	storage "imuslab.com/arozos/mod/storage"
+)
+
+/*
+	Storage Pool Handler
+	author: tobychui
+
+	This script handle the storage pool editing of different permission groups
+
+*/
+
+func StoragePoolEditorInit() {
+
+	adminRouter := prout.NewModuleRouter(prout.RouterOption{
+		ModuleName:  "System Settings",
+		AdminOnly:   true,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			utils.SendErrorResponse(w, "Permission Denied")
+		},
+	})
+
+	adminRouter.HandleFunc("/system/storage/pool/list", HandleListStoragePools)
+	adminRouter.HandleFunc("/system/storage/pool/listraw", HandleListStoragePoolsConfig)
+	//adminRouter.HandleFunc("/system/storage/pool/newHandler", HandleStorageNewFsHandler)
+	adminRouter.HandleFunc("/system/storage/pool/removeHandler", HandleStoragePoolRemove)
+	adminRouter.HandleFunc("/system/storage/pool/reload", HandleStoragePoolReload)
+	adminRouter.HandleFunc("/system/storage/pool/toggle", HandleFSHToggle)
+	adminRouter.HandleFunc("/system/storage/pool/edit", HandleFSHEdit)
+	adminRouter.HandleFunc("/system/storage/pool/bridge", HandleFSHBridging)
+	adminRouter.HandleFunc("/system/storage/pool/checkBridge", HandleFSHBridgeCheck)
+}
+
+//Handle editing of a given File System Handler
+func HandleFSHEdit(w http.ResponseWriter, r *http.Request) {
+	opr, _ := utils.Mv(r, "opr", true)
+	group, err := utils.Mv(r, "group", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid group given")
+		return
+	}
+
+	if opr == "get" {
+		uuid, err := utils.Mv(r, "uuid", true)
+		if err != nil {
+			utils.SendErrorResponse(w, "Invalid UUID")
+			return
+		}
+
+		//Load
+		fshOption, err := getFSHConfigFromGroupAndUUID(group, uuid)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+		//Hide the password info
+		fshOption.Username = ""
+		fshOption.Password = ""
+
+		//Return as JSON
+		js, _ := json.Marshal(fshOption)
+		utils.SendJSONResponse(w, string(js))
+		return
+	} else if opr == "set" {
+		config, err := utils.Mv(r, "config", true)
+		if err != nil {
+			utils.SendErrorResponse(w, "Invalid UUID")
+			return
+		}
+
+		newFsOption, err := buildOptionFromRequestForm(config)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+		//systemWideLogger.PrintAndLog("Storage", newFsOption, nil)
+
+		uuid := newFsOption.Uuid
+
+		//Read and remove the original settings from the config file
+		err = setFSHConfigByGroupAndId(group, uuid, newFsOption)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+		} else {
+			utils.SendOK(w)
+		}
+	} else if opr == "new" {
+		//New handler
+		config, err := utils.Mv(r, "config", true)
+		if err != nil {
+			utils.SendErrorResponse(w, "Invalid config")
+			return
+		}
+		newFsOption, err := buildOptionFromRequestForm(config)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+
+		//Check if group exists
+		if !permissionHandler.GroupExists(group) && group != "system" {
+			utils.SendErrorResponse(w, "Group not exists: "+group)
+			return
+		}
+
+		//Validate the config is correct
+		err = fs.ValidateOption(&newFsOption)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+
+		configFile := "./system/storage.json"
+		if group != "system" {
+			configFile = "./system/storage/" + group + ".json"
+		}
+
+		//Merge the old config file if exists
+		oldConfigs := []fs.FileSystemOption{}
+		if fs.FileExists(configFile) {
+			originalConfigFile, _ := ioutil.ReadFile(configFile)
+			err := json.Unmarshal(originalConfigFile, &oldConfigs)
+			if err != nil {
+				systemWideLogger.PrintAndLog("Storage", err.Error(), err)
+			}
+		}
+
+		oldConfigs = append(oldConfigs, newFsOption)
+		js, _ := json.MarshalIndent(oldConfigs, "", " ")
+		err = ioutil.WriteFile(configFile, js, 0775)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+
+		utils.SendOK(w)
+
+	} else {
+		//Unknown
+		utils.SendErrorResponse(w, "Unknown opr given")
+		return
+	}
+}
+
+//Get the FSH configuration for the given group and uuid
+func getFSHConfigFromGroupAndUUID(group string, uuid string) (*fs.FileSystemOption, error) {
+	//Spot the desired config file
+	targerFile := ""
+	if group == "system" {
+		targerFile = "./system/storage.json"
+	} else {
+		targerFile = "./system/storage/" + group + ".json"
+	}
+
+	//Check if file exists.
+	if !fs.FileExists(targerFile) {
+		systemWideLogger.PrintAndLog("Storage", "Config file not found: "+targerFile, nil)
+		return nil, errors.New("Configuration file not found")
+	}
+
+	if !fs.FileExists(filepath.Dir(targerFile)) {
+		os.MkdirAll(filepath.Dir(targerFile), 0775)
+	}
+
+	//Load and parse the file
+	configContent, err := ioutil.ReadFile(targerFile)
+	if err != nil {
+		return nil, err
+	}
+
+	loadedConfig := []fs.FileSystemOption{}
+	err = json.Unmarshal(configContent, &loadedConfig)
+	if err != nil {
+		systemWideLogger.PrintAndLog("Storage", "Request to parse config error: "+err.Error()+targerFile, err)
+		return nil, err
+	}
+
+	//Look for the target fsh uuid
+	for _, thisFshConfig := range loadedConfig {
+		if thisFshConfig.Uuid == uuid {
+			return &thisFshConfig, nil
+		}
+	}
+
+	return nil, errors.New("No FSH config found with the uuid")
+
+}
+
+func setFSHConfigByGroupAndId(group string, uuid string, options fs.FileSystemOption) error {
+	//Spot the desired config file
+	targerFile := ""
+	if group == "system" {
+		targerFile = "./system/storage.json"
+	} else {
+		targerFile = "./system/storage/" + group + ".json"
+	}
+
+	//Check if file exists.
+	if !fs.FileExists(targerFile) {
+		systemWideLogger.PrintAndLog("Storage", "Config file not found: "+targerFile, nil)
+		return errors.New("Configuration file not found")
+	}
+
+	if !fs.FileExists(filepath.Dir(targerFile)) {
+		os.MkdirAll(filepath.Dir(targerFile), 0775)
+	}
+
+	//Load and parse the file
+	configContent, err := ioutil.ReadFile(targerFile)
+	if err != nil {
+		return err
+	}
+
+	loadedConfig := []fs.FileSystemOption{}
+	err = json.Unmarshal(configContent, &loadedConfig)
+	if err != nil {
+		systemWideLogger.PrintAndLog("Storage", "Request to parse config error: "+err.Error()+targerFile, err)
+		return err
+	}
+
+	//Filter the old fs handler option with given uuid
+	newConfig := []fs.FileSystemOption{}
+	var overwritingConfig fs.FileSystemOption
+	for _, fso := range loadedConfig {
+		if fso.Uuid != uuid {
+			newConfig = append(newConfig, fso)
+		} else {
+			overwritingConfig = fso
+		}
+	}
+
+	//Continue using the old username and password if it is left empty
+	if options.Username == "" {
+		options.Username = overwritingConfig.Username
+	}
+	if options.Password == "" {
+		options.Password = overwritingConfig.Password
+	}
+
+	//Append the new fso to config
+	newConfig = append(newConfig, options)
+
+	//Write config back to file
+	js, _ := json.MarshalIndent(newConfig, "", " ")
+	return ioutil.WriteFile(targerFile, js, 0775)
+}
+
+//Handle Storage Pool toggle on-off
+func HandleFSHToggle(w http.ResponseWriter, r *http.Request) {
+	fsh, _ := utils.Mv(r, "fsh", true)
+	if fsh == "" {
+		utils.SendErrorResponse(w, "Invalid File System Handler ID")
+		return
+	}
+
+	group, _ := utils.Mv(r, "group", true)
+	if group == "" {
+		utils.SendErrorResponse(w, "Invalid group ID")
+		return
+	}
+
+	//Check if group exists
+	if group != "system" && !permissionHandler.GroupExists(group) {
+		utils.SendErrorResponse(w, "Group not exists")
+		return
+	}
+
+	//Not allow to modify system reserved fsh
+	if fsh == "user" || fsh == "tmp" {
+		utils.SendErrorResponse(w, "Cannot toggle system reserved File System Handler")
+		return
+	}
+
+	//Check if fsh exists
+	var targetpg *permission.PermissionGroup
+	var storagePool *storage.StoragePool
+	if group == "system" {
+		//System storage pool.
+		storagePool = baseStoragePool
+	} else {
+		targetpg = permissionHandler.GetPermissionGroupByName(group)
+		storagePool = targetpg.StoragePool
+	}
+
+	var targetFSH *fs.FileSystemHandler
+	for _, thisFsh := range storagePool.Storages {
+		if thisFsh.UUID == fsh {
+			targetFSH = thisFsh
+		}
+	}
+
+	//Target File System Handler not found
+	if targetFSH == nil {
+		utils.SendErrorResponse(w, "Target File System Handler not found, given: "+fsh)
+		return
+	}
+
+	if targetFSH.Closed {
+		//Reopen the fsh database and set this to false
+		aofsPath := filepath.ToSlash(filepath.Clean(targetFSH.Path)) + "/aofs.db"
+		conn, err := database.NewDatabase(aofsPath, false)
+		if err == nil {
+			targetFSH.FilesystemDatabase = conn
+		}
+		targetFSH.Closed = false
+	} else {
+		//Close the fsh database and set this to true
+		if targetFSH.FilesystemDatabase != nil {
+			targetFSH.FilesystemDatabase.Close()
+		}
+		targetFSH.Closed = true
+	}
+
+	//Give it some time to finish unloading
+	time.Sleep(1 * time.Second)
+
+	//Return ok
+	utils.SendOK(w)
+
+}
+
+//Handle reload of storage pool
+func HandleStoragePoolReload(w http.ResponseWriter, r *http.Request) {
+	pool, _ := utils.Mv(r, "pool", true)
+
+	//Basepool super long string just to prevent any typo
+	if pool == "1eb201a3-d0f6-6630-5e6d-2f40480115c5" {
+		//Reload ALL storage pools
+		//Reload basepool
+		baseStoragePool.Close()
+		emptyPool := storage.StoragePool{}
+		baseStoragePool = &emptyPool
+
+		//Start BasePool again
+		err := LoadBaseStoragePool()
+		if err != nil {
+			systemWideLogger.PrintAndLog("Storage", err.Error(), err)
+		} else {
+			//Update userHandler's basePool
+			userHandler.UpdateStoragePool(baseStoragePool)
+		}
+
+		//Reload all permission group's pool
+		for _, pg := range permissionHandler.PermissionGroups {
+			systemWideLogger.PrintAndLog("Storage", "Reloading Storage Pool for: "+pg.Name, err)
+
+			//Pool should be exists. Close it
+			pg.StoragePool.Close()
+
+			//Create an empty pool for this permission group
+			newEmptyPool := storage.StoragePool{}
+			pg.StoragePool = &newEmptyPool
+
+			//Recreate a new pool for this permission group
+			//If there is no handler in config, the empty one will be kept
+			LoadStoragePoolForGroup(pg)
+		}
+
+		BridgeStoragePoolInit()
+
+	} else {
+
+		if pool == "system" {
+			//Reload basepool
+			baseStoragePool.Close()
+			emptyPool := storage.StoragePool{}
+			baseStoragePool = &emptyPool
+
+			//Start BasePool again
+			err := LoadBaseStoragePool()
+			if err != nil {
+				systemWideLogger.PrintAndLog("Storage", err.Error(), err)
+			} else {
+				//Update userHandler's basePool
+				userHandler.UpdateStoragePool(baseStoragePool)
+			}
+
+			BridgeStoragePoolForGroup("system")
+
+		} else {
+			//Reload the given storage pool
+			if !permissionHandler.GroupExists(pool) {
+				utils.SendErrorResponse(w, "Permission Pool owner not exists")
+				return
+			}
+
+			systemWideLogger.PrintAndLog("Storage", "Reloading Storage Pool for: "+pool, nil)
+
+			//Pool should be exists. Close it
+			pg := permissionHandler.GetPermissionGroupByName(pool)
+
+			pg.StoragePool.Close()
+
+			//Create an empty pool for this permission group
+			newEmptyPool := storage.StoragePool{}
+			pg.StoragePool = &newEmptyPool
+
+			//Recreate a new pool for this permission group
+			//If there is no handler in config, the empty one will be kept
+			LoadStoragePoolForGroup(pg)
+			BridgeStoragePoolForGroup(pg.Name)
+		}
+	}
+
+	utils.SendOK(w)
+}
+
+func HandleStoragePoolRemove(w http.ResponseWriter, r *http.Request) {
+	groupname, err := utils.Mv(r, "group", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "group not defined")
+		return
+	}
+
+	uuid, err := utils.Mv(r, "uuid", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "File system handler UUID not defined")
+		return
+	}
+
+	targetConfigFile := "./system/storage.json"
+	if groupname == "system" {
+		if uuid == "user" || uuid == "tmp" {
+			utils.SendErrorResponse(w, "Cannot remove system reserved file system handlers")
+			return
+		}
+		//Ok to continue
+	} else {
+		//Check group exists
+		if !permissionHandler.GroupExists(groupname) {
+			utils.SendErrorResponse(w, "Group not exists")
+			return
+		}
+
+		targetConfigFile = "./system/storage/" + groupname + ".json"
+		if !fs.FileExists(targetConfigFile) {
+			//No config. Create an empty one
+			initConfig := []fs.FileSystemOption{}
+			js, _ := json.MarshalIndent(initConfig, "", " ")
+			ioutil.WriteFile(targetConfigFile, js, 0775)
+		}
+	}
+
+	//Check if this handler is bridged handler
+	bridged, _ := bridgeManager.IsBridgedFSH(uuid, groupname)
+	if bridged {
+		//Bridged FSH. Remove it from bridge config
+		basePool, err := GetStoragePoolByOwner(groupname)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+		err = DebridgeFSHandlerFromGroup(uuid, basePool)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+
+		//Remove it from the config
+		bridgeManager.RemoveFromConfig(uuid, groupname)
+		utils.SendOK(w)
+		return
+	} else {
+		//Remove it from the json file
+		//Read and parse from old config
+		oldConfigs := []fs.FileSystemOption{}
+		originalConfigFile, _ := ioutil.ReadFile(targetConfigFile)
+		err = json.Unmarshal(originalConfigFile, &oldConfigs)
+		if err != nil {
+			utils.SendErrorResponse(w, "Failed to parse original config file")
+			return
+		}
+
+		//Generate new confic by filtering
+		newConfigs := []fs.FileSystemOption{}
+		for _, config := range oldConfigs {
+			if config.Uuid != uuid {
+				newConfigs = append(newConfigs, config)
+			}
+		}
+
+		//Parse and put it into file
+		if len(newConfigs) > 0 {
+			js, _ := json.Marshal(newConfigs)
+			resultingJson := pretty.Pretty(js)
+			ioutil.WriteFile(targetConfigFile, resultingJson, 0777)
+		} else {
+			os.Remove(targetConfigFile)
+		}
+	}
+
+	utils.SendOK(w)
+}
+
+//Constract a fsoption from form
+func buildOptionFromRequestForm(payload string) (fs.FileSystemOption, error) {
+	newFsOption := fs.FileSystemOption{}
+	err := json.Unmarshal([]byte(payload), &newFsOption)
+	if err != nil {
+		return fs.FileSystemOption{}, err
+	}
+	return newFsOption, nil
+}
+
+/*
+func HandleStorageNewFsHandler(w http.ResponseWriter, r *http.Request) {
+	newFsOption, _ := buildOptionFromRequestForm(r)
+
+	type errorObject struct {
+		Message string
+		Source  string
+	}
+
+	//Get group from form data
+	groupName := r.FormValue("group")
+
+	//Check if group exists
+	if !permissionHandler.GroupExists(groupName) && groupName != "system" {
+		js, _ := json.Marshal(errorObject{
+			Message: "Group not exists: " + groupName,
+			Source:  "",
+		})
+		http.Redirect(w, r, "../../../SystemAO/storage/error.html#"+string(js), 307)
+	}
+
+	//Validate the config
+	err := fs.ValidateOption(&newFsOption)
+	if err != nil {
+		//Serve an error page
+		js, _ := json.Marshal(errorObject{
+			Message: err.Error(),
+			Source:  groupName,
+		})
+		http.Redirect(w, r, "../../../SystemAO/storage/error.html#"+string(js), 307)
+		return
+	}
+
+	//Ok. Append to the record
+	configFile := "./system/storage.json"
+	if groupName != "system" {
+		configFile = "./system/storage/" + groupName + ".json"
+	}
+
+	//If file exists, merge it to
+	oldConfigs := []fs.FileSystemOption{}
+	if fs.FileExists(configFile) {
+		originalConfigFile, _ := ioutil.ReadFile(configFile)
+		err := json.Unmarshal(originalConfigFile, &oldConfigs)
+		if err != nil {
+			systemWideLogger.PrintAndLog(err,nil)
+		}
+	}
+
+	oldConfigs = append(oldConfigs, newFsOption)
+
+	//Prepare the content to be written
+	js, _ := json.Marshal(oldConfigs)
+	resultingJson := pretty.Pretty(js)
+
+	err = ioutil.WriteFile(configFile, resultingJson, 0775)
+	if err != nil {
+		//Write Error. This could sometime happens on Windows host for unknown reason
+		js, _ := json.Marshal(errorObject{
+			Message: err.Error(),
+			Source:  groupName,
+		})
+		http.Redirect(w, r, "../../../SystemAO/storage/error.html#"+string(js), 307)
+		return
+	}
+	w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0")
+	http.Redirect(w, r, "../../../SystemAO/storage/poolEditor.html#"+groupName, 307)
+}
+*/
+
+func HandleListStoragePoolsConfig(w http.ResponseWriter, r *http.Request) {
+	target, _ := utils.Mv(r, "target", false)
+	if target == "" {
+		target = "system"
+	}
+
+	target = strings.ReplaceAll(filepath.ToSlash(target), "/", "")
+
+	//List the target storage pool config
+	targetFile := "./system/storage.json"
+	if target != "system" {
+		targetFile = "./system/storage/" + target + ".json"
+	}
+
+	if !fs.FileExists(targetFile) {
+		//Assume no storage.
+		nofsh := []*fs.FileSystemOption{}
+		js, _ := json.Marshal(nofsh)
+		utils.SendJSONResponse(w, string(js))
+		return
+	}
+
+	//Read and serve it
+	configContent, err := ioutil.ReadFile(targetFile)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	} else {
+		utils.SendJSONResponse(w, string(configContent))
+	}
+}
+
+//Return all storage pool mounted to the system, aka base pool + pg pools
+func HandleListStoragePools(w http.ResponseWriter, r *http.Request) {
+	filter, _ := utils.Mv(r, "filter", false)
+
+	storagePools := []*storage.StoragePool{}
+
+	if filter != "" {
+		if filter == "system" {
+			storagePools = append(storagePools, baseStoragePool)
+		} else {
+			for _, pg := range userHandler.GetPermissionHandler().PermissionGroups {
+				if pg.Name == filter {
+					storagePools = append(storagePools, pg.StoragePool)
+				}
+			}
+		}
+	} else {
+		//Add the base pool into the list
+		storagePools = append(storagePools, baseStoragePool)
+
+		for _, pg := range userHandler.GetPermissionHandler().PermissionGroups {
+			storagePools = append(storagePools, pg.StoragePool)
+		}
+
+	}
+
+	js, _ := json.Marshal(storagePools)
+	utils.SendJSONResponse(w, string(js))
+}
+
+//Handler for bridging two FSH, require admin permission
+func HandleFSHBridging(w http.ResponseWriter, r *http.Request) {
+	//Get the target pool and fsh to bridge
+	basePool, err := utils.Mv(r, "base", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid base pool")
+		return
+	}
+
+	//Add the target FSH into the base pool
+	basePoolObject, err := GetStoragePoolByOwner(basePool)
+	if err != nil {
+		systemWideLogger.PrintAndLog("Storage", "Bridge FSH failed: "+err.Error(), err)
+		utils.SendErrorResponse(w, "Storage pool not found")
+		return
+	}
+
+	targetFSH, err := utils.Mv(r, "fsh", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid File System Handler given")
+		return
+	}
+
+	fsh, err := GetFsHandlerByUUID(targetFSH)
+	if err != nil {
+		utils.SendErrorResponse(w, "Given File System Handler UUID does not exists")
+		return
+	}
+
+	err = BridgeFSHandlerToGroup(fsh, basePoolObject)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	bridgeConfig := bridge.BridgeConfig{
+		FSHUUID: fsh.UUID,
+		SPOwner: basePoolObject.Owner,
+	}
+
+	//Write changes to file
+	err = bridgeManager.AppendToConfig(&bridgeConfig)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+	utils.SendOK(w)
+}
+
+func HandleFSHBridgeCheck(w http.ResponseWriter, r *http.Request) {
+	basePool, err := utils.Mv(r, "base", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid base pool")
+		return
+	}
+
+	fsh, err := utils.Mv(r, "fsh", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid fsh UUID")
+		return
+	}
+
+	isBridged, err := bridgeManager.IsBridgedFSH(fsh, basePool)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	js, _ := json.Marshal(isBridged)
+	utils.SendJSONResponse(w, string(js))
+}

+ 83 - 83
subservice.go

@@ -1,83 +1,83 @@
-package main
-
-import (
-	"net/http"
-	"os"
-	"path/filepath"
-
-	"imuslab.com/arozos/mod/common"
-	fs "imuslab.com/arozos/mod/filesystem"
-	prout "imuslab.com/arozos/mod/prouter"
-	subservice "imuslab.com/arozos/mod/subservice"
-)
-
-/*
-	ArOZ Online System - Dynamic Subsystem loading services
-
-*/
-
-var (
-	ssRouter     *subservice.SubServiceRouter
-	reservePaths = []string{
-		"web",
-		"system",
-		"SystemAO",
-		"img",
-		"STDIN",
-		"STDOUT",
-		"STDERR",
-		"COM",
-		"ws",
-	}
-)
-
-func SubserviceInit() {
-	//If subservice is disabled, do not register endpoints
-	if *disable_subservices {
-		return
-	}
-
-	//Create a new subservice handler
-	ssRouter = subservice.NewSubServiceRouter(
-		reservePaths,
-		subserviceBasePort,
-		userHandler,
-		moduleHandler,
-		*listen_port,
-	)
-
-	//Create an admin router for subservice related functions
-	adminRouter := prout.NewModuleRouter(prout.RouterOption{
-		ModuleName:  "System Setting",
-		AdminOnly:   false,
-		UserHandler: userHandler,
-		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
-		},
-	})
-
-	//Register url endpoints
-	adminRouter.HandleFunc("/system/subservice/list", ssRouter.HandleListing)
-	adminRouter.HandleFunc("/system/subservice/kill", ssRouter.HandleKillSubService)
-	adminRouter.HandleFunc("/system/subservice/start", ssRouter.HandleStartSubService)
-
-	//Make subservice dir
-	os.MkdirAll("./subservice", 0644)
-
-	//Scan and load all subservice modules
-	subservices, _ := filepath.Glob("./subservice/*")
-	for _, servicePath := range subservices {
-		if fs.IsDir(servicePath) && !fs.FileExists(servicePath+"/.disabled") {
-			//Only enable module with no suspended config file
-			ssRouter.Launch(servicePath, true)
-		}
-
-	}
-}
-
-//Stop all the subprocess correctly
-func SubserviceHandleShutdown() {
-	if ssRouter != nil {
-		ssRouter.Close()
-	}
-}
+package main
+
+import (
+	"net/http"
+	"os"
+	"path/filepath"
+
+	fs "imuslab.com/arozos/mod/filesystem"
+	prout "imuslab.com/arozos/mod/prouter"
+	subservice "imuslab.com/arozos/mod/subservice"
+	"imuslab.com/arozos/mod/utils"
+)
+
+/*
+	ArOZ Online System - Dynamic Subsystem loading services
+
+*/
+
+var (
+	ssRouter     *subservice.SubServiceRouter
+	reservePaths = []string{
+		"web",
+		"system",
+		"SystemAO",
+		"img",
+		"STDIN",
+		"STDOUT",
+		"STDERR",
+		"COM",
+		"ws",
+	}
+)
+
+func SubserviceInit() {
+	//If subservice is disabled, do not register endpoints
+	if *disable_subservices {
+		return
+	}
+
+	//Create a new subservice handler
+	ssRouter = subservice.NewSubServiceRouter(
+		reservePaths,
+		subserviceBasePort,
+		userHandler,
+		moduleHandler,
+		*listen_port,
+	)
+
+	//Create an admin router for subservice related functions
+	adminRouter := prout.NewModuleRouter(prout.RouterOption{
+		ModuleName:  "System Setting",
+		AdminOnly:   false,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			utils.SendErrorResponse(w, "Permission Denied")
+		},
+	})
+
+	//Register url endpoints
+	adminRouter.HandleFunc("/system/subservice/list", ssRouter.HandleListing)
+	adminRouter.HandleFunc("/system/subservice/kill", ssRouter.HandleKillSubService)
+	adminRouter.HandleFunc("/system/subservice/start", ssRouter.HandleStartSubService)
+
+	//Make subservice dir
+	os.MkdirAll("./subservice", 0644)
+
+	//Scan and load all subservice modules
+	subservices, _ := filepath.Glob("./subservice/*")
+	for _, servicePath := range subservices {
+		if fs.IsDir(servicePath) && !fs.FileExists(servicePath+"/.disabled") {
+			//Only enable module with no suspended config file
+			ssRouter.Launch(servicePath, true)
+		}
+
+	}
+}
+
+//Stop all the subprocess correctly
+func SubserviceHandleShutdown() {
+	if ssRouter != nil {
+		ssRouter.Close()
+	}
+}

+ 213 - 213
system.go

@@ -1,213 +1,213 @@
-package main
-
-import (
-	"encoding/json"
-	"io/ioutil"
-	"log"
-	"net/http"
-	"path/filepath"
-	"strings"
-
-	uuid "github.com/satori/go.uuid"
-	"imuslab.com/arozos/mod/common"
-	fs "imuslab.com/arozos/mod/filesystem"
-)
-
-/*
-	System Identification API
-
-	This module handles cross cluster scanning, responses and more that related
-	to functions that identifiy this as a ArOZ Online device
-*/
-func SystemIDInit() {
-	//Initialize device UUID if not exists
-	systemIdGenerateSystemUUID()
-
-	//Register as a system setting
-	registerSetting(settingModule{
-		Name:     "ArozOS",
-		Desc:     "System Information",
-		IconPath: "SystemAO/info/img/small_icon.png",
-		Group:    "About",
-		StartDir: "SystemAO/info/about.html",
-	})
-
-	//Handle the about page
-	http.HandleFunc("/system/id/requestInfo", systemIdHandleRequest)
-
-	//Handle ArOZ Online Beta search methods
-	if *enable_beta_scanning_support {
-		http.HandleFunc("/AOB/hb.php", systemIdResponseBetaScan)
-		http.HandleFunc("/AOB/", func(w http.ResponseWriter, r *http.Request) {
-			http.Redirect(w, r, "../index.html", 307)
-		})
-		http.HandleFunc("/AOB/SystemAOB/functions/info/version.inf", systemIdServeVersonNumber)
-		http.HandleFunc("/AOB/SystemAOB/functions/system_statistic/getDriveStat.php", systemIdGetDriveStates)
-	}
-
-	//Handle license info
-	registerSetting(settingModule{
-		Name:     "Open Source",
-		Desc:     "License from the Open Source Community",
-		IconPath: "SystemAO/info/img/small_icon.png",
-		Group:    "About",
-		StartDir: "SystemAO/info/license.html",
-	})
-
-	registerSetting(settingModule{
-		Name:     "License",
-		Desc:     "License of ArozOS",
-		IconPath: "SystemAO/info/img/small_icon.png",
-		Group:    "About",
-		StartDir: "SystemAO/info/srcLicense.html",
-	})
-
-	//Register vendor information
-	if fs.FileExists("web/SystemAO/vendor/index.html") {
-		registerSetting(settingModule{
-			Name:     "Vendor",
-			Desc:     "Vendor Notes",
-			IconPath: "SystemAO/info/img/small_icon.png",
-			Group:    "About",
-			StartDir: "SystemAO/vendor/index.html",
-		})
-	}
-
-	http.HandleFunc("/system/info/license", systemHandleListLicense)
-
-	//Handle health check ping
-	http.HandleFunc("/system/id/ping", systemIdHandlePing)
-
-}
-
-/*
-	Ping function. This function handles the request
-*/
-func systemIdHandlePing(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Access-Control-Allow-Origin", "*")
-	w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
-	w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
-	js, _ := json.Marshal(struct {
-		Status string
-	}{
-		"OK",
-	})
-	common.SendJSONResponse(w, string(js))
-}
-
-func systemIdGenerateSystemUUID() {
-	if !fs.FileExists("./system/dev.uuid") {
-		//UUID not exist. Create one
-		thisuuid := uuid.NewV4().String()
-		if *system_uuid != "" {
-			//User has defined the uuid. Use user defined one instead.
-			thisuuid = *system_uuid
-		}
-		err := ioutil.WriteFile("./system/dev.uuid", []byte(thisuuid), 0755)
-		if err != nil {
-			log.Fatal(err)
-		}
-		deviceUUID = thisuuid
-	} else {
-		thisuuid, err := ioutil.ReadFile("./system/dev.uuid")
-		if err != nil {
-			log.Fatal("Failed to read system uuid file (system/dev.uuid).")
-		}
-		deviceUUID = string(thisuuid)
-	}
-}
-
-func systemIdGetSystemUUID() string {
-	fileUUID, err := ioutil.ReadFile("./system/dev.uuid")
-	if err != nil {
-		systemWideLogger.PrintAndLog("Storage", "Unable to read system UUID from dev.uuid file", err)
-		log.Fatal(err)
-	}
-
-	return string(fileUUID)
-}
-
-func systemHandleListLicense(w http.ResponseWriter, r *http.Request) {
-	licenses, _ := filepath.Glob("./web/SystemAO/info/license/*.txt")
-	results := [][]string{}
-	for _, file := range licenses {
-		fileName := filepath.Base(file)
-		name := strings.TrimSuffix(fileName, filepath.Ext(fileName))
-		content, _ := ioutil.ReadFile(file)
-		results = append(results, []string{name, string(content)})
-	}
-
-	js, _ := json.Marshal(results)
-	common.SendJSONResponse(w, string(js))
-}
-
-func systemIdHandleRequest(w http.ResponseWriter, r *http.Request) {
-	//Check if user has logged in
-	if authAgent.CheckAuth(r) == false {
-		common.SendErrorResponse(w, "User not logged in")
-		return
-	}
-
-	//Group everything required to show into one json string
-	type returnStruct struct {
-		SystemUUID string
-		IpAddress  string
-		Vendor     string
-		Build      string
-		Version    string
-		Model      string
-		VendorIcon string
-	}
-
-	//thisDevIP := network_info_GetOutboundIP().String()
-	thisDevIP := ""
-
-	jsonString, _ := json.Marshal(returnStruct{
-		SystemUUID: systemIdGetSystemUUID(),
-		IpAddress:  thisDevIP,
-		Vendor:     deviceVendor,
-		Build:      build_version,
-		Version:    internal_version,
-		Model:      deviceModel,
-		VendorIcon: iconVendor,
-	})
-
-	common.SendJSONResponse(w, string(jsonString))
-}
-
-func systemIdResponseBetaScan(w http.ResponseWriter, r *http.Request) {
-	//Handle beta scanning method
-	uuid := systemIdGetSystemUUID()
-	IPAddress := r.Header.Get("X-Real-Ip")
-	if IPAddress == "" {
-		IPAddress = r.Header.Get("X-Forwarded-For")
-	}
-	if IPAddress == "" {
-		IPAddress = r.RemoteAddr
-	}
-	IPAddress = IPAddress[:strings.LastIndex(IPAddress, ":")]
-	resp := *host_name + ",Alive," + uuid + "," + IPAddress
-	w.Header().Set("Access-Control-Allow-Origin", "*")
-	w.Header().Set("Access-Control-Request-Headers", "*")
-	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
-	w.Write([]byte(resp))
-}
-
-func systemIdServeVersonNumber(w http.ResponseWriter, r *http.Request) {
-	if build_version == "development" {
-		w.Write([]byte("AO-DEV_v" + internal_version))
-	} else {
-		w.Write([]byte("AO-REL_v" + internal_version))
-	}
-}
-
-func systemIdGetDriveStates(w http.ResponseWriter, r *http.Request) {
-	results := [][]string{}
-	results = append(results, []string{
-		"user",
-		"User",
-		"-1B/-1B",
-	})
-	jsonString, _ := json.Marshal(results)
-	common.SendJSONResponse(w, string(jsonString))
-}
+package main
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"path/filepath"
+	"strings"
+
+	uuid "github.com/satori/go.uuid"
+	fs "imuslab.com/arozos/mod/filesystem"
+	"imuslab.com/arozos/mod/utils"
+)
+
+/*
+	System Identification API
+
+	This module handles cross cluster scanning, responses and more that related
+	to functions that identifiy this as a ArOZ Online device
+*/
+func SystemIDInit() {
+	//Initialize device UUID if not exists
+	systemIdGenerateSystemUUID()
+
+	//Register as a system setting
+	registerSetting(settingModule{
+		Name:     "ArozOS",
+		Desc:     "System Information",
+		IconPath: "SystemAO/info/img/small_icon.png",
+		Group:    "About",
+		StartDir: "SystemAO/info/about.html",
+	})
+
+	//Handle the about page
+	http.HandleFunc("/system/id/requestInfo", systemIdHandleRequest)
+
+	//Handle ArOZ Online Beta search methods
+	if *enable_beta_scanning_support {
+		http.HandleFunc("/AOB/hb.php", systemIdResponseBetaScan)
+		http.HandleFunc("/AOB/", func(w http.ResponseWriter, r *http.Request) {
+			http.Redirect(w, r, "../index.html", 307)
+		})
+		http.HandleFunc("/AOB/SystemAOB/functions/info/version.inf", systemIdServeVersonNumber)
+		http.HandleFunc("/AOB/SystemAOB/functions/system_statistic/getDriveStat.php", systemIdGetDriveStates)
+	}
+
+	//Handle license info
+	registerSetting(settingModule{
+		Name:     "Open Source",
+		Desc:     "License from the Open Source Community",
+		IconPath: "SystemAO/info/img/small_icon.png",
+		Group:    "About",
+		StartDir: "SystemAO/info/license.html",
+	})
+
+	registerSetting(settingModule{
+		Name:     "License",
+		Desc:     "License of ArozOS",
+		IconPath: "SystemAO/info/img/small_icon.png",
+		Group:    "About",
+		StartDir: "SystemAO/info/srcLicense.html",
+	})
+
+	//Register vendor information
+	if fs.FileExists("web/SystemAO/vendor/index.html") {
+		registerSetting(settingModule{
+			Name:     "Vendor",
+			Desc:     "Vendor Notes",
+			IconPath: "SystemAO/info/img/small_icon.png",
+			Group:    "About",
+			StartDir: "SystemAO/vendor/index.html",
+		})
+	}
+
+	http.HandleFunc("/system/info/license", systemHandleListLicense)
+
+	//Handle health check ping
+	http.HandleFunc("/system/id/ping", systemIdHandlePing)
+
+}
+
+/*
+	Ping function. This function handles the request
+*/
+func systemIdHandlePing(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Access-Control-Allow-Origin", "*")
+	w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
+	w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
+	js, _ := json.Marshal(struct {
+		Status string
+	}{
+		"OK",
+	})
+	utils.SendJSONResponse(w, string(js))
+}
+
+func systemIdGenerateSystemUUID() {
+	if !fs.FileExists("./system/dev.uuid") {
+		//UUID not exist. Create one
+		thisuuid := uuid.NewV4().String()
+		if *system_uuid != "" {
+			//User has defined the uuid. Use user defined one instead.
+			thisuuid = *system_uuid
+		}
+		err := ioutil.WriteFile("./system/dev.uuid", []byte(thisuuid), 0755)
+		if err != nil {
+			log.Fatal(err)
+		}
+		deviceUUID = thisuuid
+	} else {
+		thisuuid, err := ioutil.ReadFile("./system/dev.uuid")
+		if err != nil {
+			log.Fatal("Failed to read system uuid file (system/dev.uuid).")
+		}
+		deviceUUID = string(thisuuid)
+	}
+}
+
+func systemIdGetSystemUUID() string {
+	fileUUID, err := ioutil.ReadFile("./system/dev.uuid")
+	if err != nil {
+		systemWideLogger.PrintAndLog("Storage", "Unable to read system UUID from dev.uuid file", err)
+		log.Fatal(err)
+	}
+
+	return string(fileUUID)
+}
+
+func systemHandleListLicense(w http.ResponseWriter, r *http.Request) {
+	licenses, _ := filepath.Glob("./web/SystemAO/info/license/*.txt")
+	results := [][]string{}
+	for _, file := range licenses {
+		fileName := filepath.Base(file)
+		name := strings.TrimSuffix(fileName, filepath.Ext(fileName))
+		content, _ := ioutil.ReadFile(file)
+		results = append(results, []string{name, string(content)})
+	}
+
+	js, _ := json.Marshal(results)
+	utils.SendJSONResponse(w, string(js))
+}
+
+func systemIdHandleRequest(w http.ResponseWriter, r *http.Request) {
+	//Check if user has logged in
+	if authAgent.CheckAuth(r) == false {
+		utils.SendErrorResponse(w, "User not logged in")
+		return
+	}
+
+	//Group everything required to show into one json string
+	type returnStruct struct {
+		SystemUUID string
+		IpAddress  string
+		Vendor     string
+		Build      string
+		Version    string
+		Model      string
+		VendorIcon string
+	}
+
+	//thisDevIP := network_info_GetOutboundIP().String()
+	thisDevIP := ""
+
+	jsonString, _ := json.Marshal(returnStruct{
+		SystemUUID: systemIdGetSystemUUID(),
+		IpAddress:  thisDevIP,
+		Vendor:     deviceVendor,
+		Build:      build_version,
+		Version:    internal_version,
+		Model:      deviceModel,
+		VendorIcon: iconVendor,
+	})
+
+	utils.SendJSONResponse(w, string(jsonString))
+}
+
+func systemIdResponseBetaScan(w http.ResponseWriter, r *http.Request) {
+	//Handle beta scanning method
+	uuid := systemIdGetSystemUUID()
+	IPAddress := r.Header.Get("X-Real-Ip")
+	if IPAddress == "" {
+		IPAddress = r.Header.Get("X-Forwarded-For")
+	}
+	if IPAddress == "" {
+		IPAddress = r.RemoteAddr
+	}
+	IPAddress = IPAddress[:strings.LastIndex(IPAddress, ":")]
+	resp := *host_name + ",Alive," + uuid + "," + IPAddress
+	w.Header().Set("Access-Control-Allow-Origin", "*")
+	w.Header().Set("Access-Control-Request-Headers", "*")
+	w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
+	w.Write([]byte(resp))
+}
+
+func systemIdServeVersonNumber(w http.ResponseWriter, r *http.Request) {
+	if build_version == "development" {
+		w.Write([]byte("AO-DEV_v" + internal_version))
+	} else {
+		w.Write([]byte("AO-REL_v" + internal_version))
+	}
+}
+
+func systemIdGetDriveStates(w http.ResponseWriter, r *http.Request) {
+	results := [][]string{}
+	results = append(results, []string{
+		"user",
+		"User",
+		"-1B/-1B",
+	})
+	jsonString, _ := json.Marshal(results)
+	utils.SendJSONResponse(w, string(jsonString))
+}

+ 10 - 10
system.info.go

@@ -6,11 +6,11 @@ import (
 	"runtime"
 	"time"
 
-	"imuslab.com/arozos/mod/common"
 	info "imuslab.com/arozos/mod/info/hardwareinfo"
 	usage "imuslab.com/arozos/mod/info/usageinfo"
 	prout "imuslab.com/arozos/mod/prouter"
 	"imuslab.com/arozos/mod/updates"
+	"imuslab.com/arozos/mod/utils"
 )
 
 //InitShowSysInformation xxx
@@ -24,7 +24,7 @@ func SystemInfoInit() {
 		AdminOnly:   false,
 		UserHandler: userHandler,
 		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
+			utils.SendErrorResponse(w, "Permission Denied")
 		},
 	})
 
@@ -33,7 +33,7 @@ func SystemInfoInit() {
 		AdminOnly:   false,
 		UserHandler: userHandler,
 		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
+			utils.SendErrorResponse(w, "Permission Denied")
 		},
 	})
 
@@ -42,7 +42,7 @@ func SystemInfoInit() {
 		AdminOnly:   true,
 		UserHandler: userHandler,
 		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
+			utils.SendErrorResponse(w, "Permission Denied")
 		},
 	})
 
@@ -142,22 +142,22 @@ func SystemInfoInit() {
 			adminRouter.HandleFunc("/system/update/restart", func(w http.ResponseWriter, r *http.Request) {
 				launcherVersion, err := updates.GetLauncherVersion()
 				if err != nil {
-					common.SendErrorResponse(w, err.Error())
+					utils.SendErrorResponse(w, err.Error())
 					return
 				}
-				execute, _ := common.Mv(r, "exec", true)
+				execute, _ := utils.Mv(r, "exec", true)
 				if execute == "true" && r.Method == http.MethodPost {
 					//Do the update
 					systemWideLogger.PrintAndLog("System", "REQUESTING LAUNCHER FOR UPDATE RESTART", nil)
 					executeShutdownSequence()
-					common.SendOK(w)
+					utils.SendOK(w)
 				} else if execute == "true" {
 					//Prevent redirection attack
 					w.WriteHeader(http.StatusMethodNotAllowed)
 					w.Write([]byte("405 - Method Not Allowed"))
 				} else {
 					//Return the launcher message
-					common.SendTextResponse(w, string(launcherVersion))
+					utils.SendTextResponse(w, string(launcherVersion))
 				}
 
 			})
@@ -178,7 +178,7 @@ func InfoHandleGetRuntimeInfo(w http.ResponseWriter, r *http.Request) {
 	}
 
 	js, _ := json.Marshal(runtimeInfo)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }
 
 func InfoHandleTaskInfo(w http.ResponseWriter, r *http.Request) {
@@ -199,5 +199,5 @@ func InfoHandleTaskInfo(w http.ResponseWriter, r *http.Request) {
 	}
 
 	js, _ := json.Marshal(info)
-	common.SendJSONResponse(w, string(js))
+	utils.SendJSONResponse(w, string(js))
 }

+ 151 - 151
system.resetpw.go

@@ -1,151 +1,151 @@
-package main
-
-import (
-	"errors"
-	"log"
-	"net/http"
-
-	auth "imuslab.com/arozos/mod/auth"
-	"imuslab.com/arozos/mod/common"
-)
-
-/*
-	Password Reset Module
-
-	This module exists to serve the password restart page with security check
-*/
-
-func system_resetpw_init() {
-	http.HandleFunc("/system/reset/validateResetKey", system_resetpw_validateResetKeyHandler)
-	http.HandleFunc("/system/reset/confirmPasswordReset", system_resetpw_confirmReset)
-}
-
-//Validate if the ysername and rkey is valid
-func system_resetpw_validateResetKeyHandler(w http.ResponseWriter, r *http.Request) {
-	username, err := common.Mv(r, "username", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid username or key")
-		return
-	}
-	rkey, err := common.Mv(r, "rkey", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid username or key")
-		return
-	}
-
-	if username == "" || rkey == "" {
-		common.SendErrorResponse(w, "Invalid username or rkey")
-		return
-	}
-
-	//Check if the pair is valid
-	err = system_resetpw_validateResetKey(username, rkey)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	common.SendOK(w)
-
-}
-
-func system_resetpw_confirmReset(w http.ResponseWriter, r *http.Request) {
-	username, _ := common.Mv(r, "username", true)
-	rkey, _ := common.Mv(r, "rkey", true)
-	newpw, _ := common.Mv(r, "pw", true)
-	if username == "" || rkey == "" || newpw == "" {
-		common.SendErrorResponse(w, "Internal Server Error")
-		return
-	}
-
-	//Check user exists
-	if !authAgent.UserExists(username) {
-		common.SendErrorResponse(w, "Username not exists")
-		return
-	}
-
-	//Validate rkey
-	err := system_resetpw_validateResetKey(username, rkey)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	//OK to procced
-	newHashedPassword := auth.Hash(newpw)
-	err = sysdb.Write("auth", "passhash/"+username, newHashedPassword)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	common.SendOK(w)
-
-}
-
-func system_resetpw_validateResetKey(username string, key string) error {
-	//Get current password from db
-	passwordInDB := ""
-	err := sysdb.Read("auth", "passhash/"+username, &passwordInDB)
-	if err != nil {
-		return err
-	}
-
-	//Get hashed user key
-	hashedKey := auth.Hash(key)
-	if passwordInDB != hashedKey {
-		return errors.New("Invalid Password Reset Key")
-	}
-
-	return nil
-}
-
-func system_resetpw_handlePasswordReset(w http.ResponseWriter, r *http.Request) {
-	//Check if the user click on this link with reset password key string. If not, ask the user to input one
-	acc, err := common.Mv(r, "acc", false)
-	if err != nil || acc == "" {
-		system_resetpw_serveIdEnterInterface(w, r)
-		return
-	}
-
-	resetkey, err := common.Mv(r, "rkey", false)
-	if err != nil || resetkey == "" {
-		system_resetpw_serveIdEnterInterface(w, r)
-		return
-	}
-
-	//Check if the code is valid
-	err = system_resetpw_validateResetKey(acc, resetkey)
-	if err != nil {
-		common.SendErrorResponse(w, "Invalid username or resetKey")
-		return
-	}
-
-	//OK. Create the New Password Entering UI
-	imageBase64, _ := common.LoadImageAsBase64("./web/" + iconVendor)
-	template, err := common.Templateload("system/reset/resetPasswordTemplate.html", map[string]interface{}{
-		"vendor_logo": imageBase64,
-		"host_name":   *host_name,
-		"username":    acc,
-		"rkey":        resetkey,
-	})
-	if err != nil {
-		log.Fatal(err)
-	}
-	w.Header().Set("Content-Type", "text/html; charset=UTF-8")
-	w.Write([]byte(template))
-}
-
-func system_resetpw_serveIdEnterInterface(w http.ResponseWriter, r *http.Request) {
-	//Reset Key or Username not found, Serve entering interface
-	imageBase64, _ := common.LoadImageAsBase64("./web/" + iconVendor)
-	template, err := common.Templateload("system/reset/resetCodeTemplate.html", map[string]interface{}{
-		"vendor_logo": imageBase64,
-		"host_name":   *host_name,
-	})
-	if err != nil {
-		log.Fatal(err)
-	}
-	w.Header().Set("Content-Type", "text/html; charset=UTF-8")
-	w.Write([]byte(template))
-}
+package main
+
+import (
+	"errors"
+	"log"
+	"net/http"
+
+	auth "imuslab.com/arozos/mod/auth"
+	"imuslab.com/arozos/mod/utils"
+)
+
+/*
+	Password Reset Module
+
+	This module exists to serve the password restart page with security check
+*/
+
+func system_resetpw_init() {
+	http.HandleFunc("/system/reset/validateResetKey", system_resetpw_validateResetKeyHandler)
+	http.HandleFunc("/system/reset/confirmPasswordReset", system_resetpw_confirmReset)
+}
+
+//Validate if the ysername and rkey is valid
+func system_resetpw_validateResetKeyHandler(w http.ResponseWriter, r *http.Request) {
+	username, err := utils.Mv(r, "username", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid username or key")
+		return
+	}
+	rkey, err := utils.Mv(r, "rkey", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid username or key")
+		return
+	}
+
+	if username == "" || rkey == "" {
+		utils.SendErrorResponse(w, "Invalid username or rkey")
+		return
+	}
+
+	//Check if the pair is valid
+	err = system_resetpw_validateResetKey(username, rkey)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	utils.SendOK(w)
+
+}
+
+func system_resetpw_confirmReset(w http.ResponseWriter, r *http.Request) {
+	username, _ := utils.Mv(r, "username", true)
+	rkey, _ := utils.Mv(r, "rkey", true)
+	newpw, _ := utils.Mv(r, "pw", true)
+	if username == "" || rkey == "" || newpw == "" {
+		utils.SendErrorResponse(w, "Internal Server Error")
+		return
+	}
+
+	//Check user exists
+	if !authAgent.UserExists(username) {
+		utils.SendErrorResponse(w, "Username not exists")
+		return
+	}
+
+	//Validate rkey
+	err := system_resetpw_validateResetKey(username, rkey)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	//OK to procced
+	newHashedPassword := auth.Hash(newpw)
+	err = sysdb.Write("auth", "passhash/"+username, newHashedPassword)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	utils.SendOK(w)
+
+}
+
+func system_resetpw_validateResetKey(username string, key string) error {
+	//Get current password from db
+	passwordInDB := ""
+	err := sysdb.Read("auth", "passhash/"+username, &passwordInDB)
+	if err != nil {
+		return err
+	}
+
+	//Get hashed user key
+	hashedKey := auth.Hash(key)
+	if passwordInDB != hashedKey {
+		return errors.New("Invalid Password Reset Key")
+	}
+
+	return nil
+}
+
+func system_resetpw_handlePasswordReset(w http.ResponseWriter, r *http.Request) {
+	//Check if the user click on this link with reset password key string. If not, ask the user to input one
+	acc, err := utils.Mv(r, "acc", false)
+	if err != nil || acc == "" {
+		system_resetpw_serveIdEnterInterface(w, r)
+		return
+	}
+
+	resetkey, err := utils.Mv(r, "rkey", false)
+	if err != nil || resetkey == "" {
+		system_resetpw_serveIdEnterInterface(w, r)
+		return
+	}
+
+	//Check if the code is valid
+	err = system_resetpw_validateResetKey(acc, resetkey)
+	if err != nil {
+		utils.SendErrorResponse(w, "Invalid username or resetKey")
+		return
+	}
+
+	//OK. Create the New Password Entering UI
+	imageBase64, _ := utils.LoadImageAsBase64("./web/" + iconVendor)
+	template, err := utils.Templateload("system/reset/resetPasswordTemplate.html", map[string]interface{}{
+		"vendor_logo": imageBase64,
+		"host_name":   *host_name,
+		"username":    acc,
+		"rkey":        resetkey,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	w.Header().Set("Content-Type", "text/html; charset=UTF-8")
+	w.Write([]byte(template))
+}
+
+func system_resetpw_serveIdEnterInterface(w http.ResponseWriter, r *http.Request) {
+	//Reset Key or Username not found, Serve entering interface
+	imageBase64, _ := utils.LoadImageAsBase64("./web/" + iconVendor)
+	template, err := utils.Templateload("system/reset/resetCodeTemplate.html", map[string]interface{}{
+		"vendor_logo": imageBase64,
+		"host_name":   *host_name,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	w.Header().Set("Content-Type", "text/html; charset=UTF-8")
+	w.Write([]byte(template))
+}

+ 414 - 414
user.go

@@ -1,414 +1,414 @@
-package main
-
-/*
-	User Management System
-
-	Entry points for handler user functions
-*/
-
-import (
-	"encoding/json"
-	"net/http"
-	"strconv"
-	"strings"
-
-	uuid "github.com/satori/go.uuid"
-
-	auth "imuslab.com/arozos/mod/auth"
-	"imuslab.com/arozos/mod/common"
-	module "imuslab.com/arozos/mod/modules"
-	prout "imuslab.com/arozos/mod/prouter"
-	user "imuslab.com/arozos/mod/user"
-)
-
-func UserSystemInit() {
-	//Create a new User Handler
-	uh, err := user.NewUserHandler(sysdb, authAgent, permissionHandler, baseStoragePool, &shareEntryTable)
-	if err != nil {
-		panic(err)
-	}
-	userHandler = uh
-
-	/*
-		router := prout.NewModuleRouter(prout.RouterOption{
-			ModuleName:  "System Settings",
-			AdminOnly:   false,
-			UserHandler: userHandler,
-			DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-				common.SendErrorResponse(w, "Permission Denied")
-			},
-		})
-	*/
-
-	//Create Endpoint Listeners
-	http.HandleFunc("/system/users/list", user_handleList)
-
-	//Everyone logged in should have permission to view their profile and change their password
-	http.HandleFunc("/system/users/userinfo", func(w http.ResponseWriter, r *http.Request) {
-		authAgent.HandleCheckAuth(w, r, user_handleUserInfo)
-	})
-
-	//Interface info should be able to view by everyone logged in
-	http.HandleFunc("/system/users/interfaceinfo", func(w http.ResponseWriter, r *http.Request) {
-		authAgent.HandleCheckAuth(w, r, user_getInterfaceInfo)
-	})
-
-	//Register setting interface for module configuration
-	registerSetting(settingModule{
-		Name:         "My Account",
-		Desc:         "Manage your account and password",
-		IconPath:     "SystemAO/users/img/small_icon.png",
-		Group:        "Users",
-		StartDir:     "SystemAO/users/account.html",
-		RequireAdmin: false,
-	})
-
-	registerSetting(settingModule{
-		Name:         "User List",
-		Desc:         "A list of users registered on this system",
-		IconPath:     "SystemAO/users/img/small_icon.png",
-		Group:        "Users",
-		StartDir:     "SystemAO/users/userList.html",
-		RequireAdmin: true,
-	})
-
-	//Register auth management events that requires user handler
-	adminRouter := prout.NewModuleRouter(prout.RouterOption{
-		ModuleName:  "System Settings",
-		AdminOnly:   true,
-		UserHandler: userHandler,
-		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
-		},
-	})
-
-	//Handle Authentication Unregister Handler
-	adminRouter.HandleFunc("/system/auth/unregister", authAgent.HandleUnregister)
-	adminRouter.HandleFunc("/system/users/editUser", user_handleUserEdit)
-	adminRouter.HandleFunc("/system/users/removeUser", user_handleUserRemove)
-}
-
-//Remove a user from the system
-func user_handleUserRemove(w http.ResponseWriter, r *http.Request) {
-	username, err := common.Mv(r, "username", true)
-	if err != nil {
-		common.SendErrorResponse(w, "Username not defined")
-		return
-	}
-
-	if !authAgent.UserExists(username) {
-		common.SendErrorResponse(w, "User not exists")
-		return
-	}
-
-	userinfo, err := userHandler.GetUserInfoFromUsername(username)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	currentUserinfo, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		//This user has not logged in
-		common.SendErrorResponse(w, "User not logged in")
-		return
-	}
-
-	if currentUserinfo.Username == userinfo.Username {
-		//This user has not logged in
-		common.SendErrorResponse(w, "You can't remove yourself")
-		return
-	}
-
-	//Clear Core User Data
-	userinfo.RemoveUser()
-
-	//Clearn Up FileSystem preferences
-	system_fs_removeUserPreferences(username)
-	common.SendOK(w)
-}
-
-func user_handleUserEdit(w http.ResponseWriter, r *http.Request) {
-	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		//This user has not logged in
-		common.SendErrorResponse(w, "User not logged in")
-		return
-	}
-
-	if userinfo.IsAdmin() == false {
-		//Require admin access
-		common.SendErrorResponse(w, "Permission Denied")
-		return
-	}
-
-	opr, _ := common.Mv(r, "opr", true)
-	username, _ := common.Mv(r, "username", true)
-	if !authAgent.UserExists(username) {
-		common.SendErrorResponse(w, "User not exists")
-		return
-	}
-
-	if opr == "" {
-		//List this user information
-		type returnValue struct {
-			Username  string
-			Icondata  string
-			Usergroup []string
-			Quota     int64
-		}
-		iconData := getUserIcon(username)
-		userGroup, err := permissionHandler.GetUsersPermissionGroup(username)
-		if err != nil {
-			common.SendErrorResponse(w, "Unable to get user group")
-			return
-		}
-
-		//Parse the user permission groupts
-		userGroupNames := []string{}
-		for _, gp := range userGroup {
-			userGroupNames = append(userGroupNames, gp.Name)
-		}
-
-		//Get the user's storaeg quota
-		userinfo, _ := userHandler.GetUserInfoFromUsername(username)
-
-		jsonString, _ := json.Marshal(returnValue{
-			Username:  username,
-			Icondata:  iconData,
-			Usergroup: userGroupNames,
-			Quota:     userinfo.StorageQuota.GetUserStorageQuota(),
-		})
-
-		common.SendJSONResponse(w, string(jsonString))
-	} else if opr == "updateUserGroup" {
-		//Update the target user's group
-		newgroup, err := common.Mv(r, "newgroup", true)
-		if err != nil {
-			systemWideLogger.PrintAndLog("User", err.Error(), err)
-			common.SendErrorResponse(w, "New Group not defined")
-			return
-		}
-
-		newQuota, err := common.Mv(r, "quota", true)
-		if err != nil {
-			systemWideLogger.PrintAndLog("User", err.Error(), err)
-			common.SendErrorResponse(w, "Quota not defined")
-			return
-		}
-
-		quotaInt, err := strconv.Atoi(newQuota)
-		if err != nil {
-			systemWideLogger.PrintAndLog("User", err.Error(), err)
-			common.SendErrorResponse(w, "Invalid Quota Value")
-			return
-		}
-
-		newGroupKeys := []string{}
-		err = json.Unmarshal([]byte(newgroup), &newGroupKeys)
-		if err != nil {
-			systemWideLogger.PrintAndLog("User", err.Error(), err)
-			common.SendErrorResponse(w, "Unable to parse new groups")
-			return
-		}
-
-		if len(newGroupKeys) == 0 {
-			common.SendErrorResponse(w, "User must be in at least one user permission group")
-			return
-		}
-
-		//Check if each group exists
-		for _, thisgp := range newGroupKeys {
-			if !permissionHandler.GroupExists(thisgp) {
-				common.SendErrorResponse(w, "Group not exists, given: "+thisgp)
-				return
-			}
-		}
-
-		//OK to proceed
-		userinfo, err := userHandler.GetUserInfoFromUsername(username)
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-			return
-		}
-
-		//Check if the current user is the only one admin in the administrator group and he is leaving the group
-		allAdministratorGroupUsers, err := userHandler.GetUsersInPermissionGroup("administrator")
-		if err == nil {
-			//Skip checking if error
-			if len(allAdministratorGroupUsers) == 1 && userinfo.UserIsInOneOfTheGroupOf([]string{"administrator"}) && !common.StringInArray(newGroupKeys, "administrator") {
-				//Current administrator group only contain 1 user
-				//This user is in the administrator group
-				//The user want to unset himself from administrator group
-				//Reject the operation as this will cause system lockdown
-				common.SendErrorResponse(w, "You are the only administrator. You cannot remove yourself from the administrator group.")
-				return
-			}
-		}
-
-		//Get the permission groups by their ids
-		newPermissioGroups := userHandler.GetPermissionHandler().GetPermissionGroupByNameList(newGroupKeys)
-
-		//Set the user's permission to these groups
-		userinfo.SetUserPermissionGroup(newPermissioGroups)
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-			return
-		}
-
-		//Write to quota handler
-		userinfo.StorageQuota.SetUserStorageQuota(int64(quotaInt))
-
-		common.SendOK(w)
-	} else if opr == "resetPassword" {
-		//Reset password for this user
-		//Generate a random password for this user
-		tmppassword := uuid.NewV4().String()
-		hashedPassword := auth.Hash(tmppassword)
-		err := sysdb.Write("auth", "passhash/"+username, hashedPassword)
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-			return
-		}
-		//Finish. Send back the reseted password
-		common.SendJSONResponse(w, "\""+tmppassword+"\"")
-
-	} else {
-		common.SendErrorResponse(w, "Not supported opr")
-		return
-	}
-}
-
-//Get the user interface info for the user to launch into
-func user_getInterfaceInfo(w http.ResponseWriter, r *http.Request) {
-	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		//User not logged in
-		common.SendErrorResponse(w, "User not logged in")
-		return
-	}
-
-	interfacingModules := userinfo.GetInterfaceModules()
-
-	interfaceModuleInfos := []module.ModuleInfo{}
-	for _, im := range interfacingModules {
-		interfaceModuleInfos = append(interfaceModuleInfos, *moduleHandler.GetModuleInfoByID(im))
-	}
-
-	jsonString, _ := json.Marshal(interfaceModuleInfos)
-	common.SendJSONResponse(w, string(jsonString))
-}
-
-func user_handleUserInfo(w http.ResponseWriter, r *http.Request) {
-	username, err := authAgent.GetUserName(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
-		return
-	}
-	opr, _ := common.Mv(r, "opr", true)
-
-	if opr == "" {
-		//Listing mode
-		iconData := getUserIcon(username)
-		userGroup, err := permissionHandler.GetUsersPermissionGroup(username)
-		if err != nil {
-			common.SendErrorResponse(w, "Unable to get user group")
-			return
-		}
-
-		userGroupNames := []string{}
-		for _, group := range userGroup {
-			userGroupNames = append(userGroupNames, group.Name)
-		}
-		type returnValue struct {
-			Username  string
-			Icondata  string
-			Usergroup []string
-		}
-		jsonString, _ := json.Marshal(returnValue{
-			Username:  username,
-			Icondata:  iconData,
-			Usergroup: userGroupNames,
-		})
-
-		common.SendJSONResponse(w, string(jsonString))
-		return
-	} else if opr == "changepw" {
-		oldpw, _ := common.Mv(r, "oldpw", true)
-		newpw, _ := common.Mv(r, "newpw", true)
-		if oldpw == "" || newpw == "" {
-			common.SendErrorResponse(w, "Password cannot be empty")
-			return
-		}
-		//valid the old password
-		hashedPassword := auth.Hash(oldpw)
-		var passwordInDB string
-		err = sysdb.Read("auth", "passhash/"+username, &passwordInDB)
-		if hashedPassword != passwordInDB {
-			//Old password entry invalid.
-			common.SendErrorResponse(w, "Invalid old password.")
-			return
-		}
-		//OK! Change user password
-		newHashedPassword := auth.Hash(newpw)
-		sysdb.Write("auth", "passhash/"+username, newHashedPassword)
-		common.SendOK(w)
-	} else if opr == "changeprofilepic" {
-		picdata, _ := common.Mv(r, "picdata", true)
-		if picdata != "" {
-			setUserIcon(username, picdata)
-			common.SendOK(w)
-		} else {
-			common.SendErrorResponse(w, "Empty image data received.")
-			return
-		}
-	} else {
-		common.SendErrorResponse(w, "Not supported opr")
-		return
-	}
-}
-
-func user_handleList(w http.ResponseWriter, r *http.Request) {
-	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		//This user has not logged in
-		common.SendErrorResponse(w, "User not logged in")
-		return
-	}
-	if authAgent.CheckAuth(r) {
-		entries, _ := sysdb.ListTable("auth")
-		var results [][]interface{}
-		for _, keypairs := range entries {
-			if strings.Contains(string(keypairs[0]), "group/") {
-				username := strings.Split(string(keypairs[0]), "/")[1]
-				group := []string{}
-				//Get user icon if it exists in the database
-				userIcon := getUserIcon(username)
-
-				json.Unmarshal(keypairs[1], &group)
-				var thisUserInfo []interface{}
-				thisUserInfo = append(thisUserInfo, username)
-				thisUserInfo = append(thisUserInfo, group)
-				thisUserInfo = append(thisUserInfo, userIcon)
-				thisUserInfo = append(thisUserInfo, username == userinfo.Username)
-				results = append(results, thisUserInfo)
-			}
-		}
-
-		jsonString, _ := json.Marshal(results)
-		common.SendJSONResponse(w, string(jsonString))
-	} else {
-		common.SendErrorResponse(w, "Permission Denied")
-	}
-}
-
-func getUserIcon(username string) string {
-	var userIconpath []byte
-	sysdb.Read("auth", "profilepic/"+username, &userIconpath)
-	return string(userIconpath)
-}
-
-func setUserIcon(username string, base64data string) {
-	sysdb.Write("auth", "profilepic/"+username, []byte(base64data))
-	return
-}
+package main
+
+/*
+	User Management System
+
+	Entry points for handler user functions
+*/
+
+import (
+	"encoding/json"
+	"net/http"
+	"strconv"
+	"strings"
+
+	uuid "github.com/satori/go.uuid"
+
+	auth "imuslab.com/arozos/mod/auth"
+	module "imuslab.com/arozos/mod/modules"
+	prout "imuslab.com/arozos/mod/prouter"
+	user "imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/utils"
+)
+
+func UserSystemInit() {
+	//Create a new User Handler
+	uh, err := user.NewUserHandler(sysdb, authAgent, permissionHandler, baseStoragePool, &shareEntryTable)
+	if err != nil {
+		panic(err)
+	}
+	userHandler = uh
+
+	/*
+		router := prout.NewModuleRouter(prout.RouterOption{
+			ModuleName:  "System Settings",
+			AdminOnly:   false,
+			UserHandler: userHandler,
+			DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+				utils.SendErrorResponse(w, "Permission Denied")
+			},
+		})
+	*/
+
+	//Create Endpoint Listeners
+	http.HandleFunc("/system/users/list", user_handleList)
+
+	//Everyone logged in should have permission to view their profile and change their password
+	http.HandleFunc("/system/users/userinfo", func(w http.ResponseWriter, r *http.Request) {
+		authAgent.HandleCheckAuth(w, r, user_handleUserInfo)
+	})
+
+	//Interface info should be able to view by everyone logged in
+	http.HandleFunc("/system/users/interfaceinfo", func(w http.ResponseWriter, r *http.Request) {
+		authAgent.HandleCheckAuth(w, r, user_getInterfaceInfo)
+	})
+
+	//Register setting interface for module configuration
+	registerSetting(settingModule{
+		Name:         "My Account",
+		Desc:         "Manage your account and password",
+		IconPath:     "SystemAO/users/img/small_icon.png",
+		Group:        "Users",
+		StartDir:     "SystemAO/users/account.html",
+		RequireAdmin: false,
+	})
+
+	registerSetting(settingModule{
+		Name:         "User List",
+		Desc:         "A list of users registered on this system",
+		IconPath:     "SystemAO/users/img/small_icon.png",
+		Group:        "Users",
+		StartDir:     "SystemAO/users/userList.html",
+		RequireAdmin: true,
+	})
+
+	//Register auth management events that requires user handler
+	adminRouter := prout.NewModuleRouter(prout.RouterOption{
+		ModuleName:  "System Settings",
+		AdminOnly:   true,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			utils.SendErrorResponse(w, "Permission Denied")
+		},
+	})
+
+	//Handle Authentication Unregister Handler
+	adminRouter.HandleFunc("/system/auth/unregister", authAgent.HandleUnregister)
+	adminRouter.HandleFunc("/system/users/editUser", user_handleUserEdit)
+	adminRouter.HandleFunc("/system/users/removeUser", user_handleUserRemove)
+}
+
+//Remove a user from the system
+func user_handleUserRemove(w http.ResponseWriter, r *http.Request) {
+	username, err := utils.Mv(r, "username", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "Username not defined")
+		return
+	}
+
+	if !authAgent.UserExists(username) {
+		utils.SendErrorResponse(w, "User not exists")
+		return
+	}
+
+	userinfo, err := userHandler.GetUserInfoFromUsername(username)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	currentUserinfo, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		//This user has not logged in
+		utils.SendErrorResponse(w, "User not logged in")
+		return
+	}
+
+	if currentUserinfo.Username == userinfo.Username {
+		//This user has not logged in
+		utils.SendErrorResponse(w, "You can't remove yourself")
+		return
+	}
+
+	//Clear Core User Data
+	userinfo.RemoveUser()
+
+	//Clearn Up FileSystem preferences
+	system_fs_removeUserPreferences(username)
+	utils.SendOK(w)
+}
+
+func user_handleUserEdit(w http.ResponseWriter, r *http.Request) {
+	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		//This user has not logged in
+		utils.SendErrorResponse(w, "User not logged in")
+		return
+	}
+
+	if userinfo.IsAdmin() == false {
+		//Require admin access
+		utils.SendErrorResponse(w, "Permission Denied")
+		return
+	}
+
+	opr, _ := utils.Mv(r, "opr", true)
+	username, _ := utils.Mv(r, "username", true)
+	if !authAgent.UserExists(username) {
+		utils.SendErrorResponse(w, "User not exists")
+		return
+	}
+
+	if opr == "" {
+		//List this user information
+		type returnValue struct {
+			Username  string
+			Icondata  string
+			Usergroup []string
+			Quota     int64
+		}
+		iconData := getUserIcon(username)
+		userGroup, err := permissionHandler.GetUsersPermissionGroup(username)
+		if err != nil {
+			utils.SendErrorResponse(w, "Unable to get user group")
+			return
+		}
+
+		//Parse the user permission groupts
+		userGroupNames := []string{}
+		for _, gp := range userGroup {
+			userGroupNames = append(userGroupNames, gp.Name)
+		}
+
+		//Get the user's storaeg quota
+		userinfo, _ := userHandler.GetUserInfoFromUsername(username)
+
+		jsonString, _ := json.Marshal(returnValue{
+			Username:  username,
+			Icondata:  iconData,
+			Usergroup: userGroupNames,
+			Quota:     userinfo.StorageQuota.GetUserStorageQuota(),
+		})
+
+		utils.SendJSONResponse(w, string(jsonString))
+	} else if opr == "updateUserGroup" {
+		//Update the target user's group
+		newgroup, err := utils.Mv(r, "newgroup", true)
+		if err != nil {
+			systemWideLogger.PrintAndLog("User", err.Error(), err)
+			utils.SendErrorResponse(w, "New Group not defined")
+			return
+		}
+
+		newQuota, err := utils.Mv(r, "quota", true)
+		if err != nil {
+			systemWideLogger.PrintAndLog("User", err.Error(), err)
+			utils.SendErrorResponse(w, "Quota not defined")
+			return
+		}
+
+		quotaInt, err := strconv.Atoi(newQuota)
+		if err != nil {
+			systemWideLogger.PrintAndLog("User", err.Error(), err)
+			utils.SendErrorResponse(w, "Invalid Quota Value")
+			return
+		}
+
+		newGroupKeys := []string{}
+		err = json.Unmarshal([]byte(newgroup), &newGroupKeys)
+		if err != nil {
+			systemWideLogger.PrintAndLog("User", err.Error(), err)
+			utils.SendErrorResponse(w, "Unable to parse new groups")
+			return
+		}
+
+		if len(newGroupKeys) == 0 {
+			utils.SendErrorResponse(w, "User must be in at least one user permission group")
+			return
+		}
+
+		//Check if each group exists
+		for _, thisgp := range newGroupKeys {
+			if !permissionHandler.GroupExists(thisgp) {
+				utils.SendErrorResponse(w, "Group not exists, given: "+thisgp)
+				return
+			}
+		}
+
+		//OK to proceed
+		userinfo, err := userHandler.GetUserInfoFromUsername(username)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+
+		//Check if the current user is the only one admin in the administrator group and he is leaving the group
+		allAdministratorGroupUsers, err := userHandler.GetUsersInPermissionGroup("administrator")
+		if err == nil {
+			//Skip checking if error
+			if len(allAdministratorGroupUsers) == 1 && userinfo.UserIsInOneOfTheGroupOf([]string{"administrator"}) && !utils.StringInArray(newGroupKeys, "administrator") {
+				//Current administrator group only contain 1 user
+				//This user is in the administrator group
+				//The user want to unset himself from administrator group
+				//Reject the operation as this will cause system lockdown
+				utils.SendErrorResponse(w, "You are the only administrator. You cannot remove yourself from the administrator group.")
+				return
+			}
+		}
+
+		//Get the permission groups by their ids
+		newPermissioGroups := userHandler.GetPermissionHandler().GetPermissionGroupByNameList(newGroupKeys)
+
+		//Set the user's permission to these groups
+		userinfo.SetUserPermissionGroup(newPermissioGroups)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+
+		//Write to quota handler
+		userinfo.StorageQuota.SetUserStorageQuota(int64(quotaInt))
+
+		utils.SendOK(w)
+	} else if opr == "resetPassword" {
+		//Reset password for this user
+		//Generate a random password for this user
+		tmppassword := uuid.NewV4().String()
+		hashedPassword := auth.Hash(tmppassword)
+		err := sysdb.Write("auth", "passhash/"+username, hashedPassword)
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+		//Finish. Send back the reseted password
+		utils.SendJSONResponse(w, "\""+tmppassword+"\"")
+
+	} else {
+		utils.SendErrorResponse(w, "Not supported opr")
+		return
+	}
+}
+
+//Get the user interface info for the user to launch into
+func user_getInterfaceInfo(w http.ResponseWriter, r *http.Request) {
+	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		//User not logged in
+		utils.SendErrorResponse(w, "User not logged in")
+		return
+	}
+
+	interfacingModules := userinfo.GetInterfaceModules()
+
+	interfaceModuleInfos := []module.ModuleInfo{}
+	for _, im := range interfacingModules {
+		interfaceModuleInfos = append(interfaceModuleInfos, *moduleHandler.GetModuleInfoByID(im))
+	}
+
+	jsonString, _ := json.Marshal(interfaceModuleInfos)
+	utils.SendJSONResponse(w, string(jsonString))
+}
+
+func user_handleUserInfo(w http.ResponseWriter, r *http.Request) {
+	username, err := authAgent.GetUserName(w, r)
+	if err != nil {
+		utils.SendErrorResponse(w, "User not logged in")
+		return
+	}
+	opr, _ := utils.Mv(r, "opr", true)
+
+	if opr == "" {
+		//Listing mode
+		iconData := getUserIcon(username)
+		userGroup, err := permissionHandler.GetUsersPermissionGroup(username)
+		if err != nil {
+			utils.SendErrorResponse(w, "Unable to get user group")
+			return
+		}
+
+		userGroupNames := []string{}
+		for _, group := range userGroup {
+			userGroupNames = append(userGroupNames, group.Name)
+		}
+		type returnValue struct {
+			Username  string
+			Icondata  string
+			Usergroup []string
+		}
+		jsonString, _ := json.Marshal(returnValue{
+			Username:  username,
+			Icondata:  iconData,
+			Usergroup: userGroupNames,
+		})
+
+		utils.SendJSONResponse(w, string(jsonString))
+		return
+	} else if opr == "changepw" {
+		oldpw, _ := utils.Mv(r, "oldpw", true)
+		newpw, _ := utils.Mv(r, "newpw", true)
+		if oldpw == "" || newpw == "" {
+			utils.SendErrorResponse(w, "Password cannot be empty")
+			return
+		}
+		//valid the old password
+		hashedPassword := auth.Hash(oldpw)
+		var passwordInDB string
+		err = sysdb.Read("auth", "passhash/"+username, &passwordInDB)
+		if hashedPassword != passwordInDB {
+			//Old password entry invalid.
+			utils.SendErrorResponse(w, "Invalid old password.")
+			return
+		}
+		//OK! Change user password
+		newHashedPassword := auth.Hash(newpw)
+		sysdb.Write("auth", "passhash/"+username, newHashedPassword)
+		utils.SendOK(w)
+	} else if opr == "changeprofilepic" {
+		picdata, _ := utils.Mv(r, "picdata", true)
+		if picdata != "" {
+			setUserIcon(username, picdata)
+			utils.SendOK(w)
+		} else {
+			utils.SendErrorResponse(w, "Empty image data received.")
+			return
+		}
+	} else {
+		utils.SendErrorResponse(w, "Not supported opr")
+		return
+	}
+}
+
+func user_handleList(w http.ResponseWriter, r *http.Request) {
+	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		//This user has not logged in
+		utils.SendErrorResponse(w, "User not logged in")
+		return
+	}
+	if authAgent.CheckAuth(r) {
+		entries, _ := sysdb.ListTable("auth")
+		var results [][]interface{}
+		for _, keypairs := range entries {
+			if strings.Contains(string(keypairs[0]), "group/") {
+				username := strings.Split(string(keypairs[0]), "/")[1]
+				group := []string{}
+				//Get user icon if it exists in the database
+				userIcon := getUserIcon(username)
+
+				json.Unmarshal(keypairs[1], &group)
+				var thisUserInfo []interface{}
+				thisUserInfo = append(thisUserInfo, username)
+				thisUserInfo = append(thisUserInfo, group)
+				thisUserInfo = append(thisUserInfo, userIcon)
+				thisUserInfo = append(thisUserInfo, username == userinfo.Username)
+				results = append(results, thisUserInfo)
+			}
+		}
+
+		jsonString, _ := json.Marshal(results)
+		utils.SendJSONResponse(w, string(jsonString))
+	} else {
+		utils.SendErrorResponse(w, "Permission Denied")
+	}
+}
+
+func getUserIcon(username string) string {
+	var userIconpath []byte
+	sysdb.Read("auth", "profilepic/"+username, &userIconpath)
+	return string(userIconpath)
+}
+
+func setUserIcon(username string, base64data string) {
+	sysdb.Write("auth", "profilepic/"+username, []byte(base64data))
+	return
+}

+ 268 - 268
wifi.go

@@ -1,268 +1,268 @@
-package main
-
-import (
-	"encoding/json"
-	"net/http"
-	"strings"
-
-	"imuslab.com/arozos/mod/common"
-	wifi "imuslab.com/arozos/mod/network/wifi"
-	prout "imuslab.com/arozos/mod/prouter"
-)
-
-/*
-	Network WiFi Module
-
-	This module handle wifi connections and scanning on the devices that support wpa_supplicant like the Raspberry Pi
-	Require service launch with Dbus (Work well on stock Raspberry Pi OS)
-*/
-
-var (
-	wifiManager *wifi.WiFiManager
-)
-
-func WiFiInit() {
-	//Start the Wifi Manager
-	wifiManager = wifi.NewWiFiManager(sysdb, sudo_mode, *wpa_supplicant_path, *wan_interface_name)
-
-	//Only activate script on linux and if hardware management is enabled
-	router := prout.NewModuleRouter(prout.RouterOption{
-		ModuleName:  "System Setting",
-		AdminOnly:   true,
-		UserHandler: userHandler,
-		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
-			common.SendErrorResponse(w, "Permission Denied")
-		},
-	})
-
-	//Allow hardware management. Generate the endpoint for WiFi Control
-	if *allow_hardware_management {
-
-		//Register endpoints
-		router.HandleFunc("/system/network/scanWifi", network_wifi_handleScan)
-		router.HandleFunc("/system/network/connectWifi", network_wifi_handleConnect)
-		router.HandleFunc("/system/network/removeWifi", network_wifi_handleWiFiRemove)
-		router.HandleFunc("/system/network/wifiinfo", network_wifi_handleWiFiInfo)
-
-		//Sudo mode only for wifi toggle
-		if sudo_mode {
-			router.HandleFunc("/system/network/power", network_wifi_handleWiFiPower)
-		}
-
-		//Register WiFi Settings if system have WiFi interface
-		wlanInterfaces, _ := wifiManager.GetWirelessInterfaces()
-		if len(wlanInterfaces) > 0 {
-			//Contain at least 1 wireless interface Register System Settings
-			registerSetting(settingModule{
-				Name:     "WiFi Info",
-				Desc:     "Current Connected WiFi Information",
-				IconPath: "SystemAO/network/img/WiFi.png",
-				Group:    "Network",
-				StartDir: "SystemAO/network/wifiinfo.html",
-			})
-			registerSetting(settingModule{
-				Name:         "WiFi Settings",
-				Desc:         "Setup WiFi Conenctions",
-				IconPath:     "SystemAO/network/img/WiFi.png",
-				Group:        "Network",
-				StartDir:     "SystemAO/network/wifi.html",
-				RequireAdmin: true,
-			})
-		}
-	}
-
-}
-
-func network_wifi_handleWiFiPower(w http.ResponseWriter, r *http.Request) {
-	//Require admin permission to scan and connect wifi
-	user, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, "Internal Server Error")
-		return
-	}
-
-	if !user.IsAdmin() {
-		common.SendErrorResponse(w, "Permission Denied")
-		return
-	}
-
-	status, _ := common.Mv(r, "status", true)
-	if status == "" {
-		//Show current power status
-		infs, err := wifiManager.GetWirelessInterfaces()
-		if err != nil {
-			common.SendErrorResponse(w, err.Error())
-			return
-		}
-
-		type WlanInterfaceStatus struct {
-			Name    string
-			Running bool
-		}
-
-		results := []WlanInterfaceStatus{}
-		for _, inf := range infs {
-			status, _ := wifiManager.GetInterfacePowerStatuts(strings.TrimSpace(inf))
-			results = append(results, WlanInterfaceStatus{
-				Name:    inf,
-				Running: status,
-			})
-		}
-
-		js, _ := json.Marshal(results)
-		common.SendJSONResponse(w, string(js))
-
-	} else {
-		//Change current power status
-		wlaninterface, err := common.Mv(r, "interface", true)
-		if err != nil {
-			common.SendErrorResponse(w, "Invalid interface")
-			return
-		}
-
-		if status == "on" {
-			err := wifiManager.SetInterfacePower(wlaninterface, true)
-			if err != nil {
-				common.SendErrorResponse(w, err.Error())
-			} else {
-				common.SendOK(w)
-			}
-		} else if status == "off" {
-			err := wifiManager.SetInterfacePower(wlaninterface, false)
-			if err != nil {
-				common.SendErrorResponse(w, err.Error())
-			} else {
-				common.SendOK(w)
-			}
-		} else {
-			common.SendErrorResponse(w, "Invalid status")
-		}
-	}
-
-}
-
-func network_wifi_handleScan(w http.ResponseWriter, r *http.Request) {
-	//Require admin permission to scan and connect wifi
-	user, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, "Internal Server Error")
-		return
-	}
-
-	if !user.IsAdmin() {
-		common.SendErrorResponse(w, "Permission Denied")
-		return
-	}
-
-	//Get a list of current on system wireless interface
-	wirelessInterfaces, err := wifiManager.GetWirelessInterfaces()
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-
-	if len(wirelessInterfaces) == 0 {
-		//No wireless interface
-		common.SendErrorResponse(w, "Wireless Interface Not Found")
-		return
-	}
-
-	//Get the first ethernet interface and use it to scan nearby wifi
-	scannedWiFiInfo, err := wifiManager.ScanNearbyWiFi(wirelessInterfaces[0])
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-	jsonString, _ := json.Marshal(scannedWiFiInfo)
-	common.SendJSONResponse(w, string(jsonString))
-}
-
-func network_wifi_handleConnect(w http.ResponseWriter, r *http.Request) {
-	user, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, "Internal Server Error")
-		return
-	}
-	//Get information from client and create a new network config file
-	if !user.IsAdmin() {
-		common.SendErrorResponse(w, "Permission denied")
-		return
-	}
-
-	ssid, err := common.Mv(r, "ESSID", true)
-	if err != nil {
-		common.SendErrorResponse(w, "ESSID not given")
-		return
-	}
-	connType, _ := common.Mv(r, "ConnType", true)
-	password, _ := common.Mv(r, "pwd", true)
-	systemWideLogger.PrintAndLog("WiFi", "WiFi Switch Request Received. Genering Network Configuration...", nil)
-
-	identity, err := common.Mv(r, "identity", true)
-	if err != nil {
-		identity = ""
-	}
-
-	result, err := wifiManager.ConnectWiFi(ssid, password, connType, identity)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-	jsonString, err := json.Marshal(result)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-		return
-	}
-	common.SendJSONResponse(w, string(jsonString))
-
-	systemWideLogger.PrintAndLog("WiFi", "WiFi Connected", nil)
-
-}
-
-func network_wifi_handleWiFiRemove(w http.ResponseWriter, r *http.Request) {
-	//Require admin permission to scan and connect wifi
-	user, err := userHandler.GetUserInfoFromRequest(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, "Internal Server Error")
-		return
-	}
-
-	if !user.IsAdmin() {
-		common.SendErrorResponse(w, "Permission Denied")
-		return
-	}
-
-	//Get ESSID from post request
-	ESSID, err := common.Mv(r, "ESSID", true)
-	if err != nil {
-		common.SendErrorResponse(w, "ESSID not given")
-		return
-	}
-
-	err = wifiManager.RemoveWifi(ESSID)
-	if err != nil {
-		common.SendErrorResponse(w, err.Error())
-	}
-	common.SendOK(w)
-}
-
-func network_wifi_handleWiFiInfo(w http.ResponseWriter, r *http.Request) {
-	//Get and return the current conencted WiFi Information
-	_, err := authAgent.GetUserName(w, r)
-	if err != nil {
-		common.SendErrorResponse(w, "User not logged in")
-		return
-	}
-
-	ESSID, interfaceName, err := wifiManager.GetConnectedWiFi()
-	if err != nil {
-		common.SendErrorResponse(w, "Failed to retrieve WiFi Information")
-		return
-	}
-
-	jsonString, _ := json.Marshal(map[string]string{
-		"ESSID":     ESSID,
-		"Interface": interfaceName,
-	})
-	common.SendJSONResponse(w, string(jsonString))
-}
+package main
+
+import (
+	"encoding/json"
+	"net/http"
+	"strings"
+
+	wifi "imuslab.com/arozos/mod/network/wifi"
+	prout "imuslab.com/arozos/mod/prouter"
+	"imuslab.com/arozos/mod/utils"
+)
+
+/*
+	Network WiFi Module
+
+	This module handle wifi connections and scanning on the devices that support wpa_supplicant like the Raspberry Pi
+	Require service launch with Dbus (Work well on stock Raspberry Pi OS)
+*/
+
+var (
+	wifiManager *wifi.WiFiManager
+)
+
+func WiFiInit() {
+	//Start the Wifi Manager
+	wifiManager = wifi.NewWiFiManager(sysdb, sudo_mode, *wpa_supplicant_path, *wan_interface_name)
+
+	//Only activate script on linux and if hardware management is enabled
+	router := prout.NewModuleRouter(prout.RouterOption{
+		ModuleName:  "System Setting",
+		AdminOnly:   true,
+		UserHandler: userHandler,
+		DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
+			utils.SendErrorResponse(w, "Permission Denied")
+		},
+	})
+
+	//Allow hardware management. Generate the endpoint for WiFi Control
+	if *allow_hardware_management {
+
+		//Register endpoints
+		router.HandleFunc("/system/network/scanWifi", network_wifi_handleScan)
+		router.HandleFunc("/system/network/connectWifi", network_wifi_handleConnect)
+		router.HandleFunc("/system/network/removeWifi", network_wifi_handleWiFiRemove)
+		router.HandleFunc("/system/network/wifiinfo", network_wifi_handleWiFiInfo)
+
+		//Sudo mode only for wifi toggle
+		if sudo_mode {
+			router.HandleFunc("/system/network/power", network_wifi_handleWiFiPower)
+		}
+
+		//Register WiFi Settings if system have WiFi interface
+		wlanInterfaces, _ := wifiManager.GetWirelessInterfaces()
+		if len(wlanInterfaces) > 0 {
+			//Contain at least 1 wireless interface Register System Settings
+			registerSetting(settingModule{
+				Name:     "WiFi Info",
+				Desc:     "Current Connected WiFi Information",
+				IconPath: "SystemAO/network/img/WiFi.png",
+				Group:    "Network",
+				StartDir: "SystemAO/network/wifiinfo.html",
+			})
+			registerSetting(settingModule{
+				Name:         "WiFi Settings",
+				Desc:         "Setup WiFi Conenctions",
+				IconPath:     "SystemAO/network/img/WiFi.png",
+				Group:        "Network",
+				StartDir:     "SystemAO/network/wifi.html",
+				RequireAdmin: true,
+			})
+		}
+	}
+
+}
+
+func network_wifi_handleWiFiPower(w http.ResponseWriter, r *http.Request) {
+	//Require admin permission to scan and connect wifi
+	user, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		utils.SendErrorResponse(w, "Internal Server Error")
+		return
+	}
+
+	if !user.IsAdmin() {
+		utils.SendErrorResponse(w, "Permission Denied")
+		return
+	}
+
+	status, _ := utils.Mv(r, "status", true)
+	if status == "" {
+		//Show current power status
+		infs, err := wifiManager.GetWirelessInterfaces()
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+
+		type WlanInterfaceStatus struct {
+			Name    string
+			Running bool
+		}
+
+		results := []WlanInterfaceStatus{}
+		for _, inf := range infs {
+			status, _ := wifiManager.GetInterfacePowerStatuts(strings.TrimSpace(inf))
+			results = append(results, WlanInterfaceStatus{
+				Name:    inf,
+				Running: status,
+			})
+		}
+
+		js, _ := json.Marshal(results)
+		utils.SendJSONResponse(w, string(js))
+
+	} else {
+		//Change current power status
+		wlaninterface, err := utils.Mv(r, "interface", true)
+		if err != nil {
+			utils.SendErrorResponse(w, "Invalid interface")
+			return
+		}
+
+		if status == "on" {
+			err := wifiManager.SetInterfacePower(wlaninterface, true)
+			if err != nil {
+				utils.SendErrorResponse(w, err.Error())
+			} else {
+				utils.SendOK(w)
+			}
+		} else if status == "off" {
+			err := wifiManager.SetInterfacePower(wlaninterface, false)
+			if err != nil {
+				utils.SendErrorResponse(w, err.Error())
+			} else {
+				utils.SendOK(w)
+			}
+		} else {
+			utils.SendErrorResponse(w, "Invalid status")
+		}
+	}
+
+}
+
+func network_wifi_handleScan(w http.ResponseWriter, r *http.Request) {
+	//Require admin permission to scan and connect wifi
+	user, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		utils.SendErrorResponse(w, "Internal Server Error")
+		return
+	}
+
+	if !user.IsAdmin() {
+		utils.SendErrorResponse(w, "Permission Denied")
+		return
+	}
+
+	//Get a list of current on system wireless interface
+	wirelessInterfaces, err := wifiManager.GetWirelessInterfaces()
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+
+	if len(wirelessInterfaces) == 0 {
+		//No wireless interface
+		utils.SendErrorResponse(w, "Wireless Interface Not Found")
+		return
+	}
+
+	//Get the first ethernet interface and use it to scan nearby wifi
+	scannedWiFiInfo, err := wifiManager.ScanNearbyWiFi(wirelessInterfaces[0])
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+	jsonString, _ := json.Marshal(scannedWiFiInfo)
+	utils.SendJSONResponse(w, string(jsonString))
+}
+
+func network_wifi_handleConnect(w http.ResponseWriter, r *http.Request) {
+	user, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		utils.SendErrorResponse(w, "Internal Server Error")
+		return
+	}
+	//Get information from client and create a new network config file
+	if !user.IsAdmin() {
+		utils.SendErrorResponse(w, "Permission denied")
+		return
+	}
+
+	ssid, err := utils.Mv(r, "ESSID", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "ESSID not given")
+		return
+	}
+	connType, _ := utils.Mv(r, "ConnType", true)
+	password, _ := utils.Mv(r, "pwd", true)
+	systemWideLogger.PrintAndLog("WiFi", "WiFi Switch Request Received. Genering Network Configuration...", nil)
+
+	identity, err := utils.Mv(r, "identity", true)
+	if err != nil {
+		identity = ""
+	}
+
+	result, err := wifiManager.ConnectWiFi(ssid, password, connType, identity)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+	jsonString, err := json.Marshal(result)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+		return
+	}
+	utils.SendJSONResponse(w, string(jsonString))
+
+	systemWideLogger.PrintAndLog("WiFi", "WiFi Connected", nil)
+
+}
+
+func network_wifi_handleWiFiRemove(w http.ResponseWriter, r *http.Request) {
+	//Require admin permission to scan and connect wifi
+	user, err := userHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		utils.SendErrorResponse(w, "Internal Server Error")
+		return
+	}
+
+	if !user.IsAdmin() {
+		utils.SendErrorResponse(w, "Permission Denied")
+		return
+	}
+
+	//Get ESSID from post request
+	ESSID, err := utils.Mv(r, "ESSID", true)
+	if err != nil {
+		utils.SendErrorResponse(w, "ESSID not given")
+		return
+	}
+
+	err = wifiManager.RemoveWifi(ESSID)
+	if err != nil {
+		utils.SendErrorResponse(w, err.Error())
+	}
+	utils.SendOK(w)
+}
+
+func network_wifi_handleWiFiInfo(w http.ResponseWriter, r *http.Request) {
+	//Get and return the current conencted WiFi Information
+	_, err := authAgent.GetUserName(w, r)
+	if err != nil {
+		utils.SendErrorResponse(w, "User not logged in")
+		return
+	}
+
+	ESSID, interfaceName, err := wifiManager.GetConnectedWiFi()
+	if err != nil {
+		utils.SendErrorResponse(w, "Failed to retrieve WiFi Information")
+		return
+	}
+
+	jsonString, _ := json.Marshal(map[string]string{
+		"ESSID":     ESSID,
+		"Interface": interfaceName,
+	})
+	utils.SendJSONResponse(w, string(jsonString))
+}

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff