all repos — flounder @ 961e4152251afdb819b0e16d4c8674dfc12e20d8

A small site builder for the Gemini protocol

utils.go (view raw)

  1package main
  2
  3import (
  4	"archive/zip"
  5	"fmt"
  6	"io"
  7	"os"
  8	"path"
  9	"path/filepath"
 10	"strings"
 11	"time"
 12)
 13
 14func timeago(t *time.Time) string {
 15	d := time.Since(*t)
 16	if d.Seconds() < 60 {
 17		seconds := int(d.Seconds())
 18		if seconds == 1 {
 19			return "1 second ago"
 20		}
 21		return fmt.Sprintf("%d seconds ago", seconds)
 22	} else if d.Minutes() < 60 {
 23		minutes := int(d.Minutes())
 24		if minutes == 1 {
 25			return "1 minute ago"
 26		}
 27		return fmt.Sprintf("%d minutes ago", minutes)
 28	} else if d.Hours() < 24 {
 29		hours := int(d.Hours())
 30		if hours == 1 {
 31			return "1 hour ago"
 32		}
 33		return fmt.Sprintf("%d hours ago", hours)
 34	} else {
 35		days := int(d.Hours()) / 24
 36		if days == 1 {
 37			return "1 day ago"
 38		}
 39		return fmt.Sprintf("%d days ago", days)
 40	}
 41}
 42
 43// safe
 44func getUserDirectory(username string) string {
 45	// extra filepath.clean just to be safe
 46	userFolder := path.Join(c.FilesDirectory, filepath.Clean(username))
 47	return userFolder
 48}
 49
 50// ugh idk
 51func safeGetFilePath(username string, filename string) string {
 52	return path.Join(getUserDirectory(username), filepath.Clean(filename))
 53}
 54
 55// TODO move into checkIfValidFile. rename it
 56func userHasSpace(user string, newBytes int) bool {
 57	userPath := path.Join(c.FilesDirectory, user)
 58	size, err := dirSize(userPath)
 59	if err != nil || size+int64(newBytes) > c.MaxUserBytes {
 60		return false
 61	}
 62	return true
 63}
 64
 65func dirSize(path string) (int64, error) {
 66	var size int64
 67	err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
 68		if err != nil {
 69			return err
 70		}
 71		if !info.IsDir() {
 72			size += info.Size()
 73		}
 74		return err
 75	})
 76	return size, err
 77}
 78
 79/// Perform some checks to make sure the file is OK
 80func checkIfValidFile(filename string, fileBytes []byte) error {
 81	if len(filename) == 0 {
 82		return fmt.Errorf("Please enter a filename")
 83	}
 84	if len(filename) > 256 { // arbitrarily chosen
 85		return fmt.Errorf("Filename is too long")
 86	}
 87	ext := strings.ToLower(path.Ext(filename))
 88	found := false
 89	for _, mimetype := range c.OkExtensions {
 90		if ext == mimetype {
 91			found = true
 92		}
 93	}
 94	if !found {
 95		return fmt.Errorf("Invalid file extension: %s", ext)
 96	}
 97	if len(fileBytes) > c.MaxFileBytes {
 98		return fmt.Errorf("File too large. File was %d bytes, Max file size is %d", len(fileBytes), c.MaxFileBytes)
 99	}
100	//
101	return nil
102}
103
104func zipit(source string, target io.Writer) error {
105	archive := zip.NewWriter(target)
106
107	info, err := os.Stat(source)
108	if err != nil {
109		return nil
110	}
111
112	var baseDir string
113	if info.IsDir() {
114		baseDir = filepath.Base(source)
115	}
116
117	filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
118		if err != nil {
119			return err
120		}
121
122		header, err := zip.FileInfoHeader(info)
123		if err != nil {
124			return err
125		}
126
127		if baseDir != "" {
128			header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
129		}
130
131		if info.IsDir() {
132			header.Name += "/"
133		} else {
134			header.Method = zip.Deflate
135		}
136
137		writer, err := archive.CreateHeader(header)
138		if err != nil {
139			return err
140		}
141
142		if info.IsDir() {
143			return nil
144		}
145
146		file, err := os.Open(path)
147		if err != nil {
148			return err
149		}
150		defer file.Close()
151		_, err = io.Copy(writer, file)
152		return err
153	})
154
155	archive.Close()
156
157	return err
158}