Переглянути джерело

Added compatibility mode to fix Firefox v94 breaking change

Toby Chui 3 роки тому
батько
коміт
3805d0ee0b

+ 26 - 6
file_system.go

@@ -24,6 +24,7 @@ import (
 	"github.com/gorilla/websocket"
 	uuid "github.com/satori/go.uuid"
 
+	"imuslab.com/arozos/mod/compatibility"
 	"imuslab.com/arozos/mod/disk/hybridBackup"
 	fs "imuslab.com/arozos/mod/filesystem"
 	fsp "imuslab.com/arozos/mod/filesystem/fspermission"
@@ -588,10 +589,28 @@ func system_fs_handleUpload(w http.ResponseWriter, r *http.Request) {
 	}
 
 	storeFilename := handler.Filename //Filename of the uploaded file
+
+	//Update for Firefox 94.0.2 (x64) -> Now firefox put its relative path inside Content-Disposition -> filename
+	//Skip this handler logic if Firefox version is in between 84.0.2 to 94.0.2
+	bypassMetaCheck := compatibility.FirefoxBrowserVersionForBypassUploadMetaHeaderCheck(r.UserAgent())
+	if !bypassMetaCheck && strings.Contains(handler.Header["Content-Disposition"][0], "filename=") && strings.Contains(handler.Header["Content-Disposition"][0], "/") {
+		//This is a firefox MIME Header for file inside folder. Look for the actual filename
+		headerFields := strings.Split(handler.Header["Content-Disposition"][0], "; ")
+		possibleRelativePathname := ""
+		for _, hf := range headerFields {
+			if strings.Contains(hf, "filename=") && len(hf) > 11 {
+				//Found. Overwrite original filename with the latest one
+				possibleRelativePathname = hf[10 : len(hf)-1]
+				storeFilename = possibleRelativePathname
+				break
+			}
+		}
+	}
+
 	destFilepath := filepath.ToSlash(filepath.Clean(realUploadPath)) + "/" + storeFilename
 
 	if !fileExists(filepath.Dir(destFilepath)) {
-		os.MkdirAll(filepath.Dir(destFilepath), 0755)
+		os.MkdirAll(filepath.Dir(destFilepath), 0775)
 	}
 
 	//Check if the upload target is read only.
@@ -680,11 +699,12 @@ func system_fs_handleUpload(w http.ResponseWriter, r *http.Request) {
 	}
 
 	//Finish up the upload
-
-	//fmt.Printf("Uploaded File: %+v\n", handler.Filename)
-	//fmt.Printf("File Size: %+v\n", handler.Size)
-	//fmt.Printf("MIME Header: %+v\n", handler.Header)
-	//fmt.Println("Upload target: " + realUploadPath)
+	/*
+		fmt.Printf("Uploaded File: %+v\n", handler.Filename)
+		fmt.Printf("File Size: %+v\n", handler.Size)
+		fmt.Printf("MIME Header: %+v\n", handler.Header)
+		fmt.Println("Upload target: " + realUploadPath)
+	*/
 
 	//Fnish upload. Fix the tmp filename
 	log.Println(userinfo.Username + " uploaded a file: " + handler.Filename)

+ 42 - 0
mod/compatibility/browser.go

@@ -0,0 +1,42 @@
+package compatibility
+
+import (
+	"strconv"
+	"strings"
+)
+
+/*
+	FirefoxBrowserVersionForBypassUploadMetaHeaderCheck
+
+	This function check if Firefox version is between 84 and 93.
+	If yes, this function will return TRUE and upload logic should not need to handle
+	META header for upload. If FALSE, please extract the relative filepath from the meta header.
+	Example Firefox userAgent header:
+	Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.02021/11/23
+*/
+func FirefoxBrowserVersionForBypassUploadMetaHeaderCheck(userAgent string) bool {
+	if strings.Contains(userAgent, "Mozilla") && strings.Contains(userAgent, "Firefox/") {
+		userAgentSegment := strings.Split(userAgent, " ")
+		for _, u := range userAgentSegment {
+			if len(u) > 4 && strings.TrimSpace(u)[:3] == "rv:" {
+				//This is the firefox version code
+				versionCode := strings.TrimSpace(u)[3 : len(u)-1]
+				vcodeNumeric, err := strconv.ParseFloat(versionCode, 64)
+				if err != nil {
+					//Unknown version of Firefox. Just check for META anyway
+					return false
+				}
+
+				if vcodeNumeric >= 84 && vcodeNumeric < 94 {
+					//Special versions of Firefox. Do not check for META header
+					return true
+				} else {
+					//Newer or equal to v94. Check it
+					return false
+				}
+			}
+		}
+	}
+	//Not Firefox.
+	return true
+}

+ 10 - 0
mod/compatibility/compatibility.go

@@ -0,0 +1,10 @@
+package compatibility
+
+/*
+	Compatibility.go
+
+	This script is designed to help with some strange behavour related
+	to certain version of go compiler, browser or platform dependent
+	exceptions and work-arounds
+
+*/

+ 33 - 9
mod/share/share.go

@@ -109,7 +109,7 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 			}
 
 		} else if len(subpathElements) >= 3 {
-			//E.g. /share/{id}/myfile.txt => Enter download mode
+			//E.g. /share/download/{uuid} or /share/preview/{uuid}
 			id = subpathElements[2]
 			if subpathElements[1] == "download" {
 				directDownload = true
@@ -121,9 +121,23 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 			} else if subpathElements[1] == "preview" {
 				directServe = true
 			}
+		} else if len(subpathElements) == 1 {
+			//ID is missing. Serve the id input page
+			content, err := ioutil.ReadFile("system/share/index.html")
+			if err != nil {
+				//Handling index not found. Is server updated correctly?
+				w.WriteHeader(http.StatusInternalServerError)
+				w.Write([]byte("500 - Internal Server Error"))
+				return
+			}
 
-			log.Println(len(subpathElements[3:]), subpathElements[3:], relpath)
+			t := fasttemplate.New(string(content), "{{", "}}")
+			s := t.ExecuteString(map[string]interface{}{
+				"hostname": s.options.HostName,
+			})
 
+			w.Write([]byte(s))
+			return
 		} else {
 			http.NotFound(w, r)
 			return
@@ -160,7 +174,7 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 		if shareOption.Permission == "anyone" {
 			//OK to proceed
 		} else if shareOption.Permission == "signedin" {
-			if s.options.AuthAgent.CheckAuth(r) == false {
+			if !s.options.AuthAgent.CheckAuth(r) {
 				//Redirect to login page
 				if directDownload || directServe {
 					w.WriteHeader(http.StatusUnauthorized)
@@ -288,7 +302,7 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 				Filesize string
 				IsDir    bool
 			}
-			if directDownload == true {
+			if directDownload {
 				if relpath != "" {
 					//User specified a specific file within the directory. Escape the relpath
 					targetFilepath := filepath.Join(shareOption.FileRealPath, relpath)
@@ -342,6 +356,11 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 					http.ServeFile(w, r, targetZipFilename)
 				}
 
+			} else if directServe {
+				//Folder provide no direct serve method.
+				w.WriteHeader(http.StatusBadRequest)
+				w.Write([]byte("400 - Cannot preview folder type shares"))
+				return
 			} else {
 				//Show download page. Do not allow serving
 				content, err := ioutil.ReadFile("./system/share/downloadPageFolder.html")
@@ -389,6 +408,12 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 					return nil
 				})
 
+				if err != nil {
+					w.WriteHeader(http.StatusInternalServerError)
+					w.Write([]byte("500 - Internal Server Error"))
+					return
+				}
+
 				tl, _ := json.Marshal(treeList)
 
 				//Get modification time
@@ -415,6 +440,7 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 
 			}
 		} else {
+			//This share is a file
 			if directDownload {
 				//Serve the file directly
 				w.Header().Set("Content-Disposition", "attachment; filename*=UTF-8''"+strings.ReplaceAll(url.QueryEscape(filepath.Base(shareOption.FileRealPath)), "+", "%20"))
@@ -441,7 +467,7 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 
 				//Load the preview template
 				templateRoot := "./system/share/"
-				previewTemplate := filepath.Join(templateRoot, "defaultTemplate.html")
+				previewTemplate := ""
 				if ext == ".mp4" || ext == ".webm" {
 					previewTemplate = filepath.Join(templateRoot, "video.html")
 				} else if ext == ".mp3" || ext == ".wav" || ext == ".flac" || ext == ".ogg" {
@@ -470,8 +496,6 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 				fmodtime, _ := filesystem.GetModTime(shareOption.FileRealPath)
 				timeString := time.Unix(fmodtime, 0).Format("02-01-2006 15:04:05")
 
-				downloadURI := "../../share/download/" + id + "/" + filepath.Base(shareOption.FileRealPath)
-
 				//Check if ext match with filepath ext
 				displayExt := ext
 				if ext != filepath.Ext(shareOption.FileRealPath) {
@@ -485,8 +509,8 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 					"ext":         displayExt,
 					"size":        filesystem.GetFileDisplaySize(fsize, 2),
 					"modtime":     timeString,
-					"downloadurl": downloadURI,
-					"preview_url": "/share/preview/?id=" + id + "&serve=true",
+					"downloadurl": "../../share/download/" + id + "/" + filepath.Base(shareOption.FileRealPath),
+					"preview_url": "/share/preview/" + id + "/",
 					"filename":    filepath.Base(shareOption.FileRealPath),
 					"reqtime":     strconv.Itoa(int(time.Now().Unix())),
 				})

+ 70 - 0
system/share/index.html

@@ -0,0 +1,70 @@
+<!DOCTYPE HTML>
+<html>
+    <head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <title>{{hostname}} File Share</title>
+    <link rel="stylesheet" href="../script/skeleton/offline.css">
+    <link rel="stylesheet" href="../script/skeleton/normalize.css">
+    <link rel="stylesheet" href="../script/skeleton/skeleton.css">
+    <script type="application/javascript" src="../script/jquery.min.js"></script>
+    <style>
+        .bar{
+            height: 12px;
+            background-color: #1a1a1a;
+            width: 100%;
+        }
+
+        .footer{
+            position: fixed;
+            left: 0px;
+            bottom: 0px;
+            height: 100px;
+            width: 100%;
+            background-color: #1a1a1a;
+            padding: 20px;
+            color: white;
+        }
+    </style>
+    </head>
+    <body>
+        <div class="bar"></div>
+        <br>
+        <div class="container" style="padding-bottom: 150px;">
+            <div class="row">
+                <div class="one-half column">
+                    <h5>{{hostname}} File Sharing</h5>
+                    <p>You are seeing this page because you are requesting the share API without a proper share ID. Enter a share code to continue:</p>
+                    <div>
+                        <label for="exampleEmailInput">Share Code (UUIDv4)</label>
+                        <input class="u-full-width" type="text" placeholder="00000000-0000-0000-0000-000000000000" onkeydown="handleKeyDown(event);" id="shareCodeID">
+                        <small>Example: 8dfb688c-a6da-4dd5-b657-fe21f9fbe2b1</small>
+                    </div>
+                    <button class="button-primary" onclick="gotoShare();">Continue</button>
+                </div>
+                <div class="one-half column">
+                    <img style="pointer-events: none; width: 100%;" src="../../img/public/share/noID.png">
+                </div>
+            </div>
+           
+        </div>
+        <div class="footer">
+            <div class="container">
+                Cloud File Sharing Interface, <br>Powered by <a style="color: white;" href="http://arozos.com">arozos</a>
+            </div>
+        </div>
+    <script>
+
+        function handleKeyDown(e){
+            if (e.keyCode == 13){
+                //Enter
+                gotoShare();
+            }
+        }
+        function gotoShare(){
+            var shareCode = $("#shareCodeID").val();
+            window.location.href = "./" + shareCode + "/";
+        }
+    </script>
+    </body>
+</html>

+ 1 - 1
system/share/notfound.html

@@ -40,7 +40,7 @@
                     <p>Request Timestamp: {{reqtime}}</p>
                 </div>
                 <div class="one-half column">
-                    <img style="pointer-events: none; width: 100%;" src="img/public/share/notfound.png">
+                    <img style="pointer-events: none; width: 100%;" src="../../img/public/share/notfound.png">
                 </div>
             </div>
            

+ 1 - 1
system/share/permissionDenied.html

@@ -38,7 +38,7 @@
                     <p>Permission settings on this share did not include your user group. That is all we know.</p>
                 </div>
                 <div class="one-half column">
-                    <img style="pointer-events: none; width: 100%;" src="img/public/share/denied.png">
+                    <img style="pointer-events: none; width: 100%;" src="../../img/public/share/denied.png">
                 </div>
             </div>
            

BIN
web/MS Office Viewer/img/desktop_icon.png → web/Office Viewer/img/desktop_icon.png


BIN
web/MS Office Viewer/img/desktop_icon.psd → web/Office Viewer/img/desktop_icon.psd


BIN
web/MS Office Viewer/img/icon.png → web/Office Viewer/img/icon.png


BIN
web/MS Office Viewer/img/icon.psd → web/Office Viewer/img/icon.psd


+ 0 - 0
web/MS Office Viewer/index.html → web/Office Viewer/index.html


+ 7 - 7
web/MS Office Viewer/init.agi → web/Office Viewer/init.agi

@@ -9,16 +9,16 @@
 
 //Define the launchInfo for the module
 var moduleLaunchInfo = {
-    Name: "MS Office Viewer",
-	Desc: "MS Office 365 Adapter",
+    Name: "Office Viewer",
+	Desc: "Office File Viewer Adapter",
 	Group: "office",
-	IconPath: "MS Office Viewer/img/icon.png",
-	Version: "3.0",
-	StartDir: "MS Office Viewer/index.html",
+	IconPath: "Office Viewer/img/icon.png",
+	Version: "1.0",
+	StartDir: "Office Viewer/index.html",
 	SupportFW: true,
-	LaunchFWDir: "MS Office Viewer/index.html",
+	LaunchFWDir: "Office Viewer/index.html",
 	SupportEmb: true,
-    LaunchEmb: "MS Office Viewer/viewer.html",
+    LaunchEmb: "Office Viewer/viewer.html",
 	InitFWSize: [1080, 580],
 	SupportedExt: [".doc", ".docx", ".xlsx",".xls",".pptx", ".ppt"]
 }

+ 0 - 0
web/MS Office Viewer/viewer.html → web/Office Viewer/viewer.html


BIN
web/img/public/share/noID.png


BIN
web/img/public/share/noID.psd