larc r12

173 lines ยท 4.0 KB Raw
1 package server
2
3 import (
4 "fmt"
5 "os"
6
7 "gopkg.in/yaml.v3"
8 )
9
10 /* Server configuration loaded from YAML.
11 * Supports TLS, Basic Auth via htpasswd, and per-repo access control. */
12
13 // Config is the server configuration
14 type Config struct {
15 Server ServerConfig `yaml:"server"`
16 Auth AuthConfig `yaml:"auth"`
17 Storage StorageConfig `yaml:"storage"`
18 Logging LoggingConfig `yaml:"logging"`
19 Repos []RepoConfig `yaml:"repositories"`
20 }
21
22 // ServerConfig contains HTTP server settings
23 type ServerConfig struct {
24 Host string `yaml:"host"`
25 Port int `yaml:"port"`
26 BaseURL string `yaml:"base_url"`
27 TLS TLSConfig `yaml:"tls"`
28 }
29
30 // TLSConfig contains TLS settings
31 type TLSConfig struct {
32 Enabled bool `yaml:"enabled"`
33 Cert string `yaml:"cert"`
34 Key string `yaml:"key"`
35 }
36
37 // AuthConfig contains authentication settings
38 type AuthConfig struct {
39 Enabled bool `yaml:"enabled"`
40 HtpasswdFile string `yaml:"htpasswd_file"`
41 Realm string `yaml:"realm"`
42 }
43
44 // StorageConfig contains storage settings
45 type StorageConfig struct {
46 Root string `yaml:"root"`
47 MaxRepoSize string `yaml:"max_repo_size"`
48 MaxFileSize string `yaml:"max_file_size"`
49 }
50
51 // LoggingConfig contains logging settings
52 type LoggingConfig struct {
53 Level string `yaml:"level"` // debug, info, warn, error
54 Format string `yaml:"format"` // json, text
55 File string `yaml:"file"` // log file path (empty for stdout)
56 }
57
58 // RepoConfig is per-repository configuration
59 type RepoConfig struct {
60 Name string `yaml:"name"`
61 Path string `yaml:"path"` // relative to storage.root
62 Description string `yaml:"description"` // optional description
63 Public bool `yaml:"public"` // allow anonymous read
64 AllowedUsers []string `yaml:"allowed_users"` // full access
65 ReadOnlyUsers []string `yaml:"read_only_users"` // read-only access
66 }
67
68 // LoadConfig loads configuration from YAML file
69 func LoadConfig(path string) (*Config, error) {
70 data, err := os.ReadFile(path)
71 if err != nil {
72 return nil, fmt.Errorf("read config: %w", err)
73 }
74
75 cfg := &Config{}
76 if err := yaml.Unmarshal(data, cfg); err != nil {
77 return nil, fmt.Errorf("parse config: %w", err)
78 }
79
80 /* apply defaults */
81 if cfg.Server.Host == "" {
82 cfg.Server.Host = "0.0.0.0"
83 }
84 if cfg.Server.Port == 0 {
85 cfg.Server.Port = 8080
86 }
87 if cfg.Auth.Realm == "" {
88 cfg.Auth.Realm = "Larc Repository"
89 }
90 if cfg.Logging.Level == "" {
91 cfg.Logging.Level = "info"
92 }
93 if cfg.Logging.Format == "" {
94 cfg.Logging.Format = "json"
95 }
96
97 return cfg, nil
98 }
99
100 // DefaultConfig returns default configuration
101 func DefaultConfig() *Config {
102 return &Config{
103 Server: ServerConfig{
104 Host: "0.0.0.0",
105 Port: 8080,
106 },
107 Auth: AuthConfig{
108 Enabled: false,
109 Realm: "Larc Repository",
110 },
111 Storage: StorageConfig{
112 Root: "./repos",
113 MaxRepoSize: "10GB",
114 MaxFileSize: "100MB",
115 },
116 Logging: LoggingConfig{
117 Level: "info",
118 Format: "json",
119 },
120 }
121 }
122
123 // Validate validates the configuration
124 func (c *Config) Validate() error {
125 if c.Auth.Enabled && c.Auth.HtpasswdFile == "" {
126 return fmt.Errorf("auth enabled but htpasswd_file not set")
127 }
128
129 if c.Server.TLS.Enabled {
130 if c.Server.TLS.Cert == "" || c.Server.TLS.Key == "" {
131 return fmt.Errorf("TLS enabled but cert or key not set")
132 }
133 }
134
135 return nil
136 }
137
138 // GetRepoConfig returns config for a specific repository
139 func (c *Config) GetRepoConfig(name string) *RepoConfig {
140 for i := range c.Repos {
141 if c.Repos[i].Name == name {
142 return &c.Repos[i]
143 }
144 }
145 return nil
146 }
147
148 // IsUserAllowed checks if user has access to repository
149 func (r *RepoConfig) IsUserAllowed(username string, writeAccess bool) bool {
150 /* public repos allow anonymous read */
151 if r.Public && !writeAccess && username == "" {
152 return true
153 }
154
155 /* check allowed users (full access) */
156 for _, u := range r.AllowedUsers {
157 if u == username {
158 return true
159 }
160 }
161
162 /* check read-only users */
163 if !writeAccess {
164 for _, u := range r.ReadOnlyUsers {
165 if u == username {
166 return true
167 }
168 }
169 }
170
171 return false
172 }
173