// Copyright 2026 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package credstore // Prober is an optional interface that a Store can implement to test // whether its backend is available. type Prober interface { Probe() bool } // DefaultSecureStore creates a SecureStore with the given codec and sensible defaults. // The primary backend is an EncryptedFileStore writing to filePath+".enc" // with its master key in the OS keyring; see EncryptedFileStore for why only // the key lives there. When the keyring is unavailable, it falls back to // plaintext file storage at filePath. func DefaultSecureStore[T any](serviceName, filePath string, codec Codec[T]) *SecureStore[T] { return NewSecureStore[T]( NewEncryptedFileStore[T](serviceName, filePath+".enc", codec), NewFileStore[T](filePath, codec)) } // SecureStore is a composite Store that uses the keyring-backed primary // store when the keyring is available and falls back to file-based storage // otherwise. The active backend is chosen once at construction time. type SecureStore[T any] struct { active Store[T] } // NewSecureStore creates a SecureStore. If kr implements Prober and the probe // succeeds, kr is used as the active store. Otherwise, file is used as the // fallback. func NewSecureStore[T any](kr, file Store[T]) *SecureStore[T] { if p, ok := kr.(Prober); ok && p.Probe() { return &SecureStore[T]{active: kr} } return &SecureStore[T]{active: file} } // Load loads data from the active store. func (s *SecureStore[T]) Load(clientID string) (T, error) { return s.active.Load(clientID) } // Save saves data to the active store. func (s *SecureStore[T]) Save(clientID string, data T) error { return s.active.Save(clientID, data) } // Delete removes data from the active store. func (s *SecureStore[T]) Delete(clientID string) error { return s.active.Delete(clientID) } // String returns a description of the active store. func (s *SecureStore[T]) String() string { return s.active.String() }