urit/internal/config/config.go
2026-05-02 21:11:50 -04:00

149 lines
3.6 KiB
Go

package config
import (
"fmt"
"os"
"github.com/BurntSushi/toml"
)
// Config is the top-level configuration for URIT BBS.
type Config struct {
System SystemConfig `toml:"system"`
Telnet TelnetConfig `toml:"telnet"`
SSH SSHConfig `toml:"ssh"`
HTTP HTTPConfig `toml:"http"`
Storage StorageConfig `toml:"storage"`
Users UsersConfig `toml:"users"`
Logging LoggingConfig `toml:"logging"`
}
// SystemConfig holds general BBS identity and paths.
type SystemConfig struct {
Name string `toml:"name"`
Sysop string `toml:"sysop"`
Location string `toml:"location"`
Screens string `toml:"screens"`
}
// TelnetConfig controls the telnet listener.
type TelnetConfig struct {
Enabled bool `toml:"enabled"`
Address string `toml:"address"`
}
// SSHConfig controls the SSH listener.
type SSHConfig struct {
Enabled bool `toml:"enabled"`
Address string `toml:"address"`
HostKey string `toml:"host_key"`
}
// HTTPConfig controls the HTTP file server.
// This serves file libraries for download via browser — the modern
// replacement for ZMODEM and other transfer protocols.
type HTTPConfig struct {
Enabled bool `toml:"enabled"`
Address string `toml:"address"`
}
// StorageConfig selects and configures the storage backend.
type StorageConfig struct {
Driver string `toml:"driver"`
SQLitePath string `toml:"sqlite_path"`
}
// SecurityLevel defines access levels for a user tier.
type SecurityLevel struct {
Status int `toml:"status"`
Board int `toml:"board"`
Library int `toml:"library"`
Bulletin int `toml:"bulletin"`
}
// UsersConfig holds user account defaults.
type UsersConfig struct {
MaxAccounts int `toml:"max_accounts"`
GuestTimeLimit int `toml:"guest_time_limit"`
NewTimeLimit int `toml:"new_time_limit"`
ValidTimeLimit int `toml:"valid_time_limit"`
GuestSecurity SecurityLevel `toml:"guest_security"`
NewSecurity SecurityLevel `toml:"new_security"`
ValidSecurity SecurityLevel `toml:"valid_security"`
}
// LoggingConfig controls log output.
type LoggingConfig struct {
Level string `toml:"level"`
File string `toml:"file"`
}
// Load reads a TOML config file from the given path and returns a Config.
// If the file does not exist, it returns a Config populated with defaults.
func Load(path string) (*Config, error) {
cfg := defaults()
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return cfg, nil
}
return nil, fmt.Errorf("reading config %s: %w", path, err)
}
if err := toml.Unmarshal(data, cfg); err != nil {
return nil, fmt.Errorf("parsing config %s: %w", path, err)
}
return cfg, nil
}
// defaults returns a Config with sensible default values.
// These match the values in the shipped config.toml.
func defaults() *Config {
return &Config{
System: SystemConfig{
Name: "URIT BBS",
Sysop: "Sysop",
Location: "./data/",
Screens: "./screens/",
},
Telnet: TelnetConfig{
Enabled: true,
Address: ":2323",
},
SSH: SSHConfig{
Enabled: false,
Address: ":2222",
HostKey: "./data/ssh_host_key",
},
HTTP: HTTPConfig{
Enabled: true,
Address: ":8080",
},
Storage: StorageConfig{
Driver: "sqlite",
SQLitePath: "./data/urit.db",
},
Users: UsersConfig{
MaxAccounts: 500,
GuestTimeLimit: 1800,
NewTimeLimit: 3600,
ValidTimeLimit: 7200,
GuestSecurity: SecurityLevel{
Status: 0, Board: 0, Library: 0, Bulletin: 0,
},
NewSecurity: SecurityLevel{
Status: 1, Board: 1, Library: 1, Bulletin: 1,
},
ValidSecurity: SecurityLevel{
Status: 2, Board: 2, Library: 2, Bulletin: 2,
},
},
Logging: LoggingConfig{
Level: "info",
File: "",
},
}
}