parent
							
								
									5e6ce9c2be
								
							
						
					
					
						commit
						245dd64f82
					
				
							
								
								
									
										96
									
								
								handlers.go
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								handlers.go
									
									
									
									
									
								
							@ -8,6 +8,7 @@ import (
 | 
				
			|||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gitea.hashru.nl/dsprenkels/rushlink/internal/db"
 | 
						"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{}{})
 | 
						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) {
 | 
					func (rl *rushlink) viewPasteHandler(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	rl.viewPasteHandlerFlags(w, r, 0)
 | 
						rl.viewPasteHandlerFlags(w, r, 0)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -158,31 +112,61 @@ func (rl *rushlink) viewPasteHandlerInner(w http.ResponseWriter, r *http.Request
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	switch p.State {
 | 
						switch p.State {
 | 
				
			||||||
	case db.PasteStatePresent:
 | 
						case db.PasteStatePresent:
 | 
				
			||||||
		var location string
 | 
					 | 
				
			||||||
		switch p.Type {
 | 
							switch p.Type {
 | 
				
			||||||
		case db.PasteTypeFileUpload:
 | 
							case db.PasteTypeFileUpload:
 | 
				
			||||||
			if fu == nil {
 | 
								if fu == nil {
 | 
				
			||||||
				panic(fmt.Sprintf("file for id %v does not exist in database\n", string(p.Content)))
 | 
									panic(fmt.Sprintf("file for id %v does not exist in database\n", string(p.Content)))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			location = fu.URL().String()
 | 
								rl.viewFileUploadHandler(w, r, fu)
 | 
				
			||||||
			break
 | 
								return
 | 
				
			||||||
		case db.PasteTypeRedirect:
 | 
							case db.PasteTypeRedirect:
 | 
				
			||||||
			location = p.RedirectURL().String()
 | 
								if flags&viewNoRedirect == 0 {
 | 
				
			||||||
			break
 | 
									http.Redirect(w, r, p.RedirectURL().String(), http.StatusSeeOther)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			panic("paste type unsupported")
 | 
								panic("paste type unsupported")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if flags&viewNoRedirect == 0 {
 | 
					
 | 
				
			||||||
			http.Redirect(w, r, location, http.StatusSeeOther)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		fmt.Fprint(w, location)
 | 
					 | 
				
			||||||
	case db.PasteStateDeleted:
 | 
						case db.PasteStateDeleted:
 | 
				
			||||||
		rl.renderError(w, r, http.StatusGone, "paste has been deleted\n")
 | 
							rl.renderError(w, r, http.StatusGone, "paste has been deleted\n")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		panic(errors.Errorf("invalid paste.State (%v) for key '%v'", p.State, p.Key))
 | 
							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) {
 | 
					func (rl *rushlink) viewPasteHandlerInnerMeta(w http.ResponseWriter, r *http.Request, p *db.Paste, fu *db.FileUpload) {
 | 
				
			||||||
	var cd canDelete
 | 
						var cd canDelete
 | 
				
			||||||
	deleteToken := getDeleteTokenFromRequest(r)
 | 
						deleteToken := getDeleteTokenFromRequest(r)
 | 
				
			||||||
 | 
				
			|||||||
@ -99,7 +99,6 @@ func StartMainServer(addr string, db *db.Database, fs *db.FileStore, rawRootURL
 | 
				
			|||||||
	router := mux.NewRouter()
 | 
						router := mux.NewRouter()
 | 
				
			||||||
	router.Use(rl.recoveryMiddleware)
 | 
						router.Use(rl.recoveryMiddleware)
 | 
				
			||||||
	router.Use(rl.metricsMiddleware)
 | 
						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:img/"+staticFilenameExpr+"}", rl.staticGetHandler).Methods("GET", "HEAD")
 | 
				
			||||||
	router.HandleFunc("/{path:css/"+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")
 | 
						router.HandleFunc("/{path:js/"+staticFilenameExpr+"}", rl.staticGetHandler).Methods("GET", "HEAD")
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user