Fixed up the .gitignore

More push to move towards a deployment stage
This commit is contained in:
2025-08-21 20:57:23 -04:00
parent 9502d1b1be
commit e2651456da
12 changed files with 379 additions and 265 deletions

View File

@@ -1,83 +1,95 @@
package config
package storage
import (
"crypto/sha256"
"encoding/hex"
"errors"
"io"
"os"
"gopkg.in/yaml.v3"
"path/filepath"
)
type Config struct {
ShardID string `yaml:"shard_id"`
Listen struct {
HTTP string `yaml:"http"`
HTTPS string `yaml:"https"`
WS string `yaml:"ws"`
} `yaml:"listen"`
TLS struct {
Enable bool `yaml:"enable"`
CertFile string `yaml:"cert_file"`
KeyFile string `yaml:"key_file"`
} `yaml:"tls"`
Federation struct {
MTLSEnable bool `yaml:"mtls_enable"`
Listen string `yaml:"listen"`
CertFile string `yaml:"cert_file"`
KeyFile string `yaml:"key_file"`
ClientCAFile string `yaml:"client_ca_file"`
} `yaml:"federation"`
Storage struct {
Backend string `yaml:"backend"`
Path string `yaml:"path"`
MaxObjectKB int `yaml:"max_object_kb"`
} `yaml:"storage"`
Security struct {
ZeroTrust bool `yaml:"zero_trust"`
RequireMTLSForFederation bool `yaml:"require_mtls_for_federation"`
AcceptClientSignedTokens bool `yaml:"accept_client_signed_tokens"`
LogLevel string `yaml:"log_level"`
} `yaml:"security"`
Privacy struct {
RetainIP string `yaml:"retain_ip"`
RetainUserAgent string `yaml:"retain_user_agent"`
RetainTimestamps string `yaml:"retain_timestamps"`
} `yaml:"privacy"`
Auth struct {
SigningSecret string `yaml:"signing_secret"`
SSO struct {
Discord struct {
Enabled bool `yaml:"enabled"`
ClientID string `yaml:"client_id"`
ClientSecret string `yaml:"client_secret"`
RedirectURI string `yaml:"redirect_uri"`
} `yaml:"discord"`
Google struct {
Enabled bool `yaml:"enabled"`
ClientID string `yaml:"client_id"`
ClientSecret string `yaml:"client_secret"`
RedirectURI string `yaml:"redirect_uri"`
} `yaml:"google"`
Facebook struct {
Enabled bool `yaml:"enabled"`
ClientID string `yaml:"client_id"`
ClientSecret string `yaml:"client_secret"`
RedirectURI string `yaml:"redirect_uri"`
} `yaml:"facebook"`
} `yaml:"sso"`
TwoFactor struct {
WebAuthnEnabled bool `yaml:"webauthn_enabled"`
TOTPEnabled bool `yaml:"totp_enabled"`
} `yaml:"two_factor"`
} `yaml:"auth"`
type FSStore struct {
root string
maxObjectB int64
}
func Load(path string) (*Config, error) {
b, err := os.ReadFile(path)
if err != nil {
func NewFSStore(root string, maxKB int) (*FSStore, error) {
if root == "" {
root = "./data/objects"
}
if err := os.MkdirAll(root, 0o755); err != nil {
return nil, err
}
var c Config
if err := yaml.Unmarshal(b, &c); err != nil {
return nil, err
}
return &c, nil
return &FSStore{root: root, maxObjectB: int64(maxKB) * 1024}, nil
}
func (s *FSStore) Put(r io.Reader) (string, int64, error) {
h := sha256.New()
tmp := filepath.Join(s.root, ".tmp")
_ = os.MkdirAll(tmp, 0o755)
f, err := os.CreateTemp(tmp, "obj-*")
if err != nil {
return "", 0, err
}
defer f.Close()
var n int64
buf := make([]byte, 32*1024)
for {
m, er := r.Read(buf)
if m > 0 {
n += int64(m)
if s.maxObjectB > 0 && n > s.maxObjectB {
return "", 0, errors.New("object too large")
}
_, _ = h.Write(buf[:m])
if _, werr := f.Write(buf[:m]); werr != nil {
return "", 0, werr
}
}
if er == io.EOF {
break
}
if er != nil {
return "", 0, er
}
}
sum := hex.EncodeToString(h.Sum(nil))
dst := filepath.Join(s.root, sum[:2], sum[2:4], sum)
if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil {
return "", 0, err
}
if err := os.Rename(f.Name(), dst); err != nil {
return "", 0, err
}
return sum, n, nil
}
func (s *FSStore) pathFor(hash string) string {
return filepath.Join(s.root, hash[:2], hash[2:4], hash)
}
func (s *FSStore) Get(hash string) (string, error) {
if len(hash) < 4 {
return "", os.ErrNotExist
}
p := s.pathFor(hash)
if _, err := os.Stat(p); err != nil {
return "", err
}
return p, nil
}
func (s *FSStore) Delete(hash string) error {
if len(hash) < 4 {
return os.ErrNotExist
}
p := s.pathFor(hash)
if err := os.Remove(p); err != nil {
return err
}
_ = os.Remove(filepath.Dir(p))
_ = os.Remove(filepath.Dir(filepath.Dir(p)))
return nil
}