all repos — postern @ main

Modern mail management

internal/persistence/persistence.go (view raw)

 1package persistence
 2
 3import (
 4	"errors"
 5	"fmt"
 6	"os"
 7)
 8
 9type Config struct {
10	BlobRoot      string
11	MasterkeyFile string
12}
13type Persistence struct {
14	blobRoot  string
15	masterkey []byte
16}
17
18func New(config Config) (*Persistence, error) {
19	if config.MasterkeyFile == "" {
20		return nil, errors.New("no masterkey file specified")
21	}
22
23	blobRoot := "./data/blobs"
24	if config.BlobRoot != "" {
25		blobRoot = config.BlobRoot
26	}
27
28	if err := ensureBlobsDir(blobRoot); err != nil {
29		return nil, err
30	}
31
32	// the master key used to derive encryption keys
33	masterkey, err := os.ReadFile(config.MasterkeyFile)
34	if err != nil {
35		return nil, fmt.Errorf("cannot read postern masterkey: %w", err)
36	}
37
38	return &Persistence{
39		blobRoot:  blobRoot,
40		masterkey: masterkey,
41	}, nil
42}
43
44func (p *Persistence) BlobRoot() string {
45	return p.blobRoot
46}
47
48func ensureBlobsDir(path string) error {
49	if err := os.MkdirAll(path, 0700); err != nil {
50		return fmt.Errorf("creating blobs directory %s: %w", path, err)
51	}
52	return nil
53}
54
55// CheckDirWritable ensures that the persistence layer can write to the given directory
56func CheckDirWritable(dir string) error {
57	if dir == "" {
58		return errors.New("no path given")
59	}
60	info, err := os.Stat(dir)
61	if err != nil {
62		if os.IsNotExist(err) {
63			return fmt.Errorf("directory does not exist: %s", dir)
64		}
65		return fmt.Errorf("failed to stat directory: %w", err)
66	}
67
68	// Ensure it's a directory
69	if !info.IsDir() {
70		return fmt.Errorf("path is not a directory: %s", dir)
71	}
72
73	// Test writability by creating a temporary file
74	writeTest, err := os.CreateTemp(dir, ".write_test")
75	if err != nil {
76		return fmt.Errorf("directory is not writable: %w", err)
77	}
78	_ = writeTest.Close()
79
80	// Clean up the test file
81	err = os.Remove(writeTest.Name())
82	if err != nil {
83		return fmt.Errorf("directory is writable but not deletable: %w", err)
84	}
85
86	return nil
87}