浏览代码

Added working multi-client ssh sftp server implementation in start

Toby Chui 2 年之前
父节点
当前提交
4cc3c16343
共有 12 个文件被更改,包括 304 次插入630 次删除
  1. 0 225
      common.go_disabled
  2. 15 0
      legacy/id_rsa
  3. 6 0
      legacy/pub
  4. 二进制
      mod/auth/doc.txt
  5. 0 44
      mod/database/doc.txt
  6. 0 108
      mod/filesystem/doc.txt
  7. 0 58
      mod/permission/doc.txt
  8. 二进制
      mod/quota/out.txt
  9. 143 0
      mod/storage/sftpserver/sftpserver.go
  10. 0 64
      mod/subservice/doc.txt
  11. 139 129
      startup.go
  12. 1 2
      web/desktop.system

+ 0 - 225
common.go_disabled

@@ -1,225 +0,0 @@
-package main
-
-import (
-	"bufio"
-	"encoding/base64"
-	"errors"
-	"io/ioutil"
-	"log"
-	"net/http"
-	"os"
-	"strconv"
-	"strings"
-	"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
-	} else if err != nil {
-		//Some edge case for Input Output error can occur here.
-		//Return false if that is the case
-		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
-}

+ 15 - 0
legacy/id_rsa

@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQDLXcAWHwJ2XJ9tqMELQVszLKfaMkpJGCD4Q6iPBBs24ENzAf7Y
+J+8hRFKRVEQPZlIsWZPOXBdG27nXW/q6Z68JI6dyEvj5bg4rlde6nQcNcKd3EtQc
+eB6N/nmhLZf1q6DsHvFMol7yN/Zu42bUFupyNaBDjN9H2sCyc6okebLvUQIDAQAB
+AoGAR17ngtvvKUroSLvow+Jz90m8vr7Xgz+MkpRsG4T9aAzcnwgcQBADxFEOCSLh
+n+XxAM+PJ+T55kxGtGX7YF/y9Uln39wWoy3Vm0sFyxI/6YYre/xbMHM7pCM5OkEL
+3bfPv/twXENz3y/1s5rrgICkar3x2IbZk4uC5krqW246cAECQQD4mDbX2iDAagmc
+ezhMGo9Le5P87jSQriqkmpmy0HEtIngog8O/clKcp5pE5Ckc3jVYLNfGfkyVngwS
+FddRQqPxAkEA0Wyft4ftBPvqwpZolQJEMwGoDS5VcfH0DzFsKZe3B6YrLbhVpNwI
+MKshAvYeglGQoPB0flG6epQpCELvHxzhYQJAKsaeYUQScKmOX9PAGzBSye1IyLQA
+bYjao5pKqj89ykNtI6OQskesuXIJlKMiA+qkiTimJGylJvWcJByIAV6TMQJAYlhY
+SJ+UNpr2i5qGUjNWQ32rpUT06yVsLxZObNnKIdVuwXGnBlwtnG1Ae1uIyDn1aR6C
+Fi/bGmUpP6/vCvVNAQJAJnBvPs/C1gDMrjDwqWv6E0PX9QN5tHBQbJBhdD436XIk
+WqWaOF7Rnz8aDsyX3RhBbhyTzTDmSgXTipzy8vfE9g==
+-----END RSA PRIVATE KEY-----

+ 6 - 0
legacy/pub

@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLXcAWHwJ2XJ9tqMELQVszLKfa
+MkpJGCD4Q6iPBBs24ENzAf7YJ+8hRFKRVEQPZlIsWZPOXBdG27nXW/q6Z68JI6dy
+Evj5bg4rlde6nQcNcKd3EtQceB6N/nmhLZf1q6DsHvFMol7yN/Zu42bUFupyNaBD
+jN9H2sCyc6okebLvUQIDAQAB
+-----END PUBLIC KEY-----

二进制
mod/auth/doc.txt


+ 0 - 44
mod/database/doc.txt

@@ -1,44 +0,0 @@
-
-package database // import "imuslab.com/arozos/mod/database"
-
-
-TYPES
-
-type Database struct {
-	Db       *bolt.DB
-	ReadOnly bool
-}
-
-func NewDatabase(dbfile string, readOnlyMode bool) (*Database, error)
-
-func (d *Database) Close()
-
-func (d *Database) Delete(tableName string, key string) error
-    Delete a value from the database table given tablename and key
-
-    err := sysdb.Delete("MyTable", "username/message");
-
-func (d *Database) DropTable(tableName string) error
-
-func (d *Database) KeyExists(tableName string, key string) bool
-
-func (d *Database) ListTable(tableName string) ([][][]byte, error)
-
-func (d *Database) NewTable(tableName string) error
-
-func (d *Database) Read(tableName string, key string, assignee interface{}) error
-
-func (d *Database) UpdateReadWriteMode(readOnly bool)
-
-func (d *Database) Write(tableName string, key string, value interface{}) error
-    Write to database with given tablename and key. Example Usage: type demo
-    struct{
-
-        content string
-
-    } thisDemo := demo{
-
-        content: "Hello World",
-
-    } err := sysdb.Write("MyTable", "username/message",thisDemo);
-

+ 0 - 108
mod/filesystem/doc.txt

@@ -1,108 +0,0 @@
-
-package filesystem // import "imuslab.com/arozos/mod/filesystem"
-
-
-FUNCTIONS
-
-func BufferedLargeFileCopy(src string, dst string, BUFFERSIZE int64) error
-    Use for copying large file using buffering method. Allowing copying large
-    file with little RAM
-
-func CheckMounted(mountpoint string) bool
-func DecodeURI(inputPath string) string
-func FileCopy(src string, dest string, mode string) error
-func FileMove(src string, dest string, mode string, fastMove bool) error
-func GetFileDisplaySize(filesize int64, rounding int) string
-func GetFileSize(filename string) int64
-func GetMime(filepath string) (string, string, error)
-func GetModTime(filepath string) (int64, error)
-func IsDir(path string) bool
-func MatchingFileSystem(fsa *FileSystemHandler, fsb *FileSystemHandler) bool
-    Check if the two file system are identical.
-
-func MountDevice(mountpt string, mountdev string, filesystem string) error
-func ViewZipFile(filepath string) ([]string, error)
-func ZipFile(filelist []string, outputfile string, includeTopLevelFolder bool) error
-
-TYPES
-
-type FileData struct {
-	Filename    string
-	Filepath    string
-	Realpath    string
-	IsDir       bool
-	Filesize    float64
-	Displaysize string
-}
-
-type FileProperties struct {
-	VirtualPath    string
-	StoragePath    string
-	Basename       string
-	VirtualDirname string
-	StorageDirname string
-	Ext            string
-	MimeType       string
-	Filesize       int64
-	Permission     string
-	LastModTime    string
-	LastModUnix    int64
-	IsDirectory    bool
-}
-
-type FileSystemHandler struct {
-	Name               string
-	UUID               string
-	Path               string
-	Hierarchy          string
-	ReadOnly           bool
-	InitiationTime     int64
-	FilesystemDatabase *db.Database
-	Filesystem         string
-}
-    System Handler for returing
-
-func NewFileSystemHandler(option FileSystemOption) (*FileSystemHandler, error)
-    Create a new file system handler with the given config
-
-func NewFileSystemHandlersFromJSON(jsonContent []byte) ([]*FileSystemHandler, error)
-    Create a list of file system handler from the given json content
-
-func (fsh *FileSystemHandler) Close()
-
-func (fsh *FileSystemHandler) CreateFileRecord(realpath string, owner string) error
-    Create a file ownership record
-
-func (fsh *FileSystemHandler) DeleteFileRecord(realpath string) error
-    Delete a file ownership record
-
-func (fsh *FileSystemHandler) GetFileRecord(realpath string) (string, error)
-    Read the owner of a file
-
-type FileSystemOption struct {
-	Name       string `json:"name"`                 //Display name of this device
-	Uuid       string `json:"uuid"`                 //UUID of this device, e.g. S1
-	Path       string `json:"path"`                 //Path for the storage root
-	Access     string `json:"access,omitempty"`     //Access right, allow {readonly, everyone, user:{username}, group:{groupname}}
-	Hierarchy  string `json:"hierarchy"`            //Folder hierarchy, allow {public, user}
-	Automount  bool   `json:"automount"`            //Automount this device if exists
-	Filesystem string `json:"filesystem,omitempty"` //Support {"ext4","ext2", "ext3", "fat", "vfat", "ntfs"}
-	Mountdev   string `json:"mountdev,omitempty"`   //Device file (e.g. /dev/sda1)
-	Mountpt    string `json:"mountpt,omitempty"`    //Device mount point (e.g. /media/storage1)
-	Username   string `json:"username,omitempty"`   //Username if the storage require auth
-	Password   string `json:"password,omitempty"`   //Password if the storage require auth
-}
-    FileSystem configuration. Append more lines if required.
-
-type TrashedFile struct {
-	Filename         string
-	Filepath         string
-	FileExt          string
-	IsDir            bool
-	Filesize         int64
-	RemoveTimestamp  int64
-	RemoveDate       string
-	OriginalPath     string
-	OriginalFilename string
-}
-

+ 0 - 58
mod/permission/doc.txt

@@ -1,58 +0,0 @@
-
-package permission // import "imuslab.com/arozos/mod/permission"
-
-
-FUNCTIONS
-
-func inSlice(slice []string, val string) bool
-    Helper function
-
-func mv(r *http.Request, getParamter string, postMode bool) (string, error)
-func sendErrorResponse(w http.ResponseWriter, errMsg string)
-func sendJSONResponse(w http.ResponseWriter, json string)
-    Send JSON response, with an extra json header
-
-func sendOK(w http.ResponseWriter)
-func sendTextResponse(w http.ResponseWriter, msg string)
-    Send text response with given w and message as string
-
-
-TYPES
-
-type PermissionGroup struct {
-	Name                string
-	IsAdmin             bool
-	DefaultStorageQuota int64
-	AccessibleModules   []string
-	StoragePool         *storage.StoragePool
-}
-
-func (gp *PermissionGroup) AddModule(modulename string)
-
-func (gp *PermissionGroup) RemoveModule(modulename string)
-
-type PermissionHandler struct {
-	database         *db.Database
-	PermissionGroups []PermissionGroup
-}
-
-func NewPermissionHandler(database *db.Database) (*PermissionHandler, error)
-
-func (h *PermissionHandler) GetUsersPermissionGroup(username string) ([]*PermissionGroup, error)
-    Get the user permission groups
-
-func (h *PermissionHandler) GroupExists(groupName string) bool
-
-func (h *PermissionHandler) HandleAdminCheck(w http.ResponseWriter, r *http.Request)
-
-func (h *PermissionHandler) HandleGroupCreate(w http.ResponseWriter, r *http.Request)
-
-func (h *PermissionHandler) HandleGroupRemove(w http.ResponseWriter, r *http.Request)
-
-func (h *PermissionHandler) HandleListGroup(w http.ResponseWriter, r *http.Request)
-    Handle group editing operations
-
-func (h *PermissionHandler) LoadPermissionGroupsFromDatabase() error
-
-func (h *PermissionHandler) NewPermissionGroup(name string, isadmin bool, moduleNames []string) *PermissionGroup
-

二进制
mod/quota/out.txt


+ 143 - 0
mod/storage/sftpserver/sftpserver.go

@@ -0,0 +1,143 @@
+package sftpserver
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"net"
+
+	"github.com/pkg/sftp"
+	"golang.org/x/crypto/ssh"
+)
+
+type Instance struct {
+}
+
+//Create a new SFTP Server
+//listeningIP in the format of 0.0.0.0:2022
+func NewSFTPServer(listeningIp string, keyfile string, readOnly bool, passwordCheckFunc func(string, string) bool) (*Instance, error) {
+	// An SSH server is represented by a ServerConfig, which holds
+	// certificate details and handles authentication of ServerConns.
+	config := &ssh.ServerConfig{
+		PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
+			// Should use constant-time compare (or better, salt+hash) in
+			// a production setting.
+			fmt.Printf("Login: %s\n", c.User())
+
+			if passwordCheckFunc(c.User(), string(pass)) {
+				return nil, nil
+			}
+			return nil, errors.New("password rejected for " + c.User())
+		},
+	}
+
+	privateBytes, err := ioutil.ReadFile(keyfile)
+	if err != nil {
+		return nil, err
+	}
+
+	private, err := ssh.ParsePrivateKey(privateBytes)
+	if err != nil {
+		return nil, err
+	}
+
+	config.AddHostKey(private)
+
+	// Once a ServerConfig has been configured, connections can be
+	// accepted.
+	listener, err := net.Listen("tcp", "0.0.0.0:2022")
+	if err != nil {
+		return nil, err
+	}
+	fmt.Printf("Listening on %v\n", listener.Addr())
+
+	for {
+		nConn, err := listener.Accept()
+		if err != nil {
+			return nil, err
+		}
+
+		go func(nConn net.Conn) error {
+			// Before use, a handshake must be performed on the incoming
+			// net.Conn.
+			_, chans, reqs, err := ssh.NewServerConn(nConn, config)
+			if err != nil {
+				return err
+			}
+			fmt.Println("SSH server established\n")
+
+			// The incoming Request channel must be serviced.
+			go ssh.DiscardRequests(reqs)
+
+			// Service the incoming Channel channel.
+			for newChannel := range chans {
+				// Channels have a type, depending on the application level
+				// protocol intended. In the case of an SFTP session, this is "subsystem"
+				// with a payload string of "<length=4>sftp"
+				fmt.Println("Incoming channel: %s\n", newChannel.ChannelType())
+				if newChannel.ChannelType() != "session" {
+					newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
+					fmt.Println("Unknown channel type: %s\n", newChannel.ChannelType())
+					continue
+				}
+				channel, requests, err := newChannel.Accept()
+				if err != nil {
+					return err
+				}
+				fmt.Println("Channel accepted\n")
+
+				// Sessions have out-of-band requests such as "shell",
+				// "pty-req" and "env".  Here we handle only the
+				// "subsystem" request.
+				go func(in <-chan *ssh.Request) {
+					for req := range in {
+						fmt.Println("Request: %v\n", req.Type)
+						ok := false
+						switch req.Type {
+						case "subsystem":
+							fmt.Println("Subsystem: %s\n", req.Payload[4:])
+							if string(req.Payload[4:]) == "sftp" {
+								ok = true
+							}
+						}
+						fmt.Println(" - accepted: %v\n", ok)
+						req.Reply(ok, nil)
+					}
+				}(requests)
+
+				serverOptions := []sftp.ServerOption{}
+
+				if readOnly {
+					serverOptions = append(serverOptions, sftp.ReadOnly())
+					fmt.Println("Read-only server\n")
+				} else {
+					fmt.Println("Read write server\n")
+				}
+
+				server, err := sftp.NewServer(
+					channel,
+					serverOptions...,
+				)
+				if err != nil {
+					return err
+				}
+				go func() {
+					if err := server.Serve(); err == io.EOF {
+						server.Close()
+						log.Print("sftp client exited session.")
+					} else if err != nil {
+						log.Fatal("sftp server completed with error:", err)
+					}
+				}()
+
+			}
+			log.Println("Connection cycle ended")
+			return nil
+		}(nConn)
+
+	}
+
+	return &Instance{}, nil
+}

+ 0 - 64
mod/subservice/doc.txt

@@ -1,64 +0,0 @@
-
-package subservice // import "imuslab.com/arozos/mod/subservice"
-
-
-TYPES
-
-type SubService struct {
-	Port         int                        //Port that this subservice use
-	ServiceDir   string                     //The directory where the service is located
-	Path         string                     //Path that this subservice is located
-	RpEndpoint   string                     //Reverse Proxy Endpoint
-	ProxyHandler *reverseproxy.ReverseProxy //Reverse Proxy Object
-	Info         modules.ModuleInfo         //Module information for this subservice
-	Process      *exec.Cmd                  //The CMD runtime object of the process
-}
-
-type SubServiceRouter struct {
-	ReservePaths      []string
-	RunningSubService []SubService
-	BasePort          int
-
-	// Has unexported fields.
-}
-
-func NewSubServiceRouter(ReservePaths []string, basePort int, userHandler *user.UserHandler, moduleHandler *modules.ModuleHandler, parentPort int) *SubServiceRouter
-
-func (sr *SubServiceRouter) CheckIfPortInUse(port int) bool
-
-func (sr *SubServiceRouter) CheckIfReverseProxyPath(r *http.Request) (bool, *reverseproxy.ReverseProxy, string, *SubService)
-    Check if the target is reverse proxy. If yes, return the proxy handler and
-    the rewritten url in string
-
-func (sr *SubServiceRouter) CheckUserPermissionOnSubservice(ss *SubService, u *user.User) bool
-    Check if the user has permission to access such proxy module
-
-func (sr *SubServiceRouter) Close()
-
-func (sr *SubServiceRouter) GetNextUsablePort() int
-    Scan and get the next avaible port for subservice from its basePort
-
-func (sr *SubServiceRouter) GetSubserviceRoot() []string
-    Get a list of subservice roots in realpath
-
-func (sr *SubServiceRouter) HandleKillSubService(w http.ResponseWriter, r *http.Request)
-    Kill the subservice that is currently running
-
-func (sr *SubServiceRouter) HandleListing(w http.ResponseWriter, r *http.Request)
-
-func (sr *SubServiceRouter) HandleRoutingRequest(w http.ResponseWriter, r *http.Request, proxy *reverseproxy.ReverseProxy, subserviceObject *SubService, rewriteURL string)
-
-func (sr *SubServiceRouter) HandleStartSubService(w http.ResponseWriter, r *http.Request)
-
-func (sr *SubServiceRouter) KillSubService(serviceDir string) error
-
-func (sr *SubServiceRouter) Launch(servicePath string, startupMode bool) error
-
-func (sr *SubServiceRouter) LoadSubservicesFromRootPath(rootpath string)
-    Load and start all the subservices inside this rootpath
-
-func (sr *SubServiceRouter) RestartSubService(ss *SubService)
-    Handle fail start over when the remote target is not responding
-
-func (sr *SubServiceRouter) StartSubService(serviceDir string) error
-

+ 139 - 129
startup.go

@@ -1,129 +1,139 @@
-package main
-
-/*
-	System Startup Script for ArOZ Online System
-	author: tobychui
-*/
-
-import (
-	"fmt"
-	"log"
-	"os"
-
-	db "imuslab.com/arozos/mod/database"
-	"imuslab.com/arozos/mod/filesystem"
-	fs "imuslab.com/arozos/mod/filesystem"
-	"imuslab.com/arozos/mod/info/logger"
-)
-
-func RunStartup() {
-	systemWideLogger, _ = logger.NewLogger("system", "system/logs/system/", true)
-	//1. Initiate the main system database
-
-	//Check if system or web both not exists and web.tar.gz exists. Unzip it for the user
-	if (!fs.FileExists("system/") || !fs.FileExists("web/")) && fs.FileExists("./web.tar.gz") {
-		log.Println("[Update] Unzipping system critical files from archive")
-		extErr := filesystem.ExtractTarGzipFile("./web.tar.gz", "./")
-		if extErr != nil {
-			//Extract failed
-			fmt.Println("▒▒ ERROR: UNABLE TO EXTRACT CRITICAL SYSTEM FOLDERS ▒▒")
-			fmt.Println(extErr)
-			panic("Unable to extract content from web.tar.gz to fix the missing system / web folder. Please unzip the web.tar.gz manually.")
-		}
-
-		//Extract success
-		extErr = os.Remove("./web.tar.gz")
-		if extErr != nil {
-			systemWideLogger.PrintAndLog("Update", "Unable to remove web.tar.gz: "+extErr.Error(), extErr)
-		}
-	}
-
-	if !fs.FileExists("system/") {
-		fmt.Println("▒▒ ERROR: SYSTEM FOLDER NOT FOUND ▒▒")
-		panic("This error occurs because the system folder is missing. Please follow the installation guide and don't just download a binary and run it.")
-	}
-
-	if !fs.FileExists("web/") {
-		fmt.Println("▒▒ ERROR: WEB FOLDER NOT FOUND ▒▒")
-		panic("This error occurs because the web folder is missing. Please follow the installation guide and don't just download a binary and run it.")
-	}
-
-	dbconn, err := db.NewDatabase("system/ao.db", false)
-	if err != nil {
-		panic(err)
-	}
-	sysdb = dbconn
-
-	//2. Initiate the auth Agent
-	AuthInit() //See auth.go
-
-	//3. Start Permission Management Module
-	permissionNewHandler() //See permission.go
-
-	//4. Mount and create the storage system base
-	StorageInit() //See storage.go
-
-	//5. Startup user and permission sytem
-	UserSystemInit()        //See user.go
-	permissionInit()        //Register permission interface after user
-	RegisterSystemInit()    //See register.go
-	GroupStoragePoolInit()  //Register permission groups's storage pool, require permissionInit()
-	BridgeStoragePoolInit() //Register the bridged storage pool based on mounted storage pools
-
-	//6. Start Modules and Package Manager
-	ModuleServiceInit() //Module Handler
-	PackagManagerInit() //Start APT service agent
-
-	//7. Kickstart the File System and Desktop
-	NightlyTasksInit() //Start Nightly task scheduler
-	FileSystemInit()   //Start FileSystem
-	DesktopInit()      //Start Desktop
-
-	//StorageDaemonInit() //Start File System handler daemon (for backup and other sync process)
-
-	//8 Start AGI and Subservice modules (Must start after module)
-	AGIInit()        //ArOZ Javascript Gateway Interface, must start after fs
-	SchedulerInit()  //Start System Scheudler
-	SubserviceInit() //Subservice Handler
-
-	//9. Initiate System Settings Handlers
-	SystemSettingInit()       //Start System Setting Core
-	DiskQuotaInit()           //Disk Quota Management
-	DiskServiceInit()         //Start Disk Services
-	DeviceServiceInit()       //Client Device Management
-	SystemInfoInit()          //System Information UI
-	SystemIDInit()            //System UUID Manager
-	AuthSettingsInit()        //Authentication Settings Handler, must be start after user Handler
-	AdvanceSettingInit()      //System Advance Settings
-	StartupFlagsInit()        //System BootFlag settibg
-	HardwarePowerInit()       //Start host power manager
-	RegisterStorageSettings() //Storage Settings
-
-	//10. Startup network services and schedule services
-	NetworkServiceInit() //Initalize network serves (ssdp / mdns etc)
-	WiFiInit()           //Inialize WiFi management module
-
-	//ARSM Moved to scheduler, remote support is rewrite pending
-	//ArsmInit() //Inialize ArOZ Remote Support & Management Framework
-
-	//11. Other stuffs
-	util_init()
-	system_resetpw_init()
-	mediaServer_init()
-	security_init()
-	storageHeartbeatTickerInit()
-	OAuthInit()        //Oauth system init
-	ldapInit()         //LDAP system init
-	notificationInit() //Notification system init
-
-	//Start High Level Services that requires full arozos architectures
-	FTPServerInit() //Start FTP Server Endpoints
-	WebDAVInit()    //Start WebDAV Endpoint
-	ClusterInit()   //Start Cluster Services
-	IoTHubInit()    //Inialize ArozOS IoT Hub module
-
-	ModuleInstallerInit() //Start Module Installer
-
-	//Finally
-	moduleHandler.ModuleSortList() //Sort the system module list
-}
+package main
+
+/*
+	System Startup Script for ArOZ Online System
+	author: tobychui
+*/
+
+import (
+	"fmt"
+	"log"
+	"os"
+
+	db "imuslab.com/arozos/mod/database"
+	"imuslab.com/arozos/mod/filesystem"
+	fs "imuslab.com/arozos/mod/filesystem"
+	"imuslab.com/arozos/mod/info/logger"
+	"imuslab.com/arozos/mod/storage/sftpserver"
+)
+
+func RunStartup() {
+	systemWideLogger, _ = logger.NewLogger("system", "system/logs/system/", true)
+	//1. Initiate the main system database
+
+	//Check if system or web both not exists and web.tar.gz exists. Unzip it for the user
+	if (!fs.FileExists("system/") || !fs.FileExists("web/")) && fs.FileExists("./web.tar.gz") {
+		log.Println("[Update] Unzipping system critical files from archive")
+		extErr := filesystem.ExtractTarGzipFile("./web.tar.gz", "./")
+		if extErr != nil {
+			//Extract failed
+			fmt.Println("▒▒ ERROR: UNABLE TO EXTRACT CRITICAL SYSTEM FOLDERS ▒▒")
+			fmt.Println(extErr)
+			panic("Unable to extract content from web.tar.gz to fix the missing system / web folder. Please unzip the web.tar.gz manually.")
+		}
+
+		//Extract success
+		extErr = os.Remove("./web.tar.gz")
+		if extErr != nil {
+			systemWideLogger.PrintAndLog("Update", "Unable to remove web.tar.gz: "+extErr.Error(), extErr)
+		}
+	}
+
+	if !fs.FileExists("system/") {
+		fmt.Println("▒▒ ERROR: SYSTEM FOLDER NOT FOUND ▒▒")
+		panic("This error occurs because the system folder is missing. Please follow the installation guide and don't just download a binary and run it.")
+	}
+
+	if !fs.FileExists("web/") {
+		fmt.Println("▒▒ ERROR: WEB FOLDER NOT FOUND ▒▒")
+		panic("This error occurs because the web folder is missing. Please follow the installation guide and don't just download a binary and run it.")
+	}
+
+	dbconn, err := db.NewDatabase("system/ao.db", false)
+	if err != nil {
+		panic(err)
+	}
+	sysdb = dbconn
+
+	//2. Initiate the auth Agent
+	AuthInit() //See auth.go
+
+	//3. Start Permission Management Module
+	permissionNewHandler() //See permission.go
+
+	//4. Mount and create the storage system base
+	StorageInit() //See storage.go
+
+	//5. Startup user and permission sytem
+	UserSystemInit()        //See user.go
+	permissionInit()        //Register permission interface after user
+	RegisterSystemInit()    //See register.go
+	GroupStoragePoolInit()  //Register permission groups's storage pool, require permissionInit()
+	BridgeStoragePoolInit() //Register the bridged storage pool based on mounted storage pools
+
+	//6. Start Modules and Package Manager
+	ModuleServiceInit() //Module Handler
+	PackagManagerInit() //Start APT service agent
+
+	//7. Kickstart the File System and Desktop
+	NightlyTasksInit() //Start Nightly task scheduler
+	FileSystemInit()   //Start FileSystem
+	DesktopInit()      //Start Desktop
+
+	//StorageDaemonInit() //Start File System handler daemon (for backup and other sync process)
+
+	//8 Start AGI and Subservice modules (Must start after module)
+	AGIInit()        //ArOZ Javascript Gateway Interface, must start after fs
+	SchedulerInit()  //Start System Scheudler
+	SubserviceInit() //Subservice Handler
+
+	//9. Initiate System Settings Handlers
+	SystemSettingInit()       //Start System Setting Core
+	DiskQuotaInit()           //Disk Quota Management
+	DiskServiceInit()         //Start Disk Services
+	DeviceServiceInit()       //Client Device Management
+	SystemInfoInit()          //System Information UI
+	SystemIDInit()            //System UUID Manager
+	AuthSettingsInit()        //Authentication Settings Handler, must be start after user Handler
+	AdvanceSettingInit()      //System Advance Settings
+	StartupFlagsInit()        //System BootFlag settibg
+	HardwarePowerInit()       //Start host power manager
+	RegisterStorageSettings() //Storage Settings
+
+	//10. Startup network services and schedule services
+	NetworkServiceInit() //Initalize network serves (ssdp / mdns etc)
+	WiFiInit()           //Inialize WiFi management module
+
+	//ARSM Moved to scheduler, remote support is rewrite pending
+	//ArsmInit() //Inialize ArOZ Remote Support & Management Framework
+
+	//11. Other stuffs
+	util_init()
+	system_resetpw_init()
+	mediaServer_init()
+	security_init()
+	storageHeartbeatTickerInit()
+	OAuthInit()        //Oauth system init
+	ldapInit()         //LDAP system init
+	notificationInit() //Notification system init
+
+	//Start High Level Services that requires full arozos architectures
+	FTPServerInit() //Start FTP Server Endpoints
+	WebDAVInit()    //Start WebDAV Endpoint
+	ClusterInit()   //Start Cluster Services
+	IoTHubInit()    //Inialize ArozOS IoT Hub module
+
+	ModuleInstallerInit() //Start Module Installer
+
+	//Finally
+	moduleHandler.ModuleSortList() //Sort the system module list
+
+	_, err = sftpserver.NewSFTPServer("0.0.0.0:2022", "legacy/id_rsa", false, func(username string, password string) bool {
+		if username == "admin" && password == "password" {
+			return true
+		}
+
+		return false
+	})
+	fmt.Println(err)
+}

+ 1 - 2
web/desktop.system

@@ -4672,11 +4672,10 @@
                                             if (data.error !== undefined){
                                                 console.log(data.error);
                                             }
-                                           
+                                            refresh(undefined, true);
                                         }
                                     });
                                 });
-                                refresh(undefined, true);
                             }
                         }
                     });