Browse Source

Fixed Storage Quota doubled bug, file operation CSRF security issue

TC pushbot 5 4 years ago
parent
commit
d6ac0c7c1f

+ 8 - 0
file_system.go

@@ -1332,12 +1332,20 @@ func system_fs_handleWebSocketOpr(w http.ResponseWriter, r *http.Request) {
 */
 //Handle file operations.
 func system_fs_handleOpr(w http.ResponseWriter, r *http.Request) {
+	//Check if user logged in
 	userinfo, err := userHandler.GetUserInfoFromRequest(w, r)
 	if err != nil {
 		sendErrorResponse(w, "User not logged in")
 		return
 	}
 
+	//Validate the token
+	tokenValid := CSRFTokenManager.HandleTokenValidation(w, r)
+	if !tokenValid {
+		http.Error(w, "Invalid CSRF token", 401)
+		return
+	}
+
 	operation, _ := mv(r, "opr", true)
 	vsrcFiles, _ := mv(r, "src", true)
 	vdestFile, _ := mv(r, "dest", true)

+ 0 - 154
mod/filesystem/upload/upload.go

@@ -1,154 +0,0 @@
-package upload
-
-import (
-	"errors"
-	"io"
-	"log"
-	"net/http"
-	"os"
-	"path/filepath"
-
-	user "imuslab.com/arozos/mod/user"
-)
-
-type chunk struct {
-	PartFilename string
-	DestFilename string
-}
-
-/*
-	//Usage:
-	uploadedFilepaths, err := upload.StreamUploadToDisk(userinfo, w, r)
-	if err != nil {
-		sendErrorResponse(w, err.Error())
-		return
-	}
-
-	//Set the ownership of file(s)
-	quotaFulled := false
-	for _, fileRealpath := range uploadedFilepaths {
-		//Check for storage quota
-		uploadFileSize := fs.GetFileSize(fileRealpath)
-		if !userinfo.StorageQuota.HaveSpace(uploadFileSize) {
-			//User storage quota fulled. Remove this file
-			quotaFulled = true
-
-			//Remove this file as this doesn't fit
-			os.Remove(fileRealpath)
-		} else {
-			userinfo.SetOwnerOfFile(fileRealpath)
-		}
-	}
-
-	if quotaFulled {
-		sendErrorResponse(w, "Storage Quota Full")
-		return
-	}
-
-	sendOK(w)
-	return
-*/
-
-func StreamUploadToDisk(userinfo *user.User, w http.ResponseWriter, r *http.Request) ([]string, error) {
-	//Check if this userinfo is valid
-	if userinfo == nil {
-		return []string{}, errors.New("Invalid userinfo")
-	}
-
-	vpath, ok := r.URL.Query()["path"]
-	if !ok || len(vpath) == 0 {
-		return []string{}, errors.New("Invalid upload destination")
-	}
-
-	//Get the upload destination realpath
-	realUploadPath, err := userinfo.VirtualPathToRealPath(vpath[0])
-	if err != nil {
-		//Return virtual path to real path translation error
-		return []string{}, err
-	}
-
-	//Try to parse the FORM POST using multipart reader
-	reader, err := r.MultipartReader()
-	if err != nil {
-		log.Println("Upload failed: " + err.Error())
-		return []string{}, err
-	}
-
-	//Start write process
-	uplaodedFiles := map[string]string{}
-	for {
-		part, err := reader.NextPart()
-		if err == io.EOF {
-			break
-		} else if err != nil {
-			//Connection lost when uploading. Remove the uploading file.
-			clearFailedUploadChunks(uplaodedFiles)
-			return []string{}, errors.New("Upload failed")
-		}
-		defer part.Close()
-
-		//Check if this is file or other paramters
-		if part.FileName() != "" {
-			//This part is a part of a file. Write it to destination folder
-			tmpFilepath := filepath.Join(realUploadPath, part.FileName()+".tmp")
-
-			//Check if this part is uploaded before. If not but the .tmp file exists
-			//This is from previous unsuccessful upload and it should be reoved
-			_, ok := uplaodedFiles[part.FileName()]
-			if !ok && fileExists(tmpFilepath) {
-				//This chunk is first chunk of the file and the .tmp file already exists.
-				//Remove it
-				log.Println("Removing previous failed upload: ", tmpFilepath)
-				os.Remove(tmpFilepath)
-			}
-
-			//Check if the uploading target folder exists. If not, create it
-			if !fileExists(filepath.Dir(tmpFilepath)) {
-				os.MkdirAll(filepath.Dir(tmpFilepath), 0755)
-			}
-
-			//Open the file and write to it using append mode
-			d, err := os.OpenFile(tmpFilepath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0775)
-			if err != nil {
-				//Failed to create new file.
-				clearFailedUploadChunks(uplaodedFiles)
-				return []string{}, errors.New("Write to disk failed")
-			}
-			io.Copy(d, part)
-			d.Close()
-
-			//Record this file
-			uplaodedFiles[part.FileName()] = tmpFilepath
-		} else {
-			//Unknown stuffs
-			continue
-		}
-
-	}
-
-	//Remove the .tmp extension for the file.
-	uploadedFilepaths := []string{}
-	for thisFilename, thisFilepath := range uplaodedFiles {
-		thisFilename = filepath.Base(thisFilename)
-		finalDestFilename := filepath.Join(filepath.Dir(thisFilepath), thisFilename)
-
-		//Remove the .tmp from the upload by renaming it as the original name
-		err = os.Rename(thisFilepath, finalDestFilename)
-		if err != nil {
-			clearFailedUploadChunks(uplaodedFiles)
-			return []string{}, err
-		}
-
-		uploadedFilepaths = append(uploadedFilepaths, finalDestFilename)
-		log.Println(userinfo.Username+" uploaded: ", filepath.Base(thisFilepath))
-	}
-
-	return uploadedFilepaths, nil
-}
-
-//This function remove all the chunks for failed file upload from disk
-func clearFailedUploadChunks(uplaodedFiles map[string]string) {
-	for _, tmpFiles := range uplaodedFiles {
-		os.Remove(tmpFiles)
-	}
-}

+ 3 - 0
mod/prouter/prouter.go

@@ -15,6 +15,7 @@ import (
 	"log"
 	"net/http"
 
+	"imuslab.com/arozos/mod/security/csrf"
 	user "imuslab.com/arozos/mod/user"
 )
 
@@ -22,6 +23,8 @@ type RouterOption struct {
 	ModuleName    string                                   //The name of module that permission is based on
 	AdminOnly     bool                                     //Require admin permission to use this API endpoint
 	RequireLAN    bool                                     //Require LAN connection (aka no external access)
+	CSRFTManager  *csrf.TokenManager                       //The CSRF Token Manager, can be nil if CSRFT is false
+	RequireCSRFT  bool                                     //Require CSRF Token to be accessiable
 	UserHandler   *user.UserHandler                        //System user handler
 	DeniedHandler func(http.ResponseWriter, *http.Request) //Things to do when request is rejected
 }

+ 1 - 1
mod/filesystem/upload/common.go → mod/security/csrf/common.go

@@ -1,4 +1,4 @@
-package upload
+package csrf
 
 import (
 	"bufio"

+ 113 - 0
mod/security/csrf/csrf.go

@@ -0,0 +1,113 @@
+package csrf
+
+/*
+	CSRF Token Management Module
+	Author: tobychui
+
+	This module handles the genreation and checking of a csrf token
+*/
+
+import (
+	"sync"
+	"time"
+
+	uuid "github.com/satori/go.uuid"
+	"imuslab.com/arozos/mod/user"
+)
+
+type TokenManager struct {
+	UserHandler            *user.UserHandler
+	csrfTokens             *sync.Map //The token storage
+	defaultTokenExpireTime int64     //The timeout for this token in seconds
+}
+
+type Token struct {
+	ID           string //The ID of the token
+	Creator      string //The username of the token creator
+	CreationTime int64  //The creation time of this token
+	Timeout      int64  //The timeout for this token in seconds
+}
+
+//Create a new CSRF Token Manager
+func NewTokenManager(uh *user.UserHandler, tokenExpireTime int64) *TokenManager {
+	tm := TokenManager{
+		UserHandler:            uh,
+		csrfTokens:             &sync.Map{},
+		defaultTokenExpireTime: tokenExpireTime,
+	}
+	return &tm
+}
+
+//Generate a new token
+func (m *TokenManager) GenerateNewToken(username string) string {
+	//Generate a new uuid as the token
+	newUUID := uuid.NewV4().String()
+
+	//Create a new token
+	newToken := Token{
+		ID:           newUUID,
+		Creator:      username,
+		CreationTime: time.Now().Unix(),
+		Timeout:      time.Now().Unix() + m.defaultTokenExpireTime,
+	}
+
+	//Save the user token
+	userMap := m.GetUserTokenMap(username)
+	userMap.Store(newUUID, newToken)
+
+	return newUUID
+}
+
+func (m *TokenManager) GetUserTokenMap(username string) *sync.Map {
+	usermap, ok := m.csrfTokens.Load(username)
+	if !ok {
+		//This user do not have his syncmap. Create one and save it
+		userSyncMap := sync.Map{}
+		m.csrfTokens.Store(username, &userSyncMap)
+		return &userSyncMap
+	} else {
+		//This user sync map exists. Return the pointer of it
+		userSyncMap := usermap.(*sync.Map)
+		return userSyncMap
+	}
+}
+
+//Check if a given token is valud
+func (m *TokenManager) CheckTokenValidation(username string, token string) bool {
+	userSyncMap := m.GetUserTokenMap(username)
+	tokenObject, ok := userSyncMap.Load(token)
+	if !ok {
+		return false
+	} else {
+		//Token exists. Check if it has expired
+		currentTime := time.Now().Unix()
+		thisToken := tokenObject.(Token)
+		if thisToken.Timeout < currentTime {
+			//Expired. Delete token
+			userSyncMap.Delete(token)
+			return false
+		} else {
+			userSyncMap.Delete(token)
+			return true
+		}
+
+	}
+}
+
+func (m *TokenManager) ClearExpiredTokens() {
+	currentTime := time.Now().Unix()
+	m.csrfTokens.Range(func(username, usermap interface{}) bool {
+		//For each user tokens
+		thisUserTokenMap := usermap.(*sync.Map)
+		thisUserTokenMap.Range(func(tokenid, tokenObject interface{}) bool {
+			//For each token in this user
+			thisTokenObject := tokenObject.(Token)
+			if currentTime > thisTokenObject.Timeout {
+				//This token has been expired. Remove it to save some space
+				thisUserTokenMap.Delete(tokenid)
+			}
+			return true
+		})
+		return true
+	})
+}

+ 33 - 0
mod/security/csrf/handlers.go

@@ -0,0 +1,33 @@
+package csrf
+
+import (
+	"encoding/json"
+	"net/http"
+)
+
+func (m *TokenManager) HandleNewToken(w http.ResponseWriter, r *http.Request) {
+	userinfo, err := m.UserHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		http.Error(w, "Unauthorized", 401)
+		return
+	}
+
+	newUUID := m.GenerateNewToken(userinfo.Username)
+	js, _ := json.Marshal(newUUID)
+	sendJSONResponse(w, string(js))
+}
+
+//validate the token validation from request
+func (m *TokenManager) HandleTokenValidation(w http.ResponseWriter, r *http.Request) bool {
+	userinfo, err := m.UserHandler.GetUserInfoFromRequest(w, r)
+	if err != nil {
+		return false
+	}
+
+	token, _ := mv(r, "csrft", true)
+	if token == "" {
+		return false
+	} else {
+		return m.CheckTokenValidation(userinfo.Username, token)
+	}
+}

+ 54 - 0
security.go

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

+ 1 - 1
startup.go

@@ -76,10 +76,10 @@ func RunStartup() {
 	ArsmInit() //Inialize ArOZ Remote Support & Management Framework
 
 	//11. Other stuffs
-	//system_time_init()
 	util_init()
 	system_resetpw_init()
 	mediaServer_init()
+	security_init()
 
 	//Start High Level Services that requires full arozos architectures
 	FTPServerInit() //Start FTP Server Endpoints

+ 1 - 0
web/SystemAO/disk/quota/quota.system

@@ -63,6 +63,7 @@
                     return "rgb(" + r + "," + g + "," + b + ")";
                 };
                 $.get("../../../system/disk/quota/quotaDist",function(list){
+                    accurateUsedSpace = 0;
                     if (list == null){
                         return;
                     }

+ 1 - 1
web/SystemAO/disk/space/diskspace.html

@@ -72,7 +72,7 @@
                 var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
                 if (bytes == 0) return '0 Byte';
                 var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
-                return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
+                return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
             }
 
             function toggleTmpfs(){

+ 22 - 11
web/SystemAO/disk/space/finder.html

@@ -101,22 +101,33 @@
                 var filename = filepath.split("/").pop();
                 if (confirm("Confirm remove: " + filename + " ?")){
                     //Request file system api to remove the file
-                    $.ajax({
-                        url: "../../system/file_system/fileOpr",
-                        data: {opr: "delete", src: JSON.stringify([filepath])},
-                        success: function(data){
-                            if (data.error !== undefined){
-                                alert(data.error);
-                            }else{
-                                //DONE
-                                initFileList();
-                            }   
-                        }
+                    requestCSRFToken(function(token){
+                        $.ajax({
+                            url: "../../system/file_system/fileOpr",
+                            data: {opr: "delete", src: JSON.stringify([filepath]), csrft: token},
+                            success: function(data){
+                                if (data.error !== undefined){
+                                    alert(data.error);
+                                }else{
+                                    //DONE
+                                    initFileList();
+                                }   
+                            }
 
+                        });
                     });
                 }
             }
 
+            function requestCSRFToken(callback){
+                $.ajax({
+                    url: "../../system/csrf/new",
+                    success: function(token){
+                        callback(token);
+                    }
+                })
+            }
+
             function bytesToSize(bytes) {
                 var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
                 if (bytes == 0) return '0 Byte';

+ 109 - 82
web/SystemAO/file_system/file_explorer.html

@@ -1341,23 +1341,26 @@
 
             function getUserRootIcons(foldername){
                 var icon = "folder open";
-                if (foldername == "Desktop"){
+                foldername = foldername.toLowerCase();
+                if (foldername == "desktop"){
                     icon = "computer";
-                }else if (foldername == "Document"){
+                }else if (foldername == "document"){
                     icon = "file text outline";
-                }else if (foldername == "Music"){
+                }else if (foldername == "music" || foldername == "audio"){
                     icon = "music";
-                }else if (foldername == "Photo"){
+                }else if (foldername == "photo" || foldername == "picture"){
                     icon = "image";
-                }else if (foldername == "Video"){
+                }else if (foldername == "video" || foldername == "film"){
                     icon = "video";
-                }else if (foldername == "Trash"){
+                }else if (foldername == "trash" || foldername == "bin" || foldername == "rubbish"){
                     icon = "trash"
-                }else if (foldername == "Download"){
+                }else if (foldername == "download"){
                     icon = "download"
-                }else if (foldername == "Model"){
+                }else if (foldername == "www" || foldername == "web" || foldername == "mysite"){
+                    icon = "globe"
+                }else if (foldername == "model"){
                     icon = "cube"
-                }else if (foldername == "Appdata"){
+                }else if (foldername == "appdata"){
                     icon = "code"
                 }
                 return icon;
@@ -2230,22 +2233,25 @@
                 }
                 console.log(srclist, newnamelist);
                 //Send the request to serverside
-                $.ajax({
-                    url: "../../system/file_system/fileOpr",
-                    method: "POST",
-                    data: {opr: "rename", src: JSON.stringify(srclist), new: JSON.stringify(newnamelist)},
-                    success: function(data){
-                        if (data.error !== undefined){
-                            msgbox("remove",data.error);
-                            $("#renameBox").fadeOut(100);
-                        }else{
-                            refreshList();
-                            msgbox("checkmark","Rename suceed");
-                            $("#renameBox").fadeOut(100);
+                requestCSRFToken(function(token){
+                    $.ajax({
+                        url: "../../system/file_system/fileOpr",
+                        method: "POST",
+                        data: {opr: "rename", src: JSON.stringify(srclist), new: JSON.stringify(newnamelist), csrft: token},
+                        success: function(data){
+                            if (data.error !== undefined){
+                                msgbox("remove",data.error);
+                                $("#renameBox").fadeOut(100);
+                            }else{
+                                refreshList();
+                                msgbox("checkmark","Rename suceed");
+                                $("#renameBox").fadeOut(100);
+                            }
                         }
-                    }
+                    });
+                    renameFileObjects = [];
                 });
-                renameFileObjects = [];
+               
                 hideAllPopupWindows();
             }
 
@@ -2350,21 +2356,24 @@
                                //Stsart operations
                                if (!ao_module_virtualDesktop){
                                    //Not under desktop mode. Use direct copy API
-                                    $.ajax({
-                                        type: 'POST',
-                                        url: `../../system/file_system/fileOpr`,
-                                        data: {opr: "move" ,src: JSON.stringify(fileList), dest: targetDir,existsresp: overwriteMode},
-                                        success: function(data){
-                                            if (data.error !== undefined){
-                                                msgbox("remove",data.error);
-                                            }else{
-                                                //OK
-                                                msgbox("checkmark",fileList.length + " objects moved.")
-                                                refreshList();
+                                   requestCSRFToken(function(token){
+                                        $.ajax({
+                                            type: 'POST',
+                                            url: `../../system/file_system/fileOpr`,
+                                            data: {opr: "move" ,src: JSON.stringify(fileList), dest: targetDir,existsresp: overwriteMode, csrft: token},
+                                            success: function(data){
+                                                if (data.error !== undefined){
+                                                    msgbox("remove",data.error);
+                                                }else{
+                                                    //OK
+                                                    msgbox("checkmark",fileList.length + " objects moved.")
+                                                    refreshList();
+                                                }
+                                                hideAllPopupWindows();
                                             }
-                                            hideAllPopupWindows();
-                                        }
-                                    });
+                                        });
+                                   });
+                                   
                                }else{
                                     //Pass the request to operation handler
                                     var oprConfig = {
@@ -2408,21 +2417,24 @@
                            }else{
                                //OK!
                                if (!ao_module_virtualDesktop){
-                                    $.ajax({
-                                        type: 'POST',
-                                        url: `../../system/file_system/fileOpr`,
-                                        data: {opr: "copy" ,src: JSON.stringify(fileList), dest: targetDir,existsresp: overwriteMode },
-                                        success: function(data){
-                                            if (data.error !== undefined){
-                                                msgbox("remove",data.error);
-                                            }else{
-                                                //OK
-                                                msgbox("checkmark",fileList.length + " objects copied.")
-                                                refreshList();
+                                    requestCSRFToken(function(token){
+                                        $.ajax({
+                                            type: 'POST',
+                                            url: `../../system/file_system/fileOpr`,
+                                            data: {opr: "copy" ,src: JSON.stringify(fileList), dest: targetDir,existsresp: overwriteMode, csrft: token},
+                                            success: function(data){
+                                                if (data.error !== undefined){
+                                                    msgbox("remove",data.error);
+                                                }else{
+                                                    //OK
+                                                    msgbox("checkmark",fileList.length + " objects copied.")
+                                                    refreshList();
+                                                }
+                                                hideAllPopupWindows();
                                             }
-                                            hideAllPopupWindows();
-                                        }
+                                        });
                                     });
+                                    
                                }else{
                                     //Pass the request to operation handler
                                      var oprConfig = {
@@ -2502,22 +2514,25 @@
                     //Start force delete function
                     $("#forceDeleteConfirmBox").fadeOut(100);
                     let fdlistLength = forceDeleteList.length;
-                    $.ajax({
-                        url: "../../system/file_system/fileOpr",
-                        method:"POST",
-                        data: {opr: "delete", src: JSON.stringify(forceDeleteList)},
-                        success: function(data){
-                            if (data.error !== undefined){
-                                msgbox("caution",data.error);
-                            }else{
-                                refreshList();
-                                msgbox("checkmark",fdlistLength + " objects removed.")
+                    requestCSRFToken(function(token){
+                        $.ajax({
+                            url: "../../system/file_system/fileOpr",
+                            method:"POST",
+                            data: {opr: "delete", src: JSON.stringify(forceDeleteList), csrft: token},
+                            success: function(data){
+                                if (data.error !== undefined){
+                                    msgbox("caution",data.error);
+                                }else{
+                                    refreshList();
+                                    msgbox("checkmark",fdlistLength + " objects removed.")
+                                }
+                                hideAllPopupWindows();
                             }
-                            hideAllPopupWindows();
-                        }
+                        });
+                        //Finishing up delete sequence
+                        forceDeleteList = [];
                     });
-                    //Finishing up delete sequence
-                    forceDeleteList = [];
+                    
                 }
             }
 
@@ -2543,27 +2558,30 @@
                 }else{
                     //Continue to delete files
                     let fdlistLength = deleteFileList.length;
-                    $.ajax({
-                        url: "../../system/file_system/fileOpr",
-                        method:"POST",
-                        data: {opr: "recycle", src: JSON.stringify(deleteFileList)},
-                        success: function(data){
-                            if (data.error !== undefined){
-                                msgbox("caution",data.error);
-                            }else{
-                                refreshList();
-                                msgbox("checkmark",fdlistLength + " objects moved to trash bin.")
-                            }
+                    requestCSRFToken(function(token){
+                        $.ajax({
+                            url: "../../system/file_system/fileOpr",
+                            method:"POST",
+                            data: {opr: "recycle", src: JSON.stringify(deleteFileList), csrft: token},
+                            success: function(data){
+                                if (data.error !== undefined){
+                                    msgbox("caution",data.error);
+                                }else{
+                                    refreshList();
+                                    msgbox("checkmark",fdlistLength + " objects moved to trash bin.")
+                                }
 
-                            if (currentPath == "user:/"){
-                                //Reload the User root folder list
-                                initRootDirs();
+                                if (currentPath == "user:/"){
+                                    //Reload the User root folder list
+                                    initRootDirs();
+                                }
                             }
-                        }
+                        });
+                        console.log(deleteFileList);
+                        deleteFileList = [];
+                        hideAllPopupWindows();
                     });
-                    console.log(deleteFileList);
-                    deleteFileList = [];
-                    hideAllPopupWindows();
+                   
                 }
             }
 
@@ -4664,6 +4682,15 @@
                 refreshList();
             }
 
+            function requestCSRFToken(callback){
+                $.ajax({
+                    url: "../../system/csrf/new",
+                    success: function(token){
+                        callback(token);
+                    }
+                })
+            }
+
         </script>
     </body>
 </html>

+ 51 - 31
web/SystemAO/file_system/file_operation.html

@@ -223,14 +223,17 @@ mainloop:
             function unzip(srcList, dest, overwriteMode, callback=undefined){
                 if (legacyMode){
                     //Run in legacy mode
-                    $.ajax({
-                        type: 'POST',
-                        url: `../../system/file_system/fileOpr`,
-                        data: {opr: "unzip" ,src: JSON.stringify(srcList), dest: dest},
-                        success: function(data){
-                            handleFinish(data);
-                        }
+                    requestCSRFToken(function(token){
+                        $.ajax({
+                            type: 'POST',
+                            url: `../../system/file_system/fileOpr`,
+                            data: {opr: "unzip" ,src: JSON.stringify(srcList), dest: dest, csrft: token},
+                            success: function(data){
+                                handleFinish(data);
+                            }
+                        });
                     });
+                    
                 }else{
                     //Filter all + sign in the list
                     var filteredSrcList = [];
@@ -307,13 +310,15 @@ mainloop:
             function zip(srcList, dest, overwriteMode){
                 if (legacyMode){
                     //Run in legacy mode
-                    $.ajax({
-                        type: 'POST',
-                        url: `../../system/file_system/fileOpr`,
-                        data: {opr: "zip" ,src: JSON.stringify(srcList), dest: dest},
-                        success: function(data){
-                            handleFinish(data);
-                        }
+                    requestCSRFToken(function(token){
+                        $.ajax({
+                            type: 'POST',
+                            url: `../../system/file_system/fileOpr`,
+                            data: {opr: "zip" ,src: JSON.stringify(srcList), dest: dest, csrft: token},
+                            success: function(data){
+                                handleFinish(data);
+                            }
+                        });
                     });
                 }else{
                      //Replace all + sign with tag
@@ -397,15 +402,19 @@ mainloop:
 
             function cut(srcList, dest, overwriteMode){
                 if (legacyMode){
-                    console.log("WebSocket not found, Running in legacy mode")
-                    $.ajax({
-                        type: 'POST',
-                        url: `../../system/file_system/fileOpr`,
-                        data: {opr: "move" ,src: JSON.stringify(srcList), dest: dest,existsresp: overwriteMode},
-                        success: function(data){
-                            handleFinish(data);
-                        }
+                    console.log("WebSocket not found, Running in legacy mode");
+                    requestCSRFToken(function(token){
+                        $.ajax({
+                            type: 'POST',
+                            url: `../../system/file_system/fileOpr`,
+                            data: {opr: "move" ,src: JSON.stringify(srcList), dest: dest,existsresp: overwriteMode, csrft: token},
+                            success: function(data){
+                                handleFinish(data);
+                            }
+                        });
                     });
+
+                    
                 }else{
                     //Replace all + sign in srclist with {{plus_sign}}
                     var filteredSrcList = [];
@@ -477,15 +486,19 @@ mainloop:
             function copy(srcList, dest, overwriteMode){
                 if (legacyMode){
                     //Open operation in legacy mode
-                    console.log("WebSocket not found, Running in legacy mode")
-                    $.ajax({
-                        type: 'POST',
-                        url: `../../system/file_system/fileOpr`,
-                        data: {opr: "copy" ,src: JSON.stringify(srcList), dest: dest,existsresp: overwriteMode },
-                        success: function(data){
-                            handleFinish(data);
-                        }
+                    console.log("WebSocket not found, Running in legacy mode");
+                    requestCSRFToken(function(token){
+                        $.ajax({
+                            type: 'POST',
+                            url: `../../system/file_system/fileOpr`,
+                            data: {opr: "copy" ,src: JSON.stringify(srcList), dest: dest,existsresp: overwriteMode , csrft: token},
+                            success: function(data){
+                                handleFinish(data);
+                            }
+                        });
                     });
+
+                    
                 }else{
                     var filteredSrcList = [];
                     srcList.forEach(src => {
@@ -641,7 +654,14 @@ mainloop:
                 console.log(data);
             }
 
-
+            function requestCSRFToken(callback){
+                $.ajax({
+                    url: "../../system/csrf/new",
+                    success: function(token){
+                        callback(token);
+                    }
+                })
+            }
           
         </script>
     </body>

+ 24 - 12
web/SystemAO/file_system/trashbin.html

@@ -298,20 +298,32 @@
                 for (var i =0; i <deletePendingFiles.length; i++){
                     deleteFileList.push(deletePendingFiles[i].filepath);
                 }
-                $.ajax({
-                    url: "../../system/file_system/fileOpr",
-                    method:"POST",
-                    data: {opr: "recycle", src: JSON.stringify(deleteFileList)},
-                    success: function(data){
-                        if (data.error !== undefined){
-                            console.log("Delete failed! " + data.error)
-                        }else{
-                            //Delete completed. Close this window
-                            parent.refresh(undefined, true);
-                            ao_module_close();
+                requestCSRFToken(function(token){
+                    $.ajax({
+                        url: "../../system/file_system/fileOpr",
+                        method:"POST",
+                        data: {opr: "recycle", src: JSON.stringify(deleteFileList), csrft: token},
+                        success: function(data){
+                            if (data.error !== undefined){
+                                console.log("Delete failed! " + data.error)
+                            }else{
+                                //Delete completed. Close this window
+                                parent.refresh(undefined, true);
+                                ao_module_close();
+                            }
                         }
-                    }
+                    });
                 });
+                
+            }
+
+            function requestCSRFToken(callback){
+                $.ajax({
+                    url: "../../system/csrf/new",
+                    success: function(token){
+                        callback(token);
+                    }
+                })
             }
         </script>
     </body>

+ 58 - 41
web/desktop.system

@@ -3931,18 +3931,21 @@
 
                 //Prase the filelist and pass to trash module
                 console.log(deleteFilelist);
-                $.ajax({
-                    url: "system/file_system/fileOpr",
-                    method:"POST",
-                    data: {opr: "recycle", src: JSON.stringify(deleteFilelist)},
-                    success: function(data){
-                        if (data.error !== undefined){
-                            alert(data.error);
-                        }else{
-                            refresh(undefined, true);
+                generateCSRFToken(function(csrftoken){
+                    $.ajax({
+                        url: "system/file_system/fileOpr",
+                        method:"POST",
+                        data: {opr: "recycle", src: JSON.stringify(deleteFilelist), csrft: csrftoken},
+                        success: function(data){
+                            if (data.error !== undefined){
+                                alert(data.error);
+                            }else{
+                                refresh(undefined, true);
+                            }
                         }
-                    }
+                    });
                 });
+                
 
                 //Delete the file's desktop location
                 deleteFilenameList.forEach(file => {
@@ -4830,27 +4833,29 @@
                         }else{
                             //Normal typed files / folder. Rename the object
                             let currentInputTextArea = $(this);
-                            $.ajax({
-                                url: "./system/file_system/fileOpr",
-                                method: "POST",
-                                data: {opr: "rename", src: JSON.stringify([filepath]), new: JSON.stringify([newFilename])},
-                                success: function(data){
-                                    if (data.error !== undefined){
-                                        //Cancel the operation
-                                        console.log("*ERROR* " + data.error);
-                                        currentInputTextArea.remove();
-                                    }else{
-                                        //Update the new file position
-                                        let closestLocation = findClosestGrid($(currentInputTextArea).parent().offset().left, $(currentInputTextArea).parent().offset().top);
-                                        let closestGridIndexLocation = closestLocation[1];
-                                        setIconDesktopLocation(newFilename, closestGridIndexLocation[0], closestGridIndexLocation[1], function(){
-                                            //Callback after setting location
-                                            refresh(function() {
-                                                //Refresh the desktop
+                            generateCSRFToken(function(csrftoken){
+                                $.ajax({
+                                    url: "./system/file_system/fileOpr",
+                                    method: "POST",
+                                    data: {opr: "rename", src: JSON.stringify([filepath]), new: JSON.stringify([newFilename]), token: csrftoken},
+                                    success: function(data){
+                                        if (data.error !== undefined){
+                                            //Cancel the operation
+                                            console.log("*ERROR* " + data.error);
+                                            currentInputTextArea.remove();
+                                        }else{
+                                            //Update the new file position
+                                            let closestLocation = findClosestGrid($(currentInputTextArea).parent().offset().left, $(currentInputTextArea).parent().offset().top);
+                                            let closestGridIndexLocation = closestLocation[1];
+                                            setIconDesktopLocation(newFilename, closestGridIndexLocation[0], closestGridIndexLocation[1], function(){
+                                                //Callback after setting location
+                                                refresh(function() {
+                                                    //Refresh the desktop
+                                                });
                                             });
-                                        });
+                                        }
                                     }
-                                }
+                                });
                             });
                         }
                     }
@@ -4898,19 +4903,22 @@
                 deleteFileList.push(filedata.Filepath);
             });
             console.log(deleteFileList);
-            $.ajax({
-                url: "system/file_system/fileOpr",
-                method:"POST",
-                data: {opr: "recycle", src: JSON.stringify(deleteFileList)},
-                success: function(data){
-                    if (data.error !== undefined){
-                        alert(data.error);
-                    }else{
-                       refresh(undefined, true);
+            generateCSRFToken(function(csrftoken){
+                $.ajax({
+                    url: "system/file_system/fileOpr",
+                    method:"POST",
+                    data: {opr: "recycle", src: JSON.stringify(deleteFileList), csrft: csrftoken},
+                    success: function(data){
+                        if (data.error !== undefined){
+                            alert(data.error);
+                        }else{
+                        refresh(undefined, true);
+                        }
                     }
-                }
+                });
+                hideAllContextMenus();
             });
-            hideAllContextMenus();
+            
         }
 
         //File Rename
@@ -5453,9 +5461,18 @@
             });
         }, 15000);
 
+        function generateCSRFToken(callback){
+            $.ajax({
+                url: "../../system/csrf/new",
+                success: function(token){
+                    callback(token);
+                }
+            })
+        }
+
         function getDesktopHash(callback){
             $.ajax({
-                url: "../../system/file_system/listDirHash",
+                url: "system/file_system/listDirHash",
                 data: {dir: "user:/Desktop/"},
                 success: function(data){
                     if (data.error !== undefined){