1package config
2
3import (
4 "errors"
5 "fmt"
6 "io/fs"
7 "os"
8 "path/filepath"
9 "strings"
10)
11
12const AppsDir = "apps.d"
13
14const maxAppsFile = 1 << 20
15
16func readAppsDir(configPath string, cfg *Config) []Problem {
17 dir := filepath.Join(filepath.Dir(configPath), AppsDir)
18 entries, err := os.ReadDir(dir)
19 if errors.Is(err, fs.ErrNotExist) {
20 return nil
21 }
22 if err != nil {
23 return []Problem{{File: dir, Reason: reasonUnreadable}}
24 }
25 used := map[string]bool{cfg.Server.DomainIDP: true, cfg.Server.DomainAccount: true, cfg.Server.DomainAdmin: true}
26 for _, a := range cfg.Apps {
27 used[a.Domain] = true
28 }
29 var problems []Problem
30 for _, e := range entries {
31 if e.IsDir() || !strings.HasSuffix(e.Name(), ".toml") {
32 continue
33 }
34 file := filepath.Join(dir, e.Name())
35 if cfg.Source == sourceGit {
36 problems = append(problems, Problem{File: file, Reason: reasonAppsUnderGit})
37 continue
38 }
39 data, reason := readRegular(file, maxAppsFile, reasonAppsTooLarge, nil)
40 if reason != "" {
41 problems = append(problems, Problem{File: file, Reason: reason})
42 continue
43 }
44 idx, keyProblems := indexKeys(file, data)
45 problems = append(problems, keyProblems...)
46 if idx == nil {
47 continue
48 }
49 others := map[string]bool{}
50 for path := range idx.present {
51 if top, _, _ := strings.Cut(path, "."); !strings.HasPrefix(top, "app[") && top != "app" && !others[top] {
52 problems = append(problems, Problem{File: file, Line: idx.line(top), Key: top, Reason: reasonAppsOnly})
53 others[top] = true
54 }
55 }
56 raw, typed := decodeTyped(file, data, idx, keyProblems)
57 problems = append(problems, typed...)
58 if raw == nil || len(others) > 0 || len(keyProblems) > 0 {
59 continue
60 }
61 v := &validator{file: file, idx: idx}
62 for i, a := range raw.App {
63 prefix := fmt.Sprintf("app[%d]", i)
64 app := v.app(prefix, a, cfg.Session.TTL)
65 if a.Domain != "" && used[a.Domain] {
66 v.add(prefix+".domain", reasonDomainReused)
67 }
68 used[a.Domain] = true
69 cfg.Apps = append(cfg.Apps, app)
70 }
71 problems = append(problems, v.problems...)
72 }
73 return problems
74}