All import paths updated to git.wntrmute.dev/mc/. Bumps mcdsl to v1.2.0. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
97 lines
2.1 KiB
Go
97 lines
2.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
"os"
|
|
"syscall"
|
|
|
|
"github.com/spf13/cobra"
|
|
"golang.org/x/term"
|
|
|
|
"git.wntrmute.dev/mc/metacrypt/internal/barrier"
|
|
"git.wntrmute.dev/mc/metacrypt/internal/config"
|
|
"git.wntrmute.dev/mc/metacrypt/internal/crypto"
|
|
"git.wntrmute.dev/mc/metacrypt/internal/db"
|
|
"git.wntrmute.dev/mc/metacrypt/internal/seal"
|
|
)
|
|
|
|
var initCmd = &cobra.Command{
|
|
Use: "init",
|
|
Short: "Interactive first-time setup",
|
|
Long: "Initialize Metacrypt with a seal password. This must be run before the server can be used.",
|
|
RunE: runInit,
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(initCmd)
|
|
}
|
|
|
|
func runInit(cmd *cobra.Command, args []string) error {
|
|
configPath := cfgFile
|
|
if configPath == "" {
|
|
configPath = "/srv/metacrypt/metacrypt.toml"
|
|
}
|
|
|
|
cfg, err := config.Load(configPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
database, err := db.Open(cfg.Database.Path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() { _ = database.Close() }()
|
|
|
|
if err := db.Migrate(database); err != nil {
|
|
return err
|
|
}
|
|
|
|
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
|
|
b := barrier.NewAESGCMBarrier(database)
|
|
sealMgr := seal.NewManager(database, b, nil, logger)
|
|
if err := sealMgr.CheckInitialized(); err != nil {
|
|
return err
|
|
}
|
|
if sealMgr.State() != seal.StateUninitialized {
|
|
return fmt.Errorf("already initialized")
|
|
}
|
|
|
|
fmt.Print("Enter seal password: ")
|
|
pw1, err := term.ReadPassword(int(syscall.Stdin))
|
|
fmt.Println()
|
|
if err != nil {
|
|
return fmt.Errorf("reading password: %w", err)
|
|
}
|
|
|
|
fmt.Print("Confirm seal password: ")
|
|
pw2, err := term.ReadPassword(int(syscall.Stdin))
|
|
fmt.Println()
|
|
if err != nil {
|
|
return fmt.Errorf("reading password: %w", err)
|
|
}
|
|
|
|
if !crypto.ConstantTimeEqual(pw1, pw2) {
|
|
return fmt.Errorf("passwords do not match")
|
|
}
|
|
|
|
params := crypto.Argon2Params{
|
|
Time: cfg.Seal.Argon2Time,
|
|
Memory: cfg.Seal.Argon2Memory,
|
|
Threads: cfg.Seal.Argon2Threads,
|
|
}
|
|
|
|
fmt.Println("Initializing (this may take a moment)...")
|
|
if err := sealMgr.Initialize(context.Background(), pw1, params); err != nil {
|
|
return err
|
|
}
|
|
|
|
crypto.Zeroize(pw1)
|
|
crypto.Zeroize(pw2)
|
|
|
|
fmt.Println("Metacrypt initialized and unsealed successfully.")
|
|
return nil
|
|
}
|