Browse Source

Added basic subservice and removed legacy stuffs

TC pushbot 5 4 năm trước cách đây
mục cha
commit
60f0d8f74b
55 tập tin đã thay đổi với 854 bổ sung3253 xóa
  1. 6 0
      .gitignore
  2. 0 248
      legacy/disabled/auth.go
  3. 0 47
      legacy/disabled/hardware.power.go
  4. 0 25
      legacy/disabled/language.go
  5. 0 326
      legacy/disabled/module.Music.go
  6. 0 114
      legacy/disabled/module.package.go
  7. 0 161
      legacy/disabled/network.ip2country.go
  8. 0 178
      legacy/disabled/system.boot.go
  9. 0 302
      legacy/disabled/system.disk.quota.go
  10. 0 381
      legacy/disabled/system.disk.smart.go
  11. 0 150
      legacy/disabled/system.disk.space.go
  12. 0 264
      legacy/disabled/system.permission.go
  13. 0 114
      legacy/disabled/system.power.go
  14. 0 150
      legacy/disabled/system.resetpw.go
  15. 0 237
      legacy/disabled/system.users.go
  16. 0 330
      legacy/module.Photo.go_disabled
  17. 0 138
      legacy/module.Video.go_disabled
  18. 0 25
      legacy/module.dummy.go_disabled
  19. 0 63
      legacy/module.notepadA.go_disabled
  20. 1 0
      subservice/ArSamba
  21. 5 0
      subservice/WsTTY/README.md
  22. BIN
      subservice/WsTTY/WsTTY_linux_amd64
  23. BIN
      subservice/WsTTY/WsTTY_linux_arm
  24. BIN
      subservice/WsTTY/WsTTY_linux_arm64
  25. 2 0
      subservice/WsTTY/bashstart
  26. 18 0
      subservice/WsTTY/build.sh
  27. 222 0
      subservice/WsTTY/common.go
  28. 3 0
      subservice/WsTTY/go.mod
  29. 21 0
      subservice/WsTTY/gotty/LICENSE
  30. BIN
      subservice/WsTTY/gotty/gotty_linux_amd64
  31. BIN
      subservice/WsTTY/gotty/gotty_linux_arm
  32. BIN
      subservice/WsTTY/gotty/gotty_linux_arm64
  33. 89 0
      subservice/WsTTY/main.go
  34. 70 0
      subservice/WsTTY/mod/aroz/aroz.go
  35. BIN
      subservice/WsTTY/mod/aroz/doc.txt
  36. 1 0
      subservice/WsTTY/src/gotty
  37. 0 0
      subservice/demo/.disabled
  38. 14 0
      subservice/demo/agi/listdesktop.js
  39. 70 0
      subservice/demo/aroz/aroz.go
  40. 38 0
      subservice/demo/aroz/doc.txt
  41. 31 0
      subservice/demo/build.bat
  42. 18 0
      subservice/demo/build.sh
  43. BIN
      subservice/demo/demo.exe
  44. BIN
      subservice/demo/demo_darwin_amd64
  45. BIN
      subservice/demo/demo_linux_amd64
  46. BIN
      subservice/demo/demo_linux_arm
  47. BIN
      subservice/demo/demo_linux_arm64
  48. 42 0
      subservice/demo/deprecated/aomodule.go
  49. 3 0
      subservice/demo/go.mod
  50. 116 0
      subservice/demo/main.go
  51. 1 0
      subservice/demo/test.bat
  52. 19 0
      subservice/demo/web/embedded.html
  53. 61 0
      subservice/demo/web/home.html
  54. BIN
      subservice/demo/web/icon.png
  55. 3 0
      web/desktop.system

+ 6 - 0
.gitignore

@@ -33,8 +33,14 @@ web/teleprompter/*
 
 #Subservice related
 subservice/*
+
+!subservice/ArSamba
 !subservice/ArSamba/*
+
+!subservice/demo
 !subservice/demo/*
+
+!subservice/WsTTY/
 !subservice/WsTTY/*
 
 #Binary related

+ 0 - 248
legacy/disabled/auth.go

@@ -1,248 +0,0 @@
-package main
-
-import (
-    "net/http"
-    "strings"
-    "log"
-    "encoding/json"
-
-    "imuslab.com/arozos/mod/auth"
-)
-
-
-var (
-    // key must be 16, 24 or 32 bytes long (AES-128, AES-192 or AES-256)
-    key = []byte("super-secret-key") //To be migrated to input flags
-)
-
-
-/*
-    Initiation of web services endpoints from main()
-
-    This function should be the preparation of auth services and register the url for auth services only
-    Do not put in any computational algorithms
-*/
-func authRegisterHandlerEndpoints(authAgent *auth.AuthAgent){
-    //Initiate auth services with system database
-    authAgent = auth.NewAuthenticationAgent("ao_auth", key, sysdb)
-
-    //Handle auth API
-    http.HandleFunc("/system/auth/login", authAgent.HandleLogin)
-    http.HandleFunc("/system/auth/logout", authAgent.HandleLogout)
-    http.HandleFunc("/system/auth/checkLogin", authAgent.CheckLogin)
-    http.HandleFunc("/system/auth/register", authAgent.HandleRegister)  //Require implemtantion of group check
-    http.HandleFunc("/system/auth/unregister", authAgent.HandleUnregister) //Require implementation of admin check
-    
-    //Handle other related APUs
-    http.HandleFunc("/system/auth/reflectIP", system_auth_getIPAddress)
-    http.HandleFunc("/system/auth/checkPublicRegister", system_auth_checkPublicRegister)
-    log.Println("ArOZ Online Authentication Service Loaded");
-
-
-    if (*allow_public_registry){
-        //Allow public registry. Create setting interface for this page
-        registerSetting(settingModule{
-            Name:     "Public Register",
-            Desc:     "Settings for public registration",
-            IconPath: "SystemAO/auth/img/small_icon.png",
-            Group:    "Users",
-            StartDir: "SystemAO/auth/regsetting.html",
-            RequireAdmin: true,
-        })
-
-
-        //Register the direct link for template serving
-        http.HandleFunc("/public/register", system_auth_serveRegisterInterface);
-        http.HandleFunc("/public/register/settings", system_auth_handleRegisterInterfaceUpdate);
-    }
-}
-
-func system_auth_checkPublicRegister(w http.ResponseWriter, r *http.Request){
-    if (!*allow_public_registry){
-        sendJSONResponse(w, "false");
-        return
-    }else{
-        AllowPublicRegisterValue := false
-        sysdb.Read("auth", "public/register/settings/allowRegistry", &AllowPublicRegisterValue)
-        jsonString, _ := json.Marshal(AllowPublicRegisterValue)
-        sendJSONResponse(w, string(jsonString))
-        return
-    }
-    sendJSONResponse(w, "false");
-}
-
-func system_auth_serveRegisterInterface(w http.ResponseWriter, r *http.Request){
-    username, err := mv(r, "username", true)
-    if (err != nil){
-        //Serve WebUI
-        //Prepare contents for templating
-        base64Image, _ := LoadImageAsBase64("./web/" + iconVendor)
-        requireInvitationCode := false
-        sysdb.Read("auth", "public/register/settings/enableInvitationCode", &requireInvitationCode)
-        eic := "false"
-        if (requireInvitationCode){
-            eic = "true"
-        }
-        //registerUI, _ := ioutil.ReadFile("./web/" + "SystemAO/auth/register.system");
-        registerUI, _ := template_load("./web/" + "SystemAO/auth/register.system",map[string]interface{}{
-            "vendor_logo": base64Image,
-            "host_name": *host_name,
-            "require_invitationCode": eic,
-        })
-        w.Write([]byte(registerUI))
-    }else{
-        //Data incoming. Register this user if data is valid
-        requireInvitationCode := false
-        sysdb.Read("auth", "public/register/settings/enableInvitationCode", &requireInvitationCode)
-
-        //Validate Invitation Code if enabled
-        if (requireInvitationCode){
-            //Validate the Invitation Code
-            userInputCode, _ := mv(r, "invitationcode", true)
-            correctCode := ""
-            sysdb.Read("auth", "public/register/settings/invitationCode", &correctCode)
-            if (correctCode == ""){
-                panic("Invalid Invitation Code")
-            }
-            if (userInputCode != correctCode){
-                sendErrorResponse(w, "Invalid Invitation Code")
-                return
-            }
-        }
-
-        //validate if this username already occupied
-        if authAgent.UserExists(username){
-            sendErrorResponse(w, "This username already occupied.")
-            return
-        }
-
-        //Validate password
-        password, err := mv(r, "password", true)
-        if (err != nil){
-            sendErrorResponse(w, "Invalid password")
-            return
-        }
-
-        if len(password) < 8{
-            sendErrorResponse(w, "Password too short. Password must be equal or longer than 8 characters")
-            return
-        }
-
-        //Validate default usergroup
-        DefaultUserGroupValue := ""
-        err = sysdb.Read("auth", "public/register/settings/defaultUserGroup", &DefaultUserGroupValue)
-        if (err != nil){
-            log.Println(err.Error())
-            sendErrorResponse(w, "Internal Server Error")
-            return
-        }
-
-        /*
-        if (DefaultUserGroupValue == "" || !system_permission_groupExists(DefaultUserGroupValue)){
-            log.Println("Invalid group given or group not exists: " + DefaultUserGroupValue)
-            sendErrorResponse(w, "Internal Server Error")
-            return
-        }
-        */
-
-        //Ok to create user
-        err = authAgent.CreateUserAccount(username, password, DefaultUserGroupValue)
-        if (err != nil){
-            log.Println(err.Error())
-            sendErrorResponse(w, "Internal Server Error")
-            return
-        }
-        sendOK(w);
-    }
-    
-}
-
-func system_auth_handleRegisterInterfaceUpdate(w http.ResponseWriter, r *http.Request){
-    /*
-    isAdmin := system_permission_checkUserIsAdmin(w,r)
-    if !isAdmin{
-        sendErrorResponse(w, "Permission denied")
-        return
-    }
-    */
-    
-    //keys for access the properties
-    var (
-        rootKey string = "public/register/settings/"
-        allowPublicRegister string = rootKey + "allowRegistry"
-        enableInvitationCode string = rootKey + "enableInvitationCode"
-        invitationCode string = rootKey + "invitationCode"
-        defaultUserGroup string = rootKey + "defaultUserGroup"
-    )
-
-    opr, _ := mv(r,"opr",true);
-    if (opr == "write"){
-        //Write settings to db
-        config, err := mv(r,"config",true);
-        if err != nil{
-            sendErrorResponse(w, "config not defined");
-            return
-        }
-
-        type configStruct struct {
-            Apr   bool   `json:"apr"`
-            Eivc  bool   `json:"eivc"`
-            Icode string `json:"icode"`
-            Group string `json:"group"`
-        }
-
-        newConfig := new(configStruct)
-        err = json.Unmarshal([]byte(config), &newConfig)
-        if (err != nil){
-            sendErrorResponse(w, err.Error())
-            return
-        }
-
-        /*
-        if (newConfig.Group == "" || !system_permission_groupExists(newConfig.Group)){
-            //Group is not set. Reject update
-            sendErrorResponse(w, "Invalid group selected");
-            return
-        }
-        */
-
-        //Write the configuration to file
-        sysdb.Write("auth", allowPublicRegister, newConfig.Apr)
-        sysdb.Write("auth", enableInvitationCode, newConfig.Eivc)
-        sysdb.Write("auth", invitationCode, newConfig.Icode)
-        sysdb.Write("auth", defaultUserGroup, newConfig.Group)
-
-        sendOK(w)
-    }else{
-        //Read the current settings
-        type replyStruct struct{
-            AllowPublicRegister bool
-            EnableInvitationCode bool
-            InvitationCode string
-            DefaultUserGroup string
-        }
-
-        var AllowPublicRegisterValue bool = false
-        var EnableInvitationCodeValue bool = false
-        var InvitationCodeValue string = ""
-        var DefaultUserGroupValue string = ""
-
-        sysdb.Read("auth", allowPublicRegister, &AllowPublicRegisterValue)
-        sysdb.Read("auth", enableInvitationCode, &EnableInvitationCodeValue)
-        sysdb.Read("auth", invitationCode, &InvitationCodeValue)
-        sysdb.Read("auth", defaultUserGroup, &DefaultUserGroupValue)
-
-        jsonString, _ := json.Marshal(replyStruct{
-            AllowPublicRegister:AllowPublicRegisterValue,
-            EnableInvitationCode:EnableInvitationCodeValue,
-            InvitationCode:InvitationCodeValue,
-            DefaultUserGroup:DefaultUserGroupValue,
-        })
-
-        sendJSONResponse(w, string(jsonString))
-    }
-}
-
-
-
-

+ 0 - 47
legacy/disabled/hardware.power.go

@@ -1,47 +0,0 @@
-package main
-
-import (
-	"net/http"
-	"log"
-)
-
-func hardware_power_init(){
-	if (*allow_hardware_management){
-		//Only register these paths when hardware management is enabled
-
-	}
-
-	http.HandleFunc("/system/power/accessCheck", hardware_power_checkIfHardware)
-}
-
-func hardware_power_checkIfHardware(w http.ResponseWriter, r *http.Request){
-	if (*allow_hardware_management){
-		sendJSONResponse(w, "true")
-	}else{
-		sendJSONResponse(w, "false")
-	}
-}
-
-//Pass in shutdown={deviceuuid} to shutdown
-func hardware_power_restart(w http.ResponseWriter, r *http.Request){
-	_, err := authAgent.GetUserName(w,r);
-	if (err != nil){
-		sendErrorResponse(w, "User not logged in")
-		return
-	}
-	isAdmin := system_permission_checkUserIsAdmin(w,r)
-	if (!isAdmin){
-		sendErrorResponse(w, "Permission denied")
-		return
-	}
-
-	poweroff, _ := mv(r, "shutdown", true)
-	if (poweroff == ""){
-		//Do system restart
-		log.Println("Restarting");
-	}else if (poweroff == deviceUUID){
-		//Do system shutdown
-		log.Println("Shutting down");
-	}
-}
-

+ 0 - 25
legacy/disabled/language.go

@@ -1,25 +0,0 @@
-package main
-
-import (
-
-)
-
-func system_lang_getSystemLanuage(){
-
-}
-
-func system_lang_setSystemLanuage(){
-
-}
-
-func system_lang_getLocalization(tranfile string, key string){
-	
-}
-
-/*
-	Translation Indexing functions
-
-	The following functions will do the template and indexing for lanuage translation from config files.
-
-*/
-

+ 0 - 326
legacy/disabled/module.Music.go

@@ -1,326 +0,0 @@
-package main
-
-import (
-	"net/http"
-	"log"
-	"strings"
-	"path/filepath"
-	"encoding/json"
-	"os"
-	"fmt"
-	"strconv"
-)
-
-/*
-	AirMUsic - Maybe the best music playback app on ArOZ Online 
-
-	CopyRight Toby Chui, 2020
-*/
-
-func module_Music_init(){
-	http.HandleFunc("/Music/listSong", module_airMusic_listSong)
-	http.HandleFunc("/Music/getMeta", module_airMusic_getMeta)
-	http.HandleFunc("/Music/getFileInfo", module_airMusic_getFileInfo)
-	
-
-	//Register this module to system
-	registerModule(moduleInfo{
-		Name: "Music",
-		Desc: "The basic music player for ArOZ Online",
-		Group: "Media",
-		IconPath: "Music/img/module_icon.png",
-		Version: "0.0.4",
-		StartDir: "Music/index.html",
-		SupportFW: true,
-		LaunchFWDir: "Music/index.html",
-		SupportEmb: true,
-		LaunchEmb: "Music/embedded.html",
-		InitFWSize: []int{475, 700},
-		InitEmbSize: []int{360, 240},
-		SupportedExt: []string{".mp3",".flac",".wav",".ogg",".aac",".webm",".mp4"},
-	})
-}
-
-func module_airMusic_getMeta(w http.ResponseWriter, r *http.Request){
-	username, err := authAgent.GetUserName(w,r);
-	if (err != nil){
-		sendErrorResponse(w,"User not logged in")
-		return;
-	}
-
-	playingFile, _ := mv(r, "file", false)
-	playingFile = system_fs_specialURIDecode(playingFile)
-	rPlayingFilePath, _ := virtualPathToRealPath(playingFile, username)
-	fileDir := filepath.ToSlash(filepath.Dir(rPlayingFilePath))
-	supportedFileExt := []string{".mp3",".flac",".wav",".ogg",".aac",".webm",".mp4"}
-	var fileInfos [][]string
-	objs, _ := system_fs_specialGlob(fileDir + "/*")
-	for _, obj := range objs{
-		if (!IsDir(obj) && stringInSlice(filepath.Ext(obj), supportedFileExt)){
-			//This is a file that we want to list
-			var thisFileInfo []string
-			fileExt := filepath.Ext(obj)[1:]
-			fileName := filepath.Base(obj)
-			filePath, _ := realpathToVirtualpath(obj, username)
-			_, hsize, unit, _ := system_fs_getFileSize(obj)
-			size := fmt.Sprintf("%.2f", hsize) + unit;
-
-			thisFileInfo = append(thisFileInfo, fileName)
-			thisFileInfo = append(thisFileInfo, filePath)
-			thisFileInfo = append(thisFileInfo, fileExt)
-			thisFileInfo = append(thisFileInfo, size)
-
-			fileInfos = append(fileInfos, thisFileInfo)
-		}
-	}
-	
-	jsonString, _ := json.Marshal(fileInfos);
-	sendJSONResponse(w, string(jsonString));
-}
-
-func module_airMusic_listSong(w http.ResponseWriter, r *http.Request){
-	username, err :=  authAgent.GetUserName(w,r);
-	if (err != nil){
-		redirectToLoginPage(w,r)
-		return;
-	}
-	
-	var musicDirs []string
-	var playLists []string
-
-	//Initialize user folder structure if it is not yet init
-	uploadDir, _ := virtualPathToRealPath("user:/Music/",username)
-	playList, _ := virtualPathToRealPath("user:/Music/playlist",username)
-	os.MkdirAll(uploadDir, 0755)
-	os.MkdirAll(playList, 0755)
-	musicDirs = append(musicDirs, uploadDir);
-	playLists = append(playLists, playList);
-
-	for _, extStorage := range storages{
-		path := extStorage.Path;
-		if (path[len(path) - 1:] != "/"){
-			path = path + "/"
-		}
-		musicDirs = append(musicDirs, path)
-	}
-
-	//Get which folder the user want to list
-	lsDir, _ := mv(r, "listdir", false)
-	listSong, _ := mv(r, "listSong", false)
-	listFolder, _ := mv(r, "listfolder", false)
-	supportedFileExt := []string{".mp3",".flac",".wav",".ogg",".aac",".webm"}
-
-	//Decode url component if needed
-	if (lsDir != ""){
-		lsDir = strings.ReplaceAll(lsDir, "%2B","+")
-	}
-	
-
-	if (listSong != ""){
-		//List song mode. List the song in the directories
-		if (listSong == "all"){
-			songData := [][]string{}
-			for _, directory := range musicDirs{
-				
-				filepath.Walk(directory,
-					func(path string, info os.FileInfo, err error) error {
-					if err != nil {
-						return err
-					}
-					path = filepath.ToSlash(path)
-					
-					if (stringInSlice(filepath.Ext(path),supportedFileExt)){
-						//This is an audio file. Append to songData
-						var audioFiles []string
-						_, hsize, unit, _ := system_fs_getFileSize(path)
-						size := fmt.Sprintf("%.2f", hsize) + unit;
-						vpath, _ := realpathToVirtualpath(path, username);
-						audioFiles = append(audioFiles, "/media?file=" + vpath);
-						audioFiles = append(audioFiles, strings.TrimSuffix(filepath.Base(path), filepath.Ext(path)));
-						audioFiles = append(audioFiles, filepath.Ext(path)[1:]);
-						audioFiles = append(audioFiles, size);
-						songData = append(songData, audioFiles)
-					}
-					return nil
-				})			
-			}
-
-			jsonString, _ := json.Marshal(songData);
-			sendJSONResponse(w, string(jsonString));
-
-		}else if (strings.Contains(listSong, "search:")){
-			keyword := listSong[7:]
-			songData := [][]string{}
-			for _, directory := range musicDirs{
-				
-				filepath.Walk(directory,
-					func(path string, info os.FileInfo, err error) error {
-					if err != nil {
-						return err
-					}
-					path = filepath.ToSlash(path)
-					
-					if (stringInSlice(filepath.Ext(path),supportedFileExt) && strings.Contains(filepath.Base(path),keyword)){
-						//This is an audio file. Append to songData
-						var audioFiles []string
-						_, hsize, unit, _ := system_fs_getFileSize(path)
-						size := fmt.Sprintf("%.2f", hsize) + unit;
-						vpath, _ := realpathToVirtualpath(path, username);
-						audioFiles = append(audioFiles, "/media?file=" + vpath);
-						audioFiles = append(audioFiles, strings.TrimSuffix(filepath.Base(path), filepath.Ext(path)));
-						audioFiles = append(audioFiles, filepath.Ext(path)[1:]);
-						audioFiles = append(audioFiles, size);
-						songData = append(songData, audioFiles)
-					}
-					return nil
-				})			
-			}
-
-			jsonString, _ := json.Marshal(songData);
-			sendJSONResponse(w, string(jsonString));
-		}else{
-			log.Println("Work in progress")
-		}
-	}else if (lsDir != ""){
-		//List diretory
-		if (lsDir == "root"){
-			var rootInfo [][]string
-			for _, dir := range musicDirs{
-				var thisRootInfo []string
-				//thisRootInfo = append(thisRootInfo, filepath.Base(dir))
-				virtualStorageRootName, err := system_storage_getRootNameByPath(dir, username)
-				if (err != nil){
-					thisRootInfo = append(thisRootInfo, filepath.Base(dir))
-				}else{
-					thisRootInfo = append(thisRootInfo, virtualStorageRootName)
-				}
-				
-				vpath, _ := realpathToVirtualpath(dir,username);
-				thisRootInfo = append(thisRootInfo, vpath + "/")
-				objects, _ := filepath.Glob(dir + "/*")
-				var files []string
-				var folders []string
-				for _, f := range objects{
-					if (IsDir(f)){
-						folders = append(folders, f)
-					}else if (stringInSlice(filepath.Ext(f),supportedFileExt)) {
-						files = append(files, f)
-					}
-				}
-				thisRootInfo = append(thisRootInfo, strconv.Itoa(len(files)))
-				thisRootInfo = append(thisRootInfo, strconv.Itoa(len(folders)))
-				rootInfo = append(rootInfo, thisRootInfo)
-			}
-			jsonString, _ := json.Marshal(rootInfo)
-			sendJSONResponse(w, string(jsonString))
-		}else{
-			listingTarget, _ := virtualPathToRealPath(lsDir, username);
-			if (listingTarget == ""){
-				//User try to leave the accessable area. Reject access.
-				sendErrorResponse(w, "Permission denied")
-				return;
-			}
-			var results [][][]string
-			//List all objects in the current directory and catergorize them
-			folders := []string{}
-			files :=  []string{}
-			//Special glob for handling path with [ or ]
-			objects, _ := system_fs_specialGlob(filepath.Clean(listingTarget) + "/*")
-			for _, obj := range objects{
-				if (IsDir(obj)){
-					folders = append(folders, obj)
-				}else if (stringInSlice(filepath.Ext(obj),supportedFileExt)){
-					files = append(files, obj)
-				}
-			}
-
-			folderInfos := [][]string{}
-			for _, folder := range folders{
-				var thisFolderInfo []string
-				folderName := filepath.Base(folder)
-				folderPath, _ := realpathToVirtualpath(folder, username)
-				filesInDir := 0;
-				DirInDir := 0;
-				objInDir, _ := system_fs_specialGlob(filepath.ToSlash(folder) + "/*")
-				for _, obj := range objInDir{
-					if (IsDir(obj)){
-						DirInDir++;
-					}else if (stringInSlice(filepath.Ext(obj),supportedFileExt)){
-						filesInDir++;
-					}
-				}
-				thisFolderInfo = append(thisFolderInfo, folderName)
-				thisFolderInfo = append(thisFolderInfo, folderPath + "/")
-				thisFolderInfo = append(thisFolderInfo, strconv.Itoa(filesInDir))
-				thisFolderInfo = append(thisFolderInfo, strconv.Itoa(DirInDir))
-				folderInfos = append(folderInfos, thisFolderInfo)
-			}
-
-			fileInfos := [][]string{}
-			for _, file := range files{
-				var thisFileInfo []string
-				vfilepath, _ := realpathToVirtualpath(file, username)
-				filename := filepath.Base(file)
-				ext := filepath.Ext(file)[1:]
-				_, hsize, unit, _ := system_fs_getFileSize(file)
-				size := fmt.Sprintf("%.2f", hsize) + unit;
-
-				thisFileInfo = append(thisFileInfo, "/media?file=" + vfilepath)
-				thisFileInfo = append(thisFileInfo, filename)
-				thisFileInfo = append(thisFileInfo, ext)
-				thisFileInfo = append(thisFileInfo, size)
-				fileInfos = append(fileInfos, thisFileInfo)
-			}
-
-			results = append(results, folderInfos)
-			results = append(results, fileInfos)
-			jsonString, _ := json.Marshal(results)
-			sendJSONResponse(w, string(jsonString))
-			
-		}
-	}else if (listFolder != ""){
-		
-	}
-}
-
-func module_airMusic_getFileInfo(w http.ResponseWriter, r *http.Request){
-	username, err :=  authAgent.GetUserName(w,r);
-	if (err != nil){
-		sendErrorResponse(w, "User not logged in")
-		return;
-	}
-	vpath, _ := mv(r, "filepath", false)
-	
-	//Strip away the access path
-	if (vpath[:12] == "/media?file="){
-		vpath = vpath[12:];
-	}
-
-	//Convert the virtual path to realpath
-	realpath, err := virtualPathToRealPath(vpath, username)
-	if (err != nil){
-		sendErrorResponse(w, "Invalid filepath")
-		return;
-	}
-
-	if (!fileExists(realpath)){
-		sendErrorResponse(w, "File not exists")
-		return;
-	}
-
-	//Buiild the information for sendout
-	results := []string{}
-	results = append(results, filepath.Base(realpath))
-	vdir, _ := realpathToVirtualpath(filepath.Dir(realpath), username)
-	results = append(results, vdir)
-	rawsize, hsize, unit, _ := system_fs_getFileSize(realpath)
-	size := fmt.Sprintf("%.2f", hsize) + unit;
-	results = append(results, size)
-	results = append(results, fmt.Sprintf("%.2f", rawsize))
-	info, err := os.Stat(realpath)
-	results = append(results, info.ModTime().Format("2006-01-02 15:04:05"))
-
-	jsonString, _ := json.Marshal(results)
-	sendJSONResponse(w, string(jsonString))
-}
-

+ 0 - 114
legacy/disabled/module.package.go

@@ -1,114 +0,0 @@
-package main
-
-import (
-	"encoding/json"
-	"errors"
-	"log"
-	"net/http"
-	"os"
-	"os/exec"
-	"runtime"
-	"strings"
-)
-
-/*
-	Pacakge management tool for Linux OS with APT
-
-	ONLY USABLE under Linux environment
-*/
-
-func module_package_init() {
-	http.HandleFunc("/system/apt/list", module_package_listAPT)
-}
-
-//Install the given package if not exists. Set mustComply to true for "panic on failed to install"
-func module_package_installIfNotExists(pkgname string, mustComply bool) error {
-	//Clear the pkgname
-	pkgname = strings.ReplaceAll(pkgname, "&", "")
-	pkgname = strings.ReplaceAll(pkgname, "|", "")
-
-	if runtime.GOOS == "windows" {
-		//Check if the command already exists in windows path paramters.
-		cmd := exec.Command("where", pkgname, "2>", "nul")
-		_, err := cmd.CombinedOutput()
-		if err != nil {
-			return errors.New("Package " + pkgname + " not found in Windows %PATH%.")
-		}
-		return nil
-	}
-
-	if *allow_package_autoInstall == false {
-		return errors.New("Package auto install is disabled")
-	}
-
-	cmd := exec.Command("which", pkgname)
-	out, _ := cmd.CombinedOutput()
-
-	if len(string(out)) > 1 {
-		return nil
-	} else {
-		//Package not installed. Install if now if running in sudo mode
-		log.Println("Installing package " + pkgname + "...")
-		cmd := exec.Command("apt-get", "install", "-y", pkgname)
-		cmd.Stdout = os.Stdout
-		cmd.Stderr = os.Stderr
-		err := cmd.Run()
-		if err != nil {
-			if mustComply {
-				//Panic and terminate server process
-				log.Println("Installation failed on package: "+pkgname, string(out))
-				os.Exit(0)
-			} else {
-				log.Println("Installation failed on package: " + pkgname)
-				log.Println(string(out))
-			}
-			return err
-		}
-		return nil
-	}
-
-	return nil
-}
-
-func module_package_test(w http.ResponseWriter, r *http.Request) {
-	module_package_installIfNotExists("ffmpeg", true)
-	module_package_installIfNotExists("samba", true)
-}
-
-func module_package_listAPT(w http.ResponseWriter, r *http.Request) {
-	if runtime.GOOS == "windows" {
-		sendErrorResponse(w, "Function disabled on Windows")
-		return
-	}
-	cmd := exec.Command("apt", "list", "--installed")
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		sendErrorResponse(w, err.Error())
-		return
-	}
-
-	results := [][]string{}
-	//Parse the output string
-	installedPackages := strings.Split(string(out), "\n")
-	for _, thisPackage := range installedPackages {
-		if len(thisPackage) > 0 {
-			packageInfo := strings.Split(thisPackage, "/")
-			packageName := packageInfo[0]
-			if len(packageInfo) >= 2 {
-				packageVersion := strings.Split(packageInfo[1], ",")[1]
-				if packageVersion[:3] == "now" {
-					packageVersion = packageVersion[4:]
-				}
-				if strings.Contains(packageVersion, "[installed") && packageVersion[len(packageVersion)-1:] != "]" {
-					packageVersion = packageVersion + ",automatic]"
-				}
-
-				results = append(results, []string{packageName, packageVersion})
-			}
-		}
-	}
-
-	jsonString, _ := json.Marshal(results)
-	sendJSONResponse(w, string(jsonString))
-	return
-}

+ 0 - 161
legacy/disabled/network.ip2country.go

@@ -1,161 +0,0 @@
-package main
-
-import (
-	"encoding/binary"
-	"encoding/csv"
-	"encoding/json"
-	"fmt"
-	"log"
-	"net"
-	"net/http"
-	"os"
-	"strings"
-)
-
-type ipRange struct {
-	start   uint
-	end     uint
-	country string
-}
-
-type ipReturnData struct {
-	IP      string
-	Country string
-	Status  string
-}
-
-func network_ipToCountry_service_init() {
-	log.Println("Starting ip2country service")
-
-	http.HandleFunc("/SystemAO/network/getIPLocation", network_ipToCountry_getCurrentIPLocation)
-	//http.HandleFunc("/SystemAO/network/getPing", network_info_getPing)
-	/*
-		//Register as a system setting
-		registerSetting(settingModule{
-			Name:     "Network Info",
-			Desc:     "System Information",
-			IconPath: "SystemAO/network/img/ethernet.png",
-			Group:    "Network",
-			StartDir: "SystemAO/network/hardware.html",
-		})
-	*/
-}
-
-func network_ipToCountry_getCurrentIPLocation(w http.ResponseWriter, r *http.Request) {
-	/*
-		if system_auth_chkauth(w, r) == false {
-			sendErrorResponse(w, "User not logged in")
-			return
-		}
-	*/
-
-	//Do not try to access IP information if under disable_ip_resolve_services mode
-	if *disable_ip_resolve_services {
-		data := ipReturnData{
-			IP:      "0.0.0.0",
-			Country: "ZZ",
-			Status:  "Resolve Service Disabled",
-		}
-		JSONText, _ := json.Marshal(data)
-		sendJSONResponse(w, string(JSONText))
-		return
-	}
-
-	UserIP, _, err := net.SplitHostPort(string(r.RemoteAddr))
-	if err != nil {
-		log.Println(err)
-	}
-
-	data := ipReturnData{}
-	if strings.Contains(UserIP, ":") {
-		data.IP = UserIP
-		data.Country = "ZZ"
-		data.Status = "IPv6 not supported in current release"
-
-	} else {
-		data.IP = UserIP
-		data.Country = network_ipToCountry_GetCountry(UserIP)
-		data.Status = "OK"
-
-	}
-	JSONText, _ := json.Marshal(data)
-	sendJSONResponse(w, string(JSONText))
-}
-
-//GetCountry returns the country which ip blongs to
-func network_ipToCountry_GetCountry(ip string) string {
-	var arr []ipRange
-	CSVFile := strings.Split(ip, ".")[0]
-	lines, err := network_ipToCountry_ReadCsv("./system/ip2country/" + CSVFile + ".csv")
-	if err != nil {
-		panic(err)
-	}
-
-	// Loop through lines & turn into object
-	for _, line := range lines {
-		StartS := fmt.Sprintf("%s", line[0])
-		Start, _ := network_ipToCountry_ipToInt(StartS)
-		EndS := fmt.Sprintf("%s", line[1])
-		End, _ := network_ipToCountry_ipToInt(EndS)
-
-		data := ipRange{
-			start:   Start,
-			end:     End,
-			country: line[2],
-		}
-		arr = append(arr, data)
-	}
-	ipNumb, err := network_ipToCountry_ipToInt(ip)
-	if err != nil {
-		return ""
-	}
-
-	index := network_ipToCountry_binarySearch(arr, ipNumb, 0, len(arr)-1)
-	if index == -1 {
-		return ""
-	}
-
-	return arr[index].country
-}
-
-func network_ipToCountry_binarySearch(arr []ipRange, hkey uint, low, high int) int {
-	for low <= high {
-		mid := low + (high-low)/2
-		if hkey >= arr[mid].start && hkey <= arr[mid].end {
-			return mid
-		} else if hkey < arr[mid].start {
-			high = mid - 1
-		} else if hkey > arr[mid].end {
-			low = mid + 1
-		}
-	}
-	return -1
-}
-
-func network_ipToCountry_ipToInt(ips string) (uint, error) {
-	ip := net.ParseIP(ips)
-	if len(ip) == 16 {
-		return uint(binary.BigEndian.Uint32(ip[12:16])), nil
-	}
-	return uint(binary.BigEndian.Uint32(ip)), nil
-}
-
-// ReadCsv accepts a file and returns its content as a multi-dimentional type
-// with lines and each column. Only parses to string type.
-func network_ipToCountry_ReadCsv(filename string) ([][]string, error) {
-
-	// Open CSV file
-	f, err := os.Open(filename)
-	if err != nil {
-		return [][]string{}, err
-	}
-	defer f.Close()
-
-	// Read File into a Variable
-	lines, err := csv.NewReader(f).ReadAll()
-	if err != nil {
-		return [][]string{}, err
-	}
-
-	return lines, nil
-}

+ 0 - 178
legacy/disabled/system.boot.go

@@ -1,178 +0,0 @@
-package main
-
-import (
-	"net/http"
-	"encoding/json"
-	"runtime"
-	"strings"
-	"log"
-	"io/ioutil"
-)
-
-/*
-	System Boot Configuration Module
-
-	This module handle the boot flags and settings of the booting paramters
-*/
-
-type bootConfigParamters struct {
-	Hostname                string 	`json:"Hostname"`
-	ListenPort              int 	`json:"ListenPort"`
-	MaxUpload               int 	`json:"MaxUpload"`
-	UploadBuffer            int 	`json:"UploadBuffer"`
-	FileIOBuf               int 	`json:"FileIOBuf"`
-	EnableUPnP				bool 	`json:"EnableUPnP,omitempty"`
-	AllowHardwareMan        bool   	`json:"AllowHardwareMan"`
-	AllowPackageAutoInstall bool   	`json:"AllowPackageAutoInstall"`
-	DisableIPResolve        bool   	`json:"DisableIPResolve"`
-	IsWindows               bool  	`json:"IsWindows,omitempty"`
-}
-
-func system_boot_init(){
-
-	//Register Endpoints
-	http.HandleFunc("/system/boot/generateBootConfig", system_boot_generateBootConfig)
-	http.HandleFunc("/system/boot/getCurrentBootConfig", system_boot_getCurrentBootConfig)
-
-	//Register Settings
-	registerSetting(settingModule{
-		Name:         "Boot Config",
-		Desc:         "Setup Boot Modes and Flags",
-		IconPath:     "SystemAO/boot/img/boot.png",
-		Group:        "Advance",
-		StartDir:     "SystemAO/boot/bootflags.html",
-		RequireAdmin: true,
-	})
-
-}
-
-func system_boot_generateBootConfig(w http.ResponseWriter, r *http.Request) {
-	isAdmin := system_permission_checkUserIsAdmin(w,r);
-	if !isAdmin{
-		sendErrorResponse(w, "Permission Denied")
-		return
-	}
-
-	configs, err := mv(r, "config", true)
-	if err != nil{
-		sendErrorResponse(w, "Internal Server Error")
-		return
-	}
-
-	//Decode config file
-	configs = system_fs_specialURIDecode(configs)
-
-	//Generate the boot script from the given paramters
-	parsedConfig := new(bootConfigParamters);
-	err = json.Unmarshal([]byte(configs), &parsedConfig)
-	if err != nil{
-		sendErrorResponse(w, err.Error())
-		return
-	}
-
-	log.Println("Warning! Boot configuration updated!")
-
-	commandSlice := []string{
-		"-hostname", 
-		"\"" + parsedConfig.Hostname + "\"",
-		"-port",
-		IntToString(parsedConfig.ListenPort),
-		"-max_upload_size",
-		IntToString(parsedConfig.MaxUpload),
-		"-upload_buf",
-		IntToString(parsedConfig.UploadBuffer),
-		"-iobuf",
-		IntToString(parsedConfig.FileIOBuf),
-	}
-
-	if !parsedConfig.AllowHardwareMan{
-		commandSlice = append(commandSlice, "-enable_hwman=false")
-	}
-
-	if !parsedConfig.AllowPackageAutoInstall{
-		commandSlice = append(commandSlice, "-allow_pkg_install=false")
-	}
-
-	if parsedConfig.DisableIPResolve{
-		commandSlice = append(commandSlice, "-disable_ip_resolver=true")
-	}
-		
-
-	execpath := strings.Join(commandSlice, " ")
-
-	//Replace all odd things like && and || and & etc
-	if (strings.Contains(execpath, "&&") || strings.Contains(execpath, "||") || strings.Contains(execpath, "&") || strings.Contains(execpath, ">")){
-		sendErrorResponse(w, "Configuration contains invalid characters")
-		return
-	}
-
-	//Generate the corrisponding scrip file
-	binaryPath := ""
-	scriptName := "start.sh"
-	if runtime.GOOS == "windows" {
-		binaryPath = "aroz_online_windows_amd64.exe"
-		scriptName = "start.bat"
-	} else if runtime.GOOS == "linux" {
-		if runtime.GOARCH == "arm" {
-			binaryPath = "aroz_online_linux_arm"
-		}else if runtime.GOARCH == "arm64" {
-			binaryPath = "aroz_online_linux_arm64"
-		}else if runtime.GOARCH == "386" {
-			binaryPath = "aroz_online_windows_386"
-		}else if runtime.GOARCH == "amd64" {
-			binaryPath = "aroz_online_linux_amd64"
-		}
-	}
-
-	//Build the final start script
-	execpath =  binaryPath + " " + execpath
-	if runtime.GOOS == "windows" {
-		err = ioutil.WriteFile(scriptName, []byte(execpath), 0755)
-		if err != nil{
-			sendErrorResponse(w, err.Error())
-			return
-		}
-	}else{
-		//Append other services to the script
-		scriptContent := "#/bin/bash\nsudo " + execpath
-		err = ioutil.WriteFile(scriptName, []byte(scriptContent), 0755)
-		if err != nil{
-			sendErrorResponse(w, err.Error())
-			return
-		}
-	}
-
-	sendOK(w)
-	
-}
-
-//Get the current booting flags (Only those for basic users)
-func system_boot_getCurrentBootConfig(w http.ResponseWriter, r *http.Request){
-	isAdmin := system_permission_checkUserIsAdmin(w,r);
-	if !isAdmin{
-		sendErrorResponse(w, "Permission Denied")
-		return
-	}
-
-	isWindows := false;
-	if runtime.GOOS == "windows" {
-        isWindows = true
-    }
-
-	//Create a struct for the current booting options
-	jsonString, _ := json.Marshal(bootConfigParamters{
-		ListenPort: *listen_port,
-		Hostname: *host_name,
-		EnableUPnP: *allow_upnp,
-		MaxUpload: *max_upload,
-		UploadBuffer: *upload_buf,
-		FileIOBuf: *file_opr_buff,
-		AllowHardwareMan: *allow_hardware_management,
-		AllowPackageAutoInstall: *allow_package_autoInstall,
-		DisableIPResolve: *disable_ip_resolve_services,
-		IsWindows: isWindows,
-	})
-
-	sendJSONResponse(w, string(jsonString))
-
-}

+ 0 - 302
legacy/disabled/system.disk.quota.go

@@ -1,302 +0,0 @@
-package main
-
-import (
-	"encoding/json"
-	"errors"
-	"net/http"
-	"os"
-	"path/filepath"
-	"sort"
-	"strings"
-	"log"
-)
-
-/*
-	Disk Quota Management System
-	This module manage the user groups disk quota in the system
-
-	Disk quota can only be set on a user group bases.
-	(aka all users in the same group has the identical number of disk quota to the group settings)
-*/
-
-func system_disk_quota_init() {
-	//Initiate quota storage table
-	err := sysdb.NewTable("diskquota")
-	if err != nil {
-		panic(err)
-	}
-
-	//Register Endpoints
-	http.HandleFunc("/system/disk/quota/setQuota", system_disk_quota_setQuota)
-	http.HandleFunc("/system/disk/quota/listQuota", system_disk_quota_listQuota)
-	http.HandleFunc("/system/disk/quota/quotaInfo", system_disk_quota_handleQuotaInfo)
-	http.HandleFunc("/system/disk/quota/quotaDist", system_disk_quota_handleFileDistributionView)
-
-	//Register Setting Interfaces
-	//Register interface fow viewing the user storage quota
-	registerSetting(settingModule{
-		Name:     "Storage Quota",
-		Desc:     "User Remaining Space",
-		IconPath: "SystemAO/disk/quota/img/small_icon.png",
-		Group:    "Disk",
-		StartDir: "SystemAO/disk/quota/quota.system",
-	})
-
-	//Register interface for admin to setup quota settings
-	registerSetting(settingModule{
-		Name:         "Quota Settings",
-		Desc:         "Setup Group Storage Limit",
-		IconPath:     "SystemAO/disk/quota/img/small_icon.png",
-		Group:        "Disk",
-		StartDir:     "SystemAO/disk/quota/manage.html",
-		RequireAdmin: true,
-	})
-
-}
-
-//Get a list of quota on user groups and their storage limit
-func system_disk_quota_listQuota(w http.ResponseWriter, r *http.Request) {
-	_, err := authAgent.GetUserName(w,r);
-	if err != nil {
-		sendErrorResponse(w, "User not logged in")
-		return
-	}
-	isAdmin := system_permission_checkUserIsAdmin(w, r)
-	if !isAdmin {
-		sendErrorResponse(w, "Permission denied")
-		return
-	}
-
-	groups := system_permission_listGroup()
-	results := map[string]int64{}
-	for _, group := range groups {
-		quota, _ := system_disk_quota_getQuotaFromGroupname(group)
-		results[group] = quota
-	}
-
-	jsonString, _ := json.Marshal(results)
-	sendJSONResponse(w, string(jsonString))
-}
-
-//Check the storage quota on this usergroup. Return -1 for unlimited quota and 0 if error
-func system_disk_quota_getQuotaFromGroupname(groupname string) (int64, error) {
-	//If administrator, always return -1
-	if groupname == "administrator" {
-		return -1, nil
-	}
-	//Check if group exists
-	if !system_permission_groupExists(groupname) {
-		return 0, errors.New("Group not exists")
-	}
-
-	//Group exists. Get the group quota from db
-	groupQuota := int64(0)
-	err := sysdb.Read("diskquota", "quota/"+groupname, &groupQuota)
-	if err != nil {
-		return 0, err
-	}
-	return groupQuota, nil
-}
-
-//Check if the given size can fit into the user remaining quota, return true if the file fit user quota
-func system_disk_quota_validateQuota(username string, filesize int64) bool {
-	remaining, _, _, err := system_disk_quota_quotaInfo(username)
-	if err != nil{
-		log.Println("Upload failed for user: " + username + " " + err.Error())
-		return false
-	}
-	//log.Println(remaining, filesize, err)
-	if remaining == -1{
-		//Unlimited quota. Always return true
-		return true
-	}else if (remaining == 0){
-		//Read only account. Always return false
-		return false
-	}else if (remaining >= filesize ){
-		//This file fits in the user's remaining space
-		return true
-	}else{
-		return false
-	}
-	return false
-}
-
-//Check if the given path apply quota limitation
-func system_disk_quota_checkIfQuotaApply(path string, username string) bool{
-	targetStoargeDevice, err := system_storage_getStorageByPath(path, username);
-	if (err != nil){
-		return false
-	}
-	if targetStoargeDevice.Hierarchy == "user"{
-		//User Hierarchy Storage Device, count as user's private storage
-		return true
-	}
-	//Not user's private storage. Calculate as public one
-	return false
-}
-
-//Set the storage quota of the particular user
-func system_disk_quota_setQuota(w http.ResponseWriter, r *http.Request) {
-	authed := authAgent.CheckAuth(r)
-	if !authed {
-		sendErrorResponse(w, "User not logged in")
-		return
-	}
-	isAdmin := system_permission_checkUserIsAdmin(w, r)
-	if !isAdmin {
-		sendErrorResponse(w, "Permission denied")
-		return
-	}
-
-	//OK to proceed
-	groupname, err := mv(r, "groupname", true)
-	if err != nil {
-		sendErrorResponse(w, "Group name not defned")
-		return
-	}
-
-	quotaSizeString, err := mv(r, "quota", true)
-	if err != nil {
-		sendErrorResponse(w, "Quota not defined")
-		return
-	}
-
-	quotaSize, err := StringToInt64(quotaSizeString)
-	if err != nil || quotaSize < 0 {
-		sendErrorResponse(w, "Invalid quota size given")
-		return
-	}
-	//Qutasize unit is in MB
-	quotaSize = quotaSize << 20
-
-	//Check groupname exists
-	if !system_permission_groupExists(groupname) {
-		sendErrorResponse(w, "Group name not exists. Given "+groupname)
-		return
-	}
-
-	//Ok to proceed.
-	err = sysdb.Write("diskquota", "quota/"+groupname, quotaSize)
-	if err != nil {
-		sendErrorResponse(w, err.Error())
-		return
-	}
-
-	sendOK(w)
-}
-
-//Show the current user's quota information
-func system_disk_quota_handleQuotaInfo(w http.ResponseWriter, r *http.Request) {
-	username, err := authAgent.GetUserName(w,r);
-	if err != nil {
-		sendErrorResponse(w, "User not logged in")
-		return
-	}
-
-	remainingSpace, usedSpace, totalSpace, err := system_disk_quota_quotaInfo(username)
-	type quotaInformation struct {
-		Remaining int64
-		Used      int64
-		Total     int64
-	}
-
-	jsonString, _ := json.Marshal(quotaInformation{
-		Remaining: remainingSpace,
-		Used:      usedSpace,
-		Total:     totalSpace,
-	})
-
-	sendJSONResponse(w, string(jsonString))
-
-}
-
-//Get all the users file and see how
-func system_disk_quota_handleFileDistributionView(w http.ResponseWriter, r *http.Request) {
-	//Check if the user logged in
-	username, err := authAgent.GetUserName(w,r);
-	if err != nil {
-		sendErrorResponse(w, "User not logged in")
-		return
-	}
-
-	//Create a file distribution list
-	fileDist := map[string]int64{}
-	userpaths := system_storage_getUserDirectory(username)
-	for _, thispath := range userpaths {
-		filepath.Walk(thispath, func(filepath string, info os.FileInfo, err error) error {
-			if err != nil {
-				return err
-			}
-			if !info.IsDir() {
-				mime, _, err := system_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)
-	sendJSONResponse(w, string(jsonString))
-}
-
-//Get the quota information of the current user. Return the followings
-/*
-	Remaining space of the user quota (int64)
-	Used space of the user quota (int64)
-	Total theoretical space of the user quota (int64)
-	Error (error). Standard error message if something goes wrong
-*/
-func system_disk_quota_quotaInfo(username string) (int64, int64, int64, error) {
-	//Get the user group information
-	usergroup := system_permission_getUserPermissionGroup(username)
-	groupExists := system_permission_groupExists(usergroup)
-	if !groupExists {
-		return 0, 0, 0, errors.New("User group not exists")
-	}
-
-	//Get the group quota information
-	groupQuota := int64(-1)
-	sysdb.Read("diskquota", "quota/"+usergroup, &groupQuota)
-
-	//Calculate user limit
-	userpaths := system_storage_getUserDirectory(username)
-	totalUserUsedSpace := int64(0)
-	for _, thispath := range userpaths {
-		filepath.Walk(thispath, func(_ string, info os.FileInfo, err error) error {
-			if err != nil {
-				return err
-			}
-			if !info.IsDir() {
-				totalUserUsedSpace += info.Size()
-			}
-			return err
-		})
-	}
-
-	remainingSpace := groupQuota - totalUserUsedSpace
-	if groupQuota == -1 {
-		remainingSpace = -1
-	}
-	return remainingSpace, totalUserUsedSpace, groupQuota, nil
-}

+ 0 - 381
legacy/disabled/system.disk.smart.go

@@ -1,381 +0,0 @@
-package main
-
-import (
-	"encoding/json"
-	"log"
-	"net/http"
-	"os/exec"
-	"runtime"
-	"time"
-)
-
-//SystemSmartExecutable xxx
-var SystemSmartExecutable = ""
-
-//SMARTInformation xxx
-var SMARTInformation = []SMART{}
-var lastScanTime int64 = 0
-
-// DevicesList was used for storing the disk scanning result
-type DevicesList struct {
-	JSONFormatVersion []int `json:"json_format_version"`
-	Smartctl          struct {
-		Version      []int    `json:"version"`
-		SvnRevision  string   `json:"svn_revision"`
-		PlatformInfo string   `json:"platform_info"`
-		BuildInfo    string   `json:"build_info"`
-		Argv         []string `json:"argv"`
-		Messages     []struct {
-			String   string `json:"string"`
-			Severity string `json:"severity"`
-		} `json:"messages"`
-		ExitStatus int `json:"exit_status"`
-	} `json:"smartctl"`
-	Devices []struct {
-		Name     string `json:"name"`
-		InfoName string `json:"info_name"`
-		Type     string `json:"type"`
-		Protocol string `json:"protocol"`
-	} `json:"devices"`
-}
-
-// DeviceSMART was used for storing each disk smart information
-type DeviceSMART struct {
-	JSONFormatVersion []int `json:"json_format_version"`
-	Smartctl          struct {
-		Version      []int    `json:"version"`
-		SvnRevision  string   `json:"svn_revision"`
-		PlatformInfo string   `json:"platform_info"`
-		BuildInfo    string   `json:"build_info"`
-		Argv         []string `json:"argv"`
-		Messages     []struct {
-			String   string `json:"string"`
-			Severity string `json:"severity"`
-		} `json:"messages"`
-		ExitStatus int `json:"exit_status"`
-	} `json:"smartctl"`
-	Device struct {
-		Name     string `json:"name"`
-		InfoName string `json:"info_name"`
-		Type     string `json:"type"`
-		Protocol string `json:"protocol"`
-	} `json:"device"`
-	ModelFamily  string `json:"model_family"`
-	ModelName    string `json:"model_name"`
-	SerialNumber string `json:"serial_number"`
-	Wwn          struct {
-		Naa int   `json:"naa"`
-		Oui int   `json:"oui"`
-		ID  int64 `json:"id"`
-	} `json:"wwn"`
-	FirmwareVersion string `json:"firmware_version"`
-	UserCapacity    struct {
-		Blocks int   `json:"blocks"`
-		Bytes  int64 `json:"bytes"`
-	} `json:"user_capacity"`
-	LogicalBlockSize   int  `json:"logical_block_size"`
-	PhysicalBlockSize  int  `json:"physical_block_size"`
-	RotationRate       int  `json:"rotation_rate"`
-	InSmartctlDatabase bool `json:"in_smartctl_database"`
-	AtaVersion         struct {
-		String     string `json:"string"`
-		MajorValue int    `json:"major_value"`
-		MinorValue int    `json:"minor_value"`
-	} `json:"ata_version"`
-	SataVersion struct {
-		String string `json:"string"`
-		Value  int    `json:"value"`
-	} `json:"sata_version"`
-	InterfaceSpeed struct {
-		Max struct {
-			SataValue      int    `json:"sata_value"`
-			String         string `json:"string"`
-			UnitsPerSecond int    `json:"units_per_second"`
-			BitsPerUnit    int    `json:"bits_per_unit"`
-		} `json:"max"`
-		Current struct {
-			SataValue      int    `json:"sata_value"`
-			String         string `json:"string"`
-			UnitsPerSecond int    `json:"units_per_second"`
-			BitsPerUnit    int    `json:"bits_per_unit"`
-		} `json:"current"`
-	} `json:"interface_speed"`
-	LocalTime struct {
-		TimeT   int    `json:"time_t"`
-		Asctime string `json:"asctime"`
-	} `json:"local_time"`
-	SmartStatus struct {
-		Passed bool `json:"passed"`
-	} `json:"smart_status"`
-	AtaSmartData struct {
-		OfflineDataCollection struct {
-			Status struct {
-				Value  int    `json:"value"`
-				String string `json:"string"`
-			} `json:"status"`
-			CompletionSeconds int `json:"completion_seconds"`
-		} `json:"offline_data_collection"`
-		SelfTest struct {
-			Status struct {
-				Value  int    `json:"value"`
-				String string `json:"string"`
-				Passed bool   `json:"passed"`
-			} `json:"status"`
-			PollingMinutes struct {
-				Short      int `json:"short"`
-				Extended   int `json:"extended"`
-				Conveyance int `json:"conveyance"`
-			} `json:"polling_minutes"`
-		} `json:"self_test"`
-		Capabilities struct {
-			Values                        []int `json:"values"`
-			ExecOfflineImmediateSupported bool  `json:"exec_offline_immediate_supported"`
-			OfflineIsAbortedUponNewCmd    bool  `json:"offline_is_aborted_upon_new_cmd"`
-			OfflineSurfaceScanSupported   bool  `json:"offline_surface_scan_supported"`
-			SelfTestsSupported            bool  `json:"self_tests_supported"`
-			ConveyanceSelfTestSupported   bool  `json:"conveyance_self_test_supported"`
-			SelectiveSelfTestSupported    bool  `json:"selective_self_test_supported"`
-			AttributeAutosaveEnabled      bool  `json:"attribute_autosave_enabled"`
-			ErrorLoggingSupported         bool  `json:"error_logging_supported"`
-			GpLoggingSupported            bool  `json:"gp_logging_supported"`
-		} `json:"capabilities"`
-	} `json:"ata_smart_data"`
-	AtaSctCapabilities struct {
-		Value                         int  `json:"value"`
-		ErrorRecoveryControlSupported bool `json:"error_recovery_control_supported"`
-		FeatureControlSupported       bool `json:"feature_control_supported"`
-		DataTableSupported            bool `json:"data_table_supported"`
-	} `json:"ata_sct_capabilities"`
-	AtaSmartAttributes struct {
-		Revision int `json:"revision"`
-		Table    []struct {
-			ID         int    `json:"id"`
-			Name       string `json:"name"`
-			Value      int    `json:"value"`
-			Worst      int    `json:"worst"`
-			Thresh     int    `json:"thresh"`
-			WhenFailed string `json:"when_failed"`
-			Flags      struct {
-				Value         int    `json:"value"`
-				String        string `json:"string"`
-				Prefailure    bool   `json:"prefailure"`
-				UpdatedOnline bool   `json:"updated_online"`
-				Performance   bool   `json:"performance"`
-				ErrorRate     bool   `json:"error_rate"`
-				EventCount    bool   `json:"event_count"`
-				AutoKeep      bool   `json:"auto_keep"`
-			} `json:"flags"`
-			Raw struct {
-				Value  int    `json:"value"`
-				String string `json:"string"`
-			} `json:"raw"`
-		} `json:"table"`
-	} `json:"ata_smart_attributes"`
-	PowerOnTime struct {
-		Hours   int `json:"hours"`
-		Minutes int `json:"minutes"`
-	} `json:"power_on_time"`
-	PowerCycleCount int `json:"power_cycle_count"`
-	Temperature     struct {
-		Current int `json:"current"`
-	} `json:"temperature"`
-	AtaSmartSelfTestLog struct {
-		Standard struct {
-			Revision int `json:"revision"`
-			Table    []struct {
-				Type struct {
-					Value  int    `json:"value"`
-					String string `json:"string"`
-				} `json:"type"`
-				Status struct {
-					Value  int    `json:"value"`
-					String string `json:"string"`
-					Passed bool   `json:"passed"`
-				} `json:"status,omitempty"`
-				LifetimeHours int `json:"lifetime_hours"`
-			} `json:"table"`
-			Count              int `json:"count"`
-			ErrorCountTotal    int `json:"error_count_total"`
-			ErrorCountOutdated int `json:"error_count_outdated"`
-		} `json:"standard"`
-	} `json:"ata_smart_self_test_log"`
-	AtaSmartSelectiveSelfTestLog struct {
-		Revision int `json:"revision"`
-		Table    []struct {
-			LbaMin int `json:"lba_min"`
-			LbaMax int `json:"lba_max"`
-			Status struct {
-				Value  int    `json:"value"`
-				String string `json:"string"`
-			} `json:"status"`
-		} `json:"table"`
-		Flags struct {
-			Value                int  `json:"value"`
-			RemainderScanEnabled bool `json:"remainder_scan_enabled"`
-		} `json:"flags"`
-		PowerUpScanResumeMinutes int `json:"power_up_scan_resume_minutes"`
-	} `json:"ata_smart_selective_self_test_log"`
-}
-
-// SMART was used for storing all Devices data
-type SMART struct {
-	Port       string       `json:"Port"`
-	DriveSmart *DeviceSMART `json:"SMART"`
-}
-
-// DiskSmartInit Desktop script initiation
-func system_disk_smart_init() {
-	log.Println("Starting SMART mointoring")
-	if !(fileExists("system/disk/smart/win/smartctl.exe") || fileExists("system/disk/smart/linux/smartctl_arm") || fileExists("system/disk/smart/linux/smartctl_arm64") || fileExists("system/disk/smart/linux/smartctl_i386")) {
-		if build_version == "development" {
-			log.Fatal("[SMART Mointoring] One or more binary not found.")
-		} else {
-			panic("[SMART Mointoring] One or more binary not found.")
-		}
-
-	}
-	if runtime.GOOS == "windows" {
-		SystemSmartExecutable = "./system/disk/smart/win/smartctl.exe"
-	} else if runtime.GOOS == "linux" {
-		if runtime.GOARCH == "arm" {
-			SystemSmartExecutable = "./system/disk/smart/linux/smartctl_armv6"
-		}
-		if runtime.GOARCH == "arm64" {
-			SystemSmartExecutable = "./system/disk/smart/linux/smartctl_armv6"
-		}
-		if runtime.GOARCH == "386" {
-			SystemSmartExecutable = "./system/disk/smart/linux/smartctl_i386"
-		}
-		if runtime.GOARCH == "amd64" {
-			SystemSmartExecutable = "./system/disk/smart/linux/smartctl_i386"
-		}
-	} else {
-		if build_version == "development" {
-			//log.Fatal("[SMART Mointoring] This webApp can't run on imcompitiable environment")
-		} else {
-			panic("[SMART Mointoring] This webApp can't run on imcompitiable environment")
-		}
-
-	}
-	//Register all the required API
-	http.HandleFunc("/system/disk/smart/getSMART", GetSMART)
-	http.HandleFunc("/system/disk/smart/getSMARTTable", checkDiskTable)
-	http.HandleFunc("/system/disk/smart/getLogInfo", checkDiskTestStatus)
-
-	//Only allow SMART under sudo moude
-	if sudo_mode {
-		//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,
-		})
-	}
-
-}
-
-// ReadSMART xxx
-func ReadSMART() []SMART {
-	if time.Now().Unix()-lastScanTime > 30 {
-		SMARTInformation = []SMART{}
-		//Scan disk
-		cmd := exec.Command(SystemSmartExecutable, "--scan", "--json=c")
-		out, _ := cmd.CombinedOutput()
-		Devices := new(DevicesList)
-		DevicesOutput := string(out)
-		json.Unmarshal([]byte(DevicesOutput), &Devices)
-		for _, element := range Devices.Devices {
-			//Load SMART for each drive
-			cmd := exec.Command(SystemSmartExecutable, "-i", element.Name, "-a", "--json=c")
-			out, _ = cmd.CombinedOutput()
-			InvSMARTInformation := new(DeviceSMART)
-			SMARTOutput := string(out)
-			json.Unmarshal([]byte(SMARTOutput), &InvSMARTInformation)
-			if len(InvSMARTInformation.Smartctl.Messages) > 0 {
-				if InvSMARTInformation.Smartctl.Messages[0].Severity == "error" {
-					log.Println("[SMART Mointoring] Disk " + element.Name + " cannot be readed")
-				} else {
-					//putting everything into that struct array
-					n := SMART{Port: element.Name, DriveSmart: InvSMARTInformation}
-					SMARTInformation = append(SMARTInformation, n)
-				}
-			} else {
-				//putting everything into that struct array
-				n := SMART{Port: element.Name, DriveSmart: InvSMARTInformation}
-				SMARTInformation = append(SMARTInformation, n)
-			}
-
-		}
-		lastScanTime = time.Now().Unix()
-	}
-	return SMARTInformation
-}
-
-func GetSMART(w http.ResponseWriter, r *http.Request) {
-	//Check if user has logged in
-	if authAgent.CheckAuth(r) == false {
-		redirectToLoginPage(w, r)
-		return
-	}
-	jsonText, _ := json.Marshal(ReadSMART())
-	//send!
-	sendJSONResponse(w, string(jsonText))
-}
-
-func checkDiskTable(w http.ResponseWriter, r *http.Request) {
-	//Check if user has logged in
-	if authAgent.CheckAuth(r) == false {
-		redirectToLoginPage(w, r)
-		return
-	}
-	disks, ok := r.URL.Query()["disk"]
-	if !ok || len(disks[0]) < 1 {
-		log.Println("Parameter DISK not found.")
-		return
-	}
-
-	DiskStatus := new(DeviceSMART)
-	for _, info := range ReadSMART() {
-		if info.Port == disks[0] {
-			DiskStatus = info.DriveSmart
-		}
-	}
-	JSONStr, _ := json.Marshal(DiskStatus.AtaSmartAttributes.Table)
-	//send!
-	sendJSONResponse(w, string(JSONStr))
-}
-
-func checkDiskTestStatus(w http.ResponseWriter, r *http.Request) {
-	//Check if user has logged in
-	if authAgent.CheckAuth(r) == false {
-		redirectToLoginPage(w, r)
-		return
-	}
-	disks, ok := r.URL.Query()["disk"]
-	if !ok || len(disks[0]) < 1 {
-		log.Println("Parameter DISK not found.")
-		return
-	}
-
-	DiskTestStatus := new(DeviceSMART)
-	for _, info := range ReadSMART() {
-		if info.Port == disks[0] {
-			DiskTestStatus = info.DriveSmart
-		}
-	}
-	JSONStr, _ := json.Marshal(DiskTestStatus.AtaSmartData.SelfTest.Status)
-	//send!
-	sendJSONResponse(w, string(JSONStr))
-}

+ 0 - 150
legacy/disabled/system.disk.space.go

@@ -1,150 +0,0 @@
-package main
-
-import (
-	"net/http"
-	"os/exec"
-	"strings"
-	"encoding/json"
-	"log"
-	"runtime"
-)
-
-/*
-	Disk Space Services
-
-	Return the disk information of the system. 
-	The most basic task of all
-*/
-
-type LogicalDiskSpaceInfo struct{
-	Device string
-	Volume  int64
-	Used   int64
-	Available int64
-	UsedPercentage string
-	MountPoint string
-}
-
-func system_disk_space_init(){
-	//Register API
-	http.HandleFunc("/system/disk/space/list", system_disk_space_handleList)
-
-	//Register settings
-	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",
-	})
-}
-
-func system_disk_space_handleList(w http.ResponseWriter, r *http.Request){
-	allDisksVolume := system_disk_space_getDriveInfo();
-	jsonString, _ := json.Marshal(allDisksVolume);
-	sendJSONResponse(w, string(jsonString))
-}
-
-func system_disk_space_getDriveInfo() []LogicalDiskSpaceInfo{
-	if runtime.GOOS == "windows" {
-		//Check window disk info, wip
-		cmd := exec.Command("wmic", "logicaldisk","get","caption,size,freespace")
-		out, err := cmd.CombinedOutput()
-		if (err != nil){
-			log.Println("wmic not supported.")
-			return []LogicalDiskSpaceInfo{};
-		}
-		lines := strings.Split(string(out),"\n")
-		var results []LogicalDiskSpaceInfo
-		for _,line := range lines{
-			if (strings.Contains(line, ":")){
-				//This is a valid drive
-
-				line = strings.TrimSpace(line)
-				//Tidy the line
-				for strings.Contains(line, "  "){
-					line = strings.Replace(line, "  "," ",-1)
-				}
-
-				//Split by space
-				infoChunk := strings.Split(line, " ")
-				if len(infoChunk) == 1{
-					//Drive reserved and not mounted, like SD card adapters
-					results = append(results, LogicalDiskSpaceInfo{
-						Device: infoChunk[0],
-						Volume: 0,
-						Used: 	0,
-						Available: 0,
-						UsedPercentage: "Not Mounted",
-						MountPoint: infoChunk[0],
-					})
-				}else if (len(infoChunk) > 2){
-					size, err := StringToInt64(infoChunk[2])
-					if (err != nil){
-						size = 0;
-					}
-					freespace, err := StringToInt64(infoChunk[1])
-					if (err != nil){
-						size = 0;
-					}
-					usedSpace := size - freespace;
-					percentage := int64(float64(usedSpace) / float64(size) * 100)
-
-					results = append(results, LogicalDiskSpaceInfo{
-						Device: infoChunk[0],
-						Volume: size,
-						Used: 	usedSpace,
-						Available: freespace,
-						UsedPercentage: IntToString(int(percentage)) + "%",
-						MountPoint: infoChunk[0],
-					})
-				}
-			}
-		}
-
-		return results
-	}else{
-		//Get drive status using df command
-		cmdin := `df -k | sed -e /Filesystem/d`
-		cmd := exec.Command("bash","-c",cmdin)
-		dev, err := cmd.CombinedOutput()
-		if err != nil {
-			dev = []byte{}
-		}
-
-		drives := strings.Split(string(dev), "\n")
-
-		if (len(drives) == 0){
-			return []LogicalDiskSpaceInfo{}
-		}
-
-		var arr []LogicalDiskSpaceInfo
-		for _, driveInfo := range drives {
-			if (driveInfo == ""){
-				continue;
-			}
-			for strings.Contains(driveInfo, "  "){
-				driveInfo = strings.Replace(driveInfo, "  ", " ", -1)
-			}
-			driveInfoChunk := strings.Split(driveInfo, " ")
-			volume, _ := StringToInt64(driveInfoChunk[1])
-			usedSpace, _ := StringToInt64(driveInfoChunk[2])
-			freespaceInByte, _ := StringToInt64(driveInfoChunk[3])
-			
-			LogicalDisk := LogicalDiskSpaceInfo{
-				Device: driveInfoChunk[0],
-				Volume: volume * 1024,
-				Used: 	usedSpace * 1024,
-				Available: freespaceInByte * 1024,
-				UsedPercentage: driveInfoChunk[4],
-				MountPoint: driveInfoChunk[5],
-			}
-			arr = append(arr, LogicalDisk)
-		}
-
-		return arr
-	}
-	
-	return []LogicalDiskSpaceInfo{}
-}
-

+ 0 - 264
legacy/disabled/system.permission.go

@@ -1,264 +0,0 @@
-package main
-
-import (
-	"encoding/json"
-	"errors"
-	"net/http"
-	"strings"
-	//"log"
-)
-
-/*
-	This is the permission management module of the ArOZ Online System
-
-	In default mode, the system only contains a user group named "administrator"
-	This module also handle permission checking and others
-*/
-
-//Initiate function for system permission
-func system_permission_service_init() {
-	//Register permission configuration endpoints
-	http.HandleFunc("/system/permission/listgroup", system_permission_handleListGroup)
-	http.HandleFunc("/system/permission/newgroup", system_permission_createUserGroupHandler)
-	http.HandleFunc("/system/permission/delgroup", system_permission_removeUserGroupHandler)
-	http.HandleFunc("/system/permission/isAdmin", system_permission_handleAdminCheck)
-	//http.HandleFunc("/system/permission/groupdetails", system_permission_handleGroupDetail)
-
-	//Create table if not exists
-	sysdb.NewTable("permission")
-
-	//Register setting interface for module configuration
-	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,
-	})
-
-}
-
-func system_permission_getUserGroups(username string) (string, error) {
-	group := ""
-	sysdb.Read( "auth", "group/"+username, &group)
-	if group == "" {
-		return "", errors.New("User group not found")
-	}
-	return group, nil
-}
-
-//Return a list of usergorup stored in the system
-func system_permission_listGroup() []string {
-	groups := []string{}
-	entries, _ := sysdb.ListTable("permission")
-	for _, keypairs := range entries {
-		if strings.Contains(string(keypairs[0]), "group/") {
-			groups = append(groups, strings.Split(string(keypairs[0]), "/")[1])
-		}
-	}
-
-	return groups
-}
-
-//Return the current list of usergroup from the database as JSON
-func system_permission_handleListGroup(w http.ResponseWriter, r *http.Request) {
-	groups := []string{}
-	entries, _ := sysdb.ListTable("permission")
-	listPermission, _ := mv(r, "showper", false)
-	if listPermission == "" {
-		for _, keypairs := range entries {
-			if strings.Contains(string(keypairs[0]), "group/") {
-				//This is a group name record. Append the group name only.
-				groups = append(groups, strings.Split(string(keypairs[0]), "/")[1])
-			}
-		}
-
-		//Check if the group list is empty. If yes, create the administrator group
-		if len(groups) == 0 {
-			err := system_permission_createGroup("administrator", []string{"*"})
-			if err != nil {
-				panic("Failed to create administrator group. Is database writable?")
-			}
-			groups = append(groups, "administrator")
-		}
-
-		jsonString, _ := json.Marshal(groups)
-		sendJSONResponse(w, string(jsonString))
-	} else {
-		results := map[string][]string{}
-		for _, keypairs := range entries {
-			if strings.Contains(string(keypairs[0]), "group/") {
-				//This is a group name record. Append the group name only.
-				thisGroupPermission := []string{}
-				json.Unmarshal(keypairs[1], &thisGroupPermission)
-				results[strings.Split(string(keypairs[0]), "/")[1]] = thisGroupPermission
-			}
-		}
-
-		jsonString, _ := json.Marshal(results)
-		sendJSONResponse(w, string(jsonString))
-	}
-
-	/*
-		//Deprecated method for listing group with JSON string storage
-		groupsData := "";
-		sysdb.Read( "permission", "groups", &groups)
-		//There are always at least one group and this key must be valid. Not need to check for error.
-		w.Header().Set("Content-Type", "application/json")
-		sendTextResponse(w,groups)
-	*/
-}
-
-func system_permission_handleAdminCheck(w http.ResponseWriter, r *http.Request) {
-	isAdmin := system_permission_checkUserIsAdmin(w, r)
-	if isAdmin {
-		sendJSONResponse(w, "true")
-	} else {
-		sendJSONResponse(w, "false")
-	}
-}
-
-func system_permission_handleGroupDetail(w http.ResponseWriter, r *http.Request) {
-	opr, _ := mv(r, "opr", false)
-	if opr == "" {
-		//List all groups with detail
-		var groupsRaw []byte
-		sysdb.Read( "permission", "groups", &groupsRaw)
-		var groups []string
-		json.Unmarshal(groupsRaw, &groups)
-
-	}
-}
-
-func system_permission_createGroup(groupname string, modulepermission []string) error {
-	//Check if group already exists
-	if !system_permission_groupExists(groupname) {
-		//This group do not exists. Continue to create
-		err := sysdb.Write("permission", "group/"+groupname, modulepermission)
-		if err != nil {
-			return err
-		}
-	} else {
-		//This group exists.
-		return errors.New("Group already exists")
-	}
-	return nil
-}
-
-func system_permission_removeUserGroupHandler(w http.ResponseWriter, r *http.Request) {
-	//Check if user is admin
-	isAdmin := system_permission_checkUserIsAdmin(w, r)
-	if !isAdmin {
-		sendErrorResponse(w, "Permission denied")
-		return
-	}
-
-	//Check if the groupname is provided
-	groupname, err := mv(r, "groupname", false)
-	if err != nil {
-		sendErrorResponse(w, "Groupname not defined")
-		return
-	}
-
-	//Remove the group from database
-	if system_permission_groupExists(groupname) {
-		//This group exits. Continue removal
-		err := sysdb.Delete("permission", "group/"+groupname)
-		if err != nil {
-			sendErrorResponse(w, err.Error())
-			return
-		}
-	} else {
-		//This group exists.
-		sendErrorResponse(w, "Given group not exists")
-		return
-	}
-
-	sendOK(w)
-}
-
-func system_permission_createUserGroupHandler(w http.ResponseWriter, r *http.Request) {
-	isAdmin := system_permission_checkUserIsAdmin(w, r)
-	if !isAdmin {
-		sendErrorResponse(w, "Permission denied")
-		return
-	}
-	groupname, err := mv(r, "groupname", true)
-	if err != nil {
-		sendErrorResponse(w, "Groupname not defined")
-		return
-	}
-
-	permissions, err := mv(r, "permission", true)
-	if err != nil {
-		sendErrorResponse(w, "Permission not defined")
-		return
-	}
-	permissionList := []string{}
-	err = json.Unmarshal([]byte(permissions), &permissionList)
-	if err != nil {
-		sendErrorResponse(w, "Failed to parse the permission list")
-		return
-	}
-	system_permission_createGroup(groupname, permissionList)
-	sendOK(w)
-}
-
-
-func system_permission_getGroupAccessList(groupname string) []string {
-	moduleList := []string{}
-	err := sysdb.Read( "permission", "group/"+groupname, &moduleList)
-	if err != nil {
-		return []string{}
-	}
-	return moduleList
-}
-
-func system_permission_checkUserHasAccessToModule(username string, modulename string) bool {
-	//Get user group and see if group exists.
-	usergroup := system_permission_getUserPermissionGroup(username)
-	groupExists := system_permission_groupExists(usergroup)
-	if !groupExists {
-		return false
-	}
-
-	//Group exists. Check permission on module
-	groupAccessList := system_permission_getGroupAccessList(usergroup)
-	if len(groupAccessList) == 1 && groupAccessList[0] == "*" {
-		return true
-	}
-	if stringInSlice(modulename, groupAccessList) {
-		return true
-	}
-
-	return false
-}
-
-func system_permission_checkUserIsAdmin(w http.ResponseWriter, r *http.Request) bool {
-	username, err := authAgent.GetUserName(w, r)
-	if err != nil{
-		return false
-	}
-	userGroup := system_permission_getUserPermissionGroup(username)
-	if userGroup == "administrator" {
-		return true
-	}
-	return false
-}
-
-func system_permission_getUserPermissionGroup(username string) string {
-	usergroup := ""
-	sysdb.Read( "auth", "group/"+username, &usergroup)
-	return (usergroup)
-}
-
-//This function check if the given usergroup ID exists.
-func system_permission_groupExists(group string) bool {
-	dummyPermission := []string{}
-	err := sysdb.Read( "permission", "group/"+group, &dummyPermission)
-	if err != nil || len(dummyPermission) == 0 {
-		return false
-	}
-	return true
-}

+ 0 - 114
legacy/disabled/system.power.go

@@ -1,114 +0,0 @@
-package main
-
-import (
-	"log"
-	"net/http"
-	"os/exec"
-	"runtime"
-)
-
-/*
-	Power Management Module
-
-	This module will handle the power condition of the system, including poweroff and restart
-*/
-
-func system_power_init() {
-	http.HandleFunc("/system/power/shutdown", system_power_poweroff)
-	http.HandleFunc("/system/power/restart", system_power_restart)
-}
-
-func system_power_poweroff(w http.ResponseWriter, r *http.Request) {
-	isAdmin := system_permission_checkUserIsAdmin(w, r)
-	if !isAdmin {
-		sendErrorResponse(w, "Permission Denied")
-		return
-	}
-
-	if !sudo_mode {
-		sendErrorResponse(w, "Sudo mode required")
-		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 {
-			log.Println(string(out))
-			sendErrorResponse(w, string(out))
-		}
-		log.Println(string(out))
-	}
-
-	if runtime.GOOS == "linux" {
-		//Only allow Linux to do power operation
-		cmd := exec.Command("/sbin/shutdown")
-		out, err := cmd.CombinedOutput()
-		if err != nil {
-			log.Println(string(out))
-			sendErrorResponse(w, string(out))
-		}
-		log.Println(string(out))
-	}
-
-	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 {
-			log.Println(string(out))
-			sendErrorResponse(w, string(out))
-		}
-		log.Println(string(out))
-	}
-
-	sendOK(w)
-}
-
-func system_power_restart(w http.ResponseWriter, r *http.Request) {
-	isAdmin := system_permission_checkUserIsAdmin(w, r)
-	if !isAdmin {
-		sendErrorResponse(w, "Permission Denied")
-		return
-	}
-
-	if !sudo_mode {
-		sendErrorResponse(w, "Sudo mode required")
-		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 {
-			log.Println(string(out))
-			sendErrorResponse(w, string(out))
-		}
-		log.Println(string(out))
-	}
-
-	if runtime.GOOS == "linux" {
-		//Only allow Linux to do power operation
-		cmd := exec.Command("systemctl", "reboot")
-		out, err := cmd.CombinedOutput()
-		if err != nil {
-			log.Println(string(out))
-			sendErrorResponse(w, string(out))
-		}
-		log.Println(string(out))
-	}
-
-	if runtime.GOOS == "darwin" {
-		//Only allow Linux to do power operation
-		cmd := exec.Command("shutdown", "-r", "+1")
-		out, err := cmd.CombinedOutput()
-		if err != nil {
-			log.Println(string(out))
-			sendErrorResponse(w, string(out))
-		}
-		log.Println(string(out))
-	}
-	sendOK(w)
-}

+ 0 - 150
legacy/disabled/system.resetpw.go

@@ -1,150 +0,0 @@
-package main
-
-import (
-	"net/http"
-	"log"
-	"errors"
-
-	auth "imuslab.com/arozos/mod/auth"
-)
-
-/*
-	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 := mv(r, "username", true)
-	if err != nil{
-		sendErrorResponse(w, "Internal Server Error")
-		return
-	}
-	rkey, err := mv(r, "rkey", true)
-	if err != nil{
-		sendErrorResponse(w, "Internal Server Error")
-		return
-	}
-
-	if username == "" || rkey == "" {
-		sendErrorResponse(w, "Invalid username or rkey")
-		return
-	}
-
-	//Check if the pair is valid
-	err = system_resetpw_validateResetKey(username, rkey)
-	if err != nil{
-		sendErrorResponse(w, err.Error())
-		return
-	}
-
-	sendOK(w)
-
-}
-
-func system_resetpw_confirmReset(w http.ResponseWriter, r *http.Request){
-	username, _ := mv(r, "username", true)
-	rkey, _ := mv(r, "rkey", true)
-	newpw, _ := mv(r, "pw", true)
-	if (username == "" || rkey == "" || newpw == ""){
-		sendErrorResponse(w, "Internal Server Error")
-		return
-	}
-
-	//Check user exists
-	if !authAgent.UserExists(username){
-		sendErrorResponse(w, "Username not exists")
-		return
-	}
-
-	//Validate rkey
-	err := system_resetpw_validateResetKey(username, rkey)
-	if err != nil{
-		sendErrorResponse(w, err.Error())
-		return
-	}
-
-	//OK to procced
-	newHashedPassword := auth.Hash(newpw)
-	err = sysdb.Write("auth", "passhash/" + username, newHashedPassword)
-	if err != nil{
-		sendErrorResponse(w, err.Error())
-		return
-	}
-
-	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 := mv(r, "acc", false)
-	if err != nil || acc == "" {
-		system_resetpw_serveIdEnterInterface(w,r);
-		return
-	}
-
-	resetkey, err := 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 {
-		sendErrorResponse(w, "Invalid username or resetKey")
-		return
-	}
-
-	//OK. Create the New Password Entering UI
-	imageBase64, _ := LoadImageAsBase64("./web/" + iconVendor)
-	template, err := template_load("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, _ := LoadImageAsBase64("./web/" + iconVendor)
-	template, err := template_load("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))
-}

+ 0 - 237
legacy/disabled/system.users.go

@@ -1,237 +0,0 @@
-package main
-
-import (
-	"net/http"
-	"log"
-	"strings"
-	"encoding/json"
-	"github.com/satori/go.uuid"
-
-	auth "imuslab.com/arozos/mod/auth"
-)
-
-/*
-	USERS MANAGER
-
-	Manage user creation, listing, remove and others
-*/
-
-func system_user_init(){
-	http.HandleFunc("/system/users/list", system_user_handleList)
-	http.HandleFunc("/system/users/editUser", system_user_handleUserEdit)
-	http.HandleFunc("/system/users/userinfo", system_user_handleUserInfo)
-
-	//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,
-	})
-}
-
-//User edit handle. For admin to change settings for a user
-func system_user_handleUserEdit(w http.ResponseWriter, r *http.Request){
-	//Require admin access
-	if !system_permission_checkUserIsAdmin(w,r){
-        sendErrorResponse(w, "Permission denied")
-	}
-	
-	opr, _ := mv(r, "opr", true)
-	username, _ := mv(r, "username", true)
-	if !system_user_userExists(username){
-		sendErrorResponse(w, "User not exists")
-		return
-	}
-
-	if opr == ""{
-		//List this user information
-		type returnValue struct{
-			Username string;
-			Icondata string;
-			Usergroup string;
-		}
-		iconData := getUserIcon(username)
-		userGroup, err := system_permission_getUserGroups(username)
-		if (err != nil){
-			sendErrorResponse(w, "Unable to get user group")
-			return;
-		}
-		jsonString, _ := json.Marshal(returnValue{
-			Username: username,
-			Icondata: iconData,
-			Usergroup: userGroup,
-		})
-
-		sendJSONResponse(w, string(jsonString))
-	}else if opr == "updateUserGroup"{
-		//Update the target user's group
-		newgroup, err := mv(r, "newgroup", true)
-		if err != nil{
-			sendErrorResponse(w, "New Group not defined");
-			return
-		}
-
-		//Check if new group exists
-		if !system_permission_groupExists(newgroup){
-			sendErrorResponse(w, "Group not exists")
-			return
-		}
-
-		//OK to proceed
-		err = sysdb.Write("auth", "group/" + username, newgroup)
-		if err != nil{
-			sendErrorResponse(w, err.Error())
-			return
-		}
-		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{
-			sendErrorResponse(w, err.Error())
-			return
-		}
-		//Finish. Send back the reseted password
-		sendJSONResponse(w, "\"" + tmppassword + "\"")
-
-	}else{
-		sendErrorResponse(w, "Not supported opr")
-		return
-	}
-
-	
-}
-
-//User Info handler. Handle user's editing for his / her own profile
-func system_user_handleUserInfo(w http.ResponseWriter, r *http.Request){
-	username, err := authAgent.GetUserName(w,r);
-	if (err != nil){
-		sendErrorResponse(w, "User not logged in")
-		return;
-	}
-	opr, _ := mv(r, "opr", true)
-
-	if (opr == ""){
-		//Listing mode
-		iconData := getUserIcon(username)
-		userGroup, err := system_permission_getUserGroups(username)
-		if (err != nil){
-			sendErrorResponse(w, "Unable to get user group")
-			return;
-		}
-		type returnValue struct{
-			Username string;
-			Icondata string;
-			Usergroup string;
-		}
-		jsonString, _ := json.Marshal(returnValue{
-			Username: username,
-			Icondata: iconData,
-			Usergroup: userGroup,
-		})
-
-		sendJSONResponse(w, string(jsonString))
-		return;
-	}else if (opr == "changepw"){
-		oldpw, _ := mv(r, "oldpw", true)
-		newpw, _ := mv(r, "newpw", true)
-		if (oldpw == "" || newpw == ""){
-			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.
-			sendErrorResponse(w, "Invalid old password.")
-			return;
-		}
-		//OK! Change user password
-		newHashedPassword := auth.Hash(newpw)
-		sysdb.Write("auth", "passhash/" + username, newHashedPassword)
-		sendOK(w);
-	}else if (opr == "changeprofilepic"){
-		picdata, _ := mv(r, "picdata", true)
-		if (picdata != ""){
-			setUserIcon(username, picdata);
-			sendOK(w);
-		}else{
-			sendErrorResponse(w, "Empty image data received.")
-			return
-		}
-	}else{
-		sendErrorResponse(w, "Not supported opr")
-		return
-	}
-}
-
-//Get and set user profile icon
-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
-}
-
-func system_user_userExists(username string) bool{
-	//Implement alternative interface for checking user exists
-	return authAgent.UserExists(username);
-}
-
-func system_user_handleList(w http.ResponseWriter, r *http.Request){
-	//List all users within the auth database.
-	if (authAgent.CheckAuth(r) == false){
-        //This user has not logged in
-        sendErrorResponse(w, "User not logged in");
-        return;
-    }
-	if (system_permission_checkUserIsAdmin(w,r) == true){
-		entries,_ := sysdb.ListTable("auth")
-		results := [][]string{}
-		for _, keypairs := range entries{
-			if (strings.Contains(string(keypairs[0]), "group/")){
-				username:= strings.Split(string(keypairs[0]),"/")[1]
-				group := ""
-				//Get user icon if it exists in the database
-				userIcon := getUserIcon(username)
-				
-				//Get the user account states
-				accountStatus := "normal"
-				sysdb.Read("auth","acstatus/" + username, &accountStatus)
-
-				json.Unmarshal(keypairs[1], &group)
-				results = append(results, []string{username, group, userIcon, accountStatus})
-			}
-		}
-		
-		jsonString, _ := json.Marshal(results)
-		sendJSONResponse(w, string(jsonString))
-		return
-	}else{
-		username, _ := authAgent.GetUserName(w,r);
-		log.Println("[Permission] " + username + " tries to access admin only function.")
-		sendErrorResponse(w, "Permission denied")
-		return;
-	}
-}

+ 0 - 330
legacy/module.Photo.go_disabled

@@ -1,330 +0,0 @@
-package main
-
-import (
-	"crypto/md5"
-	"encoding/hex"
-	"encoding/json"
-	"errors"
-	"fmt"
-	"image"
-	"io"
-	"log"
-	"net/http"
-	"os"
-	"path/filepath"
-
-	"strings"
-
-	"github.com/disintegration/imaging"
-
-	reflect "reflect"
-)
-
-/*
-	Photo - The worst Photo Viewer for ArOZ Online
-
-	 By Alan Yeung, 2020
-
-*/
-
-//SupportFileExt shouldn't be exported
-var SupportFileExt = []string{".jpg", ".jpeg", ".gif", ".tiff", ".png", ".tif", ".heif"}
-
-//Output shouldn't be exported.
-type Output struct {
-	URL      string
-	Filename string
-	Size     string
-	CacheURL string
-	Height   int
-	Width    int
-}
-
-//OutputFolder shouldn't be exported
-type OutputFolder struct {
-	VPath      string
-	Foldername string
-}
-
-//SearchReturn shouldn't be exported
-type SearchReturn struct {
-	Success bool `json:"success"`
-	Results []struct {
-		Name     string `json:"name"`
-		Value    string `json:"value"`
-		Text     string `json:"text"`
-		Disabled bool   `json:"disabled,omitempty"`
-	} `json:"results"`
-}
-
-func module_Photo_init() {
-	http.HandleFunc("/Photo/listPhoto", ModulePhotoListPhoto)
-	http.HandleFunc("/Photo/listFolder", ModulePhotoListFolder)
-	http.HandleFunc("/Photo/search", ModulePhotoSearch)
-	//http.HandleFunc("/Photo/getMeta", module_Photo_getMeta)
-
-	//Register this module to system
-	registerModule(moduleInfo{
-		Name:         "Photo",
-		Desc:         "The Photo Viewer for ArOZ Online",
-		Group:        "Media",
-		IconPath:     "Photo/img/module_icon.png",
-		Version:      "0.0.1",
-		StartDir:     "Photo/index.html",
-		SupportFW:    true,
-		LaunchFWDir:  "Photo/index.html",
-		SupportEmb:   true,
-		LaunchEmb:    "Photo/embedded.html",
-		InitFWSize:   []int{800, 600},
-		InitEmbSize:  []int{800, 600},
-		SupportedExt: SupportFileExt,
-	})
-
-}
-
-//ModulePhotoListPhoto shouldn't be exported
-func ModulePhotoListPhoto(w http.ResponseWriter, r *http.Request) {
-	username, err := system_auth_getUserName(w, r)
-	if err != nil {
-		redirectToLoginPage(w, r)
-		return
-	}
-
-	//obtain folder name from GET request
-	folder, ok := r.URL.Query()["folder"]
-
-	//check if GET request exists, if not then using default path
-	if !ok || len(folder[0]) < 1 {
-		folder = append(folder, "user:/Photo/Photo/uploads")
-	}
-
-	//obtain filter from GET request
-	filter, ok := r.URL.Query()["q"]
-
-	//check if GET request exists, if not then using null
-	if !ok || len(folder[0]) < 1 {
-		filter = append(filter, "")
-	}
-
-	Alldata, _ := QueryDir(folder[0], filter[0], username)
-	jsonString, _ := json.Marshal(Alldata)
-	sendJSONResponse(w, string(jsonString))
-}
-
-//ModulePhotoListFolder shouldn't be exported
-func ModulePhotoListFolder(w http.ResponseWriter, r *http.Request) {
-	username, err := system_auth_getUserName(w, r)
-	if err != nil {
-		redirectToLoginPage(w, r)
-		return
-	}
-
-	storageDir, _ := virtualPathToRealPath("user:/Photo/Photo/storage", username)
-	os.MkdirAll(storageDir, 0755)
-
-	Alldata := []OutputFolder{}
-
-	filepath.Walk(storageDir, func(path string, info os.FileInfo, e error) error {
-		if e != nil {
-			return e
-		}
-
-		if info.Mode().IsDir() && path != storageDir {
-			vPath, _ := realpathToVirtualpath(path, username)
-
-			folderData := OutputFolder{
-				VPath:      vPath,
-				Foldername: filepath.Base(path),
-			}
-			Alldata = append(Alldata, folderData)
-		}
-		return nil
-	})
-
-	jsonString, _ := json.Marshal(Alldata)
-	sendJSONResponse(w, string(jsonString))
-}
-
-//QueryDir shouldn't be exported.
-func QueryDir(vPath string, filter string, username string) ([]Output, error) {
-	//create dir
-	uploadDir, _ := virtualPathToRealPath(vPath, username)
-	cacheDir, _ := virtualPathToRealPath("user:/Photo/Photo/thumbnails", username)
-	os.MkdirAll(uploadDir, 0755)
-	os.MkdirAll(cacheDir, 0755)
-
-	Alldata := []Output{}
-	files, _ := filepath.Glob(uploadDir + "/*")
-	for _, file := range files {
-		if stringInSlice(filepath.Ext(file), SupportFileExt) {
-			if chkFilter(file, filter) {
-				//File path (vpath)
-				vpath, _ := realpathToVirtualpath(file, username)
-
-				//File Size
-				_, hsize, unit, _ := system_fs_getFileSize(file)
-				size := fmt.Sprintf("%.2f", hsize) + unit
-
-				//File cache location
-				cacheFilename, _ := resizePhoto(file, username)
-				cacheFilevPath := "user:/Photo/Photo/thumbnails/" + cacheFilename
-
-				//Get image width height
-				cacheFilePhyPath, _ := virtualPathToRealPath(cacheFilevPath, username)
-				width, height := getImageDimension(cacheFilePhyPath)
-
-				fileData := Output{
-					URL:      vpath,
-					Filename: filepath.Base(file),
-					Size:     size,
-					CacheURL: cacheFilevPath,
-					Height:   height,
-					Width:    width,
-				}
-				Alldata = append(Alldata, fileData)
-			}
-		}
-	}
-	return Alldata, nil
-}
-
-//ModulePhotoSearch shouldn't be exported
-func ModulePhotoSearch(w http.ResponseWriter, r *http.Request) {
-	username, err := system_auth_getUserName(w, r)
-	if err != nil {
-		redirectToLoginPage(w, r)
-		return
-	}
-	_ = username
-
-	//obtain folder name from GET request
-	queryString, ok := r.URL.Query()["q"]
-
-	QResult := new(SearchReturn)
-	QResult.Success = true
-
-	//check if GET request exists, if not then using default val
-	if !ok || len(queryString[0]) < 1 {
-		QResult.Success = false
-	} else {
-		n := struct {
-			Name     string `json:"name"`
-			Value    string `json:"value"`
-			Text     string `json:"text"`
-			Disabled bool   `json:"disabled,omitempty"`
-		}{Name: "file:" + queryString[0], Value: "file:" + queryString[0], Text: "file:" + queryString[0], Disabled: false}
-		QResult.Results = append(QResult.Results, n)
-	}
-
-	jsonString, _ := json.Marshal(QResult)
-	sendJSONResponse(w, string(jsonString))
-}
-
-func resizePhoto(filename string, username string) (string, error) {
-	cacheDir, _ := virtualPathToRealPath("user:/Photo/Photo/thumbnails", username)
-	//Generate hash for that file
-	md5, err := hashFilemd5(filename)
-	if err != nil {
-		return "", err
-	}
-	//check if file exist, if true then return
-	if fileExists(cacheDir + "/" + md5 + ".jpg") {
-		return md5 + ".jpg", nil
-	}
-
-	// Open image.
-	src, _ := imaging.Open(filename)
-	// Resize the cropped image to width = 200px preserving the aspect ratio.
-	src = imaging.Resize(src, 200, 0, imaging.Lanczos)
-	// Save the resulting image as JPEG.
-	err = imaging.Save(src, cacheDir+"/"+md5+".jpg")
-	if err != nil {
-		log.Fatalf("failed to save image: %v", err)
-	}
-
-	return md5 + ".jpg", nil
-}
-
-//hashFilemd5 copy from https://mrwaggel.be/post/generate-md5-hash-of-a-file-in-golang/
-func hashFilemd5(filePath string) (string, error) {
-	var returnMD5String string
-	file, err := os.Open(filePath)
-	if err != nil {
-		return returnMD5String, err
-	}
-	defer file.Close()
-	hash := md5.New()
-	if _, err := io.Copy(hash, file); err != nil {
-		return returnMD5String, err
-	}
-	hashInBytes := hash.Sum(nil)[:16]
-	returnMD5String = hex.EncodeToString(hashInBytes)
-	return returnMD5String, nil
-
-}
-
-//thanks https://gist.github.com/sergiotapia/7882944
-func getImageDimension(imagePath string) (int, int) {
-	file, err := os.Open(imagePath)
-	if err != nil {
-		//log.Fprintf(os.Stderr, "%v\n", err)
-	}
-
-	image, _, err := image.DecodeConfig(file)
-	if err != nil {
-		//log.Fprintf(os.Stderr, "%s: %v\n", imagePath, err)
-	}
-	return image.Width, image.Height
-}
-
-var funcs = map[string]interface{}{"file": file}
-
-func chkFilter(imagePath string, filter string) bool {
-	if filter == "" {
-		return true
-	}
-	filtersli := strings.Split(filter, ",")
-	Filterbool := make(map[string]bool)
-
-	if len(filtersli) > 0 {
-		log.Println(filtersli)
-		for _, item := range filtersli {
-			itemArr := strings.Split(item, ":") // [0] = func name , [1] = value
-			log.Println(item)
-			returnResult, _ := Call(funcs, itemArr[0], itemArr[1], imagePath, filepath.Base(imagePath))
-			Filterbool[item] = Filterbool[item] || returnResult[0].Bool()
-		}
-	}
-
-	returnBool := true
-	if len(Filterbool) > 0 {
-		for _, item := range Filterbool {
-			returnBool = returnBool && item
-		}
-	}
-	return returnBool
-}
-
-//https://mikespook.com/2012/07/function-call-by-name-in-golang/
-//Call shouldn not be exported
-func Call(m map[string]interface{}, name string, params ...interface{}) (result []reflect.Value, err error) {
-	f := reflect.ValueOf(m[name])
-	if len(params) != f.Type().NumIn() {
-		err = errors.New("The number of params is not adapted.")
-		return
-	}
-	in := make([]reflect.Value, len(params))
-	for k, param := range params {
-		in[k] = reflect.ValueOf(param)
-	}
-	result = f.Call(in)
-	return
-}
-
-func file(queryString, filename string, filePath string) bool {
-	if strings.Contains(filename, queryString) {
-		return true
-	} else {
-		return false
-	}
-}

+ 0 - 138
legacy/module.Video.go_disabled

@@ -1,138 +0,0 @@
-package main
-
-import (
-	"net/http"
-	"path/filepath"
-	"encoding/json"
-	"log"
-)
-
-func module_Video_init(){
-	http.HandleFunc("/Video/buildPlaylist", module_ArdPlayer_buildPlaylist)
-
-	//Register module
-	registerModule(moduleInfo{
-		Name: "Video",
-		Desc: "The basic video player for ArOZ Online",
-		Group: "Media",
-		IconPath: "Video/img/module_icon.png",
-		Version: "0.0.4",
-		StartDir: "Video/index.html",
-		SupportFW: true,
-		LaunchFWDir: "Video/index.html",
-		SupportEmb: true,
-		LaunchEmb: "Video/embedded.html",
-		InitFWSize: []int{585, 820},
-		InitEmbSize: []int{700, 470},
-		SupportedExt: []string{".webm",".mp4",".ogg"},
-	})
-}
-
-//Scan all the attached storage devices and generate a global playlist
-func module_ArdPlayer_buildPlaylist(w http.ResponseWriter, r *http.Request){
-	username, err := system_auth_getUserName(w,r);
-	if (err != nil){
-		sendErrorResponse(w,"User not logged in")
-		return;
-	}
-	
-	type videoFile struct{
-		Filename string
-		Filepath string
-		Ext string
-	}
-
-	type playList struct{
-		Name string
-		Files []videoFile
-	}
-
-	type viewPoint struct{
-		StorageName string
-		PlayLists []playList
-		UnsortedVideos []videoFile
-	}
-
-	results := []viewPoint{}
-	for _, dev := range storages{
-		//Get the base dir of this storage device
-		scanBaseDir := ""
-		devicePath := dev.Path;
-		if (devicePath[len(devicePath)-1:] != "/"){
-			devicePath = devicePath + "/"
-		}
-		if (dev.Hierarchy == "users"){
-			scanBaseDir = devicePath + username + "/Video"
-		}else if (dev.Hierarchy == "public"){
-			scanBaseDir = devicePath
-		}
-
-		if (scanBaseDir == "" || !fileExists(scanBaseDir)){
-			//This directory has no supported hierarchy or root folder not exists
-			continue;
-		}
-		//log.Println(scanBaseDir)
-
-		//Scan this directory for folders or video files and build a playlist out of it
-		
-		supportExt := []string{".mp4",".webm",".ogg"}
-		objs, _ := system_fs_specialGlob(scanBaseDir)
-		//Declare a new ViewPort for this device
-		thisViewPort := new(viewPoint)
-		allPlayLists := []playList{}
-		unsortedFiles := []videoFile{}
-		for _, file := range objs{
-			if (IsDir(file)){
-				//This is a playlist. List all its contents
-				filesInside := []string{}
-				filesInPlaylist, _ := system_fs_specialGlob(file + "/")
-				for _, videoInList := range filesInPlaylist{
-					if (system_fs_matchFileExt(videoInList, supportExt)){
-						filesInside = append(filesInside, videoInList)
-					}
-				}
-				if (len(filesInside) > 0){
-					//This is a valid playlist
-					thisPlayList := new(playList)
-					thisPlayList.Name = filepath.Base(file)
-					videosInPlaylist := []videoFile{}
-					for _, videoInPlaylist := range filesInside{
-						thisVideoFile := new(videoFile)
-						thisVideoFile.Filename = filepath.Base(videoInPlaylist)
-						thisVideoFile.Filepath, _ = realpathToVirtualpath(videoInPlaylist, username)
-						thisVideoFile.Ext = filepath.Ext(videoInPlaylist)
-						videosInPlaylist = append(videosInPlaylist, *thisVideoFile)
-					}
-					thisPlayList.Files = videosInPlaylist;
-					allPlayLists = append(allPlayLists, *thisPlayList)
-				}
-			}else if (system_fs_matchFileExt(file, supportExt)){
-				//This is an unsorted video file
-				vpath, _ := realpathToVirtualpath(file, username)
-				thisVideoFile := &videoFile{
-					Filename: filepath.Base(file),
-					Filepath: vpath,
-					Ext: filepath.Ext(file),
-				}
-				unsortedFiles = append(unsortedFiles, *thisVideoFile)
-			}
-		}
-
-		//Build the required objects from information
-		thisViewPort.PlayLists = allPlayLists
-		thisViewPort.UnsortedVideos = unsortedFiles
-		thisViewPort.StorageName = dev.Name
-		results = append(results,*thisViewPort)
-	}
-
-	//Format the results as JSON string and output
-	jsonString, err := json.Marshal(results);
-	if (err != nil){
-		log.Println("[ArdPlayer] Unable to parse playlist")
-		sendErrorResponse(w, "Unable to parse playlist.")
-		return
-	}
-	sendJSONResponse(w, string(jsonString))
-	return;
-
-}

+ 0 - 25
legacy/module.dummy.go_disabled

@@ -1,25 +0,0 @@
-package main
-
-import (
-
-)
-
-/*
-	DUMMY MODULE
-
-	This is a module for testing API functionality. 
-	DO NOT COMPILE THIS MODULE INTO PRODUCTION
-*/
-
-func module_dummy_init(){
-
-	//Register the module
-	registerModule(moduleInfo{
-		Name: "Dummy",
-		Group: "Development",
-		IconPath: "Dummy/img/small_icon.png",
-		Version: "0.1",
-		StartDir: "Dummy/index.html",
-	})
-}
-

+ 0 - 63
legacy/module.notepadA.go_disabled

@@ -1,63 +0,0 @@
-package main
-
-import (
-	"net/http"
-	"encoding/json"
-)
-
-func module_notepadA_init(){
-	http.HandleFunc("/NotepadA/store", module_notepadA_handleStorage)
-
-	//Create database for this module
-	system_db_newTable(sysdb, "NotepadA")
-
-	//Register this module to system
-	registerModule(moduleInfo{
-		Name: "NotepadA",
-		Desc: "The best code editor on ArOZ Online",
-		Group: "Office",
-		IconPath: "NotepadA/img/module_icon.png",
-		Version: "1.2",
-		StartDir: "NotepadA/index.html",
-		SupportFW: true,
-		LaunchFWDir: "NotepadA/index.html",
-		SupportEmb: true,
-		LaunchEmb: "NotepadA/embedded.html",
-		InitFWSize: []int{1024, 768},
-		InitEmbSize: []int{360, 200},
-		SupportedExt: []string{".bat",".coffee",".cpp",".cs",".csp",".csv",".fs",".dockerfile",".go",".html",".ini",".java",".js",".lua",".mips",".md", ".sql",".txt",".php",".py",".ts",".xml",".yaml"},
-	})
-}
-
-func module_notepadA_handleStorage(w http.ResponseWriter, r *http.Request){
-	username, err := system_auth_getUserName(w,r);
-	if (err != nil){
-		sendErrorResponse(w,"User not logged in")
-		return;
-	}
-	opr, _ := mv(r, "opr", true)
-	key, _ := mv(r, "key", true)
-	value, _ := mv(r, "value", true)
-
-	userKey := username + "/" + key;
-	if (opr == "get"){
-		returnString := "";
-		err := system_db_read(sysdb, "NotepadA", userKey, &returnString)
-		if (err != nil){
-			sendErrorResponse(w, err.Error())
-			return
-		}
-		jsonstring, _ := json.Marshal(returnString)
-		sendJSONResponse(w, string(jsonstring));
-		return
-	}else if (opr == "set"){
-		err := system_db_write(sysdb, "NotepadA", userKey, value)
-		if (err != nil){
-			sendErrorResponse(w, err.Error())
-			return
-		}
-		sendOK(w);
-	}
-	
-}
-

+ 1 - 0
subservice/ArSamba

@@ -0,0 +1 @@
+Subproject commit 429001be2e0dad995ea1b102cb05ea973da76cd7

+ 5 - 0
subservice/WsTTY/README.md

@@ -0,0 +1,5 @@
+# WsTTY
+
+WebSocket Terminal Module for arozos system
+If you are using Windows as your host, do not use this subservice.
+Use the build in WsShell Instead.

BIN
subservice/WsTTY/WsTTY_linux_amd64


BIN
subservice/WsTTY/WsTTY_linux_arm


BIN
subservice/WsTTY/WsTTY_linux_arm64


+ 2 - 0
subservice/WsTTY/bashstart

@@ -0,0 +1,2 @@
+export TERM=xterm
+cd ~/

+ 18 - 0
subservice/WsTTY/build.sh

@@ -0,0 +1,18 @@
+# /bin/sh
+echo "Building darwin"
+#GOOS=darwin GOARCH=amd64 go build
+#mv "${PWD##*/}" "${PWD##*/}_darwin_amd64"
+
+echo "Building linux"
+GOOS=linux GOARCH=amd64 go build
+mv "${PWD##*/}" "${PWD##*/}_linux_amd64"
+GOOS=linux GOARCH=arm go build
+mv "${PWD##*/}" "${PWD##*/}_linux_arm"
+GOOS=linux GOARCH=arm64 go build
+mv "${PWD##*/}" "${PWD##*/}_linux_arm64"
+
+echo "Building windows"
+#GOOS=windows GOARCH=amd64 go build
+
+
+echo "Completed"

+ 222 - 0
subservice/WsTTY/common.go

@@ -0,0 +1,222 @@
+package main
+
+import (
+	"os"
+    "log"
+	"net/http"
+	"strconv"
+	"strings"
+	"errors"
+	"encoding/base64"
+	"bufio"
+	"io/ioutil"
+	"time"
+)
+
+/*
+	SYSTEM COMMON FUNCTIONS
+
+	This is a system function that put those we usually use function but not belongs to
+	any module / system.
+
+	E.g. fileExists / IsDir etc
+
+*/
+
+/*
+	Basic Response Functions
+
+	Send response with ease
+*/
+//Send text response with given w and message as string
+func sendTextResponse(w http.ResponseWriter, msg string) {
+	w.Write([]byte(msg))
+}
+
+//Send JSON response, with an extra json header
+func sendJSONResponse(w http.ResponseWriter, json string) {
+	w.Header().Set("Content-Type", "application/json")
+	w.Write([]byte(json))
+}
+
+func sendErrorResponse(w http.ResponseWriter, errMsg string) {
+	w.Header().Set("Content-Type", "application/json")
+	w.Write([]byte("{\"error\":\"" + errMsg + "\"}"))
+}
+
+func sendOK(w http.ResponseWriter) {
+	w.Header().Set("Content-Type", "application/json")
+	w.Write([]byte("\"OK\""))
+}
+/*
+	The paramter move function (mv)
+
+	You can find similar things in the PHP version of ArOZ Online Beta. You need to pass in
+	r (HTTP Request Object)
+	getParamter (string, aka $_GET['This string])
+
+	Will return
+	Paramter string (if any)
+	Error (if error)
+
+*/
+func mv(r *http.Request, getParamter string, postMode bool) (string, error) {
+	if postMode == false {
+		//Access the paramter via GET
+		keys, ok := r.URL.Query()[getParamter]
+
+		if !ok || len(keys[0]) < 1 {
+			//log.Println("Url Param " + getParamter +" is missing")
+			return "", errors.New("GET paramter " + getParamter + " not found or it is empty")
+		}
+
+		// Query()["key"] will return an array of items,
+		// we only want the single item.
+		key := keys[0]
+		return string(key), nil
+	} else {
+		//Access the parameter via POST
+		r.ParseForm()
+		x := r.Form.Get(getParamter)
+		if len(x) == 0 || x == "" {
+			return "", errors.New("POST paramter " + getParamter + " not found or it is empty")
+		}
+		return string(x), nil
+	}
+
+}
+
+func stringInSlice(a string, list []string) bool {
+    for _, b := range list {
+        if b == a {
+            return true
+        }
+    }
+    return false
+}
+
+
+func fileExists(filename string) bool {
+    _, err := os.Stat(filename)
+    if os.IsNotExist(err) {
+        return false
+    }
+    return true
+}
+
+
+func IsDir(path string) bool{
+	if (fileExists(path) == false){
+		return false
+	}
+	fi, err := os.Stat(path)
+    if err != nil {
+        log.Fatal(err)
+        return false
+    }
+    switch mode := fi.Mode(); {
+    case mode.IsDir():
+        return true
+    case mode.IsRegular():
+        return false
+	}
+	return false
+}
+
+func inArray(arr []string, str string) bool {
+	for _, a := range arr {
+	   if a == str {
+		  return true
+	   }
+	}
+	return false
+ }
+
+ func timeToString(targetTime time.Time) string{
+	 return targetTime.Format("2006-01-02 15:04:05")
+ }
+
+ func IntToString(number int) string{
+	return strconv.Itoa(number)
+ }
+
+ func StringToInt(number string) (int, error){
+	return strconv.Atoi(number)
+ }
+
+ 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
+ }
+
+ func GetUnixTime() int64{
+	return time.Now().Unix()
+ }
+
+ func LoadImageAsBase64(filepath string) (string, error){
+	if !fileExists(filepath){
+		return "", errors.New("File not exists")
+	}
+	f, _ := os.Open(filepath)
+    reader := bufio.NewReader(f)
+    content, _ := ioutil.ReadAll(reader)
+	encoded := base64.StdEncoding.EncodeToString(content)
+	return string(encoded), nil
+ }
+
+ func PushToSliceIfNotExist(slice []string, newItem string) []string {
+	itemExists := false
+	for _, item := range slice{
+		if item == newItem{
+			itemExists = true
+		}
+	}
+
+	if !itemExists{
+		slice = append(slice, newItem)
+	}
+
+	return slice
+ }
+
+ func RemoveFromSliceIfExists(slice []string, target string) []string {
+	 newSlice := []string{}
+	 for _, item := range slice{
+		 if item != target{
+			newSlice = append(newSlice, item)
+		 }
+	 }
+
+	 return newSlice;
+ }
+
+ //Get the IP address of the current authentication user
+func ReflectUserIP(w http.ResponseWriter, r *http.Request) {
+    requestPort,_ :=  mv(r, "port", false)
+    showPort := false;
+    if (requestPort == "true"){
+        //Show port as well
+        showPort = true;
+    }
+    IPAddress := r.Header.Get("X-Real-Ip")
+    if IPAddress == "" {
+        IPAddress = r.Header.Get("X-Forwarded-For")
+    }
+    if IPAddress == "" {
+        IPAddress = r.RemoteAddr
+    }
+    if (!showPort){
+        IPAddress = IPAddress[:strings.LastIndex(IPAddress, ":")]
+
+    }
+    w.Write([]byte(IPAddress))
+    return;
+}

+ 3 - 0
subservice/WsTTY/go.mod

@@ -0,0 +1,3 @@
+module imuslab.com/WsTTY
+
+go 1.14

+ 21 - 0
subservice/WsTTY/gotty/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-2017 Iwasaki Yudai
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

BIN
subservice/WsTTY/gotty/gotty_linux_amd64


BIN
subservice/WsTTY/gotty/gotty_linux_arm


BIN
subservice/WsTTY/gotty/gotty_linux_arm64


+ 89 - 0
subservice/WsTTY/main.go

@@ -0,0 +1,89 @@
+package main
+
+import (
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"os/signal"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"syscall"
+
+	"imuslab.com/WsTTY/mod/aroz"
+)
+
+var (
+	handler *aroz.ArozHandler
+)
+
+func SetupCloseHandler() {
+	c := make(chan os.Signal, 2)
+	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
+	go func() {
+		<-c
+		log.Println("\r- Shutting down WsTTY Service.")
+
+		os.Exit(0)
+	}()
+}
+
+func main() {
+	//Start the aoModule pipeline (which will parse the flags as well). Pass in the module launch information
+	handler = aroz.HandleFlagParse(aroz.ServiceInfo{
+		Name:        "WsTTY",
+		Desc:        "arozos Websocket Terminal",
+		Group:       "System Tools",
+		IconPath:    "SystemAO/wstty/img/small_icon.png",
+		Version:     "1.0",
+		StartDir:    "wstty/",
+		SupportFW:   true,
+		LaunchFWDir: "wstty/",
+		InitFWSize:  []int{740, 500},
+	})
+
+	SetupCloseHandler()
+
+	//Start the gotty and rproxy it to the main system
+
+	if runtime.GOOS == "windows" {
+		//Not supported, and this should not be compiled to windows binary
+		panic("Not supported platform")
+
+	}
+
+	absolutePath := ""
+	if runtime.GOARCH == "amd64" {
+		abs, _ := filepath.Abs("./gotty/gotty_linux_amd64")
+		absolutePath = abs
+	} else if runtime.GOARCH == "arm" {
+		abs, _ := filepath.Abs("./gotty/gotty_linux_arm")
+		absolutePath = abs
+	} else if runtime.GOARCH == "arm64" {
+		abs, _ := filepath.Abs("./gotty/ggotty_linux_arm64")
+		absolutePath = abs
+	} else {
+		//Unsupported platform. Default use amd64
+		abs, _ := filepath.Abs("./gotty/gotty_linux_amd64")
+		absolutePath = abs
+	}
+
+	//Extract port number from listening addr
+	tmp := strings.Split(handler.Port, ":")
+	tmp = tmp[len(tmp)-1:]
+	portOnly := strings.Join(tmp, "")
+
+	log.Println("Starting WsTTY Adapter on: ", portOnly)
+
+	//Start the gotty. This shoud be blocking by itself
+	cmd := exec.Command(absolutePath, "-w", "-p", portOnly, "-a", "localhost", "--ws-origin", `\w*`, "bash", "--init-file", "bashstart")
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	if err := cmd.Start(); err != nil {
+		//Fail to start gotty. Disable this module
+		ioutil.WriteFile(".disabled", []byte(""), 0755)
+		return
+	}
+
+}

+ 70 - 0
subservice/WsTTY/mod/aroz/aroz.go

@@ -0,0 +1,70 @@
+package aroz
+
+import (
+	"flag"
+	"fmt"
+	"net/http"
+	"net/url"
+	"encoding/json"
+	"os"
+)
+
+type ArozHandler struct{
+	Port string
+	restfulEndpoint string
+}
+
+//Information required for registering this subservice to arozos
+type ServiceInfo struct{
+	Name string				//Name of this module. e.g. "Audio"
+	Desc string				//Description for this module
+	Group string			//Group of the module, e.g. "system" / "media" etc
+	IconPath string			//Module icon image path e.g. "Audio/img/function_icon.png"
+	Version string			//Version of the module. Format: [0-9]*.[0-9][0-9].[0-9]
+	StartDir string 		//Default starting dir, e.g. "Audio/index.html"
+	SupportFW bool 			//Support floatWindow. If yes, floatWindow dir will be loaded
+	LaunchFWDir string 		//This link will be launched instead of 'StartDir' if fw mode
+	SupportEmb bool			//Support embedded mode
+	LaunchEmb string 		//This link will be launched instead of StartDir / Fw if a file is opened with this module
+	InitFWSize []int 		//Floatwindow init size. [0] => Width, [1] => Height
+	InitEmbSize []int		//Embedded mode init size. [0] => Width, [1] => Height
+	SupportedExt []string 	//Supported File Extensions. e.g. ".mp3", ".flac", ".wav"
+}
+
+//This function will request the required flag from the startup paramters and parse it to the need of the arozos.
+func HandleFlagParse(info ServiceInfo) *ArozHandler{
+	var infoRequestMode = flag.Bool("info", false, "Show information about this subservice")
+	var port = flag.String("port", ":80", "The default listening endpoint for this subservice")
+	var restful = flag.String("rpt", "http://localhost:8080/api/ajgi/interface", "The RESTFUL Endpoint of the parent")
+	//Parse the flags
+	flag.Parse();
+	if (*infoRequestMode == true){
+		//Information request mode
+		jsonString, _ := json.Marshal(info);
+		fmt.Println(string(jsonString))
+		os.Exit(0);
+	}
+	return &ArozHandler{
+		Port: *port,
+		restfulEndpoint: *restful,
+	};
+}
+
+//Get the username and resources access token from the request, return username, token
+func (a *ArozHandler)GetUserInfoFromRequest(w http.ResponseWriter, r *http.Request)(string, string){
+	username := r.Header.Get("aouser")
+	token := r.Header.Get("aotoken")
+
+	return username, token
+}
+
+func (a *ArozHandler)RequestGatewayInterface(token string, script string)(*http.Response, error){
+	resp, err := http.PostForm(a.restfulEndpoint,
+		url.Values{"token":{token}, "script":{script}})
+    if err != nil {
+		// handle error
+		return nil, err
+	}
+	
+	return resp, nil
+}

BIN
subservice/WsTTY/mod/aroz/doc.txt


+ 1 - 0
subservice/WsTTY/src/gotty

@@ -0,0 +1 @@
+Subproject commit a080c85cbc59226c94c6941ad8c395232d72d517

+ 0 - 0
subservice/demo/.disabled


+ 14 - 0
subservice/demo/agi/listdesktop.js

@@ -0,0 +1,14 @@
+/*
+    Demo for showing agi script running in subservice
+
+*/
+//Request access to filelib
+if (requirelib("filelib")){
+    //Scan the user desktop
+    var filelist = filelib.glob("user:/Desktop/*")
+    sendJSONResp(JSON.stringify(filelist));
+}else{
+    sendJSONResp(JSON.stringify({
+        error: "Filelib require failed"
+    }));
+}

+ 70 - 0
subservice/demo/aroz/aroz.go

@@ -0,0 +1,70 @@
+package aroz
+
+import (
+	"flag"
+	"fmt"
+	"net/http"
+	"net/url"
+	"encoding/json"
+	"os"
+)
+
+type ArozHandler struct{
+	Port string
+	restfulEndpoint string
+}
+
+//Information required for registering this subservice to arozos
+type ServiceInfo struct{
+	Name string				//Name of this module. e.g. "Audio"
+	Desc string				//Description for this module
+	Group string			//Group of the module, e.g. "system" / "media" etc
+	IconPath string			//Module icon image path e.g. "Audio/img/function_icon.png"
+	Version string			//Version of the module. Format: [0-9]*.[0-9][0-9].[0-9]
+	StartDir string 		//Default starting dir, e.g. "Audio/index.html"
+	SupportFW bool 			//Support floatWindow. If yes, floatWindow dir will be loaded
+	LaunchFWDir string 		//This link will be launched instead of 'StartDir' if fw mode
+	SupportEmb bool			//Support embedded mode
+	LaunchEmb string 		//This link will be launched instead of StartDir / Fw if a file is opened with this module
+	InitFWSize []int 		//Floatwindow init size. [0] => Width, [1] => Height
+	InitEmbSize []int		//Embedded mode init size. [0] => Width, [1] => Height
+	SupportedExt []string 	//Supported File Extensions. e.g. ".mp3", ".flac", ".wav"
+}
+
+//This function will request the required flag from the startup paramters and parse it to the need of the arozos.
+func HandleFlagParse(info ServiceInfo) *ArozHandler{
+	var infoRequestMode = flag.Bool("info", false, "Show information about this subservice")
+	var port = flag.String("port", ":80", "The default listening endpoint for this subservice")
+	var restful = flag.String("rpt", "http://localhost:8080/api/ajgi/interface", "The RESTFUL Endpoint of the parent")
+	//Parse the flags
+	flag.Parse();
+	if (*infoRequestMode == true){
+		//Information request mode
+		jsonString, _ := json.Marshal(info);
+		fmt.Println(string(jsonString))
+		os.Exit(0);
+	}
+	return &ArozHandler{
+		Port: *port,
+		restfulEndpoint: *restful,
+	};
+}
+
+//Get the username and resources access token from the request, return username, token
+func (a *ArozHandler)GetUserInfoFromRequest(w http.ResponseWriter, r *http.Request)(string, string){
+	username := r.Header.Get("aouser")
+	token := r.Header.Get("aotoken")
+
+	return username, token
+}
+
+func (a *ArozHandler)RequestGatewayInterface(token string, script string)(*http.Response, error){
+	resp, err := http.PostForm(a.restfulEndpoint,
+		url.Values{"token":{token}, "script":{script}})
+    if err != nil {
+		// handle error
+		return nil, err
+	}
+	
+	return resp, nil
+}

+ 38 - 0
subservice/demo/aroz/doc.txt

@@ -0,0 +1,38 @@
+
+package aroz // import "imuslab.com/arozos/demo/aroz"
+
+
+TYPES
+
+type ArozHandler struct {
+	Port string
+	// Has unexported fields.
+}
+
+func HandleFlagParse(info ServiceInfo) *ArozHandler
+    This function will request the required flag from the startup paramters and
+    parse it to the need of the arozos.
+
+func (a *ArozHandler) GetUserInfoFromRequest(w http.ResponseWriter, r *http.Request) (string, string)
+    Get the username and resources access token from the request, return
+    username, token
+
+func (a *ArozHandler) RequestGatewayInterface(token string, script string) (*http.Response, error)
+
+type ServiceInfo struct {
+	Name         string   //Name of this module. e.g. "Audio"
+	Desc         string   //Description for this module
+	Group        string   //Group of the module, e.g. "system" / "media" etc
+	IconPath     string   //Module icon image path e.g. "Audio/img/function_icon.png"
+	Version      string   //Version of the module. Format: [0-9]*.[0-9][0-9].[0-9]
+	StartDir     string   //Default starting dir, e.g. "Audio/index.html"
+	SupportFW    bool     //Support floatWindow. If yes, floatWindow dir will be loaded
+	LaunchFWDir  string   //This link will be launched instead of 'StartDir' if fw mode
+	SupportEmb   bool     //Support embedded mode
+	LaunchEmb    string   //This link will be launched instead of StartDir / Fw if a file is opened with this module
+	InitFWSize   []int    //Floatwindow init size. [0] => Width, [1] => Height
+	InitEmbSize  []int    //Embedded mode init size. [0] => Width, [1] => Height
+	SupportedExt []string //Supported File Extensions. e.g. ".mp3", ".flac", ".wav"
+}
+    Information required for registering this subservice to arozos
+

+ 31 - 0
subservice/demo/build.bat

@@ -0,0 +1,31 @@
+echo "Building darwin"
+set GOOS=darwin
+set GOARCH=amd64
+
+for %%I in (.) do SET EXENAME=%%~nxI
+
+go build
+MOVE "%EXENAME%" "%EXENAME%_darwin_amd64"
+
+echo "Building linux"
+set GOOS=linux
+set GOARCH=amd64
+go build
+MOVE "%EXENAME%" "%EXENAME%_linux_amd64"
+
+set GOOS=linux
+set GOARCH=arm
+go build
+MOVE "%EXENAME%" "%EXENAME%_linux_arm"
+
+set GOOS=linux
+set GOARCH=arm64
+go build
+MOVE "%EXENAME%" "%EXENAME%_linux_arm64"
+
+echo "Building windows"
+set GOOS=windows
+set GOARCH=amd64
+go build
+
+echo "Completed"

+ 18 - 0
subservice/demo/build.sh

@@ -0,0 +1,18 @@
+# /bin/sh
+echo "Building darwin"
+GOOS=darwin GOARCH=amd64 go build
+mv "${PWD##*/}" "${PWD##*/}_darwin_amd64"
+
+echo "Building linux"
+GOOS=linux GOARCH=amd64 go build
+mv "${PWD##*/}" "${PWD##*/}_linux_amd64"
+GOOS=linux GOARCH=arm go build
+mv "${PWD##*/}" "${PWD##*/}_linux_arm"
+GOOS=linux GOARCH=arm64 go build
+mv "${PWD##*/}" "${PWD##*/}_linux_arm64"
+
+echo "Building windows"
+GOOS=windows GOARCH=amd64 go build
+
+
+echo "Completed"

BIN
subservice/demo/demo.exe


BIN
subservice/demo/demo_darwin_amd64


BIN
subservice/demo/demo_linux_amd64


BIN
subservice/demo/demo_linux_arm


BIN
subservice/demo/demo_linux_arm64


+ 42 - 0
subservice/demo/deprecated/aomodule.go

@@ -0,0 +1,42 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"encoding/json"
+	"os"
+)
+
+//Struct for storing module information
+type serviecInfo struct{
+	Name string				//Name of this module. e.g. "Audio"
+	Desc string				//Description for this module
+	Group string			//Group of the module, e.g. "system" / "media" etc
+	IconPath string			//Module icon image path e.g. "Audio/img/function_icon.png"
+	Version string			//Version of the module. Format: [0-9]*.[0-9][0-9].[0-9]
+	StartDir string 		//Default starting dir, e.g. "Audio/index.html"
+	SupportFW bool 			//Support floatWindow. If yes, floatWindow dir will be loaded
+	LaunchFWDir string 		//This link will be launched instead of 'StartDir' if fw mode
+	SupportEmb bool			//Support embedded mode
+	LaunchEmb string 		//This link will be launched instead of StartDir / Fw if a file is opened with this module
+	InitFWSize []int 		//Floatwindow init size. [0] => Width, [1] => Height
+	InitEmbSize []int		//Embedded mode init size. [0] => Width, [1] => Height
+	SupportedExt []string 	//Supported File Extensions. e.g. ".mp3", ".flac", ".wav"
+}
+
+func initaoModulePipeline(info serviecInfo) (string, bool){
+	var infoRequestMode = flag.Bool("info", false, "Show information about this subservice")
+	var port = flag.String("port", ":80", "The default listening endpoint for this subservice")
+	var aoService = flag.Bool("aoservice", false, "Check if the system is running in aoservice mode")
+	flag.Parse();
+
+	if (*infoRequestMode == true){
+		//Information request mode
+		jsonString, _ := json.Marshal(info);
+		fmt.Println(string(jsonString))
+		os.Exit(0);
+	}
+
+	//Run mode. Continue to run the web services with given port
+	return *port, *aoService;
+}

+ 3 - 0
subservice/demo/go.mod

@@ -0,0 +1,3 @@
+module imuslab.com/arozos/demo
+
+go 1.14

+ 116 - 0
subservice/demo/main.go

@@ -0,0 +1,116 @@
+package main
+
+import (
+	"io/ioutil"
+	"log"
+	"net/http"
+	"os"
+	"os/signal"
+	"syscall"
+
+	aroz "imuslab.com/arozos/demo/aroz"
+)
+
+var (
+	handler *aroz.ArozHandler
+)
+
+/*
+	Demo for showing the implementation of ArOZ Online Subservice Structure
+
+	Proxy url is get from filepath.Dir(StartDir) of the serviceInfo.
+	In this example, the proxy path is demo/*
+*/
+
+//Kill signal handler. Do something before the system the core terminate.
+func SetupCloseHandler() {
+	c := make(chan os.Signal, 2)
+	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
+	go func() {
+		<-c
+		log.Println("\r- Shutting down demo module.")
+		//Do other things like close database or opened files
+
+		os.Exit(0)
+	}()
+}
+
+func main() {
+	//If you have other flags, please add them here
+
+	//Start the aoModule pipeline (which will parse the flags as well). Pass in the module launch information
+	handler = aroz.HandleFlagParse(aroz.ServiceInfo{
+		Name:     "Demo Subservice",
+		Desc:     "A simple subservice code for showing how subservice works in ArOZ Online",
+		Group:    "Development",
+		IconPath: "demo/icon.png",
+		Version:  "0.0.1",
+		//You can define any path before the actualy html file. This directory (in this case demo/ ) will be the reverse proxy endpoint for this module
+		StartDir:     "demo/home.html",
+		SupportFW:    true,
+		LaunchFWDir:  "demo/home.html",
+		SupportEmb:   true,
+		LaunchEmb:    "demo/embedded.html",
+		InitFWSize:   []int{720, 480},
+		InitEmbSize:  []int{720, 480},
+		SupportedExt: []string{".txt", ".md"},
+	})
+
+	//Register the standard web services urls
+	fs := http.FileServer(http.Dir("./web"))
+	http.HandleFunc("/api_test", apiTestDemo)
+	http.Handle("/", fs)
+
+	//To receive kill signal from the System core, you can setup a close handler to catch the kill signal
+	//This is not nessary if you have no opened files / database running
+	SetupCloseHandler()
+
+	//Any log println will be shown in the core system via STDOUT redirection. But not STDIN.
+	log.Println("Demo module started. Listening on " + handler.Port)
+	err := http.ListenAndServe(handler.Port, nil)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+}
+
+//API Test Demo. This showcase how can you access arozos resources with RESTFUL API CALL
+func apiTestDemo(w http.ResponseWriter, r *http.Request) {
+	//Get username and token from request
+	username, token := handler.GetUserInfoFromRequest(w, r)
+	log.Println("Received request from: ", username, " with token: ", token)
+
+	//Create an AGI Call that get the user desktop files
+	script := `
+		if (requirelib("filelib")){
+			var filelist = filelib.glob("user:/Desktop/*")
+			sendJSONResp(JSON.stringify(filelist));
+		}else{
+			sendJSONResp(JSON.stringify({
+				error: "Filelib require failed"
+			}));
+		}
+	`
+
+	//Execute the AGI request on server side
+	resp, err := handler.RequestGatewayInterface(token, script)
+	if err != nil {
+		//Something went wrong when performing POST request
+		log.Println(err)
+	} else {
+		//Try to read the resp body
+		bodyBytes, err := ioutil.ReadAll(resp.Body)
+		if err != nil {
+			log.Println(err)
+			w.Write([]byte(err.Error()))
+			return
+		}
+		resp.Body.Close()
+
+		//Relay the information to the request using json header
+		//Or you can process the information within the go program
+		w.Header().Set("Content-Type", "application/json")
+		w.Write(bodyBytes)
+
+	}
+}

+ 1 - 0
subservice/demo/test.bat

@@ -0,0 +1 @@
+for %%I in (.) do SET EXECNAME=%%~nxI

+ 19 - 0
subservice/demo/web/embedded.html

@@ -0,0 +1,19 @@
+<html>
+    <head>
+        <title>Hello World!</title>
+		<style>
+			body{
+				background-color: rgba(250,250,250,0.7);
+			}
+		</style>
+    </head>
+    <body>
+        <h1>Hello World! This is a demo subservice for ArOZ Online System.</h1>
+        <button onclick="doSomething();">Click Me</button>
+        <script>
+            function doSomething(){
+                
+            }
+        </script>
+    </body>
+</html>

+ 61 - 0
subservice/demo/web/home.html

@@ -0,0 +1,61 @@
+<html>
+    <head>
+        <title>Hello World!</title>
+        <!-- You can use the files located inside the ./web directory of the core system as well-->
+        <link rel="stylesheet" href="../script/semantic/semantic.min.css">
+        <script src="../script/jquery.min.js"></script>
+        <script src="../script/ao_module.js"></script>
+        <style>
+            body{
+                background-color:white;
+            }
+        </style>
+    </head>
+    <body>
+        <br>
+        <div class="ui container">
+            <h1>Hello World! This is a demo subservice for ArOZ Online System.</h1>
+            <p>You can also try to open txt / md file with this subservice module</p>
+            <p>Selected Files: </p>
+            <p id="fileList"></p>
+            <button class="ui button" onclick="doSomething();">Call ao_module API (File Selector)</button>
+			<button class="ui button" onclick="runAGI();">Check Desktop Files</button>
+            <div class="ui divider"></div>
+            <p>File List (Click the button above to test)</p>
+            <div id="filelist" class="ui ordered list">
+
+            </div>
+        </div>
+        
+        <script>
+            function doSomething(){
+                //You can call ao_module directly after included ao_module.js
+                ao_module_openFileSelector(fileSelected);
+            }
+
+            function fileSelected(filedata){
+                $("#fileList").html("");
+                for (var i=0; i < filedata.length; i++){
+                    var filename = filedata[i].filename;
+                    var filepath = filedata[i].filepath;
+                    $("#fileList").append(`<p>${filename} / ${filepath}</p>`)
+                }
+            }
+
+            function runAGI(){
+                ao_module_agirun("demo/agi/listdesktop.js", {}, function(results){
+                    if (results.error !== undefined){
+                        alert(results.error);
+                    }else{
+                        $("#filelist").html("");
+                        results.forEach(item => {
+                            $("#filelist").append(`<div class="item">${item}</div>`);
+                        });
+                    }
+                });
+            }
+            
+			
+        </script>
+    </body>
+</html>

BIN
subservice/demo/web/icon.png


+ 3 - 0
web/desktop.system

@@ -3390,6 +3390,8 @@
         }
 
         //Ask for confirmation before window close
+        //Update 16 Feb 2021: Disabled confirmation and use a new method of implementing this later
+        /*
         function myConfirmation() {
             if (!loggingOut){
                 return 'Your data might not been saved. Are you sure you want to quit?';
@@ -3397,6 +3399,7 @@
         }
 
         window.onbeforeunload = myConfirmation;
+        */
 
         function iconClicked(object, evt) {
             if (renameMode){