dkforest

A forum and chat platform (onion)
git clone https://git.dasho.dev/n0tr1v/dkforest.git
Log | Files | Refs | LICENSE

commit 34caa6914a83e1f6192f35b37fa6202a22ec8002
parent 062c073b84705a9cf8449739355508fda1c30415
Author: n0tr1v <n0tr1v@protonmail.com>
Date:   Fri,  3 Feb 2023 19:49:46 -0800

1 endpoint for dkfupload

Diffstat:
Mcmd/dkfupload/main.go | 23+++++++++++++++++++++--
Mpkg/web/handlers/handlers.go | 204++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mpkg/web/web.go | 2--
3 files changed, 125 insertions(+), 104 deletions(-)

diff --git a/cmd/dkfupload/main.go b/cmd/dkfupload/main.go @@ -111,12 +111,13 @@ func main() { logrus.Debug("sending metadata") client := doGetClient(isLocal, httpTimeout) body := url.Values{} + body.Set("init", "1") body.Set("fileName", fs.Name()) body.Set("fileSize", strconv.FormatInt(fileSize, 10)) body.Set("fileSha256", fileSha256) body.Set("chunkSize", strconv.FormatInt(maxChunkSize, 10)) body.Set("nbChunks", strconv.FormatInt(nbChunks, 10)) - req, _ := http.NewRequest(http.MethodPost, baseUrl+"/file-drop/"+filedropUUID+"/dkfupload-init", strings.NewReader(body.Encode())) + req, _ := http.NewRequest(http.MethodPost, baseUrl+"/file-drop/"+filedropUUID+"/dkfupload", strings.NewReader(body.Encode())) req.Header.Set("User-Agent", userAgent) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") resp, err := client.Do(req) @@ -151,6 +152,24 @@ func main() { // Wait for all workers to have completed wg.Wait() + + if !dry { + client := doGetClient(isLocal, httpTimeout) + body := url.Values{} + body.Set("completed", "1") + req, _ := http.NewRequest(http.MethodPost, baseUrl+"/file-drop/"+filedropUUID+"/dkfupload", strings.NewReader(body.Encode())) + req.Header.Set("User-Agent", userAgent) + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + resp, err := client.Do(req) + if err != nil { + logrus.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + logrus.Fatal(fmt.Errorf("invalid status code %s", resp.Status)) + } + } + logrus.Infof("All done in %s\n", ShortDur(time.Since(start))) } @@ -170,7 +189,7 @@ func work(i int, wg *sync.WaitGroup, chunksCh chan int64, isLocal, dry bool, max // Ask server if he already has the chunk { body := url.Values{} - body.Set("fileName", partFileName) + body.Set("chunkFileName", partFileName) req, _ := http.NewRequest(http.MethodPost, baseUrl+"/file-drop/"+filedropUUID+"/dkfupload", strings.NewReader(body.Encode())) req.Header.Set("User-Agent", userAgent) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") diff --git a/pkg/web/handlers/handlers.go b/pkg/web/handlers/handlers.go @@ -4318,136 +4318,140 @@ func FileDropHandler(c echo.Context) error { return c.Render(http.StatusOK, filedropTmplName, data) } -func FileDropDkfUploadReconstructHandler(c echo.Context) error { - filedropUUID := c.Param("uuid") +func FileDropDkfUploadHandler(c echo.Context) error { + // Init + if c.Request().PostFormValue("init") != "" { + filedropUUID := c.Param("uuid") + _, err := database.GetFiledropByUUID(filedropUUID) + if err != nil { + return c.Redirect(http.StatusFound, "/") + } - filedrop, err := database.GetFiledropByUUID(filedropUUID) - if err != nil { - return c.Redirect(http.StatusFound, "/") - } + _ = os.Mkdir(filepath.Join(config.Global.ProjectFiledropPath(), filedropUUID), 0755) + metadataPath := filepath.Join(config.Global.ProjectFiledropPath(), filedropUUID, "metadata") - dirEntries, _ := os.ReadDir(filepath.Join(config.Global.ProjectFiledropPath(), filedropUUID)) - fileNames := make([]string, 0) - for _, dirEntry := range dirEntries { - if !strings.HasPrefix(dirEntry.Name(), "part_") { - continue + fileName := c.Request().PostFormValue("fileName") + fileSize := c.Request().PostFormValue("fileSize") + fileSha256 := c.Request().PostFormValue("fileSha256") + chunkSize := c.Request().PostFormValue("chunkSize") + nbChunks := c.Request().PostFormValue("nbChunks") + data := []byte(fileName + "\n" + fileSize + "\n" + fileSha256 + "\n" + chunkSize + "\n" + nbChunks + "\n") + + if _, err := os.Stat(metadataPath); err != nil { + if err := os.WriteFile(metadataPath, data, 0644); err != nil { + logrus.Error(err) + return c.String(http.StatusInternalServerError, err.Error()) + } + } else { + by, err := os.ReadFile(metadataPath) + if err != nil { + logrus.Error(err) + return c.String(http.StatusInternalServerError, err.Error()) + } + if bytes.Compare(by, data) != 0 { + err := errors.New("metadata file already exists with different configuration") + logrus.Error(err) + return c.String(http.StatusInternalServerError, err.Error()) + } } - fileNames = append(fileNames, dirEntry.Name()) - } - sort.Slice(fileNames, func(i, j int) bool { - a := strings.Split(fileNames[i], "_")[1] - b := strings.Split(fileNames[j], "_")[1] - numA, _ := strconv.Atoi(a) - numB, _ := strconv.Atoi(b) - return numA < numB - }) - metadata, err := os.ReadFile(filepath.Join(config.Global.ProjectFiledropPath(), filedropUUID, "metadata")) - if err != nil { - logrus.Error(err) - return c.NoContent(http.StatusInternalServerError) + return c.NoContent(http.StatusOK) } - lines := strings.Split(string(metadata), "\n") - origFileName := lines[0] - fileSha256 := lines[2] - f, err := os.OpenFile(filepath.Join(config.Global.ProjectFiledropPath(), filedrop.FileName), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) - if err != nil { - logrus.Error(err) - return c.NoContent(http.StatusInternalServerError) - } - defer f.Close() - h := sha256.New() + // completed + if c.Request().PostFormValue("completed") != "" { + filedropUUID := c.Param("uuid") - password := make([]byte, 16) - _, _ = cryptoRand.Read(password) + filedrop, err := database.GetFiledropByUUID(filedropUUID) + if err != nil { + return c.Redirect(http.StatusFound, "/") + } - stream, _, iv, err := crypto.NewCtrStram(password) - if err != nil { - logrus.Error(err) - return c.NoContent(http.StatusInternalServerError) - } - written := int64(0) - for _, fileName := range fileNames { - by, err := os.ReadFile(filepath.Join(config.Global.ProjectFiledropPath(), filedropUUID, fileName)) + dirEntries, _ := os.ReadDir(filepath.Join(config.Global.ProjectFiledropPath(), filedropUUID)) + fileNames := make([]string, 0) + for _, dirEntry := range dirEntries { + if !strings.HasPrefix(dirEntry.Name(), "part_") { + continue + } + fileNames = append(fileNames, dirEntry.Name()) + } + sort.Slice(fileNames, func(i, j int) bool { + a := strings.Split(fileNames[i], "_")[1] + b := strings.Split(fileNames[j], "_")[1] + numA, _ := strconv.Atoi(a) + numB, _ := strconv.Atoi(b) + return numA < numB + }) + + metadata, err := os.ReadFile(filepath.Join(config.Global.ProjectFiledropPath(), filedropUUID, "metadata")) if err != nil { logrus.Error(err) return c.NoContent(http.StatusInternalServerError) } + lines := strings.Split(string(metadata), "\n") + origFileName := lines[0] + fileSha256 := lines[2] - dst := make([]byte, len(by)) - _, _ = h.Write(by) - stream.XORKeyStream(dst, by) - _, err = f.Write(dst) + f, err := os.OpenFile(filepath.Join(config.Global.ProjectFiledropPath(), filedrop.FileName), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { logrus.Error(err) return c.NoContent(http.StatusInternalServerError) } - written += int64(len(by)) - } - - newFileSha256 := hex.EncodeToString(h.Sum(nil)) + defer f.Close() + h := sha256.New() - if newFileSha256 != fileSha256 { - logrus.Errorf("%s != %s", newFileSha256, fileSha256) - return c.NoContent(http.StatusInternalServerError) - } + password := make([]byte, 16) + _, _ = cryptoRand.Read(password) - filedrop.Password = database.EncryptedString(password) - filedrop.IV = iv - filedrop.OrigFileName = origFileName - filedrop.FileSize = written - filedrop.DoSave() + stream, _, iv, err := crypto.NewCtrStram(password) + if err != nil { + logrus.Error(err) + return c.NoContent(http.StatusInternalServerError) + } + written := int64(0) + for _, fileName := range fileNames { + by, err := os.ReadFile(filepath.Join(config.Global.ProjectFiledropPath(), filedropUUID, fileName)) + if err != nil { + logrus.Error(err) + return c.NoContent(http.StatusInternalServerError) + } - return c.NoContent(http.StatusOK) -} + dst := make([]byte, len(by)) + _, _ = h.Write(by) + stream.XORKeyStream(dst, by) + _, err = f.Write(dst) + if err != nil { + logrus.Error(err) + return c.NoContent(http.StatusInternalServerError) + } + written += int64(len(by)) + } -func FileDropDkfUploadInitHandler(c echo.Context) error { - filedropUUID := c.Param("uuid") + newFileSha256 := hex.EncodeToString(h.Sum(nil)) - _, err := database.GetFiledropByUUID(filedropUUID) - if err != nil { - return c.Redirect(http.StatusFound, "/") - } + if newFileSha256 != fileSha256 { + logrus.Errorf("%s != %s", newFileSha256, fileSha256) + return c.NoContent(http.StatusInternalServerError) + } - _ = os.Mkdir(filepath.Join(config.Global.ProjectFiledropPath(), filedropUUID), 0755) - metadataPath := filepath.Join(config.Global.ProjectFiledropPath(), filedropUUID, "metadata") + // Cleanup + _ = os.RemoveAll(filepath.Join(config.Global.ProjectFiledropPath(), filedropUUID)) - fileName := c.Request().PostFormValue("fileName") - fileSize := c.Request().PostFormValue("fileSize") - fileSha256 := c.Request().PostFormValue("fileSha256") - chunkSize := c.Request().PostFormValue("chunkSize") - nbChunks := c.Request().PostFormValue("nbChunks") - data := []byte(fileName + "\n" + fileSize + "\n" + fileSha256 + "\n" + chunkSize + "\n" + nbChunks + "\n") + filedrop.Password = database.EncryptedString(password) + filedrop.IV = iv + filedrop.OrigFileName = origFileName + filedrop.FileSize = written + filedrop.DoSave() - if _, err := os.Stat(metadataPath); err != nil { - if err := os.WriteFile(metadataPath, data, 0644); err != nil { - logrus.Error(err) - return c.String(http.StatusInternalServerError, err.Error()) - } - } else { - by, err := os.ReadFile(metadataPath) - if err != nil { - logrus.Error(err) - return c.String(http.StatusInternalServerError, err.Error()) - } - if bytes.Compare(by, data) != 0 { - err := errors.New("metadata file already exists with different configuration") - logrus.Error(err) - return c.String(http.StatusInternalServerError, err.Error()) - } + return c.NoContent(http.StatusOK) } - return c.NoContent(http.StatusOK) -} - -func FileDropDkfUploadHandler(c echo.Context) error { filedropUUID := c.Param("uuid") { - fileName := c.Request().PostFormValue("fileName") - if fileName != "" { - if _, err := os.Stat(filepath.Join(config.Global.ProjectFiledropPath(), filedropUUID, fileName)); err != nil { + chunkFileName := c.Request().PostFormValue("chunkFileName") + if chunkFileName != "" { + if _, err := os.Stat(filepath.Join(config.Global.ProjectFiledropPath(), filedropUUID, chunkFileName)); err != nil { return c.NoContent(http.StatusOK) } // Let's use the teapot response (because why not) to say that we already have the file diff --git a/pkg/web/web.go b/pkg/web/web.go @@ -248,7 +248,6 @@ func getMainServer(i18nBundle *i18n.Bundle, renderer *tmp.Templates) echo.Handle adminGroup.POST("/admin/uploads", handlers.AdminUploadsHandler) adminGroup.GET("/admin/filedrops", handlers.AdminFiledropsHandler) adminGroup.POST("/admin/filedrops", handlers.AdminFiledropsHandler) - adminGroup.GET("/file-drop/:uuid/dkfupload-reconstruct", handlers.FileDropDkfUploadReconstructHandler) adminGroup.GET("/admin/file-drop/:filename", handlers.FiledropDownloadHandler) adminGroup.GET("/admin/downloads", handlers.AdminDownloadsHandler) adminGroup.POST("/admin/downloads/:downloadID/delete", handlers.AdminDeleteDownloadHandler) @@ -302,7 +301,6 @@ func getBaseServer() *echo.Echo { e.Use(middlewares.I18nMiddleware(i18nBundle, "en")) e.GET("/file-drop/:uuid", handlers.FileDropHandler) e.POST("/file-drop/:uuid", handlers.FileDropHandler) - e.POST("/file-drop/:uuid/dkfupload-init", handlers.FileDropDkfUploadInitHandler) e.POST("/file-drop/:uuid/dkfupload", handlers.FileDropDkfUploadHandler) e.POST("/file-drop/:uuid/dkfdownload", handlers.FileDropDkfDownloadHandler) e.GET("/downloads/:fileName", handlers.FileDropDownloadHandler)