server auth
This commit is contained in:
@@ -137,6 +137,10 @@ func (s *Server) handleDocsIndex(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (s *Server) handleDocument(w http.ResponseWriter, r *http.Request) {
|
||||
pagePath := chi.URLParam(r, "*")
|
||||
if isContentAssetPath(pagePath) {
|
||||
s.handleContentAsset(w, r, pagePath)
|
||||
return
|
||||
}
|
||||
if editPath, ok := trimEditSuffix(pagePath); ok {
|
||||
s.renderDocumentEditor(w, r, editPath)
|
||||
return
|
||||
@@ -144,6 +148,64 @@ func (s *Server) handleDocument(w http.ResponseWriter, r *http.Request) {
|
||||
s.renderDocumentPage(w, r, pagePath)
|
||||
}
|
||||
|
||||
func (s *Server) handleContentAsset(w http.ResponseWriter, r *http.Request, assetPath string) {
|
||||
cleanPath := filepath.Clean(filepath.FromSlash(strings.TrimPrefix(assetPath, "/")))
|
||||
if cleanPath == "." || strings.HasPrefix(cleanPath, ".."+string(filepath.Separator)) || filepath.IsAbs(cleanPath) {
|
||||
s.renderError(w, r, http.StatusNotFound, "asset not found")
|
||||
return
|
||||
}
|
||||
|
||||
fullPath := filepath.Join(s.config.Content.SourceDir, cleanPath)
|
||||
sourceRoot, err := filepath.Abs(s.config.Content.SourceDir)
|
||||
if err != nil {
|
||||
s.renderError(w, r, http.StatusInternalServerError, "resolve content root")
|
||||
return
|
||||
}
|
||||
assetAbs, err := filepath.Abs(fullPath)
|
||||
if err != nil {
|
||||
s.renderError(w, r, http.StatusNotFound, "asset not found")
|
||||
return
|
||||
}
|
||||
relative, err := filepath.Rel(sourceRoot, assetAbs)
|
||||
if err != nil || relative == ".." || strings.HasPrefix(relative, ".."+string(filepath.Separator)) {
|
||||
s.renderError(w, r, http.StatusNotFound, "asset not found")
|
||||
return
|
||||
}
|
||||
|
||||
file, err := os.Open(assetAbs)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
s.renderError(w, r, http.StatusNotFound, "asset not found")
|
||||
return
|
||||
}
|
||||
s.renderError(w, r, http.StatusInternalServerError, "read asset")
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
info, err := file.Stat()
|
||||
if err != nil || info.IsDir() {
|
||||
s.renderError(w, r, http.StatusNotFound, "asset not found")
|
||||
return
|
||||
}
|
||||
|
||||
buffer := make([]byte, 512)
|
||||
n, _ := file.Read(buffer)
|
||||
if _, err := file.Seek(0, io.SeekStart); err != nil {
|
||||
s.renderError(w, r, http.StatusInternalServerError, "read asset")
|
||||
return
|
||||
}
|
||||
contentType := http.DetectContentType(buffer[:n])
|
||||
if !isAllowedContentType(contentType) {
|
||||
s.renderError(w, r, http.StatusNotFound, "asset not found")
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
w.Header().Set("Content-Length", fmt.Sprintf("%d", info.Size()))
|
||||
http.ServeContent(w, r, info.Name(), info.ModTime(), file)
|
||||
}
|
||||
|
||||
func (s *Server) renderDocumentEditor(w http.ResponseWriter, r *http.Request, pagePath string) {
|
||||
page, err := s.documents.LoadSourcePage(r.Context(), pagePath)
|
||||
if err != nil {
|
||||
@@ -469,6 +531,11 @@ func trimEditSuffix(path string) (string, bool) {
|
||||
return strings.TrimSuffix(path, "/edit"), true
|
||||
}
|
||||
|
||||
func isContentAssetPath(path string) bool {
|
||||
extension := strings.ToLower(filepath.Ext(path))
|
||||
return extension != "" && extension != ".md"
|
||||
}
|
||||
|
||||
func buildBrowser(records []docs.DocumentRecord, activePath string) browserData {
|
||||
paths := make([]string, 0, len(records))
|
||||
titleByPath := make(map[string]string, len(records))
|
||||
|
||||
Reference in New Issue
Block a user