From: Jeff Halter Date: Sat, 20 Jul 2024 04:31:42 +0000 (-0700) Subject: Add option for account-specific file root X-Git-Url: https://git.r.bdr.sh/rbdr/mobius/commitdiff_plain/dcd23d5355badf66c34ffd63d3c44734e87ebf17?ds=sidebyside Add option for account-specific file root --- diff --git a/hotline/account.go b/hotline/account.go index 7f770b1..526eb05 100644 --- a/hotline/account.go +++ b/hotline/account.go @@ -15,6 +15,7 @@ type Account struct { Name string `yaml:"Name"` Password string `yaml:"Password"` Access AccessBitmap `yaml:"Access,flow"` + FileRoot string `yaml:"FileRoot"` readOffset int // Internal offset to track read progress } diff --git a/hotline/client_conn.go b/hotline/client_conn.go index 060a2b9..d324591 100644 --- a/hotline/client_conn.go +++ b/hotline/client_conn.go @@ -42,6 +42,13 @@ type ClientConn struct { mu sync.RWMutex } +func (cc *ClientConn) FileRoot() string { + if cc.Account.FileRoot != "" { + return cc.Account.FileRoot + } + return cc.Server.Config.FileRoot +} + type ClientFileTransferMgr struct { transfers map[FileTransferType]map[FileTransferID]*FileTransfer diff --git a/hotline/file_transfer.go b/hotline/file_transfer.go index 806466b..12725db 100644 --- a/hotline/file_transfer.go +++ b/hotline/file_transfer.go @@ -87,6 +87,7 @@ func (ftm *MemFileTransferMgr) Delete(id FileTransferID) { } type FileTransfer struct { + FileRoot string FileName []byte FilePath []byte RefNum [4]byte @@ -116,9 +117,10 @@ func (wc *WriteCounter) Write(p []byte) (int, error) { return n, nil } -func (cc *ClientConn) NewFileTransfer(transferType FileTransferType, fileName, filePath, size []byte) *FileTransfer { +func (cc *ClientConn) NewFileTransfer(transferType FileTransferType, fileroot string, fileName, filePath, size []byte) *FileTransfer { ft := &FileTransfer{ FileName: fileName, + FileRoot: fileroot, FilePath: filePath, Type: transferType, TransferSize: size, diff --git a/hotline/server.go b/hotline/server.go index 04ac8c7..c4d8f7f 100644 --- a/hotline/server.go +++ b/hotline/server.go @@ -526,7 +526,7 @@ func (s *Server) handleFileTransfer(ctx context.Context, rwc io.ReadWriter) erro "Name", string(fileTransfer.ClientConn.UserName), ) - fullPath, err := ReadPath(s.Config.FileRoot, fileTransfer.FilePath, fileTransfer.FileName) + fullPath, err := ReadPath(fileTransfer.FileRoot, fileTransfer.FilePath, fileTransfer.FileName) if err != nil { return err } @@ -534,7 +534,7 @@ func (s *Server) handleFileTransfer(ctx context.Context, rwc io.ReadWriter) erro switch fileTransfer.Type { case BannerDownload: if _, err := io.Copy(rwc, bytes.NewBuffer(s.Banner)); err != nil { - return fmt.Errorf("error sending Banner: %w", err) + return fmt.Errorf("banner download: %w", err) } case FileDownload: s.Stats.Increment(StatDownloadCounter, StatDownloadsInProgress) @@ -555,7 +555,7 @@ func (s *Server) handleFileTransfer(ctx context.Context, rwc io.ReadWriter) erro err = UploadHandler(rwc, fullPath, fileTransfer, s.FS, rLogger, s.Config.PreserveResourceForks) if err != nil { - return fmt.Errorf("file upload error: %w", err) + return fmt.Errorf("file upload: %w", err) } case FolderDownload: @@ -566,7 +566,7 @@ func (s *Server) handleFileTransfer(ctx context.Context, rwc io.ReadWriter) erro err = DownloadFolderHandler(rwc, fullPath, fileTransfer, s.FS, rLogger, s.Config.PreserveResourceForks) if err != nil { - return fmt.Errorf("file upload error: %w", err) + return fmt.Errorf("folder download: %w", err) } case FolderUpload: @@ -584,7 +584,7 @@ func (s *Server) handleFileTransfer(ctx context.Context, rwc io.ReadWriter) erro err = UploadFolderHandler(rwc, fullPath, fileTransfer, s.FS, rLogger, s.Config.PreserveResourceForks) if err != nil { - return fmt.Errorf("file upload error: %w", err) + return fmt.Errorf("folder upload: %w", err) } } return nil diff --git a/hotline/server_test.go b/hotline/server_test.go index c3d38da..d0e2372 100644 --- a/hotline/server_test.go +++ b/hotline/server_test.go @@ -99,12 +99,7 @@ func TestServer_handleFileTransfer(t *testing.T) { { name: "file download", fields: fields{ - FS: &OSFileStore{}, - Config: Config{ - FileRoot: func() string { - path, _ := os.Getwd() - return path + "/test/config/Files" - }()}, + FS: &OSFileStore{}, Logger: NewTestLogger(), Stats: NewStats(), FileTransferMgr: &MemFileTransferMgr{ @@ -114,6 +109,10 @@ func TestServer_handleFileTransfer(t *testing.T) { Type: FileDownload, FileName: []byte("testfile-8b"), FilePath: []byte{}, + FileRoot: func() string { + path, _ := os.Getwd() + return path + "/test/config/Files" + }(), ClientConn: &ClientConn{ Account: &Account{ Login: "foo", diff --git a/internal/mobius/transaction_handlers.go b/internal/mobius/transaction_handlers.go index 399a8c0..759ee66 100644 --- a/internal/mobius/transaction_handlers.go +++ b/internal/mobius/transaction_handlers.go @@ -204,7 +204,7 @@ func HandleGetFileInfo(cc *hotline.ClientConn, t *hotline.Transaction) (res []ho fileName := t.GetField(hotline.FieldFileName).Data filePath := t.GetField(hotline.FieldFilePath).Data - fullFilePath, err := hotline.ReadPath(cc.Server.Config.FileRoot, filePath, fileName) + fullFilePath, err := hotline.ReadPath(cc.FileRoot(), filePath, fileName) if err != nil { return res } @@ -253,7 +253,7 @@ func HandleSetFileInfo(cc *hotline.ClientConn, t *hotline.Transaction) (res []ho fileName := t.GetField(hotline.FieldFileName).Data filePath := t.GetField(hotline.FieldFilePath).Data - fullFilePath, err := hotline.ReadPath(cc.Server.Config.FileRoot, filePath, fileName) + fullFilePath, err := hotline.ReadPath(cc.FileRoot(), filePath, fileName) if err != nil { return res } @@ -292,7 +292,7 @@ func HandleSetFileInfo(cc *hotline.ClientConn, t *hotline.Transaction) (res []ho } } - fullNewFilePath, err := hotline.ReadPath(cc.Server.Config.FileRoot, filePath, t.GetField(hotline.FieldFileNewName).Data) + fullNewFilePath, err := hotline.ReadPath(cc.FileRoot(), filePath, t.GetField(hotline.FieldFileNewName).Data) if err != nil { return nil } @@ -314,7 +314,7 @@ func HandleSetFileInfo(cc *hotline.ClientConn, t *hotline.Transaction) (res []ho if !cc.Authorize(hotline.AccessRenameFile) { return cc.NewErrReply(t, "You are not allowed to rename files.") } - fileDir, err := hotline.ReadPath(cc.Server.Config.FileRoot, filePath, []byte{}) + fileDir, err := hotline.ReadPath(cc.FileRoot(), filePath, []byte{}) if err != nil { return nil } @@ -346,7 +346,7 @@ func HandleDeleteFile(cc *hotline.ClientConn, t *hotline.Transaction) (res []hot fileName := t.GetField(hotline.FieldFileName).Data filePath := t.GetField(hotline.FieldFilePath).Data - fullFilePath, err := hotline.ReadPath(cc.Server.Config.FileRoot, filePath, fileName) + fullFilePath, err := hotline.ReadPath(cc.FileRoot(), filePath, fileName) if err != nil { return res } @@ -384,12 +384,12 @@ func HandleDeleteFile(cc *hotline.ClientConn, t *hotline.Transaction) (res []hot func HandleMoveFile(cc *hotline.ClientConn, t *hotline.Transaction) (res []hotline.Transaction) { fileName := string(t.GetField(hotline.FieldFileName).Data) - filePath, err := hotline.ReadPath(cc.Server.Config.FileRoot, t.GetField(hotline.FieldFilePath).Data, t.GetField(hotline.FieldFileName).Data) + filePath, err := hotline.ReadPath(cc.FileRoot(), t.GetField(hotline.FieldFilePath).Data, t.GetField(hotline.FieldFileName).Data) if err != nil { return res } - fileNewPath, err := hotline.ReadPath(cc.Server.Config.FileRoot, t.GetField(hotline.FieldFileNewPath).Data, nil) + fileNewPath, err := hotline.ReadPath(cc.FileRoot(), t.GetField(hotline.FieldFileNewPath).Data, nil) if err != nil { return res } @@ -446,7 +446,7 @@ func HandleNewFolder(cc *hotline.ClientConn, t *hotline.Transaction) (res []hotl subPath = filepath.Join("/", subPath, string(pathItem.Name)) } } - newFolderPath := path.Join(cc.Server.Config.FileRoot, subPath, folderName) + newFolderPath := path.Join(cc.FileRoot(), subPath, folderName) newFolderPath, err := txtDecoder.String(newFolderPath) if err != nil { return res @@ -1279,7 +1279,7 @@ func HandleDownloadFile(cc *hotline.ClientConn, t *hotline.Transaction) (res []h dataOffset = int64(binary.BigEndian.Uint32(frd.ForkInfoList[0].DataSize[:])) } - fullFilePath, err := hotline.ReadPath(cc.Server.Config.FileRoot, filePath, fileName) + fullFilePath, err := hotline.ReadPath(cc.FileRoot(), filePath, fileName) if err != nil { return res } @@ -1291,9 +1291,14 @@ func HandleDownloadFile(cc *hotline.ClientConn, t *hotline.Transaction) (res []h xferSize := hlFile.Ffo.TransferSize(0) - ft := cc.NewFileTransfer(hotline.FileDownload, fileName, filePath, xferSize) + ft := cc.NewFileTransfer( + hotline.FileDownload, + cc.FileRoot(), + fileName, + filePath, + xferSize, + ) - // TODO: refactor to remove this if resumeData != nil { var frd hotline.FileResumeData if err := frd.UnmarshalBinary(t.GetField(hotline.FieldFileResumeData).Data); err != nil { @@ -1326,26 +1331,26 @@ func HandleDownloadFolder(cc *hotline.ClientConn, t *hotline.Transaction) (res [ return cc.NewErrReply(t, "You are not allowed to download folders.") } - fullFilePath, err := hotline.ReadPath(cc.Server.Config.FileRoot, t.GetField(hotline.FieldFilePath).Data, t.GetField(hotline.FieldFileName).Data) + fullFilePath, err := hotline.ReadPath(cc.FileRoot(), t.GetField(hotline.FieldFilePath).Data, t.GetField(hotline.FieldFileName).Data) if err != nil { - return res + return nil } transferSize, err := hotline.CalcTotalSize(fullFilePath) if err != nil { - return res + return nil } itemCount, err := hotline.CalcItemCount(fullFilePath) if err != nil { - return res + return nil } - fileTransfer := cc.NewFileTransfer(hotline.FolderDownload, t.GetField(hotline.FieldFileName).Data, t.GetField(hotline.FieldFilePath).Data, transferSize) + fileTransfer := cc.NewFileTransfer(hotline.FolderDownload, cc.FileRoot(), t.GetField(hotline.FieldFileName).Data, t.GetField(hotline.FieldFilePath).Data, transferSize) var fp hotline.FilePath _, err = fp.Write(t.GetField(hotline.FieldFilePath).Data) if err != nil { - return res + return nil } res = append(res, cc.NewReply(t, @@ -1380,6 +1385,7 @@ func HandleUploadFolder(cc *hotline.ClientConn, t *hotline.Transaction) (res []h } fileTransfer := cc.NewFileTransfer(hotline.FolderUpload, + cc.FileRoot(), t.GetField(hotline.FieldFileName).Data, t.GetField(hotline.FieldFilePath).Data, t.GetField(hotline.FieldTransferSize).Data, @@ -1420,7 +1426,7 @@ func HandleUploadFile(cc *hotline.ClientConn, t *hotline.Transaction) (res []hot return cc.NewErrReply(t, fmt.Sprintf("Cannot accept upload of the file \"%v\" because you are only allowed to upload to the \"Uploads\" folder.", string(fileName))) } } - fullFilePath, err := hotline.ReadPath(cc.Server.Config.FileRoot, filePath, fileName) + fullFilePath, err := hotline.ReadPath(cc.FileRoot(), filePath, fileName) if err != nil { return res } @@ -1429,7 +1435,7 @@ func HandleUploadFile(cc *hotline.ClientConn, t *hotline.Transaction) (res []hot return cc.NewErrReply(t, fmt.Sprintf("Cannot accept upload because there is already a file named \"%v\". Try choosing a different Name.", string(fileName))) } - ft := cc.NewFileTransfer(hotline.FileUpload, fileName, filePath, transferSize) + ft := cc.NewFileTransfer(hotline.FileUpload, cc.FileRoot(), fileName, filePath, transferSize) replyT := cc.NewReply(t, hotline.NewField(hotline.FieldRefNum, ft.RefNum[:])) @@ -1509,7 +1515,7 @@ func HandleKeepAlive(cc *hotline.ClientConn, t *hotline.Transaction) (res []hotl func HandleGetFileNameList(cc *hotline.ClientConn, t *hotline.Transaction) (res []hotline.Transaction) { fullPath, err := hotline.ReadPath( - cc.Server.Config.FileRoot, + cc.FileRoot(), t.GetField(hotline.FieldFilePath).Data, nil, ) @@ -1756,12 +1762,12 @@ func HandleMakeAlias(cc *hotline.ClientConn, t *hotline.Transaction) (res []hotl filePath := t.GetField(hotline.FieldFilePath).Data fileNewPath := t.GetField(hotline.FieldFileNewPath).Data - fullFilePath, err := hotline.ReadPath(cc.Server.Config.FileRoot, filePath, fileName) + fullFilePath, err := hotline.ReadPath(cc.FileRoot(), filePath, fileName) if err != nil { return res } - fullNewFilePath, err := hotline.ReadPath(cc.Server.Config.FileRoot, fileNewPath, fileName) + fullNewFilePath, err := hotline.ReadPath(cc.FileRoot(), fileNewPath, fileName) if err != nil { return res } @@ -1783,7 +1789,7 @@ func HandleMakeAlias(cc *hotline.ClientConn, t *hotline.Transaction) (res []hotl // 107 FieldRefNum Used later for transfer // 108 FieldTransferSize Size of data to be downloaded func HandleDownloadBanner(cc *hotline.ClientConn, t *hotline.Transaction) (res []hotline.Transaction) { - ft := cc.NewFileTransfer(hotline.BannerDownload, []byte{}, []byte{}, make([]byte, 4)) + ft := cc.NewFileTransfer(hotline.BannerDownload, "", []byte{}, []byte{}, make([]byte, 4)) binary.BigEndian.PutUint32(ft.TransferSize, uint32(len(cc.Server.Banner))) return append(res, cc.NewReply(t, diff --git a/internal/mobius/transaction_handlers_test.go b/internal/mobius/transaction_handlers_test.go index 63d2946..26ea950 100644 --- a/internal/mobius/transaction_handlers_test.go +++ b/internal/mobius/transaction_handlers_test.go @@ -782,7 +782,8 @@ func TestHandleGetFileInfo(t *testing.T) { name: "returns expected fields when a valid file is requested", args: args{ cc: &hotline.ClientConn{ - ID: [2]byte{0x00, 0x01}, + ID: [2]byte{0, 1}, + Account: &hotline.Account{}, Server: &hotline.Server{ FS: &hotline.OSFileStore{}, Config: hotline.Config{ @@ -2629,14 +2630,13 @@ func TestHandleGetFileNameList(t *testing.T) { name: "with file root", args: args{ cc: &hotline.ClientConn{ - Server: &hotline.Server{ - Config: hotline.Config{ - FileRoot: func() string { - path, _ := os.Getwd() - return filepath.Join(path, "/test/config/Files/getFileNameListTestDir") - }(), - }, + Account: &hotline.Account{ + FileRoot: func() string { + path, _ := os.Getwd() + return filepath.Join(path, "/test/config/Files/getFileNameListTestDir") + }(), }, + Server: &hotline.Server{}, }, t: hotline.NewTransaction( hotline.TranGetFileNameList, [2]byte{0, 1},