aboutsummaryrefslogtreecommitdiff
path: root/src/server.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/server.go')
-rw-r--r--src/server.go298
1 files changed, 298 insertions, 0 deletions
diff --git a/src/server.go b/src/server.go
new file mode 100644
index 0000000..16df50f
--- /dev/null
+++ b/src/server.go
@@ -0,0 +1,298 @@
+package main
+
+import (
+ "archive/zip"
+ "bytes"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "path/filepath"
+ "reflect"
+ "strings"
+
+ "golang.org/x/crypto/bcrypt"
+)
+
+func processAction(w http.ResponseWriter, r *http.Request, action string) *ServerError {
+ switch action {
+ default:
+ return &ServerError{nil, "Invalid Action", 400}
+ case "cut":
+ return addSelectionToBuffer(w, r, cutBuffer)
+ case "copy":
+ return addSelectionToBuffer(w, r, copyBuffer)
+ case "cancel-cut":
+ return deleteBuffer(w, r, cutBuffer)
+ case "cancel-copy":
+ return deleteBuffer(w, r, copyBuffer)
+ case "cut-paste":
+ return moveFilesFromBuffer(w, r, cutBuffer)
+ case "copy-paste":
+ return pasteFilesFromBuffer(w, r, copyBuffer)
+ case "newdir":
+ return createNewDirectory(w, r)
+ case "delete":
+ return deleteSelectedFiles(w, r)
+ }
+}
+
+func viewHandler(w http.ResponseWriter, r *http.Request) *ServerError {
+ var err error
+ var serr *ServerError
+ for k, v := range r.URL.Query() {
+ switch k {
+ default:
+ http.Redirect(w, r, r.URL.Path, 302)
+ case "action":
+ return processAction(w, r, v[0])
+ }
+ }
+ fileNode, serr := getFileNode(r.URL.Path)
+ if serr != nil {
+ return serr
+ }
+ if fileNode.Info.Mode()&os.ModeSymlink != 0 {
+ fileURI := fileNode.URI
+ target := ""
+ target, fileNode, err = fileNode.EvalSymlinks()
+ if err != nil {
+ if !os.IsNotExist(err) {
+ return &ServerError{err, "", 500}
+ }
+ if len(target) != 0 {
+ return &ServerError{err, fileURI + ": broken link to '" + target + "'", 404}
+ } else {
+ return &ServerError{err, fileURI + ": Inaccessible link", 404}
+ }
+ }
+ }
+ if !fileNode.IsDir {
+ http.ServeFile(w, r, fileNode.Path)
+ return nil
+ }
+ dirList, err := getDirList(fileNode.Path, "name", true, true)
+ if err != nil {
+ return &ServerError{err, "", 404}
+ }
+
+ fileNode.Data = dirList
+ fmt.Printf("View: '%s'\n", fileNode.URI)
+ if strings.TrimSpace(fileNode.URI) == "" {
+ return renderTemplate(w, "viewHome", &FSData{
+ FileCount: len(dirList),
+ File: fileNode,
+ })
+ }
+
+ cutBuf, err := readBuffer(cutBuffer)
+ if err != nil {
+ return &ServerError{err, "", 500}
+ }
+ copyBuf, err := readBuffer(copyBuffer)
+ if err != nil {
+ return &ServerError{err, "", 500}
+ }
+ return renderTemplate(w, "viewDir", &FSData{
+ CutCount: len(cutBuf),
+ CutBuffer: cutBuf,
+ CopyCount: len(copyBuf),
+ CopyBuffer: copyBuf,
+ FileCount: len(dirList),
+ File: fileNode,
+ })
+}
+
+func profileHandler(w http.ResponseWriter, r *http.Request) *ServerError {
+ username, err := readData("username")
+ if err != nil {
+ return &ServerError{err, "", 500}
+ }
+
+ if r.Method == "GET" {
+ return renderTemplate(w, "profile", &Profile{
+ Username: string(username),
+ })
+ }
+
+ newUsername := strings.TrimSpace(r.FormValue("username"))
+ if newUsername == "" {
+ return renderTemplate(w, "profile", &Profile{
+ Message: "Username cannot be empty.",
+ Status: "warning",
+ })
+ }
+ if newUsername != string(username) {
+ if err := writeData("username", []byte(newUsername)); err != nil {
+ return &ServerError{err, "", 500}
+ }
+ }
+
+ newPassword := r.FormValue("password")
+ confirmPassword := r.FormValue("confirm-pass")
+ if newPassword != "" {
+ if newPassword != confirmPassword {
+ return renderTemplate(w, "profile", &Profile{
+ Username: string(username),
+ Message: "Passwords do not match.",
+ Status: "warning",
+ })
+ }
+ newPassHash, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
+ if err != nil {
+ return &ServerError{err, "", 500}
+ }
+ writeData("password", newPassHash)
+ }
+
+ return renderTemplate(w, "profile", &Profile{
+ Username: string(username),
+ Message: "Profile updated successfully.",
+ Status: "success",
+ })
+}
+
+func downloadHandler(w http.ResponseWriter, r *http.Request) *ServerError {
+ fmt.Printf("%s\n", r.Form)
+ fileNode, files, serr := getSelectedNodes(r)
+ if serr != nil {
+ return serr
+ }
+ if len(files) == 1 && !files[0].IsDir {
+ sendFile(w, r, files[0].Path)
+ return nil
+ }
+ zipName := fileNode.Info.Name() + ".zip"
+ target := "/tmp/cloud/" + zipName
+
+ archive, err := os.Create(target)
+ if err != nil {
+ return &ServerError{err, "", 500}
+ }
+ defer archive.Close()
+
+ zipWriter := zip.NewWriter(archive)
+ defer zipWriter.Close()
+
+ for _, file := range files {
+ err := addToZip(file.Path, zipWriter)
+ if err != nil {
+ return &ServerError{err, "", 500}
+ }
+ }
+ zipWriter.Close()
+ sendFile(w, r, target, zipName)
+ return nil
+}
+
+func uploadHandler(w http.ResponseWriter, r *http.Request) *ServerError {
+ fileNode, serr := getFileNode(r.URL.Path)
+ if serr != nil {
+ return serr
+ }
+ r.ParseMultipartForm(65536)
+ formData := r.MultipartForm
+
+ for _, handler := range formData.File["attachments"] {
+ fmt.Printf("%v\n", handler.Header)
+ fmt.Println(handler.Filename, ":", handler.Size)
+ file, err := handler.Open()
+ if err != nil {
+ return &ServerError{err, "", 500}
+ }
+ defer file.Close()
+ filepath := filepath.Join(fileNode.Path, handler.Filename)
+ fmt.Printf("Saving to %v...", filepath)
+ f, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ return &ServerError{err, "", 500}
+ }
+ defer f.Close()
+ io.Copy(f, file)
+ fmt.Println("Saved.")
+ }
+ http.Redirect(w, r, "/view/"+fileNode.URI, 303)
+ return nil
+}
+
+func fileHandler(w http.ResponseWriter, r *http.Request) *ServerError {
+ fileNode, serr := getFileNode(r.URL.Path)
+ if serr != nil {
+ return serr
+ }
+ if fileNode.IsDir {
+ return &ServerError{nil, "File not Found.", 404}
+ }
+ http.ServeFile(w, r, fileNode.Path)
+ return nil
+}
+
+func handler(w http.ResponseWriter, r *http.Request) *ServerError {
+ if r.URL.Path != "/" {
+ return &ServerError{nil, "Invalid URL", 404}
+ }
+ http.Redirect(w, r, "view", 303)
+ return nil
+}
+
+type httpHandler func(http.ResponseWriter, *http.Request) *ServerError
+
+func (fn httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ username, password, ok := r.BasicAuth()
+ if !ok {
+ w.Header().Add("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
+ http.Error(w, "Basic Auth Missing.", 401)
+ return
+ }
+
+ realUsername, err := readData("username")
+ if err != nil {
+ http.Error(w, "Couldn't retreive username from server.", 500)
+ }
+ realPassword, err := readData("password")
+ if err != nil {
+ http.Error(w, "Couldn't retreive password from server.", 500)
+ }
+ realUsername = bytes.TrimRight(realUsername, "\n")
+ realPassword = bytes.TrimRight(realPassword, "\n")
+
+ // fmt.Printf("Given credentials: %s:%s\n", username, password)
+ // fmt.Printf("Requred credentials: %s:%s\n", realUsername, realPassword)
+
+ if string(realUsername) != username {
+ w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
+ http.Error(w, "Username not matched.", http.StatusUnauthorized)
+ return
+ }
+
+ if err := bcrypt.CompareHashAndPassword(realPassword, []byte(password)); err != nil {
+ w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
+ http.Error(w, "Authentication Error", http.StatusUnauthorized)
+ return
+ }
+
+ if serr := fn(w, r); serr != nil {
+ if serr.Err != nil {
+ fmt.Println("\n\nError Type:", reflect.TypeOf(serr.Err))
+ fmt.Println("Error Message:", serr.Error())
+ }
+ if serr.Message == "" {
+ serr.Message = "Internal Server Error"
+ }
+ http.Error(w, serr.Message, serr.Status)
+ }
+}
+
+func main() {
+ fileServer := http.FileServer(http.Dir("./static"))
+ http.Handle("/", httpHandler(handler))
+ http.Handle("/view/", httpHandler(viewHandler))
+ http.Handle("/profile/", httpHandler(profileHandler))
+ http.Handle("/upload/", httpHandler(uploadHandler))
+ http.Handle("/download/", httpHandler(downloadHandler))
+ http.Handle("/file/", httpHandler(fileHandler))
+ http.Handle("/static/", http.StripPrefix("/static/", fileServer))
+ fmt.Println("\nServer Listening on :8080")
+ log.Fatal(http.ListenAndServe(":8080", nil))
+}