commit
a5d4f754e7
10
display.go
10
display.go
|
@ -17,6 +17,8 @@ import (
|
||||||
"github.com/zenazn/goji/web"
|
"github.com/zenazn/goji/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const maxDisplayFileSizeBytes = 1024 * 512
|
||||||
|
|
||||||
func fileDisplayHandler(c web.C, w http.ResponseWriter, r *http.Request) {
|
func fileDisplayHandler(c web.C, w http.ResponseWriter, r *http.Request) {
|
||||||
fileName := c.URLParams["name"]
|
fileName := c.URLParams["name"]
|
||||||
filePath := path.Join(Config.filesDir, fileName)
|
filePath := path.Join(Config.filesDir, fileName)
|
||||||
|
@ -29,8 +31,8 @@ func fileDisplayHandler(c web.C, w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
expiry, _ := metadataGetExpiry(fileName)
|
expiry, _ := metadataGetExpiry(fileName)
|
||||||
var expiryHuman string
|
var expiryHuman string
|
||||||
if expiry != 0 {
|
if !expiry.IsZero() {
|
||||||
expiryHuman = humanize.RelTime(time.Now(), time.Unix(expiry, 0), "", "")
|
expiryHuman = humanize.RelTime(time.Now(), expiry, "", "")
|
||||||
}
|
}
|
||||||
sizeHuman := humanize.Bytes(uint64(fileInfo.Size()))
|
sizeHuman := humanize.Bytes(uint64(fileInfo.Size()))
|
||||||
extra := make(map[string]string)
|
extra := make(map[string]string)
|
||||||
|
@ -47,7 +49,7 @@ func fileDisplayHandler(c web.C, w http.ResponseWriter, r *http.Request) {
|
||||||
js, _ := json.Marshal(map[string]string{
|
js, _ := json.Marshal(map[string]string{
|
||||||
"filename": fileName,
|
"filename": fileName,
|
||||||
"mimetype": mimetype,
|
"mimetype": mimetype,
|
||||||
"expiry": strconv.FormatInt(expiry, 10),
|
"expiry": strconv.FormatInt(expiry.Unix(), 10),
|
||||||
"size": strconv.FormatInt(fileInfo.Size(), 10),
|
"size": strconv.FormatInt(fileInfo.Size(), 10),
|
||||||
})
|
})
|
||||||
w.Write(js)
|
w.Write(js)
|
||||||
|
@ -65,7 +67,7 @@ func fileDisplayHandler(c web.C, w http.ResponseWriter, r *http.Request) {
|
||||||
} else if mimetype == "application/pdf" {
|
} else if mimetype == "application/pdf" {
|
||||||
tpl = Templates["display/pdf.html"]
|
tpl = Templates["display/pdf.html"]
|
||||||
} else if supportedBinExtension(extension) {
|
} else if supportedBinExtension(extension) {
|
||||||
if fileInfo.Size() < 500000 {
|
if fileInfo.Size() < maxDisplayFileSizeBytes {
|
||||||
bytes, err := ioutil.ReadFile(filePath)
|
bytes, err := ioutil.ReadFile(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tpl = Templates["display/file.html"]
|
tpl = Templates["display/file.html"]
|
||||||
|
|
29
expiry.go
29
expiry.go
|
@ -4,37 +4,14 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Get what the unix timestamp will be in "seconds".
|
|
||||||
func getFutureTimestamp(seconds int64) (ts int64) {
|
|
||||||
now := int64(time.Now().Unix())
|
|
||||||
|
|
||||||
if seconds == 0 {
|
|
||||||
ts = 0
|
|
||||||
} else {
|
|
||||||
ts = now + seconds
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine if a file with expiry set to "ts" has expired yet
|
// Determine if a file with expiry set to "ts" has expired yet
|
||||||
func isTsExpired(ts int64) (expired bool) {
|
func isTsExpired(ts time.Time) bool {
|
||||||
now := int64(time.Now().Unix())
|
now := time.Now()
|
||||||
|
return !ts.IsZero() && now.After(ts)
|
||||||
if ts == 0 {
|
|
||||||
expired = false
|
|
||||||
} else if now > ts {
|
|
||||||
expired = true
|
|
||||||
} else {
|
|
||||||
expired = false
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine if the given filename is expired
|
// Determine if the given filename is expired
|
||||||
func isFileExpired(filename string) bool {
|
func isFileExpired(filename string) bool {
|
||||||
exp, _ := metadataGetExpiry(filename)
|
exp, _ := metadataGetExpiry(filename)
|
||||||
|
|
||||||
return isTsExpired(exp)
|
return isTsExpired(exp)
|
||||||
}
|
}
|
||||||
|
|
24
meta.go
24
meta.go
|
@ -7,6 +7,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Write metadata from Upload struct to file
|
// Write metadata from Upload struct to file
|
||||||
|
@ -47,29 +48,24 @@ func metadataRead(filename string) ([]string, error) {
|
||||||
return lines, scanner.Err()
|
return lines, scanner.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
func metadataGetExpiry(filename string) (int64, error) {
|
func metadataGetExpiry(filename string) (expiry time.Time, err error) {
|
||||||
metadata, err := metadataRead(filename)
|
metadata, err := metadataRead(filename)
|
||||||
|
|
||||||
if len(metadata) < 1 {
|
|
||||||
err := errors.New("ERR: Metadata file does not contain expiry")
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX in this case it's up to the caller to determine proper behavior
|
// XXX in this case it's up to the caller to determine proper behavior
|
||||||
// for a nonexistant metadata file or broken file
|
// for a nonexistant metadata file or broken file
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var expiry int64
|
if len(metadata) < 1 {
|
||||||
expiry, err = strconv.ParseInt(metadata[0], 10, 32)
|
err = errors.New("ERR: Metadata file does not contain expiry")
|
||||||
|
return
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
} else {
|
|
||||||
return int64(expiry), err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expirySecs, err := strconv.ParseInt(metadata[0], 10, 64)
|
||||||
|
expiry = time.Unix(expirySecs, 0)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func metadataGetDeleteKey(filename string) (string, error) {
|
func metadataGetDeleteKey(filename string) (string, error) {
|
||||||
|
|
21
server.go
21
server.go
|
@ -2,7 +2,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -22,15 +21,15 @@ var Config struct {
|
||||||
bind string
|
bind string
|
||||||
filesDir string
|
filesDir string
|
||||||
metaDir string
|
metaDir string
|
||||||
noLogs bool
|
|
||||||
allowHotlink bool
|
|
||||||
siteName string
|
siteName string
|
||||||
siteURL string
|
siteURL string
|
||||||
fastcgi bool
|
|
||||||
remoteUploads bool
|
|
||||||
contentSecurityPolicy string
|
contentSecurityPolicy string
|
||||||
fileContentSecurityPolicy string
|
fileContentSecurityPolicy string
|
||||||
xFrameOptions string
|
xFrameOptions string
|
||||||
|
noLogs bool
|
||||||
|
allowHotlink bool
|
||||||
|
fastcgi bool
|
||||||
|
remoteUploads bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var Templates = make(map[string]*pongo2.Template)
|
var Templates = make(map[string]*pongo2.Template)
|
||||||
|
@ -52,14 +51,12 @@ func setup() {
|
||||||
// make directories if needed
|
// make directories if needed
|
||||||
err := os.MkdirAll(Config.filesDir, 0755)
|
err := os.MkdirAll(Config.filesDir, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error: could not create files directory")
|
log.Fatal("Could not create files directory:", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.MkdirAll(Config.metaDir, 0700)
|
err = os.MkdirAll(Config.metaDir, 0700)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error: could not create metadata directory")
|
log.Fatal("Could not create metadata directory:", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure siteURL ends wth '/'
|
// ensure siteURL ends wth '/'
|
||||||
|
@ -70,15 +67,13 @@ func setup() {
|
||||||
// Template setup
|
// Template setup
|
||||||
p2l, err := NewPongo2TemplatesLoader()
|
p2l, err := NewPongo2TemplatesLoader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error: could not load templates")
|
log.Fatal("Error: could not load templates", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
TemplateSet := pongo2.NewSet("templates", p2l)
|
TemplateSet := pongo2.NewSet("templates", p2l)
|
||||||
TemplateSet.Globals["sitename"] = Config.siteName
|
TemplateSet.Globals["sitename"] = Config.siteName
|
||||||
err = populateTemplatesMap(TemplateSet, Templates)
|
err = populateTemplatesMap(TemplateSet, Templates)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error: could not load templates")
|
log.Fatal("Error: could not load templates", err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
staticBox = rice.MustFindBox("static")
|
staticBox = rice.MustFindBox("static")
|
||||||
|
|
|
@ -41,8 +41,7 @@ func (fs *Pongo2Loader) Abs(base, name string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func populateTemplatesMap(tSet *pongo2.TemplateSet, tMap map[string]*pongo2.Template) error {
|
func populateTemplatesMap(tSet *pongo2.TemplateSet, tMap map[string]*pongo2.Template) error {
|
||||||
|
templates := []string{
|
||||||
templates := [...]string{
|
|
||||||
"index.html",
|
"index.html",
|
||||||
"paste.html",
|
"paste.html",
|
||||||
"404.html",
|
"404.html",
|
||||||
|
|
15
upload.go
15
upload.go
|
@ -14,6 +14,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"bitbucket.org/taruti/mimemagic"
|
"bitbucket.org/taruti/mimemagic"
|
||||||
"github.com/dchest/uniuri"
|
"github.com/dchest/uniuri"
|
||||||
|
@ -32,7 +33,7 @@ var fileBlacklist = map[string]bool{
|
||||||
type UploadRequest struct {
|
type UploadRequest struct {
|
||||||
src io.Reader
|
src io.Reader
|
||||||
filename string
|
filename string
|
||||||
expiry int64 // Seconds until expiry, 0 = never
|
expiry time.Duration // Seconds until expiry, 0 = never
|
||||||
randomBarename bool
|
randomBarename bool
|
||||||
deletionKey string // Empty string if not defined
|
deletionKey string // Empty string if not defined
|
||||||
}
|
}
|
||||||
|
@ -41,7 +42,7 @@ type UploadRequest struct {
|
||||||
type Upload struct {
|
type Upload struct {
|
||||||
Filename string // Final filename on disk
|
Filename string // Final filename on disk
|
||||||
Size int64
|
Size int64
|
||||||
Expiry int64 // Unix timestamp of expiry, 0=never
|
Expiry time.Time // Unix timestamp of expiry, 0=never
|
||||||
DeleteKey string // Deletion key, one generated if not provided
|
DeleteKey string // Deletion key, one generated if not provided
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,7 +244,9 @@ func processUpload(upReq UploadRequest) (upload Upload, err error) {
|
||||||
defer dst.Close()
|
defer dst.Close()
|
||||||
|
|
||||||
// Get the rest of the metadata needed for storage
|
// Get the rest of the metadata needed for storage
|
||||||
upload.Expiry = getFutureTimestamp(upReq.expiry)
|
if upReq.expiry != 0 {
|
||||||
|
upload.Expiry = time.Now().Add(upReq.expiry)
|
||||||
|
}
|
||||||
|
|
||||||
// If no delete key specified, pick a random one.
|
// If no delete key specified, pick a random one.
|
||||||
if upReq.deletionKey == "" {
|
if upReq.deletionKey == "" {
|
||||||
|
@ -279,7 +282,7 @@ func generateJSONresponse(upload Upload) []byte {
|
||||||
"url": Config.siteURL + upload.Filename,
|
"url": Config.siteURL + upload.Filename,
|
||||||
"filename": upload.Filename,
|
"filename": upload.Filename,
|
||||||
"delete_key": upload.DeleteKey,
|
"delete_key": upload.DeleteKey,
|
||||||
"expiry": strconv.FormatInt(int64(upload.Expiry), 10),
|
"expiry": strconv.FormatInt(upload.Expiry.Unix(), 10),
|
||||||
"size": strconv.FormatInt(upload.Size, 10),
|
"size": strconv.FormatInt(upload.Size, 10),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -302,7 +305,7 @@ func barePlusExt(filename string) (barename, extension string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseExpiry(expStr string) int64 {
|
func parseExpiry(expStr string) time.Duration {
|
||||||
if expStr == "" {
|
if expStr == "" {
|
||||||
return 0
|
return 0
|
||||||
} else {
|
} else {
|
||||||
|
@ -310,7 +313,7 @@ func parseExpiry(expStr string) int64 {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0
|
return 0
|
||||||
} else {
|
} else {
|
||||||
return int64(expiry)
|
return time.Duration(expiry) * time.Second
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue