Browse Source

Fixed file manager new folder bug in filepath join

TC pushbot 5 4 years ago
parent
commit
9d6b68f8ff
8 changed files with 249 additions and 13 deletions
  1. 1 1
      file_system.go
  2. 3 1
      main.flags.go
  3. 6 11
      main.router.go
  4. 161 0
      mod/user/www/common.go
  5. 70 0
      mod/user/www/www.go
  6. 8 0
      user.go
  7. 0 0
      web/SystemAO/www/favicon.png
  8. 0 0
      web/SystemAO/www/index.html

+ 1 - 1
file_system.go

@@ -1008,7 +1008,7 @@ func system_fs_handleNewObjects(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 		//Check if the file already exists. If yes, fix its filename.
-		newfilePath := rpath + filename
+		newfilePath := filepath.ToSlash(filepath.Join(rpath, filename))
 
 		if fileType == "file" {
 			for fileExists(newfilePath) {

+ 3 - 1
main.flags.go

@@ -9,6 +9,7 @@ import (
 	db "imuslab.com/arozos/mod/database"
 	permission "imuslab.com/arozos/mod/permission"
 	user "imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/user/www"
 )
 
 /*
@@ -21,6 +22,7 @@ var authAgent *auth.AuthAgent //System authentication agent
 var permissionHandler *permission.PermissionHandler
 var userHandler *user.UserHandler         //User Handler
 var packageManager *apt.AptPackageManager //Manager for package auto installation
+var userWwwHandler *www.Handler           //User Webroot handler
 var subserviceBasePort = 12810            //Next subservice port
 
 // =========== SYSTEM BUILD INFORMATION ==============
@@ -85,7 +87,7 @@ var allow_public_registry = flag.Bool("public_reg", false, "Enable public regist
 var allow_autologin = flag.Bool("allow_autologin", true, "Allow RESTFUL login redirection that allow machines like billboards to login to the system on boot")
 var demo_mode = flag.Bool("demo_mode", false, "Run the system in demo mode. All directories and database are read only.")
 var allow_package_autoInstall = flag.Bool("allow_pkg_install", true, "Allow the system to install package using Advanced Package Tool (aka apt or apt-get)")
-var allow_homepage = flag.Bool("enable_homepage", false, "Redirect not logged in users to public web hosting folder (web/www/) instead of login interface")
+var allow_homepage = flag.Bool("homepage", true, "Enable user homepage. Accessible via /www/{username}/")
 
 //Scheduling and System Service Related
 var nightlyTaskRunTime = flag.Int("ntt", 3, "Nightly tasks execution time. Default 3 = 3 am in the morning")

+ 6 - 11
main.router.go

@@ -88,9 +88,9 @@ func mrouter(h http.Handler) http.Handler {
 					http.Redirect(w, r, "desktop.system", 307)
 				}
 			}
-		} else if r.URL.Path == "/" && !authAgent.CheckAuth(r) && *allow_homepage == true {
-			//User not logged in but request the index, redirect to homepage
-			http.Redirect(w, r, "/www/index.html", 307)
+		} else if ((len(r.URL.Path) >= 5 && r.URL.Path[:5] == "/www/") || r.URL.Path == "/www") && *allow_homepage == true {
+			//Serve the custom homepage of the user defined. Hand over to the www router
+			userWwwHandler.RouteRequest(w, r)
 		} else if authAgent.CheckAuth(r) {
 			//User logged in. Continue to serve the file the client want
 			authAgent.UpdateSessionExpireTime(w, r)
@@ -143,15 +143,10 @@ func mrouter(h http.Handler) http.Handler {
 				h.ServeHTTP(w, r)
 			} else {
 				//Other paths
-				if *allow_homepage {
-					//Redirect to home page if home page function is enabled
-					http.Redirect(w, r, "/www/index.html", 307)
-				} else {
-					//Rediect to login page
-					w.Header().Set("Cache-Control", "no-cache, no-store, no-transform, must-revalidate, private, max-age=0")
-					http.Redirect(w, r, "/login.system?redirect="+r.URL.Path, 307)
-				}
 
+				//Rediect to login page
+				w.Header().Set("Cache-Control", "no-cache, no-store, no-transform, must-revalidate, private, max-age=0")
+				http.Redirect(w, r, "/login.system?redirect="+r.URL.Path, 307)
 			}
 
 		}

+ 161 - 0
mod/user/www/common.go

@@ -0,0 +1,161 @@
+package www
+
+import (
+	"bufio"
+	"encoding/base64"
+	"errors"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"os"
+	"time"
+)
+
+/*
+	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 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
+}

+ 70 - 0
mod/user/www/www.go

@@ -0,0 +1,70 @@
+package www
+
+import (
+	"log"
+	"net/http"
+	"path/filepath"
+	"strings"
+
+	"imuslab.com/arozos/mod/user"
+)
+
+/*
+	www package
+
+	This package is the replacement handler for global homepage function in ArozOS.
+	This allow users to host and create their website using any folder within the user
+	access file system.
+
+*/
+
+type Options struct {
+	UserHandler *user.UserHandler
+}
+
+type Handler struct {
+	Options Options
+}
+
+/*
+	New WebRoot Handler create a new handler for handling and routing webroots
+*/
+func NewWebRootHandler(options Options) *Handler {
+	return &Handler{
+		Options: options,
+	}
+}
+
+func (h *Handler) RouteRequest(w http.ResponseWriter, r *http.Request) {
+	//Check if it is reaching www root folder or any files directly under www.
+	if filepath.ToSlash(filepath.Clean(r.RequestURI)) == "/www" {
+		//Direct access of the root folder. Serve the homepage description.
+		http.ServeFile(w, r, "web/SystemAO/www/index.html")
+		return
+	} else if filepath.ToSlash(filepath.Dir(r.RequestURI)) == "/www" {
+		//Reaching file under www root and not root. Redirect to www root
+		http.Redirect(w, r, "/www/", 307)
+		return
+	}
+
+	//Check the user name of the user root
+	parsedRequestURL := strings.Split(filepath.ToSlash(filepath.Clean(r.RequestURI)[1:]), "/")
+
+	//Malparsed URL. Ignore request
+	if len(parsedRequestURL) < 2 {
+		http.NotFound(w, r)
+		return
+	}
+
+	//Extract user information
+	username := parsedRequestURL[1]
+
+	_, err := h.Options.UserHandler.GetUserInfoFromUsername(username)
+	if err != nil {
+		http.NotFound(w, r)
+		return
+	}
+
+	log.Println("Serving user webroot: ", username)
+	sendOK(w)
+}

+ 8 - 0
user.go

@@ -19,6 +19,7 @@ import (
 	module "imuslab.com/arozos/mod/modules"
 	prout "imuslab.com/arozos/mod/prouter"
 	user "imuslab.com/arozos/mod/user"
+	"imuslab.com/arozos/mod/user/www"
 )
 
 func UserSystemInit() {
@@ -70,6 +71,13 @@ func UserSystemInit() {
 		RequireAdmin: true,
 	})
 
+	//Handle user webroot routings if homepage is enabled
+	if *allow_homepage {
+		userWwwHandler = www.NewWebRootHandler(www.Options{
+			UserHandler: userHandler,
+		})
+	}
+
 	//Handle db / auth / permissions related functions that requires user permission systems. See user.go
 	user_createPostUserHandlers()
 }

+ 0 - 0
web/www/favicon.png → web/SystemAO/www/favicon.png


+ 0 - 0
web/www/index.html → web/SystemAO/www/index.html