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)) }