rin
Публичный Open-source lightweight git hosting.
media.go · 81 строка · 1.8 KB
Raw
1 package handlers
2
3 import (
4 "encoding/base64"
5 "errors"
6 "io"
7 "net/http"
8 "strings"
9
10 "github.com/gofiber/fiber/v2"
11 )
12
13 const (
14 maxAvatarImageBytes = 2 << 20
15 maxBackgroundImageBytes = 6 << 20
16 )
17
18 var (
19 errImageTooLarge = errors.New("image is too large")
20 errImageType = errors.New("unsupported image type")
21 )
22
23 func validImageDataURI(value string) bool {
24 for _, prefix := range []string{
25 "data:image/png;base64,",
26 "data:image/jpeg;base64,",
27 "data:image/webp;base64,",
28 "data:image/gif;base64,",
29 } {
30 if strings.HasPrefix(value, prefix) {
31 return true
32 }
33 }
34 return false
35 }
36
37 // readImageField accepts either a browser-resized data URI or a multipart
38 // upload for one image field. An empty result means the field was not changed.
39 func readImageField(c *fiber.Ctx, dataField, fileField string, maxBytes int64) (string, error) {
40 if data := strings.TrimSpace(c.FormValue(dataField)); data != "" {
41 if !validImageDataURI(data) {
42 return "", errImageType
43 }
44 if int64(len(data)) > maxBytes*4/3+4096 {
45 return "", errImageTooLarge
46 }
47 return data, nil
48 }
49
50 file, err := c.FormFile(fileField)
51 if err != nil || file == nil || file.Size <= 0 {
52 return "", nil
53 }
54 if file.Size > maxBytes {
55 return "", errImageTooLarge
56 }
57
58 f, err := file.Open()
59 if err != nil {
60 return "", err
61 }
62 defer f.Close()
63
64 buf, err := io.ReadAll(io.LimitReader(f, maxBytes+1))
65 if err != nil {
66 return "", err
67 }
68 if int64(len(buf)) > maxBytes {
69 return "", errImageTooLarge
70 }
71 mime := http.DetectContentType(buf)
72 if semi := strings.IndexByte(mime, ';'); semi >= 0 {
73 mime = mime[:semi]
74 }
75 switch mime {
76 case "image/png", "image/jpeg", "image/gif", "image/webp":
77 default:
78 return "", errImageType
79 }
80 return "data:" + mime + ";base64," + base64.StdEncoding.EncodeToString(buf), nil
81 }
82