Eric Bower
·
2025-07-21
scp_hooks.go
1package prose
2
3import (
4 "fmt"
5 "strings"
6
7 "slices"
8
9 "github.com/picosh/pico/pkg/db"
10 "github.com/picosh/pico/pkg/filehandlers"
11 "github.com/picosh/pico/pkg/pssh"
12 "github.com/picosh/pico/pkg/shared"
13 "github.com/picosh/utils"
14 pipeUtil "github.com/picosh/utils/pipe"
15)
16
17type MarkdownHooks struct {
18 Cfg *shared.ConfigSite
19 Db db.DB
20 Pipe *pipeUtil.ReconnectReadWriteCloser
21}
22
23func (p *MarkdownHooks) FileValidate(s *pssh.SSHServerConnSession, data *filehandlers.PostMetaData) (bool, error) {
24 if !utils.IsTextFile(data.Text) {
25 err := fmt.Errorf(
26 "ERROR: (%s) invalid file must be plain text (utf-8), skipping",
27 data.Filename,
28 )
29 return false, err
30 }
31
32 fp := strings.Replace(data.Filename, "/", "", 1)
33 // special styles css file we want to permit but no other css file.
34 // sometimes the directory is provided in the filename, so we want to
35 // remove that before we perform this check.
36 if fp == "_styles.css" {
37 return true, nil
38 }
39 // allow users to upload robots file
40 if fp == "robots.txt" {
41 return true, nil
42 }
43
44 if !utils.IsExtAllowed(data.Filename, p.Cfg.AllowedExt) {
45 extStr := strings.Join(p.Cfg.AllowedExt, ",")
46 err := fmt.Errorf(
47 "ERROR: (%s) invalid file, format must be (%s), skipping",
48 data.Filename,
49 extStr,
50 )
51 return false, err
52 }
53
54 if data.FileSize > MAX_FILE_SIZE {
55 return false, fmt.Errorf(
56 "ERROR: file (%s) has exceeded maximum file size (%d bytes)",
57 data.Filename,
58 MAX_FILE_SIZE,
59 )
60 }
61
62 return true, nil
63}
64
65func (p *MarkdownHooks) FileMeta(s *pssh.SSHServerConnSession, data *filehandlers.PostMetaData) error {
66 parsedText, err := shared.ParseText(data.Text)
67 if err != nil {
68 return fmt.Errorf("%s: %w", data.Filename, err)
69 }
70
71 if parsedText.Title == "" {
72 data.Title = utils.ToUpper(data.Slug)
73 } else {
74 data.Title = parsedText.Title
75 }
76
77 data.Aliases = parsedText.Aliases
78 data.Tags = parsedText.Tags
79 data.Description = parsedText.Description
80
81 if parsedText.PublishAt != nil && !parsedText.PublishAt.IsZero() {
82 data.PublishAt = parsedText.PublishAt
83 }
84
85 isHiddenFilename := slices.Contains(p.Cfg.HiddenPosts, data.Filename)
86 data.Hidden = parsedText.Hidden || isHiddenFilename
87
88 return nil
89}