cluster

Infrastructure files for Nordgedanken and Midnightthoughts.
git clone git://archive.git.mtrnord.blog/MTRNord/cluster.git
Log | Files | Refs | README

config.go (2933B)


      1 // config.go — global configuration, account definitions, and age key initialisation.
      2 package main
      3 
      4 import (
      5 	"fmt"
      6 	"log/slog"
      7 	"os"
      8 	"strings"
      9 	"time"
     10 
     11 	"filippo.io/age"
     12 	"maunium.net/go/mautrix/id"
     13 )
     14 
     15 // ourServerName is used to decide whose media and avatars to download.
     16 // Override with S3_SERVER_NAME if needed.
     17 var ourServerName = envOrDefault("SERVER_NAME", "mtrnord.blog")
     18 
     19 type accountCfg struct {
     20 	UserID   id.UserID
     21 	Password string
     22 	SSSSKey  string
     23 	Prefix   string
     24 	StoreDir string
     25 }
     26 
     27 var (
     28 	homeserver    = mustEnv("HOMESERVER")
     29 	s3Endpoint    = mustEnv("S3_ENDPOINT")
     30 	s3BucketName  = mustEnv("S3_BUCKET")
     31 	s3AccessKey   = mustEnv("S3_ACCESS_KEY")
     32 	s3SecretKey   = mustEnv("S3_SECRET_KEY")
     33 	s3Region      = envOrDefault("S3_REGION", "hel1")
     34 	keyExportPass = mustEnv("KEY_EXPORT_PASSPHRASE")
     35 	dateStr       = time.Now().UTC().Format("20060102")
     36 	runStr        = time.Now().UTC().Format("20060102-150405")
     37 
     38 	accounts = []accountCfg{
     39 		{
     40 			UserID:   "@mtrnord:mtrnord.blog",
     41 			Password: os.Getenv("MTRNORD_PASSWORD"),
     42 			SSSSKey:  os.Getenv("MTRNORD_SSSS_KEY"),
     43 			Prefix:   "mtrnord",
     44 			StoreDir: "/data/crypto/mtrnord",
     45 		},
     46 		{
     47 			UserID:   "@lexi:mtrnord.blog",
     48 			Password: os.Getenv("LEXI_PASSWORD"),
     49 			SSSSKey:  os.Getenv("LEXI_SSSS_KEY"),
     50 			Prefix:   "lexi",
     51 			StoreDir: "/data/crypto/lexi",
     52 		},
     53 	}
     54 
     55 	// ageRecipients holds the parsed public keys used to encrypt history files.
     56 	ageRecipients []age.Recipient
     57 
     58 	// ageIdentity is the optional private key used to decrypt files written by
     59 	// this tool (loaded from AGE_PRIVATE_KEY). Allows reading back previously
     60 	// encrypted objects without storing plain copies in S3.
     61 	ageIdentity age.Identity
     62 )
     63 
     64 func mustEnv(key string) string {
     65 	v := os.Getenv(key)
     66 	if v == "" {
     67 		slog.Error("Required environment variable not set", "key", key)
     68 		os.Exit(1)
     69 	}
     70 	return v
     71 }
     72 
     73 func envOrDefault(key, def string) string {
     74 	if v := os.Getenv(key); v != "" {
     75 		return v
     76 	}
     77 	return def
     78 }
     79 
     80 // initAgeRecipients parses a comma-separated list of age public keys.
     81 func initAgeRecipients(s string) error {
     82 	for _, raw := range strings.Split(s, ",") {
     83 		raw = strings.TrimSpace(raw)
     84 		if raw == "" {
     85 			continue
     86 		}
     87 		r, err := age.ParseX25519Recipient(raw)
     88 		if err != nil {
     89 			return fmt.Errorf("invalid age recipient %q: %w", raw, err)
     90 		}
     91 		ageRecipients = append(ageRecipients, r)
     92 	}
     93 	if len(ageRecipients) == 0 {
     94 		return fmt.Errorf("AGE_RECIPIENTS is empty — at least one public key is required")
     95 	}
     96 	return nil
     97 }
     98 
     99 // initAgeIdentity parses an AGE-SECRET-KEY-1… line for decrypting previously
    100 // written .age objects (e.g. the room list, session token).
    101 func initAgeIdentity(privKey string) error {
    102 	privKey = strings.TrimSpace(privKey)
    103 	if privKey == "" {
    104 		return nil
    105 	}
    106 	ids, err := age.ParseIdentities(strings.NewReader(privKey))
    107 	if err != nil {
    108 		return fmt.Errorf("parse age identity: %w", err)
    109 	}
    110 	if len(ids) > 0 {
    111 		ageIdentity = ids[0]
    112 	}
    113 	return nil
    114 }