package cert import ( "crypto/sha256" "encoding/hex" "fmt" "os" "path/filepath" "sync" ) type Storage struct { basePath string certs map[string]*Certificate mu sync.RWMutex } type Certificate struct { ID string OriginalPath string StoredPath string Password string } func NewStorage(basePath string) *Storage { if basePath == "" { basePath = "./certs/" } return &Storage{ basePath: basePath, certs: make(map[string]*Certificate), } } func (s *Storage) Init() error { if err := os.MkdirAll(s.basePath, 0700); err != nil { return fmt.Errorf("creating cert storage directory: %w", err) } return nil } func (s *Storage) Store(id, origPath, password string) (string, error) { s.mu.Lock() defer s.mu.Unlock() exists := false for _, c := range s.certs { if c.ID == id { exists = true break } } if exists { return "", fmt.Errorf("certificate already exists with this ID") } ext := filepath.Ext(origPath) storedFilename := fmt.Sprintf("%s%s", id, ext) storedPath := filepath.Join(s.basePath, storedFilename) data, err := os.ReadFile(origPath) if err != nil { return "", fmt.Errorf("reading certificate file: %w", err) } if err := os.WriteFile(storedPath, data, 0600); err != nil { return "", fmt.Errorf("storing certificate: %w", err) } cert := &Certificate{ ID: id, OriginalPath: origPath, StoredPath: storedPath, Password: password, } s.certs[id] = cert return storedPath, nil } func (s *Storage) Get(id string) (*Certificate, error) { s.mu.RLock() defer s.mu.RUnlock() cert, ok := s.certs[id] if !ok { return nil, fmt.Errorf("certificate not found") } return cert, nil } func (s *Storage) Delete(id string) error { s.mu.Lock() defer s.mu.Unlock() cert, ok := s.certs[id] if !ok { return fmt.Errorf("certificate not found") } if err := os.Remove(cert.StoredPath); err != nil { return fmt.Errorf("removing certificate file: %w", err) } delete(s.certs, id) return nil } func GenerateID() string { hash := sha256.Sum256([]byte(fmt.Sprintf("%d", os.Getpid()))) return hex.EncodeToString(hash[:])[:16] }