From 73d025a1d928712bb9ffc8b68c687578365ca597 Mon Sep 17 00:00:00 2001 From: RissRIce Date: Wed, 12 Aug 2026 19:59:57 -0600 Subject: [PATCH] fix(gopher): serve public files from SFTP storage --- internal/gopher/server.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/internal/gopher/server.go b/internal/gopher/server.go index 170ccb7..2159f18 100644 --- a/internal/gopher/server.go +++ b/internal/gopher/server.go @@ -262,7 +262,7 @@ func (s *Server) newsArticles(group string) Response { } // filesRoot lists every non-banned member, each linking to their public files -// area (/users//public), mirroring the anonymous web files surface. +// area (/files/public/), mirroring the anonymous web files surface. func (s *Server) filesRoot() Response { users, err := s.c.ListUsers(1000) if err != nil { @@ -287,7 +287,8 @@ func (s *Server) filesRoot() Response { // userTree serves a member's per-user area (public_html homepage, or the public // files area) as gopher content. prefix is the selector root ("" for homepages, // "files" for the files area); sel is the remainder after the prefix, of the form -// "~name[/subpath]". area is the on-disk subdirectory under /users/. +// "~name[/subpath]". Homepages live under /users//; public +// files share the SFTP service's /files/public/ storage root. // // The subpath is confined to the member's area: it is cleaned as an absolute // path (so any ".." that would escape is neutralised) and the resolved target is @@ -301,6 +302,9 @@ func (s *Server) userTree(prefix, sel, area string) Response { return errResp("bad member name") } base := filepath.Join(s.dataDir, "users", name, area) + if prefix == "files" { + base = filepath.Join(s.dataDir, "files", "public", name) + } // Confine sub to base. Cleaning as an absolute path drops any leading ".." // components; the HasPrefix re-check is belt-and-suspenders against edge