parent
							
								
									5e6ce9c2be
								
							
						
					
					
						commit
						245dd64f82
					
				
							
								
								
									
										96
									
								
								handlers.go
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								handlers.go
									
									
									
									
									
								
							@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"gitea.hashru.nl/dsprenkels/rushlink/internal/db"
 | 
			
		||||
@ -60,53 +61,6 @@ func (rl *rushlink) indexGetHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	rl.render(w, r, "index", map[string]interface{}{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rl *rushlink) uploadFileGetHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	vars := mux.Vars(r)
 | 
			
		||||
	id := vars["id"]
 | 
			
		||||
 | 
			
		||||
	var fu *db.FileUpload
 | 
			
		||||
	var badID bool
 | 
			
		||||
	if err := rl.db.Bolt.View(func(tx *bolt.Tx) error {
 | 
			
		||||
		fuID, err := uuid.Parse(id)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			badID = true
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		fu, err = db.GetFileUpload(tx, fuID)
 | 
			
		||||
		return err
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		if badID {
 | 
			
		||||
			rl.renderError(w, r, http.StatusNotFound, "malformed file id")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// unexpected error
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	filePath := fu.Path(rl.fs)
 | 
			
		||||
	file, err := os.Open(filePath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if os.IsNotExist(err) {
 | 
			
		||||
			log.Printf("error: '%v' should exist according to the database, but it doesn't", filePath)
 | 
			
		||||
			rl.renderError(w, r, http.StatusNotFound, "file not found")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// unexpected error
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	info, err := file.Stat()
 | 
			
		||||
	var modtime time.Time
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Printf("error: %v", errors.Wrapf(err, "could not stat file '%v'", filePath))
 | 
			
		||||
	} else {
 | 
			
		||||
		modtime = info.ModTime()
 | 
			
		||||
	}
 | 
			
		||||
	// We use http.ServeContent (instead of http.ServeFile) because we cannot
 | 
			
		||||
	// use http.ServeFile together with the assertion that the file exists,
 | 
			
		||||
	// without introducing a TOCTOU flaw.
 | 
			
		||||
	http.ServeContent(w, r, fu.FileName, modtime, file)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rl *rushlink) viewPasteHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	rl.viewPasteHandlerFlags(w, r, 0)
 | 
			
		||||
}
 | 
			
		||||
@ -158,31 +112,61 @@ func (rl *rushlink) viewPasteHandlerInner(w http.ResponseWriter, r *http.Request
 | 
			
		||||
 | 
			
		||||
	switch p.State {
 | 
			
		||||
	case db.PasteStatePresent:
 | 
			
		||||
		var location string
 | 
			
		||||
		switch p.Type {
 | 
			
		||||
		case db.PasteTypeFileUpload:
 | 
			
		||||
			if fu == nil {
 | 
			
		||||
				panic(fmt.Sprintf("file for id %v does not exist in database\n", string(p.Content)))
 | 
			
		||||
			}
 | 
			
		||||
			location = fu.URL().String()
 | 
			
		||||
			break
 | 
			
		||||
			rl.viewFileUploadHandler(w, r, fu)
 | 
			
		||||
			return
 | 
			
		||||
		case db.PasteTypeRedirect:
 | 
			
		||||
			location = p.RedirectURL().String()
 | 
			
		||||
			break
 | 
			
		||||
			if flags&viewNoRedirect == 0 {
 | 
			
		||||
				http.Redirect(w, r, p.RedirectURL().String(), http.StatusSeeOther)
 | 
			
		||||
			}
 | 
			
		||||
			return
 | 
			
		||||
		default:
 | 
			
		||||
			panic("paste type unsupported")
 | 
			
		||||
		}
 | 
			
		||||
		if flags&viewNoRedirect == 0 {
 | 
			
		||||
			http.Redirect(w, r, location, http.StatusSeeOther)
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Fprint(w, location)
 | 
			
		||||
 | 
			
		||||
	case db.PasteStateDeleted:
 | 
			
		||||
		rl.renderError(w, r, http.StatusGone, "paste has been deleted\n")
 | 
			
		||||
		return
 | 
			
		||||
	default:
 | 
			
		||||
		panic(errors.Errorf("invalid paste.State (%v) for key '%v'", p.State, p.Key))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rl *rushlink) viewFileUploadHandler(w http.ResponseWriter, r *http.Request, fu *db.FileUpload) {
 | 
			
		||||
	filePath := fu.Path(rl.fs)
 | 
			
		||||
	file, err := os.Open(filePath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if os.IsNotExist(err) {
 | 
			
		||||
			log.Printf("error: '%v' should exist according to the database, but it doesn't", filePath)
 | 
			
		||||
			rl.renderError(w, r, http.StatusNotFound, "file not found")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		// unexpected error
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var modtime time.Time
 | 
			
		||||
	info, err := file.Stat()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Printf("error: %v", errors.Wrapf(err, "could not stat file '%v'", filePath))
 | 
			
		||||
	} else {
 | 
			
		||||
		modtime = info.ModTime()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Provide the real filename to the client (to be used in Ctrl+S etc.)
 | 
			
		||||
	quotedName := strings.ReplaceAll(fu.FileName, "\"", "\\\"")
 | 
			
		||||
	w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=\"%s\"", quotedName))
 | 
			
		||||
 | 
			
		||||
	// We use http.ServeContent (instead of http.ServeFile) because we cannot
 | 
			
		||||
	// use http.ServeFile together with the assertion that the file exists,
 | 
			
		||||
	// without introducing a TOCTOU flaw.
 | 
			
		||||
	http.ServeContent(w, r, fu.FileName, modtime, file)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rl *rushlink) viewPasteHandlerInnerMeta(w http.ResponseWriter, r *http.Request, p *db.Paste, fu *db.FileUpload) {
 | 
			
		||||
	var cd canDelete
 | 
			
		||||
	deleteToken := getDeleteTokenFromRequest(r)
 | 
			
		||||
 | 
			
		||||
@ -99,7 +99,6 @@ func StartMainServer(addr string, db *db.Database, fs *db.FileStore, rawRootURL
 | 
			
		||||
	router := mux.NewRouter()
 | 
			
		||||
	router.Use(rl.recoveryMiddleware)
 | 
			
		||||
	router.Use(rl.metricsMiddleware)
 | 
			
		||||
	router.HandleFunc("/uploads/{id:[A-Za-z0-9-_]+}/{filename:.+}", rl.uploadFileGetHandler).Methods("GET", "HEAD")
 | 
			
		||||
	router.HandleFunc("/{path:img/"+staticFilenameExpr+"}", rl.staticGetHandler).Methods("GET", "HEAD")
 | 
			
		||||
	router.HandleFunc("/{path:css/"+staticFilenameExpr+"}", rl.staticGetHandler).Methods("GET", "HEAD")
 | 
			
		||||
	router.HandleFunc("/{path:js/"+staticFilenameExpr+"}", rl.staticGetHandler).Methods("GET", "HEAD")
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user