Antonio Mika
·
2026-10-10
1package feeds
2
3import (
4 "errors"
5 "fmt"
6 "net/url"
7 "strings"
8
9 "github.com/adhocore/gronx"
10 "github.com/picosh/pico/pkg/db"
11 "github.com/picosh/pico/pkg/filehandlers"
12 "github.com/picosh/pico/pkg/pssh"
13 "github.com/picosh/pico/pkg/shared"
14)
15
16type FeedHooks struct {
17 Cfg *shared.ConfigSite
18 Db db.DB
19}
20
21func (p *FeedHooks) FileValidate(s *pssh.SSHServerConnSession, data *filehandlers.PostMetaData) (bool, error) {
22 if !shared.IsTextFile(string(data.Text)) {
23 err := fmt.Errorf(
24 "WARNING: (%s) invalid file must be plain text (utf-8), skipping",
25 data.Filename,
26 )
27 return false, err
28 }
29
30 if !shared.IsExtAllowed(data.Filename, p.Cfg.AllowedExt) {
31 extStr := strings.Join(p.Cfg.AllowedExt, ",")
32 err := fmt.Errorf(
33 "WARNING: (%s) invalid file, format must be (%s), skipping",
34 data.Filename,
35 extStr,
36 )
37 return false, err
38 }
39
40 // SFTP validates a file when it is opened, before its contents
41 // arrive, so there is nothing to parse yet.
42 if data.Text == "" {
43 return true, nil
44 }
45
46 parsed := shared.ListParseText(string(data.Text))
47 if parsed.Email == "" {
48 return false, fmt.Errorf("ERROR: no email variable detected for %s, check the format of your file, skipping", data.Filename)
49 }
50
51 if parsed.DigestInterval != "" {
52 return false, fmt.Errorf("ERROR: `digest_interval` is deprecated; use `cron`: https://pico.sh/feeds#cron")
53 }
54
55 if parsed.Cron != "" {
56 if !gronx.IsValid(parsed.Cron) {
57 return false, fmt.Errorf("ERROR: `cron` is invalid, reference: https://github.com/adhocore/gronx?tab=readme-ov-file#cron-expression")
58 }
59 }
60
61 var allErr error
62 for _, txt := range parsed.Items {
63 u := ""
64 if txt.IsText {
65 u = txt.Value
66 } else if txt.IsURL {
67 u = string(txt.URL)
68 }
69
70 _, err := url.Parse(u)
71 if err != nil {
72 allErr = errors.Join(allErr, fmt.Errorf("%s: %w", u, err))
73 continue
74 }
75 }
76 if allErr != nil {
77 return false, fmt.Errorf("ERROR: some urls provided were invalid check the format of your file, skipping: %w", allErr)
78 }
79
80 return true, nil
81}
82
83func (p *FeedHooks) FileMeta(s *pssh.SSHServerConnSession, data *filehandlers.PostMetaData) error {
84 return nil
85}