Эх сурвалжийг харах

Completed compatibily mode

Toby Chui 2 жил өмнө
parent
commit
adc1b5ea25

+ 114 - 3
mod/fileservers/servers/dirserv/dirserv.go

@@ -1,10 +1,16 @@
 package dirserv
 
 import (
+	"fmt"
+	"io"
 	"net/http"
+	"net/url"
+	"path/filepath"
+	"strings"
 
 	"imuslab.com/arozos/mod/database"
 	"imuslab.com/arozos/mod/fileservers"
+	"imuslab.com/arozos/mod/filesystem/arozfs"
 	"imuslab.com/arozos/mod/user"
 )
 
@@ -16,7 +22,10 @@ import (
 */
 
 type Option struct {
-	Sysdb *database.Database
+	Sysdb       *database.Database
+	UserManager *user.UserHandler
+	ServerPort  int
+	ServerUUID  string
 }
 
 type Manager struct {
@@ -45,13 +54,18 @@ func (m *Manager) DirServerEnabled() bool {
 }
 
 func (m *Manager) Toggle(enabled bool) error {
-	m.enabled = !m.enabled
+	m.enabled = enabled
+	m.option.Sysdb.Write("dirserv", "enabled", m.enabled)
 	return nil
 }
 
 func (m *Manager) ListEndpoints(userinfo *user.User) []*fileservers.Endpoint {
 	results := []*fileservers.Endpoint{}
-
+	results = append(results, &fileservers.Endpoint{
+		ProtocolName: "//",
+		Port:         m.option.ServerPort,
+		Subpath:      "/fileview",
+	})
 	return results
 }
 
@@ -60,5 +74,102 @@ func (m *Manager) ListEndpoints(userinfo *user.User) []*fileservers.Endpoint {
 */
 
 func (m *Manager) ServerWebFileRequest(w http.ResponseWriter, r *http.Request) {
+	if !m.enabled {
+		//Dirlisting is not enabled.
+		http.NotFound(w, r)
+		return
+	}
+	//Request basic auth
+	username, password, ok := r.BasicAuth()
+	if !ok {
+		w.Header().Set("WWW-Authenticate", `Basic realm="`+m.option.ServerUUID+`", charset="UTF-8"`)
+		http.Error(w, "401 - Unauthorized", http.StatusUnauthorized)
+		return
+	}
+
+	//Validate username and password
+	allowAccess, reason := m.option.UserManager.GetAuthAgent().ValidateUsernameAndPasswordWithReason(username, password)
+	if !allowAccess {
+		w.Header().Set("WWW-Authenticate", `Basic realm="`+m.option.ServerUUID+`", charset="UTF-8"`)
+		http.Error(w, "401 - Unauthorized: "+reason, http.StatusUnauthorized)
+		return
+	}
 
+	//Get user info
+	userinfo, err := m.option.UserManager.GetUserInfoFromUsername(username)
+	if err != nil {
+		http.Error(w, "500 - Internal Server Error: "+err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	requestPath := arozfs.ToSlash(filepath.Clean(r.RequestURI))
+	requestPath = requestPath[1:]                     //Trim away the first "/"
+	pathChunks := strings.Split(requestPath, "/")[1:] //Trim away the fileview prefix
+
+	html := ""
+	if len(pathChunks) == 0 {
+		//Show root
+		html += getPageHeader("/")
+		fshs := userinfo.GetAllFileSystemHandler()
+		for _, fsh := range fshs {
+			html += getItemHTML(fsh.Name, arozfs.ToSlash(filepath.Join(r.RequestURI, fsh.UUID)), true, "-", "-")
+		}
+
+	} else {
+		//Show path inside fsh
+		fshId := pathChunks[0]
+		subpath := strings.Join(pathChunks[1:], "/")
+		targetFsh, err := userinfo.GetFileSystemHandlerFromVirtualPath(fshId + ":/")
+		if err != nil {
+			http.Error(w, "404 - Not Found: "+err.Error(), http.StatusNotFound)
+			return
+		}
+
+		sp, err := url.QueryUnescape(subpath)
+		if err != nil {
+			sp = subpath
+		}
+		subpath = sp
+		html += getPageHeader(fshId + ":/" + subpath)
+		fshAbs := targetFsh.FileSystemAbstraction
+		rpath, err := fshAbs.VirtualPathToRealPath(subpath, userinfo.Username)
+		if err != nil {
+			http.Error(w, "500 - Virtual Path Conversion Failed: "+err.Error(), http.StatusNotFound)
+			return
+		}
+		if fshAbs.IsDir(rpath) {
+			//Append a back button
+			html += getBackButton(r.RequestURI)
+
+			//Load Directory
+			entries, err := fshAbs.ReadDir(rpath)
+			if err != nil {
+				http.Error(w, "500 - Internal Server Error: "+err.Error(), http.StatusInternalServerError)
+				return
+			}
+
+			for _, entry := range entries {
+				finfo, err := entry.Info()
+				if err != nil {
+					continue
+				}
+				html += getItemHTML(entry.Name(), arozfs.ToSlash(filepath.Join(r.RequestURI, entry.Name())), entry.IsDir(), finfo.ModTime().Format("2006-01-02 15:04:05"), byteCountIEC(finfo.Size()))
+			}
+
+		} else {
+			//Serve the file
+			f, err := fshAbs.ReadStream(rpath)
+			if err != nil {
+				fmt.Println(err)
+				http.Error(w, "500 - Internal Server Error: "+err.Error(), http.StatusInternalServerError)
+				return
+			}
+			defer f.Close()
+
+			io.Copy(w, f)
+		}
+
+	}
+	html += getPageFooter()
+	w.Write([]byte(html))
 }

+ 126 - 0
mod/fileservers/servers/dirserv/template.go

@@ -0,0 +1,126 @@
+package dirserv
+
+import (
+	"fmt"
+	"mime"
+	"path/filepath"
+	"strings"
+
+	"imuslab.com/arozos/mod/filesystem/arozfs"
+)
+
+func getPageHeader(pathname string) string {
+	return `<!DOCTYPE HTML>
+	<html>
+		<head>
+			<title>Index of ` + pathname + `</title>
+			<style>
+				body{
+					padding: 14px;
+					color: #2e2e2e;
+					font-family: Arial;
+				}
+
+				hr{
+					border: 0px;
+					border-top: 1px solid #e8e8e8;
+				}
+
+				td{
+					padding-left: 8px;
+					border-left: 1px solid #dbdbdb;
+				}
+
+				td.fx{
+					border-left: 0px;
+				}
+
+				.textfield{
+					min-width: 60px;
+					text-align: left;
+				}
+			</style>
+   		</head>
+   		<body>
+			<h2>Index of ` + pathname + `</h2>
+		<hr>
+		<table>
+		<tr>
+			<th></th>
+			<th class="textfield">Name</th>
+			<th class="textfield">Last Modifiy</th>
+			<th class="textfield">Size</th>
+			<th class="textfield"></th>
+		</tr>
+		`
+}
+
+func getItemHTML(displayText string, link string, isDir bool, modTime string, size string) string {
+	icon := "🗋"
+	downloadBtn := ""
+	hidden := ""
+	if isDir {
+		icon = "🗀"
+		if strings.HasPrefix(displayText, ".") {
+			//Hidden folder
+			icon = "🖿"
+			hidden = "filter: alpha(opacity=50); opacity: 0.5;  zoom: 1;"
+		}
+
+		size = "-"
+	} else {
+		fileMime := mime.TypeByExtension(filepath.Ext(link))
+		if strings.HasPrefix(fileMime, "audio/") {
+			icon = "♫"
+		} else if strings.HasPrefix(fileMime, "video/") {
+			icon = "🎞"
+		} else if strings.HasPrefix(fileMime, "image/") {
+			icon = "🖻"
+		} else if strings.HasPrefix(fileMime, "text/") {
+			icon = "🗎"
+		}
+		//fmt.Println(fileMime, filepath.Ext(displayText))
+
+		downloadBtn = `<a href="` + link + `" download>Download</a>`
+	}
+	return `<tr style="` + hidden + `">
+		<td class="fx">` + icon + `</td>
+		<td><a href="` + link + `">` + displayText + `</a></td>
+		<td>` + modTime + `</td>
+		<td>` + size + `</td>
+		<td>` + downloadBtn + `</td>
+	</tr>`
+}
+
+func getBackButton(currentPath string) string {
+	backPath := arozfs.ToSlash(filepath.Dir(currentPath))
+	return `<tr>
+		<td class="fx">←</td>
+		<td colspan="3"><a href="` + backPath + `">Back</a></td>	
+	</tr>`
+}
+
+func getPageFooter() string {
+	return `</table><hr>
+		<img src="/img/public/compatibility.png" style="display: inline-block; width: 120px;"></img>
+		</body>
+	</html>`
+}
+
+/*
+	Utilities
+*/
+
+func byteCountIEC(b int64) string {
+	const unit = 1024
+	if b < unit {
+		return fmt.Sprintf("%d B", b)
+	}
+	div, exp := int64(unit), 0
+	for n := b / unit; n >= unit; n /= unit {
+		div *= unit
+		exp++
+	}
+	return fmt.Sprintf("%.1f %ciB",
+		float64(b)/float64(div), "KMGTPE"[exp])
+}

+ 1 - 0
mod/fileservers/servers/webdavserv/webdavserv.go

@@ -79,6 +79,7 @@ func (m *Manager) HandleStatusChange(w http.ResponseWriter, r *http.Request) {
 */
 func (m *Manager) WebDavToogle(enabled bool) error {
 	m.WebDavHandler.Enabled = enabled
+	m.option.Sysdb.Write("webdav", "enabled", enabled)
 	return nil
 }
 

+ 9 - 2
network.go

@@ -309,8 +309,15 @@ func FileServerInit() {
 		Sysdb:       sysdb,
 	})
 
+	listeningPort := *listen_port
+	if *use_tls {
+		listeningPort = *tls_listen_port
+	}
 	DirListManager = dirserv.NewDirectoryServer(&dirserv.Option{
-		Sysdb: sysdb,
+		Sysdb:       sysdb,
+		ServerPort:  listeningPort,
+		UserManager: userHandler,
+		ServerUUID:  deviceUUID,
 	})
 
 	//Register Endpoints
@@ -383,7 +390,7 @@ func FileServerInit() {
 		ID:                "dirserv",
 		Name:              "Directory Server",
 		Desc:              "List direcotires with basic HTML",
-		IconPath:          "img/system/network-folder-blue.svg",
+		IconPath:          "img/system/network-dirserv.svg",
 		DefaultPorts:      []int{},
 		Ports:             []int{},
 		ForwardPortIfUpnp: false,

+ 31 - 0
web/SystemAO/disk/dirserv.html

@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <!-- 
+	<meta name="mobile-web-app-capable" content="yes">
+	<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
+	<meta charset="UTF-8">
+    <link rel="stylesheet" href="../../script/semantic/semantic.min.css">
+    <script src="../../script/jquery.min.js"></script>
+	<script src="../../script/semantic/semantic.min.js"></script>
+    -->
+    <style>
+        .hidden{
+            display:none;
+        }
+
+        .disabled{
+            opacity: 0.5;
+            pointer-events: none;
+        }
+    </style>
+</head>
+<body>
+    <small>No configuration needed</small>
+    <br><br>
+    <script>
+      
+       
+    </script>
+</body>
+</html>

+ 12 - 0
web/SystemAO/disk/instr/dirserv.html

@@ -0,0 +1,12 @@
+<div class="ui basic message">
+    <h4 class="ui header">
+        <i class="folder icon"></i>
+        <div class="content">
+            Accessing ArozOS on Legacy Devices
+        </div>
+    </h4>
+    <p>To access files on legacy devices with browsers (e.g. Some older smartphone or handheld with WiFi functionality), you can use a HTML only interface to list and download your files stored on ArozOS.
+        <br><b>Note that this interface is READ ONLY.</b>
+    <br><br>
+    Tips: To login, use your ArozOS username and password. </p>
+</div>

BIN
web/img/public/compatibility.png


BIN
web/img/public/compatibility.psd


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 27 - 0
web/img/system/network-dirserv.ai


BIN
web/img/system/network-dirserv.png


+ 25 - 0
web/img/system/network-dirserv.svg

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="128px"
+	 height="128px" viewBox="0 0 128 128" enable-background="new 0 0 128 128" xml:space="preserve">
+<g id="圖層_2">
+</g>
+<g id="圖層_3">
+</g>
+<g id="圖層_4">
+	<rect x="17.001" y="103.51" fill="#595757" width="93.997" height="4.691"/>
+	<rect x="60.985" y="84.064" fill="#595757" width="6.029" height="19.445"/>
+	<path fill="#C9CACA" d="M72.935,110.512c0,2.221-1.8,4.02-4.021,4.02h-9.827c-2.221,0-4.021-1.799-4.021-4.02v-9.828
+		c0-2.221,1.8-4.021,4.021-4.021h9.827c2.221,0,4.021,1.801,4.021,4.021V110.512z"/>
+</g>
+<g id="圖層_5">
+	<rect x="30.333" y="15.084" fill="#DCDDDD" width="25.333" height="25.333"/>
+	<polygon fill="#EFEFEF" points="50.287,13.125 27.917,35.495 27.917,94.666 100.084,94.666 100.084,13.125 	"/>
+	<rect x="41.039" y="44.594" fill="#679AD2" width="39.5" height="6.875"/>
+	<rect x="41.039" y="56.094" fill="#679AD2" width="39.5" height="6.875"/>
+	<rect x="41.039" y="68.781" fill="#679AD2" width="39.5" height="6.875"/>
+	<rect x="41.039" y="80.281" fill="#679AD2" width="39.5" height="6.875"/>
+	<rect x="41.039" y="29.25" width="51.952" height="9.083"/>
+</g>
+</svg>

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно